diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2017-06-13 08:53:22 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2017-06-13 08:53:22 -0700 |
commit | cbd0eecf261c2447781f8c89b0d955ee66fae7e9 (patch) | |
tree | 1a8139f0a7989d71079057f6000877af275b546d /ld/ldlang.c | |
parent | 6490dc678bc35f2204afb38449de5127ef8bcca0 (diff) | |
download | binutils-gdb-cbd0eecf261c2447781f8c89b0d955ee66fae7e9.tar.gz |
Always define referenced __start_SECNAME/__stop_SECNAME
Currently, linker will define __start_SECNAME and __stop_SECNAME symbols
only for orphaned sections.
However, during garbage collection, ELF linker marks all sections with
references to __start_SECNAME and __stop_SECNAME symbols as used even
when section SECNAME isn't an orphaned section and linker won't define
__start_SECNAME nor __stop_SECNAME. And ELF linker stores the first
input section whose name matches __start_SECNAME or __stop_SECNAME in
u.undef.section for garbage collection. If these symbols are provided
in linker script, u.undef.section is set to the section where they will
defined by linker script, which leads to the incorrect output.
This patch changes linker to always define referenced __start_SECNAME and
__stop_SECNAME if the input section name is the same as the output section
name, which is always true for orphaned sections, and SECNAME is a C
identifier. Also __start_SECNAME and __stop_SECNAME symbols are marked
as hidden by ELF linker so that __start_SECNAME and __stop_SECNAME symbols
for section SECNAME in different modules are unique. For garbage
collection, ELF linker stores the first matched input section in the
unused vtable field.
bfd/
PR ld/20022
PR ld/21557
PR ld/21562
PR ld/21571
* elf-bfd.h (elf_link_hash_entry): Add start_stop. Change the
vtable field to a union.
(_bfd_elf_is_start_stop): Removed.
* elf32-i386.c (elf_i386_convert_load_reloc): Also check for
__start_SECNAME and __stop_SECNAME symbols.
* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Likewise.
* elflink.c (_bfd_elf_is_start_stop): Removed.
(_bfd_elf_gc_mark_rsec): Check start_stop instead of calling
_bfd_elf_is_start_stop.
(elf_gc_propagate_vtable_entries_used): Skip __start_SECNAME and
__stop_SECNAME symbols. Updated.
(elf_gc_smash_unused_vtentry_relocs): Likewise.
(bfd_elf_gc_record_vtinherit): Likewise.
(bfd_elf_gc_record_vtentry): Likewise.
ld/
PR ld/20022
PR ld/21557
PR ld/21562
PR ld/21571
* ld.texinfo: Update __start_SECNAME/__stop_SECNAME symbols.
* ldlang.c (lang_insert_orphan): Move handling of __start_SECNAME
and __stop_SECNAME symbols to ...
(lang_set_startof): Here. Also define __start_SECNAME and
__stop_SECNAME for -Ur.
* emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Mark
referenced __start_SECNAME and __stop_SECNAME symbols as hidden
and set start_stop for garbage collection.
* testsuite/ld-elf/pr21562a.d: New file.
* testsuite/ld-elf/pr21562a.s: Likewise.
* testsuite/ld-elf/pr21562a.t: Likewise.
* testsuite/ld-elf/pr21562b.d: Likewise.
* testsuite/ld-elf/pr21562b.s: Likewise.
* testsuite/ld-elf/pr21562b.t: Likewise.
* testsuite/ld-elf/pr21562c.d: Likewise.
* testsuite/ld-elf/pr21562c.t: Likewise.
* testsuite/ld-elf/pr21562d.d: Likewise.
* testsuite/ld-elf/pr21562d.t: Likewise.
* testsuite/ld-elf/pr21562e.d: Likewise.
* testsuite/ld-elf/pr21562f.d: Likewise.
* testsuite/ld-elf/pr21562g.d: Likewise.
* testsuite/ld-elf/pr21562h.d: Likewise.
* testsuite/ld-elf/pr21562i.d: Likewise.
* testsuite/ld-elf/pr21562j.d: Likewise.
* testsuite/ld-elf/pr21562k.d: Likewise.
* testsuite/ld-elf/pr21562l.d: Likewise.
* testsuite/ld-elf/pr21562m.d: Likewise.
* testsuite/ld-elf/pr21562n.d: Likewise.
* testsuite/ld-gc/pr20022.d: Likewise.
* testsuite/ld-gc/pr20022a.s: Likewise.
* testsuite/ld-gc/pr20022b.s: Likewise.
* testsuite/ld-gc/gc.exp: Run PR ld/20022 tests.
* testsuite/ld-gc/pr19161.d: Also accept local __start_SECNAME
symbol.
* testsuite/ld-gc/start.d: Likewise.
* testsuite/ld-x86-64/lea1a.d: Updated.
* testsuite/ld-x86-64/lea1b.d: Updated.
* testsuite/ld-x86-64/lea1d.d: Updated.
* testsuite/ld-x86-64/lea1e.d: Likewise.
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 115 |
1 files changed, 54 insertions, 61 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index 252400bd510..f8e4f528799 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1829,8 +1829,6 @@ lang_insert_orphan (asection *s, lang_statement_list_type *add_child) { lang_statement_list_type add; - const char *ps; - lang_assignment_statement_type *start_assign; lang_output_section_statement_type *os; lang_output_section_statement_type **os_tail; @@ -1852,29 +1850,6 @@ lang_insert_orphan (asection *s, os = lang_enter_output_section_statement (secname, address, normal_section, NULL, NULL, NULL, constraint, 0); - ps = NULL; - start_assign = NULL; - if (config.build_constructors && *os_tail == os) - { - /* If the name of the section is representable in C, then create - symbols to mark the start and the end of the section. */ - for (ps = secname; *ps != '\0'; ps++) - if (!ISALNUM ((unsigned char) *ps) && *ps != '_') - break; - if (*ps == '\0') - { - char *symname; - - symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); - symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); - sprintf (symname + (symname[0] != 0), "__start_%s", secname); - start_assign - = lang_add_assignment (exp_provide (symname, - exp_nameop (NAME, "."), - FALSE)); - } - } - if (add_child == NULL) add_child = &os->children; lang_add_section (add_child, s, NULL, os); @@ -1894,27 +1869,6 @@ lang_insert_orphan (asection *s, lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL, NULL); - if (start_assign != NULL) - { - char *symname; - lang_assignment_statement_type *stop_assign; - bfd_vma dot; - - symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); - symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); - sprintf (symname + (symname[0] != 0), "__stop_%s", secname); - stop_assign - = lang_add_assignment (exp_provide (symname, - exp_nameop (NAME, "."), - FALSE)); - /* Evaluate the expression to define the symbol if referenced, - before sizing dynamic sections. */ - dot = os->bfd_section->vma; - exp_fold_tree (start_assign->exp, os->bfd_section, &dot); - dot += TO_ADDR (s->size); - exp_fold_tree (stop_assign->exp, os->bfd_section, &dot); - } - /* Restore the global list pointer. */ if (after != NULL) pop_stat_ptr (); @@ -5924,20 +5878,25 @@ section_for_dot (void) return bfd_abs_section_ptr; } -/* Fix any .startof. or .sizeof. symbols. When the assemblers see the - operator .startof. (section_name), it produces an undefined symbol - .startof.section_name. Similarly, when it sees +/* Fix any .startof., .sizeof., __start or __stop symbols. When the + assemblers see the operator .startof. (section_name), it produces + an undefined symbol .startof.section_name. Similarly, when it sees .sizeof. (section_name), it produces an undefined symbol - .sizeof.section_name. For all the output sections, we look for - such symbols, and set them to the correct value. */ + .sizeof.section_name. Also for ELF linker, __start_XXX or __stop_XXX + symbols should be resolved to the start and end of section XXX. For + all the output sections, we look for such symbols, and set them to + the correct value. */ static void lang_set_startof (void) { asection *s; + char leading_char; + bfd_boolean is_elf = (bfd_get_flavour (link_info.output_bfd) + == bfd_target_elf_flavour); + bfd_boolean is_elocatable = bfd_link_relocatable (&link_info); - if (bfd_link_relocatable (&link_info)) - return; + leading_char = bfd_get_symbol_leading_char (link_info.output_bfd); for (s = link_info.output_bfd->sections; s != NULL; s = s->next) { @@ -5948,24 +5907,58 @@ lang_set_startof (void) secname = bfd_get_section_name (link_info.output_bfd, s); buf = (char *) xmalloc (10 + strlen (secname)); - sprintf (buf, ".startof.%s", secname); - h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); - if (h != NULL && h->type == bfd_link_hash_undefined) + if (!is_elocatable) + { + sprintf (buf, ".startof.%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, + TRUE); + if (h != NULL && h->type == bfd_link_hash_undefined) + { + h->type = bfd_link_hash_defined; + h->u.def.value = 0; + h->u.def.section = s; + } + + sprintf (buf, ".sizeof.%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, + TRUE); + if (h != NULL && h->type == bfd_link_hash_undefined) + { + h->type = bfd_link_hash_defined; + h->u.def.value = TO_ADDR (s->size); + h->u.def.section = bfd_abs_section_ptr; + } + } + + buf[0] = leading_char; + sprintf (buf + (buf[0] != 0), "__start_%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, + TRUE); + if (h != NULL + && (h->type == bfd_link_hash_undefined + || h->type == bfd_link_hash_undefweak)) { h->type = bfd_link_hash_defined; h->u.def.value = 0; h->u.def.section = s; + if (is_elf) + ((struct elf_link_hash_entry *) h)->def_regular = 1; } - sprintf (buf, ".sizeof.%s", secname); - h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); - if (h != NULL && h->type == bfd_link_hash_undefined) + buf[0] = leading_char; + sprintf (buf + (buf[0] != 0), "__stop_%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, + TRUE); + if (h != NULL + && (h->type == bfd_link_hash_undefined + || h->type == bfd_link_hash_undefweak)) { h->type = bfd_link_hash_defined; h->u.def.value = TO_ADDR (s->size); - h->u.def.section = bfd_abs_section_ptr; + h->u.def.section = s; + if (is_elf) + ((struct elf_link_hash_entry *) h)->def_regular = 1; } - free (buf); } } |