On Sat, 2015-10-03 at 18:34 -0400, Rich Felker wrote: > > > > I found and fixed the problem, but I have a new concern: calls to the > > new shift instructions are using the following address forms: > > > > -mno-fdpic -fPIC: > > .long __ashlsi3_r0@GOTOFF > > > > -mfdpic: > > .long __ashlsi3_r0-(.LPCS1+2) > > > > Neither of these seems valid. Both assume __ashlsi3_r0 will be defined > > in the same DSO, which is not true in general; shared libgcc_s.so > > might be in use. In this case the call would need to go through the > > PLT, which (for PIC or FDPIC) requires r12 to be loaded with the GOT > > address. In the non-FDPIC case, r12 _happens_ to contain the GOT > > address just because it was used as an addend to get the function > > address from the @GOTOFF address, but this does not seem > > safe/reliable. In the FDPIC case there's nothing to cause r12 to > > contain the GOT address, and in fact if the function has already made > > another function call (which uses and clobbers r12), no code is > > generated to save and restore r12 for the libgcc call.
I might be missing something, but usually R12 is preserved across function calls. The special functions in libgcc tell the compiler exactly which things they clobber and which not. R12 is not clobbered by the shift functions. > > Calls to other functions lib libgcc (e.g. division) seem to work fine > > and either go through the PLT or bypass it and load from the GOT > > directly. It's only these new special-calling-convention ones that are > > broken, and I can't figure out why... Sorry, I wasn't paying attention to dynamic linking or *PIC when changing the shift patterns back then, so maybe I've screwed up something there. To me it looks like they do the same thing as expanders for division or the SH1 multiplication ("mulsi3" pattern). Each of the libgcc support functions have a different "ABI", so "__ashlsi3_r0" or "__lshrsi3_r0" doesn't introduce a new special ABI, it already is as per definition. These function calls are not expanded like regular function calls, via e.g. (define_expand "call" ... ). The function call is hidden from the regular function call machinery and everything thinks it's a regular instruction that just has some special register constraints and clobbers. I've just tried compiling the following with -m2 -ml -fPIC unsigned int test_2 (unsigned int x, unsigned int y) { return x << y; } unsigned int test_3 (unsigned int x, unsigned int y) { return x / y; } And the compiled code is basically identically for both. For the labels I get: .L4: .long _GLOBAL_OFFSET_TABLE_ .L5: .long ___ashlsi3_r0@GOTOFF and .L10: .long _GLOBAL_OFFSET_TABLE_ .L11: .long ___udivsi3@GOTOFF So the shifts do not work, but the divisions do work that way? > Hmm, according to sh-protos.h: > > /* A special function that should be linked statically. These are typically > smaller or not much larger than a PLT entry. > Some also have a non-standard ABI which precludes dynamic linking. */ > SFUNC_STATIC > > So apparently the strange behavior I observed is intended. Presumably > there is some mechanism to ensure that these functions are always > static-linked? But I don't see it. The libgcc spec I see is: > > *libgcc: > %{static|static-libgcc:-lgcc > -lgcc_eh}%{!static:%{!static-libgcc:%{!shared-libgcc:-lgcc --as-needed > -lgcc_s --no-as-needed}%{shared-libgcc:-lgcc_s%{!shared: -lgcc}}}} > > This explicitly omits -lgcc when -shared-libgcc is used with -shared. > Thankfully __ashlsi3_r0 is not exported from libgcc.so.1 (as far as I > can tell), so this will just be a link error rather than horribly > wrong behavior, but it still seems like there's a bug here unless I'm > misunderstanding something. I think the final %{!shared: -lgcc} in the > spec is an error and should be replaced by simply -lgcc if there are > targets where libgcc.a contains necessary symbols that are not/cannot > be defined in libgcc_s.so.1. Hm, maybe, but I don't know enough about this, sorry. Kaz, maybe you have a comment on that? Cheers, Oleg