On the alpha elf target there are basically two types of functions, they are marked with .prologue 0 or .prologue 1 by the compiler. The difference is setup of the gp register for access to variables via GOT. The caller restores this register after the call, but in some cases setup can be skipped and restoration NOP'd. I think we are hitting a case where such an optimization is erroneously applied in NetBSD when linking threaded programs statically. The original bug report is here: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=48709 The problem happens with a weak symbol function of type ".prologue 0" being overwritten by another implementation of type ".prologue 1". In the NetBSD case the issue is obscured a bit more by symbol renaming, but I think the below code demonstrates the mis-relaxation already (unless I misunderstand something). With this code in "main.c": --8<-- #include <stdio.h> int external_init_used = 0; __attribute__((weak)) void subsys_init(void) { /* do nothing */ } int main(int argc, char **argv) { subsys_init(); if (external_init_used) printf("something overwrote subsys_init\n"); else printf("our own subsys_init stub has been used\n"); return 0; } -->8-- and this in "extern.c": --8<-- #include <stdio.h> extern int external_init_used; void subsys_init(void) { external_init_used = 1; printf("initializing...\n"); } -->8-- use this command line: cc -static -Wall -O2 main.c extern.c For details, check with -S and see that .prologue values differ between the stub in main.c and the overwrite in extern.c. Also note that gcc did generate correct code (including restoring gp after the call to subsys_init). Now invoke gdb on the resulting binary and look at the call to subsys_init: (gdb) x/16i main 0x120026d40 <main>: ldah gp,2(t12) 0x120026d44 <main+4>: lda gp,11112(gp) 0x120026d48 <main+8>: lda sp,-16(sp) 0x120026d4c <main+12>: stq ra,0(sp) 0x120026d50 <main+16>: unop 0x120026d54 <main+20>: bsr ra,0x1200003d8 <subsys_init+8> 0x120026d58 <main+24>: unop 0x120026d5c <main+28>: unop Note the +8 offset for the subsys_init call, which means gp setup will be skipped. The last two lines are stubbed out reload instructions for the gp register ldah $29,0($26) !gpdisp!7 lda $29,0($29) !gpdisp!7 This relaxation would be valid if the final call target would be the stub in main.c, but as the weak symbol is overwritten they are invalid.
This has been fixed by: author Alan Modra <amodra@gmail.com> Sat, 14 Dec 2013 02:40:04 +0000 (12:40 +1030) committer Alan Modra <amodra@gmail.com> Sat, 14 Dec 2013 02:44:03 +0000 (12:44 +1030) commit 57fa7b8c7e59e35bced580f9bcb9668af43fdbce Correct elf_merge_st_other arguments for weak symbols * elflink.c (_bfd_elf_merge_symbol): If merging a new weak symbol that will be skipped, we don't have a new definition.