This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: Change to GOT initialization?
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Jason R Thorpe <thorpej at wasabisystems dot com>, binutils at sources dot redhat dot com
- Date: Thu, 28 Nov 2002 08:45:31 +1030
- Subject: Re: Change to GOT initialization?
- References: <20021127212624.GA7858@yeah-baby.shagadelic.org>
On Wed, Nov 27, 2002 at 01:26:24PM -0800, Jason R Thorpe wrote:
> The way we compute our relocation base is:
>
> bl _GLOBAL_OFFSET_TABLE_@local-4
> mflr %r31 # r31 = (real) GOT
> lwz %r30,_GLOBAL_OFFSET_TABLE_@got(31)
> # the linker thought GOT were ...
> subf %r4,%r30,%r31 # r4 = relocbase
>
> ...but this falls over completely, because 0 ends up being loaded
> info %r30, so we can't compute the relocbase (nor can we compute
> the real address of _DYNAMIC, since we don't know the relocbase to
> add to the base-relative offset in _DYNAMIC's GOT entry).
>
> So, I guess I have two questions:
>
> 1. Can anyone tell me when this change was made, and why?
http://sources.redhat.com/ml/binutils/2002-09/msg00322.html
http://sources.redhat.com/ml/libc-alpha/2002-09/msg00630.html
> 2. Can anyone suggest a way for me to deal with the problem
> (I guess the question really is: Can anyone suggest another
> way for me to compute the relocbase?)
Extract from glibc/sysdeps/powerpc/powerpc32/dl-machine.h
Instead, we use the following trick:
The linker puts the _link-time_ address of _DYNAMIC at the first
word in the GOT. We could branch to that address, if we wanted,
by using an @local reloc; the linker works this out, so it's safe
to use now. We can't, of course, actually branch there, because
we'd cause an illegal instruction exception; so we need to compute
the address ourselves. That gives us the following code: */
/* Get address of the 'b _DYNAMIC@local'... */
asm ("bl 0f ;"
"b _DYNAMIC@local;"
"0:"
: "=l"(branchaddr));
/* ... and the address of the GOT. */
asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
: "=l"(got));
/* So now work out the difference between where the branch actually points,
and the offset of that location in memory from the start of the file. */
return ((Elf32_Addr)branchaddr - *got
+ ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
}
--
Alan Modra
IBM OzLabs - Linux Technology Centre