This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
MIPS multigot fixes for Linux
- From: Daniel Jacobowitz <drow at mvista dot com>
- To: binutils at sources dot redhat dot com
- Cc: Atsushi Nemoto <anemo at mba dot ocn dot ne dot jp>,Richard Sandiford <rsandifo at redhat dot com>,Eric Christopher <echristo at redhat dot com>
- Date: Tue, 11 Nov 2003 12:35:17 -0500
- Subject: MIPS multigot fixes for Linux
I humbly request an opinion from Richard S, who understands this stuff a
whole lot better than I do. This is based on his earlier message:
http://sources.redhat.com/ml/binutils/2003-06/msg00724.html
This patch fixes two bugs. The first is that, as Richard described, glibc
needs a zero in the GOT entry for a global symbol or else it has a tendency
to treat that value as an addend and add the resolved value to it. This is
an incompatibility. I'm sticking with !SGI_COMPAT(output_bfd); there is
room in the glibc loader to vary the ABI if someone has a reason to fix all
this someday. I'd recommend changing the special value used to identify GNU
objects in got[1].
The other issue is that we must not emit stubs for multiple-got symbols.
There are two reasons:
- Efficiency. We need to resolve the symbol at start time anyway so why
do it lazily also? Plus this would require tweaking the dynamic linker;
this appears to be why SGI has R_MIPS_RELGOT.
- Stub simplicity. Our stubs do not load $gp. Therefore, if they are
called from a function with a different GOT, they will fail to load
_dl_runtime_resolve. *boom*.
We already knew this. Unfortunately, somehow, we ended up setting
no_fn_stub after reading it.
Look OK? If you prefer I think the no_fn_stub setting below could be moved
into the else branch, since the second time is redundant. I'm not thrilled
with how complicated the uses of mips_elf_set_global_got_offset are; it's
really three different functions with the same outer if test.
I believe this patch will fix Atsushi-san's testcase.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer
2003-11-11 Daniel Jacobowitz <drow@mvista.com>
* elfxx-mips.c (mips_elf_set_global_got_offset): Set no_fn_stub
in the first pass.
(_bfd_mips_elf_finish_dynamic_symbol): Fill global GOT entries with
zero for ! SGI_COMPAT.
Index: elfxx-mips.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/bfd/elfxx-mips.c,v
retrieving revision 1.78
diff -u -p -r1.78 elfxx-mips.c
--- elfxx-mips.c 13 Oct 2003 19:51:09 -0000 1.78
+++ elfxx-mips.c 11 Nov 2003 17:00:24 -0000
@@ -2333,15 +2333,19 @@ mips_elf_set_global_got_offset (entryp,
if (entry->abfd != NULL && entry->symndx == -1
&& entry->d.h->root.dynindx != -1)
{
+ /* We can't do lazy update of GOT entries for non-primary GOTs since
+ the PLT entries don't use the right offsets, so punt at it for now.
+ We set this here because we are called via mips_elf_multi_got
+ before _bfd_mips_elf_adjust_dynamic_symbol reads the no_fn_stub
+ flag; this only matters for the global case, but
+ _bfd_mips_elf_size_dynamic_sections is too late. */
+ entry->d.h->no_fn_stub = TRUE;
+
if (g)
{
BFD_ASSERT (g->global_gotsym == NULL);
entry->gotidx = arg->value * (long) g->assigned_gotno++;
- /* We can't do lazy update of GOT entries for
- non-primary GOTs since the PLT entries don't use the
- right offsets, so punt at it for now. */
- entry->d.h->no_fn_stub = TRUE;
if (arg->info->shared
|| (elf_hash_table (arg->info)->dynamic_sections_created
&& ((entry->d.h->root.elf_link_hash_flags
@@ -6693,18 +6697,25 @@ _bfd_mips_elf_finish_dynamic_symbol (out
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
- if ((info->shared
- || (elf_hash_table (info)->dynamic_sections_created
- && p->d.h != NULL
- && ((p->d.h->root.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
- && ((p->d.h->root.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)))
- && ! (mips_elf_create_dynamic_relocation
- (output_bfd, info, rel,
- e.d.h, NULL, value, &addend, sgot)))
- return FALSE;
- BFD_ASSERT (addend == 0);
+ if (info->shared
+ || (elf_hash_table (info)->dynamic_sections_created
+ && p->d.h != NULL
+ && ((p->d.h->root.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+ && ((p->d.h->root.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+ {
+ /* Unfortunately this is another one of the differences
+ between glibc and the Irix rld. */
+ if (!SGI_COMPAT (output_bfd))
+ MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents + offset);
+
+ if (! (mips_elf_create_dynamic_relocation
+ (output_bfd, info, rel,
+ e.d.h, NULL, value, &addend, sgot)))
+ return FALSE;
+ BFD_ASSERT (addend == 0);
+ }
}
}
}