elf: Strip unreferenced weak undefined symbols

Linker will resolve an undefined symbol only if it is referenced by
relocation.  Unreferenced weak undefined symbols serve no purpose.
Weak undefined symbols appear in the dynamic symbol table only when they
are referenced by dynamic relocation.  Mark symbols with relocation and
strip undefined weak symbols if they don't have relocation and aren't
in the dynamic symbol table.

bfd/

	PR ld/31652
	* elf-bfd.h (elf_link_hash_entry): Add has_reloc.
	* elf-vxworks.c (elf_vxworks_emit_relocs): Set has_reloc.
	* elflink.c (_bfd_elf_link_output_relocs): Likewise.
	(elf_link_output_extsym): Strip undefined weak symbols if they
	don't have relocation and aren't in the dynamic symbol table.

ld/

	PR ld/31652
	* testsuite/ld-elf/elf.exp: Run undefweak tests.
	* testsuite/ld-elf/undefweak-1.rd: New file.
	* testsuite/ld-elf/undefweak-1a.s: Likewise.
	* testsuite/ld-elf/undefweak-1b.s: Likewise.
	* testsuite/ld-x86-64/weakundef-1.nd: Likewise.
	* testsuite/ld-x86-64/weakundef-1a.s: Likewise.
	* testsuite/ld-x86-64/weakundef-1b.s: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run undefweak tests.
This commit is contained in:
H.J. Lu
2024-04-18 05:28:56 -07:00
parent 2304772225
commit eebad48efe
11 changed files with 133 additions and 27 deletions

View File

@@ -232,6 +232,8 @@ struct elf_link_hash_entry
a strong defined symbol alias. U.ALIAS points to a list of aliases,
the definition having is_weakalias clear. */
unsigned int is_weakalias : 1;
/* Symbol has a relocation. */
unsigned int has_reloc : 1;
/* String table index in .dynstr if this is a dynamic symbol. */
unsigned long dynstr_index;

View File

@@ -172,35 +172,39 @@ elf_vxworks_emit_relocs (bfd *output_bfd,
irela += bed->s->int_rels_per_ext_rel,
hash_ptr++)
{
if (*hash_ptr
&& (*hash_ptr)->def_dynamic
&& !(*hash_ptr)->def_regular
&& ((*hash_ptr)->root.type == bfd_link_hash_defined
|| (*hash_ptr)->root.type == bfd_link_hash_defweak)
&& (*hash_ptr)->root.u.def.section->output_section != NULL)
if (*hash_ptr)
{
/* This is a relocation from an executable or shared
library against a symbol in a different shared
library. We are creating a definition in the output
file but it does not come from any of our normal (.o)
files. ie. a PLT stub. Normally this would be a
relocation against against SHN_UNDEF with the VMA of
the PLT stub. This upsets the VxWorks loader.
Convert it to a section-relative relocation. This
gets some other symbols (for instance .dynbss), but
is conservatively correct. */
for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
(*hash_ptr)->has_reloc = 1;
if ((*hash_ptr)->def_dynamic
&& !(*hash_ptr)->def_regular
&& ((*hash_ptr)->root.type == bfd_link_hash_defined
|| (*hash_ptr)->root.type == bfd_link_hash_defweak)
&& (*hash_ptr)->root.u.def.section->output_section != NULL)
{
asection *sec = (*hash_ptr)->root.u.def.section;
int this_idx = sec->output_section->target_index;
/* This is a relocation from an executable or shared
library against a symbol in a different shared
library. We are creating a definition in the output
file but it does not come from any of our normal (.o)
files. ie. a PLT stub. Normally this would be a
relocation against against SHN_UNDEF with the VMA of
the PLT stub. This upsets the VxWorks loader.
Convert it to a section-relative relocation. This
gets some other symbols (for instance .dynbss), but
is conservatively correct. */
for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
{
asection *sec = (*hash_ptr)->root.u.def.section;
int this_idx = sec->output_section->target_index;
irela[j].r_info
= ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info));
irela[j].r_addend += (*hash_ptr)->root.u.def.value;
irela[j].r_addend += sec->output_offset;
irela[j].r_info
= ELF32_R_INFO (this_idx,
ELF32_R_TYPE (irela[j].r_info));
irela[j].r_addend += (*hash_ptr)->root.u.def.value;
irela[j].r_addend += sec->output_offset;
}
/* Stop the generic routine adjusting this entry. */
*hash_ptr = NULL;
}
/* Stop the generic routine adjusting this entry. */
*hash_ptr = NULL;
}
}
}

View File

@@ -2942,8 +2942,7 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
asection *input_section,
Elf_Internal_Shdr *input_rel_hdr,
Elf_Internal_Rela *internal_relocs,
struct elf_link_hash_entry **rel_hash
ATTRIBUTE_UNUSED)
struct elf_link_hash_entry **rel_hash)
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
@@ -2986,9 +2985,12 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
* bed->s->int_rels_per_ext_rel);
while (irela < irelaend)
{
if (*rel_hash)
(*rel_hash)->has_reloc = 1;
(*swap_out) (output_bfd, irela, erel);
irela += bed->s->int_rels_per_ext_rel;
erel += input_rel_hdr->sh_entsize;
rel_hash++;
}
/* Bump the counter, so that we know where to add the next set of
@@ -10769,6 +10771,13 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
&& (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
strip = true;
/* Remember if this symbol should be stripped. */
bool should_strip = strip;
/* Strip undefined weak symbols link if they don't have relocation. */
if (!strip)
strip = !h->has_reloc && h->root.type == bfd_link_hash_undefweak;
type = h->type;
/* If we're stripping it, and it's not a dynamic symbol, there's
@@ -10917,6 +10926,10 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
eoinfo->failed = true;
return false;
}
/* If a symbol is in the dynamic symbol table and isn't a
should-strip symbol, also keep it in the symbol table. */
if (!should_strip)
strip = false;
}
/* If we are marking the symbol as undefined, and there are no

View File

@@ -171,6 +171,21 @@ run_ld_link_tests [list \
"implib" ] \
] \[uses_genelf\]
run_ld_link_tests [list \
[list "Generate undefweak-1.a" \
"" "" \
$hpux \
{undefweak-1a.s} \
{} \
"undefweak-1.a" ] \
[list "Generate undefweak-1.o" \
"-r" "tmpdir/undefweak-1.a" \
$hpux \
{undefweak-1b.s} \
{{readelf {-rsW} undefweak-1.rd}} \
"undefweak-1.o" ] \
] \[uses_genelf\]
#v850 gas complains about .tbss.var section attributes.
if { [check_gc_sections_available] && ![istarget "v850-*-*"] } {
run_ld_link_tests {

View File

@@ -0,0 +1,10 @@
#source: undefweak-1a.s
#source: undefweak-1b.s
#as:
#ld: -r
#readelf: -sW
#failif
#...
.*: 0+ +0 +FUNC +WEAK +DEFAULT +UND +bar
#pass

View File

@@ -0,0 +1,14 @@
.section .text.foobar,"axG",%progbits,foo,comdat
.weak foo
.type foo,%function
foo:
.nop
.size foo, . - foo
.weak bar
.set bar, foo
.text
.global baz
.type baz,%function
baz:
.dc.a foo
.size baz, . - baz

View File

@@ -0,0 +1,10 @@
.section .text.foobar,"axG",%progbits,foo,comdat
.weak foo
.type foo,%function
foo:
.nop
.size foo, . - foo
.text
.global _start
.set _start,foo
.dc.a baz

View File

@@ -0,0 +1,6 @@
#nm: -n
#target: x86_64-*-*
#...
+w +bar
#pass

View File

@@ -0,0 +1,6 @@
.text
.global foo
.type foo,%function
foo:
.nop
.size foo, . - foo

View File

@@ -0,0 +1,8 @@
.weak bar
.text
.global _start
.type _start,%function
_start:
mov bar@GOTPCREL(%rip), %rax
mov foo@GOTPCREL(%rip), %rax
.size _start, . - _start

View File

@@ -264,6 +264,24 @@ run_ld_link_tests [list \
{objdump -drj.plt tlsdesc.pd}} \
"libtlsdesc.so" \
] \
[list \
"Generate x86-64-weakundef-1.so" \
"-shared -melf_x86_64" \
"" \
"--64" \
{weakundef-1a.s} \
{} \
"x86-64-weakundef-1.so" \
] \
[list \
"Generate x86-64-weakundef-1" \
"-melf_x86_64" \
"tmpdir/x86-64-weakundef-1.so" \
"--64" \
{weakundef-1b.s} \
{{nm -n weakundef-1.nd}} \
"x86-64-weakundef-1" \
] \
]
set test_name "Mixed x86_64 and i386 input test 1"