MIPS multi-got link support
Alexandre Oliva
aoliva@redhat.com
Tue Jan 14 05:08:00 GMT 2003
Ok, so, GNU ld is finally up to the task of bootstrapping the entire
toolchain on IRIX, including gdb, that would formerly fail to link due
to GOT overflow.
The multi-got strategy I came up with was significantly different from
that used on IRIX. Instead of using DT_MIPS_AUX_DYNAMIC to point to
additional GOTs, I thought it was saner to just use explicit
relocations, so we wouldn't have to touch other mips dynamic linkers
(say, the one in glibc, for mips-linux) to cope with additional
.dynamic sections. The downside is that we spend some more space with
dynamic relocations, especially on shared libraries, that take one
dynamic relocation per local GOT entry in GOTs other than the primary.
I considered it a very reasonable trade-off.
Another downsize is that symbols referenced from the non-primary GOT
can't be resolved lazily at the moment, mainly because this would take
a significant amount of additional effort to generate additional stubs
that could fetch (resolved) addresses from the primary GOT then jump
to them, after adjusting $gp so that, if the function wasn't resolved
yet, things would work. And even though this would work for o32, it
would get trickier for n32 and n64, since $gp is call-saved for them.
Not that it can't be done (I have some untested ideas), it's just far
trickier. I found it saner to just force dynamic resolution for such
symbols, at least for now.
I used this multi-got code to build a lot of executables and shared
libraries in all of o32, n32 and n64 ABIs, and they all worked
beautifully. Of course, it would have been meaningless without some
additional tricks I used to force the code to be exercised, since only
building gdb required multi-got at first. In my debugging code, I had
environment variables I could set to (a) force multi-got mode on
regardless of the initially-estimated got size, (b) disable merging of
GOTs of different input BFDs into a single GOT and (c) disable the use
of the primary GOT by any input BFDs that need GOT entries. Even for
inputs as tricky as glibc's libc.so and ld.so, I managed to use all
combinations of (a), (b) and (c) to build a working libc.so, and both
(a) and (b) to build a working ld.so. It wouldn't work with (c) just
because there's some code in the dynamic loader that assumes $gp
points to the primary got, and this assumption didn't hold when (c)
was used.
I had to move most of the code that sized the .got section to another
function that gets called earlier, because... erhm... I'm sure I had
a good reason for that at some point, and I *think* it had to do with
allocating dynamic relocations too late otherwise, but now I can't see
how this could have been the case, but I'd rather not try to change it
back at this time, since I know there are a number of other changes
that actually depend on the early GOT splitting (updating counters
during symbol hiding comes to mind).
Yeah, testcases, I hear someone screaming :-) Well, there's gdb, that
actually requires multi-got. I tested it with glibc, that does not by
default, but it's the ultimate linker test, and I could actually
exercise all of the multi-got code with it (and uncover and fix a
number of bugs in the process) by means of the
environment-variable-controlled flags that I used during testing, as
described above. I doubt any reasonably-sized testcase would actually
be useful, and we'd still face the problem of deciding whether to
introduce (undocumented?) linker command-line flags that could be used
to force such non-standard behavior as (a), (b) and (c). I'd be happy
to offer an additional patch that introduced the code I used for
testing, but I don't think it should be enabled by default, therefore
it can't be used for testing... Tricky, eh? :-)
Oh, while working on this patch, I actually fixed a few additional
problems that I ran into. IRIX has this odd EF_MIPS_XGOT bit set in
one of the object files of its BSD-compatibility library; I found a
reference to the name XGOT in Google somewhere, so I brought it into
include/elf and decided we'd be better off simply ignoring that bit
for now. It doesn't seem to have any effect I could tell by linking
gdb (which was what exposed the problem at first). Another problem
that was fixed was that non-hidden weak undefined symbols would have
their GOT entries initialized with junk. Another problem was that the
GP offset was incorrect for GNU/Linux (not that it matters a lot, it
was only used in relocatable links, and only really mattered if you
had REL relocations that would have overflown their addends by a few
bytes), and we didn't generate ELF64 PLT stubs (and the comment next
to the last entry in LW_STUB was broken). I could split them into
separate patches, but...
Oh, one more nit: if you do a multi-got link with object files that
add code to .init/.fini, you'll have to double-check the assumption
that $gp is already properly initialized for your code. I had to fix
this in GCC's crtbegin/crtend, for one, in a separate patch I'm
posting to the GCC list momentarily.
Anyway, enough rambling, the patch is big enough :-) Here it is. Ok
to install?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: include-mips-multi-got.patch
Type: text/x-patch
Size: 706 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20030114/4d988f94/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bfd-mips-multi-got.patch
Type: text/x-patch
Size: 72023 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20030114/4d988f94/attachment-0001.bin>
-------------- next part --------------
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer
More information about the Binutils
mailing list