From 165f707ac88916aedecc96fa518be8879704d6da Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 27 Nov 2017 13:40:43 +1030 Subject: [PATCH] PR22471, undefined reference to linker-defined symbols This patch processes linker script assignment statements before ld opens DT_NEEDED libraries, in order to define symbols like __bss_start that might also be defined by a library, falsely triggering an error about "DSO missing from command line". The initial value won't be correct when assigning a symbol from dot, and I make no attempt to handle all expressions. For example, an assignment like "_start_foo = ADDR (.foo)" isn't valid until sections are laid out, so won't define _start_foo early. What's here should be enough for most common scripts, and hopefully won't perturb fragile scripts. bfd/ PR 22471 * elflink.c (_bfd_elf_merge_symbol): Allow weak symbols to override early passes over linker script symbols. * linker.c (_bfd_generic_link_add_one_symbol): Allow symbols to override early passes over linker script symbols. Clear ldscript_def on symbol definitions. ld/ PR 22471 * ldexp.c (struct definedness_hash_entry): Delete "by_script". Make "iteration" an 8-bit field, and update mask in all uses. (definedness_newfunc): Don't init "by_script". (update_definedness): Test ldscript_def rather than by_script. (is_sym_value): Likewise. (fold_name ): Return a result for first phase. Test ldscript_def. (fold_name ): Return a result for first phase. * ldlang.c (open_input_bfds): Process all assignments, not just defsym. (lang_process): Increment lang_statement_iteration before open_input_bfds. * testsuite/ld-mips-elf/tlsdyn-o32-1.d: Adjust for larger .dynsym. * testsuite/ld-mips-elf/tlsdyn-o32-1.got: Likewise. * testsuite/ld-mips-elf/tlsdyn-o32-2.d: Likewise. * testsuite/ld-mips-elf/tlsdyn-o32-2.got: Likewise. * testsuite/ld-mips-elf/tlsdyn-o32-3.d: Likewise. * testsuite/ld-mips-elf/tlsdyn-o32-3.got: Likewise. --- bfd/ChangeLog | 9 ++++ bfd/elflink.c | 7 ++- bfd/linker.c | 9 +++- ld/ChangeLog | 22 ++++++++ ld/ldexp.c | 64 +++++++++-------------- ld/ldlang.c | 6 +-- ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d | 4 +- ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got | 2 +- ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d | 4 +- ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got | 2 +- ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d | 4 +- ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got | 2 +- 12 files changed, 82 insertions(+), 53 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index dc3aa2f0d9d..c9c24079a45 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2017-11-28 Alan Modra + + PR 22471 + * elflink.c (_bfd_elf_merge_symbol): Allow weak symbols to override + early passes over linker script symbols. + * linker.c (_bfd_generic_link_add_one_symbol): Allow symbols to + override early passes over linker script symbols. Clear ldscript_def + on symbol definitions. + 2017-11-28 Alan Modra * elf64-mmix.c (bfd_elf64_bfd_copy_link_hash_symbol_type): Define. diff --git a/bfd/elflink.c b/bfd/elflink.c index ddd088c1447..fed7caa5f2f 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1471,10 +1471,15 @@ _bfd_elf_merge_symbol (bfd *abfd, treated as strong if the new symbol is from a dynamic library. This reflects the way glibc's ld.so works. + Also allow a weak symbol to override a linker script symbol + defined by an early pass over the script. This is done so the + linker knows the symbol is defined in an object file, for the + DEFINED script function. + Do this before setting *type_change_ok or *size_change_ok so that we warn properly when dynamic library symbols are overridden. */ - if (newdef && !newdyn && olddyn) + if (newdef && !newdyn && (olddyn || h->root.ldscript_def)) newweak = FALSE; if (olddef && newdyn) oldweak = FALSE; diff --git a/bfd/linker.c b/bfd/linker.c index a96c6ed1dd0..9c19df4e570 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1443,9 +1443,14 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, do { enum link_action action; + int prev; + prev = h->type; + /* Treat symbols defined by early linker script pass as undefined. */ + if (h->ldscript_def) + prev = bfd_link_hash_undefined; cycle = FALSE; - action = link_action[(int) row][(int) h->type]; + action = link_action[(int) row][prev]; switch (action) { case FAIL: @@ -1489,6 +1494,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, h->u.def.section = section; h->u.def.value = value; h->linker_def = 0; + h->ldscript_def = 0; /* If we have been asked to, we act like collect2 and identify all functions that might be global @@ -1588,6 +1594,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, else h->u.c.p->section = section; h->linker_def = 0; + h->ldscript_def = 0; break; case REF: diff --git a/ld/ChangeLog b/ld/ChangeLog index 058318dfaba..2b204543a6a 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,25 @@ +2017-11-28 Alan Modra + + PR 22471 + * ldexp.c (struct definedness_hash_entry): Delete "by_script". Make + "iteration" an 8-bit field, and update mask in all uses. + (definedness_newfunc): Don't init "by_script". + (update_definedness): Test ldscript_def rather than by_script. + (is_sym_value): Likewise. + (fold_name ): Return a result for first phase. Test + ldscript_def. + (fold_name ): Return a result for first phase. + * ldlang.c (open_input_bfds): Process all assignments, not just + defsym. + (lang_process): Increment lang_statement_iteration before + open_input_bfds. + * testsuite/ld-mips-elf/tlsdyn-o32-1.d: Adjust for larger .dynsym. + * testsuite/ld-mips-elf/tlsdyn-o32-1.got: Likewise. + * testsuite/ld-mips-elf/tlsdyn-o32-2.d: Likewise. + * testsuite/ld-mips-elf/tlsdyn-o32-2.got: Likewise. + * testsuite/ld-mips-elf/tlsdyn-o32-3.d: Likewise. + * testsuite/ld-mips-elf/tlsdyn-o32-3.got: Likewise. + 2017-11-28 Alan Modra * ldexp.h (struct ldexp_control): Add "assign_src". diff --git a/ld/ldexp.c b/ld/ldexp.c index 33ca289682c..1f1420bb418 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -60,15 +60,12 @@ struct definedness_hash_entry section statement, the section we'd like it relative to. */ asection *final_sec; + /* Low bits of iteration count. Symbols with matching iteration have + been defined in this pass over the script. */ + unsigned int iteration : 8; + /* Symbol was defined by an object file. */ unsigned int by_object : 1; - - /* Symbols was defined by a script. */ - unsigned int by_script : 1; - - /* Low bit of iteration count. Symbols with matching iteration have - been defined in this pass over the script. */ - unsigned int iteration : 1; }; static struct bfd_hash_table definedness_table; @@ -286,7 +283,6 @@ definedness_newfunc (struct bfd_hash_entry *entry, einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); ret->by_object = 0; - ret->by_script = 0; ret->iteration = 0; return &ret->root; } @@ -320,7 +316,7 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) /* If the symbol was already defined, and not by a script, then it must be defined by an object file or by the linker target code. */ ret = TRUE; - if (!defentry->by_script + if (!h->ldscript_def && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak || h->type == bfd_link_hash_common)) @@ -332,7 +328,6 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) ret = FALSE; } - defentry->by_script = 1; defentry->iteration = lang_statement_iteration; defentry->final_sec = bfd_abs_section_ptr; if (expld.phase == lang_final_phase_enum @@ -686,6 +681,9 @@ fold_trinary (etree_type *tree) static void fold_name (etree_type *tree) { + struct bfd_link_hash_entry *h; + struct definedness_hash_entry *def; + memset (&expld.result, 0, sizeof (expld.result)); switch (tree->type.node_code) @@ -703,23 +701,18 @@ fold_name (etree_type *tree) break; case DEFINED: - if (expld.phase != lang_first_phase_enum) - { - struct bfd_link_hash_entry *h; - struct definedness_hash_entry *def; - - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, - &link_info, - tree->name.name, - FALSE, FALSE, TRUE); - new_number (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak - || h->type == bfd_link_hash_common) - && ((def = symbol_defined (tree->name.name)) == NULL - || def->by_object - || def->iteration == (lang_statement_iteration & 1))); - } + h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, + &link_info, + tree->name.name, + FALSE, FALSE, TRUE); + new_number (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak + || h->type == bfd_link_hash_common) + && (!h->ldscript_def + || (def = symbol_defined (tree->name.name)) == NULL + || def->by_object + || def->iteration == (lang_statement_iteration & 255))); break; case NAME: @@ -728,9 +721,6 @@ fold_name (etree_type *tree) { /* Self-assignment is only allowed for absolute symbols defined in a linker script. */ - struct bfd_link_hash_entry *h; - struct definedness_hash_entry *def; - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, @@ -740,17 +730,13 @@ fold_name (etree_type *tree) || h->type == bfd_link_hash_defweak) && h->u.def.section == bfd_abs_section_ptr && (def = symbol_defined (tree->name.name)) != NULL - && def->iteration == (lang_statement_iteration & 1))) + && def->iteration == (lang_statement_iteration & 255))) expld.assign_name = NULL; } - if (expld.phase == lang_first_phase_enum) - ; - else if (tree->name.name[0] == '.' && tree->name.name[1] == 0) + if (tree->name.name[0] == '.' && tree->name.name[1] == 0) new_rel_from_abs (expld.dot); else { - struct bfd_link_hash_entry *h; - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, @@ -765,7 +751,7 @@ fold_name (etree_type *tree) output_section = h->u.def.section->output_section; if (output_section == NULL) { - if (expld.phase == lang_mark_phase_enum) + if (expld.phase <= lang_mark_phase_enum) new_rel (h->u.def.value, h->u.def.section); else einfo (_("%X%S: unresolvable symbol `%s'" @@ -957,12 +943,12 @@ is_sym_value (const etree_type *tree, bfd_vma val) return (tree->type.node_class == etree_name && tree->type.node_code == NAME && (def = symbol_defined (tree->name.name)) != NULL - && def->by_script - && def->iteration == (lang_statement_iteration & 1) + && def->iteration == (lang_statement_iteration & 255) && (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, FALSE, FALSE, TRUE)) != NULL + && h->ldscript_def && h->type == bfd_link_hash_defined && h->u.def.section == bfd_abs_section_ptr && h->u.def.value == val); diff --git a/ld/ldlang.c b/ld/ldlang.c index 674004ee389..bf1b5d31ed5 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -3359,9 +3359,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) #endif break; case lang_assignment_statement_enum: - if (s->assignment_statement.exp->type.node_class != etree_assert - && s->assignment_statement.exp->assign.defsym) - /* This is from a --defsym on the command line. */ + if (s->assignment_statement.exp->type.node_class != etree_assert) exp_fold_tree_no_dot (s->assignment_statement.exp); break; default: @@ -7167,6 +7165,7 @@ lang_process (void) /* Create a bfd for each input file. */ current_target = default_target; + lang_statement_iteration++; open_input_bfds (statement_list.head, OPEN_BFD_NORMAL); #ifdef ENABLE_PLUGINS @@ -7222,6 +7221,7 @@ lang_process (void) /* Rescan archives in case new undefined symbols have appeared. */ files = file_chain; + lang_statement_iteration++; open_input_bfds (statement_list.head, OPEN_BFD_RESCAN); lang_list_remove_tail (&file_chain, &files); while (files.head != NULL) diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d b/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d index 011df6c69c4..17e42d01f84 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d @@ -5,7 +5,7 @@ Disassembly of section .text: .* <__start>: .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7c30 addiu gp,gp,31792 + .*: 279c7b80 addiu gp,gp,31616 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) @@ -55,7 +55,7 @@ Disassembly of section .text: .* : .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7b70 addiu gp,gp,31600 + .*: 279c7ac0 addiu gp,gp,31424 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got b/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got index 1dbcab40a0a..508fed2d719 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got @@ -13,6 +13,6 @@ OFFSET TYPE VALUE Contents of section .got: - 10000020 00000000 80000000 0040048c 00000000 .........@...... + 10000020 00000000 80000000 0040053c 00000000 .........@...... 10000030 00000000 00000000 00000000 00000000 ................ 10000040 00000000 00000001 00000000 ............ diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d b/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d index 011df6c69c4..17e42d01f84 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d @@ -5,7 +5,7 @@ Disassembly of section .text: .* <__start>: .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7c30 addiu gp,gp,31792 + .*: 279c7b80 addiu gp,gp,31616 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) @@ -55,7 +55,7 @@ Disassembly of section .text: .* : .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7b70 addiu gp,gp,31600 + .*: 279c7ac0 addiu gp,gp,31424 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got b/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got index fb50635f049..4a97099885d 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got @@ -13,6 +13,6 @@ OFFSET TYPE VALUE Contents of section .got: - 10000020 00000000 80000000 0040048c 00000000 .* + 10000020 00000000 80000000 0040053c 00000000 .* 10000030 00000000 00000000 00000000 00000000 .* 10000040 00000000 00000001 00000000 .* diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d b/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d index 3828aca8dfd..fb3750a95d6 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d @@ -5,7 +5,7 @@ Disassembly of section .text: .* : .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7c30 addiu gp,gp,31792 + .*: 279c7b80 addiu gp,gp,31616 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) @@ -51,7 +51,7 @@ Disassembly of section .text: .* <__start>: .*: 3c1c0fc0 lui gp,0xfc0 - .*: 279c7b80 addiu gp,gp,31616 + .*: 279c7ad0 addiu gp,gp,31440 .*: 0399e021 addu gp,gp,t9 .*: 27bdfff0 addiu sp,sp,-16 .*: afbe0008 sw s8,8\(sp\) diff --git a/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got b/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got index 4a97099885d..d96375cdf6e 100644 --- a/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got +++ b/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got @@ -13,6 +13,6 @@ OFFSET TYPE VALUE Contents of section .got: - 10000020 00000000 80000000 0040053c 00000000 .* + 10000020 00000000 80000000 004005ec 00000000 .* 10000030 00000000 00000000 00000000 00000000 .* 10000040 00000000 00000001 00000000 .* -- 2.30.2