The compiler generates two different relocs for the same function call, which causes the linker to get confused.
----- Input ----- #include "pthread.h" #include <map> #include <ext/pool_allocator.h> typedef __gnu_cxx::__pool_alloc<std::pair<int const, int> > myalloc; int main() { std::map<int, int, std::less<int>, myalloc> y; pthread_mutex_lock(0); } ----------------- build with: mipsel-linux-g++ -Os -fno-inline -c foo.cc (No command line flags are required; they don't appear to make a difference, but the examples here will reflect those above.) In this code chunk, pthread_mutex_lock is called from two places. The first is from inside the allocator, the second is directly in main. From the allocator, a R_MIPS_GOT16/R_MIPS_LO16 reloc is generated. From main(), a R_MIPS_CALL16 reloc is generated. 0000001c <__gthread_mutex_lock(pthread_mutex_t*)>: 1c: 3c1c0000 lui gp,0x0 1c: R_MIPS_HI16 _gp_disp 20: 279c0000 addiu gp,gp,0 20: R_MIPS_LO16 _gp_disp 24: 0399e021 addu gp,gp,t9 28: 27bdffe0 addiu sp,sp,-32 2c: afbf001c sw ra,28(sp) 30: afb00018 sw s0,24(sp) 34: afbc0010 sw gp,16(sp) 38: 8f990000 lw t9,0(gp) 38: R_MIPS_GOT16 .text 3c: 27390000 addiu t9,t9,0 3c: R_MIPS_LO16 .text 40: 0320f809 jalr t9 44: 00808021 move s0,a0 48: 10400008 beqz v0,6c <__gthread_mutex_lock(pthread_mutex_t*)+0x 50> 4c: 8fbc0010 lw gp,16(sp) 50: 8f990000 lw t9,0(gp) 50: R_MIPS_GOT16 pthread_mutex_lock 54: 02002021 move a0,s0 58: 8fbf001c lw ra,28(sp) 5c: 8fb00018 lw s0,24(sp) 60: 27390000 addiu t9,t9,0 60: R_MIPS_LO16 pthread_mutex_lock 64: 03200008 jr t9 68: 27bd0020 addiu sp,sp,32 6c: 8fbf001c lw ra,28(sp) 70: 8fb00018 lw s0,24(sp) 74: 03e00008 jr ra 78: 27bd0020 addiu sp,sp,32 000000dc <main>: dc: 3c1c0000 lui gp,0x0 dc: R_MIPS_HI16 _gp_disp e0: 279c0000 addiu gp,gp,0 e0: R_MIPS_LO16 _gp_disp e4: 0399e021 addu gp,gp,t9 e8: 27bdffc8 addiu sp,sp,-56 ec: afbf0034 sw ra,52(sp) f0: afb00030 sw s0,48(sp) f4: afbc0010 sw gp,16(sp) f8: 8f990000 lw t9,0(gp) f8: R_MIPS_CALL16 std::map<int, int, std::less<int >, __gnu_cxx::__pool_alloc<std::pair<int const, int> > >::map() fc: 27b00018 addiu s0,sp,24 100: 0320f809 jalr t9 104: 02002021 move a0,s0 108: 8fbc0010 lw gp,16(sp) 10c: 8f990000 lw t9,0(gp) 10c: R_MIPS_CALL16 pthread_mutex_lock 110: 0320f809 jalr t9 114: 00002021 move a0,zero 118: 8fbc0010 lw gp,16(sp) 11c: 8f990000 lw t9,0(gp) 11c: R_MIPS_CALL16 std::map<int, int, std::less<int >, __gnu_cxx::__pool_alloc<std::pair<int const, int> > >::~map() 120: 0320f809 jalr t9 124: 02002021 move a0,s0 128: 8fbc0010 lw gp,16(sp) 12c: 8fbf0034 lw ra,52(sp) 130: 8fb00030 lw s0,48(sp) 134: 00001021 move v0,zero 138: 03e00008 jr ra 13c: 27bd0038 addiu sp,sp,56 When the linker sees the R_MIPS_CALL16, it decides that a PLT entry should be generated for the symbol, and thusly changes its object-modification behavior for *all* invocations of the function. The R_MIPS_CALL16 relocs are then linked correctly, but the R_MIPS_GOT16 are linked incorrectly. This is just as likely a bug in the linker as it is in the compiler, but gcc 4.0.0 (the only other version I have tested) doesn't have this problem. It is more consistent and generates R_MIPS_CALL16 in both cases. If this is not a bug in the compiler, I'll report to binutils. -- Summary: Compiler generates two different relocs for the same symbol Product: gcc Version: 4.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: atgraham at gmail dot com GCC host triplet: i686-pc-linux-gnu GCC target triplet: mipsel-linux http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33169