Bug 17205 - alpha procedure call invalid relaxation
Summary: alpha procedure call invalid relaxation
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.23
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-07-27 15:21 UTC by Martin Husemann
Modified: 2014-08-12 07:02 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Husemann 2014-07-27 15:21:38 UTC
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.
Comment 1 Martin Husemann 2014-08-12 07:02:36 UTC
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.