This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: MIPS multigot fixes for Linux
Richard Sandiford <rsandifo@redhat.com> writes:
> Just thinking... maybe the _bfd_mips_elf_finish_dynamic_symbol code
> could look like this? Then we wouldn't have any pesky SGI_COMPAT tests.
> Haven't tested this at all though.
Now I have, and it doesn't work. create_dynamic_relocation quite rightly
does nothing with existing R_MIPS_REL32 relocations. If we want to reuse
the compatibility logic, we should be passing it an R_MIPS_32 or R_MIPS_64
entry instead.
Updated patch below. Tested:
- by bootstrapping & regression testing on mips-sgi-irix6.5 (n32 & n64)
- against the binutils, gas & ld testsuites, targets: mips64-linux-gnu,
mips64el-linux-gnu and mips-sgi-irix6.5
- mocking up an executable multi-got testcase and verifying that it works
for all three ABIs on mips64-linux-gnu
- running the same test case on mips-sgi-irix6.5 and verifying that the
test now passes for n32 & n64 (it failed before)
The test case causes ld to segfault for o32 on mips-sgi-irix6.5,
but for unrelated reasons. Same thing happened before the patch.
OK to install?
Richard
2003-11-26 Daniel Jacobowitz <drow@mvista.com>
Richard Sandiford <rsandifo@redhat.com>
* elfxx-mips.c (mips_elf_set_global_got_offset): Don't set no_fn_stub.
(mips_elf_set_no_stub): New function.
(mips_elf_multi_got): Call it.
(_bfd_mips_elf_finish_dynamic_symbol): If a relocation is needed for
a secondary GOT entry, create an R_MIPS_32 or R_MIPS_64 entry and
use mips_elf_create_dynamic_relocation to deal with any compatibility
issues. Store the adjusted addend in the GOT slot.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.82
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.82 elfxx-mips.c
*** bfd/elfxx-mips.c 14 Nov 2003 16:05:13 -0000 1.82
--- bfd/elfxx-mips.c 26 Nov 2003 20:32:04 -0000
*************** static int mips_elf_bfd2got_entry_eq PAR
*** 471,476 ****
--- 471,477 ----
static int mips_elf_make_got_per_bfd PARAMS ((void **, void *));
static int mips_elf_merge_gots PARAMS ((void **, void *));
static int mips_elf_set_global_got_offset PARAMS ((void**, void *));
+ static int mips_elf_set_no_stub PARAMS ((void **, void *));
static int mips_elf_resolve_final_got_entry PARAMS ((void**, void *));
static void mips_elf_resolve_final_got_entries
PARAMS ((struct mips_got_info *));
*************** mips_elf_set_global_got_offset (entryp,
*** 2338,2347 ****
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
--- 2339,2344 ----
*************** mips_elf_set_global_got_offset (entryp,
*** 2357,2362 ****
--- 2354,2376 ----
return 1;
}
+ /* Mark any global symbols referenced in the GOT we are iterating over
+ as inelligible for lazy resolution stubs. */
+ static int
+ mips_elf_set_no_stub (entryp, p)
+ void **entryp;
+ void *p ATTRIBUTE_UNUSED;
+ {
+ struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+
+ if (entry->abfd != NULL
+ && entry->symndx == -1
+ && entry->d.h->root.dynindx != -1)
+ entry->d.h->no_fn_stub = TRUE;
+
+ return 1;
+ }
+
/* Follow indirect and warning hash entries so that each got entry
points to the final symbol definition. P must point to a pointer
to the hash table we're traversing. Since this traversal may
*************** mips_elf_multi_got (abfd, info, g, got,
*** 2624,2629 ****
--- 2638,2648 ----
g->next = gg->next;
gg->next = g;
g = gn;
+
+ /* Mark global symbols in every non-primary GOT as ineligible for
+ stubs. */
+ if (g)
+ htab_traverse (g->got_entries, mips_elf_set_no_stub, NULL);
}
while (g);
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6660,6669 ****
if (g->next && h->dynindx != -1)
{
struct mips_got_entry e, *p;
bfd_vma offset;
- bfd_vma value;
- Elf_Internal_Rela rel[3];
- bfd_vma addend = 0;
gg = g;
--- 6679,6686 ----
if (g->next && h->dynindx != -1)
{
struct mips_got_entry e, *p;
+ bfd_vma entry;
bfd_vma offset;
gg = g;
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6671,6688 ****
e.symndx = -1;
e.d.h = (struct mips_elf_link_hash_entry *)h;
- if (info->shared
- || h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
- value = 0;
- else if (sym->st_value)
- value = sym->st_value;
- else
- value = h->root.u.def.value;
-
- memset (rel, 0, sizeof (rel));
- rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_REL32);
-
for (g = g->next; g->next != gg; g = g->next)
{
if (g->got_entries
--- 6688,6693 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6690,6711 ****
&e)))
{
offset = p->gotidx;
! rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset;
!
! 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);
}
}
}
--- 6695,6731 ----
&e)))
{
offset = p->gotidx;
! 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)))
! {
! /* Create an R_MIPS_REL32 relocation for this entry. Due to
! the various compatibility problems, it's easier to mock
! up an R_MIPS_32 or R_MIPS_64 relocation and leave
! mips_elf_create_dynamic_relocation to calculate the
! appropriate addend. */
! Elf_Internal_Rela rel[3];
!
! memset (rel, 0, sizeof (rel));
! if (ABI_64_P (output_bfd))
! rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_64);
! else
! rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_32);
! rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset;
! entry = 0;
! if (! (mips_elf_create_dynamic_relocation
! (output_bfd, info, rel,
! e.d.h, NULL, sym->st_value, &entry, sgot)))
! return FALSE;
! }
! else
! entry = sym->st_value;
! MIPS_ELF_PUT_WORD (output_bfd, entry, sgot->contents + offset);
}
}
}