mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
bfd/
* elfxx-mips.c (GGA_NORMAL, GGA_RELOC_ONLY, GGA_NONE): New macros. (mips_elf_link_hash_entry): Add a "global_got_area" field. (mips_elf_link_hash_newfunc): Initialize it. (mips_elf_sort_hash_table_f): Use h->global_got_area instead of h->root.got.offset. Do not handle forced_local symbols specially. (mips_elf_record_global_got_symbol): Set h->global_got_area instead of h->root.got.offset. (mips_elf_recreate_got): Assert that h->global_got_area == GGA_NONE for indirect and warning symbols. (mips_elf_count_forced_local_got_symbols): Change the argument from a "elf_link_hash_entry" to "mips_elf_link_hash_entry". Use and set h->global_got_area instead of h->root.got.offset. Set it to GGA_NONE for all forced-local symbols. (mips_elf_set_global_got_offset): Set h->global_got_area instead of h->root.got.offset. Use g->global_got_area instead of a combination of dynindx, forced_local and tls_type. (mips_elf_multi_got): Remove disabled code. Pass GGA_* values to mips_elf_set_global_got_offset. (mips_elf_lay_out_got): Use mips_elf_link_hash_traverse instead of elf_link_hash_traverse. (_bfd_mips_elf_copy_indirect_symbol): Copy the indirect symbol's global_got_area to the direct symbol if the latter's value is higher. Set the indirect symbol's area to GGA_NONE. ld/testsuite/ * ld-mips-elf/got-vers-1a.s, ld-mips-elf/got-vers-1b.s, ld-mips-elf/got-vers-1.ver, ld-mips-elf/got-vers-1.dd, ld-mips-elf/got-vers-1.sd, ld-mips-elf/got-vers-1.rd: New tests. * ld-mips-elf/mips-elf.exp: Run them.
This commit is contained in:
parent
33bb52fb4e
commit
634835aefb
@ -1,3 +1,29 @@
|
||||
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* elfxx-mips.c (GGA_NORMAL, GGA_RELOC_ONLY, GGA_NONE): New macros.
|
||||
(mips_elf_link_hash_entry): Add a "global_got_area" field.
|
||||
(mips_elf_link_hash_newfunc): Initialize it.
|
||||
(mips_elf_sort_hash_table_f): Use h->global_got_area instead of
|
||||
h->root.got.offset. Do not handle forced_local symbols specially.
|
||||
(mips_elf_record_global_got_symbol): Set h->global_got_area
|
||||
instead of h->root.got.offset.
|
||||
(mips_elf_recreate_got): Assert that h->global_got_area == GGA_NONE
|
||||
for indirect and warning symbols.
|
||||
(mips_elf_count_forced_local_got_symbols): Change the argument
|
||||
from a "elf_link_hash_entry" to "mips_elf_link_hash_entry".
|
||||
Use and set h->global_got_area instead of h->root.got.offset.
|
||||
Set it to GGA_NONE for all forced-local symbols.
|
||||
(mips_elf_set_global_got_offset): Set h->global_got_area
|
||||
instead of h->root.got.offset. Use g->global_got_area instead
|
||||
of a combination of dynindx, forced_local and tls_type.
|
||||
(mips_elf_multi_got): Remove disabled code. Pass GGA_* values to
|
||||
mips_elf_set_global_got_offset.
|
||||
(mips_elf_lay_out_got): Use mips_elf_link_hash_traverse instead
|
||||
of elf_link_hash_traverse.
|
||||
(_bfd_mips_elf_copy_indirect_symbol): Copy the indirect symbol's
|
||||
global_got_area to the direct symbol if the latter's value is higher.
|
||||
Set the indirect symbol's area to GGA_NONE.
|
||||
|
||||
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* elf32-mips.c (elf_backend_hide_symbol): Delete.
|
||||
|
146
bfd/elfxx-mips.c
146
bfd/elfxx-mips.c
@ -241,6 +241,27 @@ struct _mips_elf_section_data
|
||||
#define mips_elf_section_data(sec) \
|
||||
((struct _mips_elf_section_data *) elf_section_data (sec))
|
||||
|
||||
/* The ABI says that every symbol used by dynamic relocations must have
|
||||
a global GOT entry. Among other things, this provides the dynamic
|
||||
linker with a free, directly-indexed cache. The GOT can therefore
|
||||
contain symbols that are not referenced by GOT relocations themselves
|
||||
(in other words, it may have symbols that are not referenced by things
|
||||
like R_MIPS_GOT16 and R_MIPS_GOT_PAGE).
|
||||
|
||||
GOT relocations are less likely to overflow if we put the associated
|
||||
GOT entries towards the beginning. We therefore divide the global
|
||||
GOT entries into two areas: "normal" and "reloc-only". Entries in
|
||||
the first area can be used for both dynamic relocations and GP-relative
|
||||
accesses, while those in the "reloc-only" area are for dynamic
|
||||
relocations only.
|
||||
|
||||
These GGA_* ("Global GOT Area") values are organised so that lower
|
||||
values are more general than higher values. Also, non-GGA_NONE
|
||||
values are ordered by the position of the area in the GOT. */
|
||||
#define GGA_NORMAL 0
|
||||
#define GGA_RELOC_ONLY 1
|
||||
#define GGA_NONE 2
|
||||
|
||||
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
|
||||
the dynamic symbols. */
|
||||
|
||||
@ -303,6 +324,9 @@ struct mips_elf_link_hash_entry
|
||||
overloaded already. */
|
||||
bfd_vma tls_got_offset;
|
||||
|
||||
/* The highest GGA_* value that satisfies all references to this symbol. */
|
||||
unsigned int global_got_area : 2;
|
||||
|
||||
/* True if one of the relocations described by possibly_dynamic_relocs
|
||||
is against a readonly section. */
|
||||
unsigned int readonly_reloc : 1;
|
||||
@ -868,6 +892,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
|
||||
ret->call_stub = NULL;
|
||||
ret->call_fp_stub = NULL;
|
||||
ret->tls_type = GOT_NORMAL;
|
||||
ret->global_got_area = GGA_NONE;
|
||||
ret->readonly_reloc = FALSE;
|
||||
ret->no_fn_stub = FALSE;
|
||||
ret->need_fn_stub = FALSE;
|
||||
@ -2948,27 +2973,26 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
|
||||
if (h->root.dynindx == -1)
|
||||
return TRUE;
|
||||
|
||||
/* Global symbols that need GOT entries that are not explicitly
|
||||
referenced are marked with got offset 2. Those that are
|
||||
referenced get a 1, and those that don't need GOT entries get
|
||||
-1. Forced local symbols may also be marked with got offset 1,
|
||||
but are never given global GOT entries. */
|
||||
if (h->root.got.offset == 2)
|
||||
switch (h->global_got_area)
|
||||
{
|
||||
case GGA_NONE:
|
||||
h->root.dynindx = hsd->max_non_got_dynindx++;
|
||||
break;
|
||||
|
||||
case GGA_NORMAL:
|
||||
BFD_ASSERT (h->tls_type == GOT_NORMAL);
|
||||
|
||||
h->root.dynindx = --hsd->min_got_dynindx;
|
||||
hsd->low = (struct elf_link_hash_entry *) h;
|
||||
break;
|
||||
|
||||
case GGA_RELOC_ONLY:
|
||||
BFD_ASSERT (h->tls_type == GOT_NORMAL);
|
||||
|
||||
if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
|
||||
hsd->low = (struct elf_link_hash_entry *) h;
|
||||
h->root.dynindx = hsd->max_unref_got_dynindx++;
|
||||
}
|
||||
else if (h->root.got.offset != 1 || h->root.forced_local)
|
||||
h->root.dynindx = hsd->max_non_got_dynindx++;
|
||||
else
|
||||
{
|
||||
BFD_ASSERT (h->tls_type == GOT_NORMAL);
|
||||
|
||||
h->root.dynindx = --hsd->min_got_dynindx;
|
||||
hsd->low = (struct elf_link_hash_entry *) h;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -2984,10 +3008,12 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
|
||||
unsigned char tls_flag)
|
||||
{
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
struct mips_elf_link_hash_entry *hmips;
|
||||
struct mips_got_entry entry, **loc;
|
||||
struct mips_got_info *g;
|
||||
|
||||
htab = mips_elf_hash_table (info);
|
||||
hmips = (struct mips_elf_link_hash_entry *) h;
|
||||
|
||||
/* A global symbol in the GOT must also be in the dynamic symbol
|
||||
table. */
|
||||
@ -3034,14 +3060,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
|
||||
|
||||
memcpy (*loc, &entry, sizeof entry);
|
||||
|
||||
if (h->got.offset != MINUS_ONE)
|
||||
return TRUE;
|
||||
|
||||
if (tls_flag == 0)
|
||||
/* By setting this to a value other than -1, we are indicating that
|
||||
there needs to be a GOT entry for H. Avoid using zero, as the
|
||||
generic ELF copy_indirect_symbol tests for <= 0. */
|
||||
h->got.offset = 1;
|
||||
hmips->global_got_area = GGA_NORMAL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -3296,7 +3316,10 @@ mips_elf_recreate_got (void **entryp, void *data)
|
||||
h = entry->d.h;
|
||||
while (h->root.root.type == bfd_link_hash_indirect
|
||||
|| h->root.root.type == bfd_link_hash_warning)
|
||||
h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
|
||||
{
|
||||
BFD_ASSERT (h->global_got_area == GGA_NONE);
|
||||
h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
|
||||
}
|
||||
entry->d.h = h;
|
||||
}
|
||||
slot = htab_find_slot (*new_got, entry, INSERT);
|
||||
@ -3340,26 +3363,26 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* An elf_link_hash_traverse callback for which DATA points to a mips_got_info.
|
||||
Add each forced-local GOT symbol to DATA's local_gotno field. */
|
||||
/* A mips_elf_link_hash_traverse callback for which DATA points
|
||||
to a mips_got_info. Add each forced-local GOT symbol to DATA's
|
||||
local_gotno field. */
|
||||
|
||||
static int
|
||||
mips_elf_count_forced_local_got_symbols (struct elf_link_hash_entry *h,
|
||||
mips_elf_count_forced_local_got_symbols (struct mips_elf_link_hash_entry *h,
|
||||
void *data)
|
||||
{
|
||||
struct mips_got_info *g;
|
||||
|
||||
g = (struct mips_got_info *) data;
|
||||
if (h->got.offset != MINUS_ONE
|
||||
&& (h->forced_local || h->dynindx == -1))
|
||||
if (h->global_got_area != GGA_NONE
|
||||
&& (h->root.forced_local || h->root.dynindx == -1))
|
||||
{
|
||||
/* We no longer need this entry if it was only used for
|
||||
relocations; those relocations will be against the
|
||||
null or section symbol instead of H. */
|
||||
if (h->got.offset == 2)
|
||||
h->got.offset = MINUS_ONE;
|
||||
else
|
||||
if (h->global_got_area != GGA_RELOC_ONLY)
|
||||
g->local_gotno++;
|
||||
h->global_got_area = GGA_NONE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -3725,10 +3748,9 @@ mips_elf_set_global_got_offset (void **entryp, void *p)
|
||||
mips_tls_got_relocs (arg->info, entry->tls_type,
|
||||
entry->symndx == -1 ? &entry->d.h->root : NULL);
|
||||
|
||||
if (entry->abfd != NULL && entry->symndx == -1
|
||||
&& entry->d.h->root.dynindx != -1
|
||||
&& !entry->d.h->root.forced_local
|
||||
&& entry->d.h->tls_type == GOT_NORMAL)
|
||||
if (entry->abfd != NULL
|
||||
&& entry->symndx == -1
|
||||
&& entry->d.h->global_got_area != GGA_NONE)
|
||||
{
|
||||
if (g)
|
||||
{
|
||||
@ -3742,7 +3764,7 @@ mips_elf_set_global_got_offset (void **entryp, void *p)
|
||||
++arg->needed_relocs;
|
||||
}
|
||||
else
|
||||
entry->d.h->root.got.offset = arg->value;
|
||||
entry->d.h->global_got_area = arg->value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -3908,47 +3930,17 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
|
||||
*bfdgotp = bfdgot;
|
||||
}
|
||||
|
||||
/* The IRIX dynamic linker requires every symbol that is referenced
|
||||
in a dynamic relocation to be present in the primary GOT, so
|
||||
arrange for them to appear after those that are actually
|
||||
referenced.
|
||||
/* Every symbol that is referenced in a dynamic relocation must be
|
||||
present in the primary GOT, so arrange for them to appear after
|
||||
those that are actually referenced. */
|
||||
gg->assigned_gotno = gg->global_gotno - g->global_gotno;
|
||||
g->global_gotno = gg->global_gotno;
|
||||
|
||||
GNU/Linux could very well do without it, but it would slow down
|
||||
the dynamic linker, since it would have to resolve every dynamic
|
||||
symbol referenced in other GOTs more than once, without help from
|
||||
the cache. Also, knowing that every external symbol has a GOT
|
||||
helps speed up the resolution of local symbols too, so GNU/Linux
|
||||
follows IRIX's practice.
|
||||
|
||||
The number 2 is used by mips_elf_sort_hash_table_f to count
|
||||
global GOT symbols that are unreferenced in the primary GOT, with
|
||||
an initial dynamic index computed from gg->assigned_gotno, where
|
||||
the number of unreferenced global entries in the primary GOT is
|
||||
preserved. */
|
||||
if (1)
|
||||
{
|
||||
gg->assigned_gotno = gg->global_gotno - g->global_gotno;
|
||||
g->global_gotno = gg->global_gotno;
|
||||
set_got_offset_arg.value = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This could be used for dynamic linkers that don't optimize
|
||||
symbol resolution while applying relocations so as to use
|
||||
primary GOT entries or assuming the symbol is locally-defined.
|
||||
With this code, we assign lower dynamic indices to global
|
||||
symbols that are not referenced in the primary GOT, so that
|
||||
their entries can be omitted. */
|
||||
gg->assigned_gotno = 0;
|
||||
set_got_offset_arg.value = -1;
|
||||
}
|
||||
|
||||
/* Reorder dynamic symbols as described above (which behavior
|
||||
depends on the setting of VALUE). */
|
||||
set_got_offset_arg.g = NULL;
|
||||
set_got_offset_arg.value = GGA_RELOC_ONLY;
|
||||
htab_traverse (gg->got_entries, mips_elf_set_global_got_offset,
|
||||
&set_got_offset_arg);
|
||||
set_got_offset_arg.value = 1;
|
||||
set_got_offset_arg.value = GGA_NORMAL;
|
||||
htab_traverse (g->got_entries, mips_elf_set_global_got_offset,
|
||||
&set_got_offset_arg);
|
||||
if (! mips_elf_sort_hash_table (info, 1))
|
||||
@ -7881,8 +7873,8 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
|
||||
return FALSE;
|
||||
|
||||
/* Count the number of forced-local entries. */
|
||||
elf_link_hash_traverse (elf_hash_table (info),
|
||||
mips_elf_count_forced_local_got_symbols, g);
|
||||
mips_elf_link_hash_traverse (htab,
|
||||
mips_elf_count_forced_local_got_symbols, g);
|
||||
|
||||
/* There has to be a global GOT entry for every symbol with
|
||||
a dynamic symbol table index of DT_MIPS_GOTSYM or
|
||||
@ -10264,6 +10256,10 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
|
||||
dirmips->readonly_reloc = TRUE;
|
||||
if (indmips->no_fn_stub)
|
||||
dirmips->no_fn_stub = TRUE;
|
||||
if (indmips->global_got_area < dirmips->global_got_area)
|
||||
dirmips->global_got_area = indmips->global_got_area;
|
||||
if (indmips->global_got_area < GGA_NONE)
|
||||
indmips->global_got_area = GGA_NONE;
|
||||
|
||||
if (dirmips->tls_type == 0)
|
||||
dirmips->tls_type = indmips->tls_type;
|
||||
|
@ -1,3 +1,10 @@
|
||||
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* ld-mips-elf/got-vers-1a.s, ld-mips-elf/got-vers-1b.s,
|
||||
ld-mips-elf/got-vers-1.ver, ld-mips-elf/got-vers-1.dd,
|
||||
ld-mips-elf/got-vers-1.sd, ld-mips-elf/got-vers-1.rd: New tests.
|
||||
* ld-mips-elf/mips-elf.exp: Run them.
|
||||
|
||||
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* ld-mips-elf/tlsdyn-o32-2.got, ld-mips-elf/tlsdyn-o32-3.got,
|
||||
|
6
ld/testsuite/ld-mips-elf/got-vers-1.dd
Normal file
6
ld/testsuite/ld-mips-elf/got-vers-1.dd
Normal file
@ -0,0 +1,6 @@
|
||||
# There must be one global GOT symbol. Its index doesn't matter.
|
||||
#...
|
||||
0x70000011 \(MIPS_SYMTABNO\) * 4
|
||||
#...
|
||||
0x70000013 \(MIPS_GOTSYM\) * 0x3
|
||||
#pass
|
6
ld/testsuite/ld-mips-elf/got-vers-1.rd
Normal file
6
ld/testsuite/ld-mips-elf/got-vers-1.rd
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
Relocation section '\.rel\.dyn' at offset .* contains 2 entries:
|
||||
*Offset * Info * Type * Sym\.Value * Sym\. Name
|
||||
00000000 * 00000000 * R_MIPS_NONE *
|
||||
# This index must be the same as DT_MIPS_GOTsYM.
|
||||
[^ ]+ * 00000303 * R_MIPS_REL32 * [^ ]+ * foo
|
6
ld/testsuite/ld-mips-elf/got-vers-1.sd
Normal file
6
ld/testsuite/ld-mips-elf/got-vers-1.sd
Normal file
@ -0,0 +1,6 @@
|
||||
# foo@@V2 must have index DT_MIPS_GOTSYM
|
||||
#...
|
||||
*3: .* 4 * OBJECT * GLOBAL * DEFAULT * [0-9]+ * foo@@V2
|
||||
|
||||
Symbol table '\.symtab' contains .*:
|
||||
#pass
|
1
ld/testsuite/ld-mips-elf/got-vers-1.ver
Normal file
1
ld/testsuite/ld-mips-elf/got-vers-1.ver
Normal file
@ -0,0 +1 @@
|
||||
V2 { global: foo; local: *; };
|
2
ld/testsuite/ld-mips-elf/got-vers-1a.s
Normal file
2
ld/testsuite/ld-mips-elf/got-vers-1a.s
Normal file
@ -0,0 +1,2 @@
|
||||
.abicalls
|
||||
.word foo
|
7
ld/testsuite/ld-mips-elf/got-vers-1b.s
Normal file
7
ld/testsuite/ld-mips-elf/got-vers-1b.s
Normal file
@ -0,0 +1,7 @@
|
||||
.abicalls
|
||||
.symver foo2,foo@@V2
|
||||
.global foo2
|
||||
.data
|
||||
.type foo2,%object
|
||||
.size foo2,4
|
||||
foo2: .word 0
|
@ -363,3 +363,15 @@ run_dump_test "attr-gnu-4-43"
|
||||
run_dump_test "attr-gnu-4-44"
|
||||
run_dump_test "attr-gnu-4-45"
|
||||
run_dump_test "attr-gnu-4-51"
|
||||
|
||||
if { $linux_gnu } {
|
||||
run_ld_link_tests {
|
||||
{"GOT and versioning 1"
|
||||
"-shared -melf32btsmip --version-script got-vers-1.ver"
|
||||
"-EB -mips2 -32" {got-vers-1a.s got-vers-1b.s}
|
||||
{{readelf -d got-vers-1.dd}
|
||||
{readelf --symbols got-vers-1.sd}
|
||||
{readelf --relocs got-vers-1.rd}}
|
||||
"got-vers-1.so"}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user