Evaluate __start_* and __stop_* symbol PROVIDE expressions early

Makes these symbols defined before bfd_elf_size_dynamic_sections, to
avoid horrible hacks elsewhere.  The exp_fold_tree undefweak change
is necessary to define undefweak symbols early too.  The comment was
wrong.  PROVIDE in fact defines undefweak symbols, via
bfd_elf_record_link_assignment.

	PR ld/19175
	* ldlang.c (lang_insert_orphan): Evaluate __start_* and __stop_*
	symbol PROVIDE expressions.
	* ldexp.c (exp_fold_tree_1 <etree_provide>): Define undefweak
	references.
This commit is contained in:
Alan Modra
2015-10-27 12:01:55 +10:30
parent d7f3ff3ea7
commit 321df0656c
3 changed files with 32 additions and 9 deletions

View File

@ -1,3 +1,11 @@
2015-10-27 Alan Modra <amodra@gmail.com>
PR ld/19175
* ldlang.c (lang_insert_orphan): Evaluate __start_* and __stop_*
symbol PROVIDE expressions.
* ldexp.c (exp_fold_tree_1 <etree_provide>): Define undefweak
references.
2015-10-22 H.J. Lu <hongjiu.lu@intel.com> 2015-10-22 H.J. Lu <hongjiu.lu@intel.com>
* configure.ac: Properly check * configure.ac: Properly check

View File

@ -1126,11 +1126,14 @@ exp_fold_tree_1 (etree_type *tree)
if (h == NULL if (h == NULL
|| !(h->type == bfd_link_hash_new || !(h->type == bfd_link_hash_new
|| h->type == bfd_link_hash_undefined || h->type == bfd_link_hash_undefined
|| h->type == bfd_link_hash_undefweak
|| h->linker_def)) || h->linker_def))
{ {
/* Do nothing. The symbol was never referenced, or /* Do nothing. The symbol was never referenced, or
was defined in some object file. Undefined weak was defined in some object file. Note that
symbols stay undefined. */ undefweak symbols are defined by PROVIDE. This
is to support glibc use of __rela_iplt_start and
similar weak references. */
break; break;
} }
} }

View File

@ -1805,6 +1805,7 @@ lang_insert_orphan (asection *s,
{ {
lang_statement_list_type add; lang_statement_list_type add;
const char *ps; const char *ps;
lang_assignment_statement_type *start_assign;
lang_output_section_statement_type *os; lang_output_section_statement_type *os;
lang_output_section_statement_type **os_tail; lang_output_section_statement_type **os_tail;
@ -1827,6 +1828,7 @@ lang_insert_orphan (asection *s,
NULL, NULL, NULL, constraint, 0); NULL, NULL, NULL, constraint, 0);
ps = NULL; ps = NULL;
start_assign = NULL;
if (config.build_constructors && *os_tail == os) if (config.build_constructors && *os_tail == os)
{ {
/* If the name of the section is representable in C, then create /* If the name of the section is representable in C, then create
@ -1841,9 +1843,10 @@ lang_insert_orphan (asection *s,
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
sprintf (symname + (symname[0] != 0), "__start_%s", secname); sprintf (symname + (symname[0] != 0), "__start_%s", secname);
lang_add_assignment (exp_provide (symname, start_assign
exp_nameop (NAME, "."), = lang_add_assignment (exp_provide (symname,
FALSE)); exp_nameop (NAME, "."),
FALSE));
} }
} }
@ -1866,16 +1869,25 @@ lang_insert_orphan (asection *s,
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL, lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
NULL); NULL);
if (ps != NULL && *ps == '\0') if (start_assign != NULL)
{ {
char *symname; char *symname;
lang_assignment_statement_type *stop_assign;
bfd_vma dot;
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
sprintf (symname + (symname[0] != 0), "__stop_%s", secname); sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
lang_add_assignment (exp_provide (symname, stop_assign
exp_nameop (NAME, "."), = lang_add_assignment (exp_provide (symname,
FALSE)); 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 += s->size;
exp_fold_tree (stop_assign->exp, os->bfd_section, &dot);
} }
/* Restore the global list pointer. */ /* Restore the global list pointer. */