Rewrite __start and __stop symbol handling

This arranges for __start and __stop symbols to be defined before
garbage collection, for all target formats.  That should allow the
COFF and PE --gc-sections to keep a singleton orphan input section,
a feature lost by 2017-06-13 commit cbd0eecf26.  The fancier ELF
treatment of keeping all input sections associated with a __start or
__stop symbol, from 2015-10-23 commit 1cce69b9dc, is retained.

.startof. and .sizeof. symbols are deliberately not defined before
garbage collection, so these won't affect garbage collection of
sections.

The patch also ensures __start, __stop, .startof. and .sizeof. symbols
are defined before target size_dynamic_sections is called, albeit
with a preliminary value, so that target code doesn't need to cope
with a symbol changing from undefined at size_dynamic_sections to
defined at relocate_section.

Also, a number of problems with the testcases have been fixed.

	PR ld/20022
	PR ld/21557
	PR ld/21562
	PR ld/21571
include/
	* bfdlink.h (struct bfd_link_hash_entry): Delete undef.section.
bfd/
	* targets.c (struct bfd_target): Add _bfd_define_start_stop.
	(BFD_JUMP_TABLE_LINK): Likewise.
	* elf-bfd.h (bfd_elf_define_start_stop): Declare.
	* elflink.c (_bfd_elf_gc_mark_rsec): Update comment.
	(bfd_elf_define_start_stop): New function.
	* linker.c (bfd_generic_define_start_stop): New function.
	* coff64-rs6000.c (rs6000_xcoff64_vec, rs6000_xcoff64_aix_vec): Init
	new field.
	* aout-adobe.c (aout_32_bfd_define_start_stop): Define.
	* aout-target.h (MY_bfd_define_start_stop): Define.
	* aout-tic30.c (MY_bfd_define_start_stop): Define.
	* binary.c (binary_bfd_define_start_stop): Define.
	* bout.c (b_out_bfd_define_start_stop): Define.
	* coff-alpha.c (_bfd_ecoff_bfd_define_start_stop): Define.
	* coff-mips.c (_bfd_ecoff_bfd_define_start_stop): Define.
	* coff-rs6000.c (_bfd_xcoff_bfd_define_start_stop): Define.
	* coffcode.h (coff_bfd_define_start_stop): Define.
	* elfxx-target.h (bfd_elfNN_bfd_define_start_stop): Define.
	* i386msdos.c (msdos_bfd_define_start_stop): Define.
	* i386os9k.c (os9k_bfd_define_start_stop): Define.
	* ieee.c (ieee_bfd_define_start_stop): Define.
	* ihex.c (ihex_bfd_define_start_stop): Define.
	* libbfd-in.h (_bfd_nolink_bfd_define_start_stop): Define.
	* mach-o-target.c (bfd_mach_o_bfd_define_start_stop): Define.
	* mmo.c (mmo_bfd_define_start_stop): Define.
	* nlm-target.h (nlm_bfd_define_start_stop): Define.
	* oasys.c (oasys_bfd_define_start_stop): Define.
	* pef.c (bfd_pef_bfd_define_start_stop): Define.
	* plugin.c (bfd_plugin_bfd_define_start_stop): Define.
	* ppcboot.c (ppcboot_bfd_define_start_stop): Define.
	* som.c (som_bfd_define_start_stop): Define.
	* srec.c (srec_bfd_define_start_stop): Define.
	* tekhex.c (tekhex_bfd_define_start_stop): Define.
	* versados.c (versados_bfd_define_start_stop): Define.
	* vms-alpha.c (vms_bfd_define_start_stop): Define.
	(alpha_vms_bfd_define_start_stop): Define.
	* xsym.c (bfd_sym_bfd_define_start_stop): Define.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
ld/
	* emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Don't set
	__start/__stop syms here.
	* ldlang.c (lang_set_startof): Delete.
	(start_stop_syms, start_stop_count, start_stop_alloc): New vars.
	(lang_define_start_stop, lang_init_start_stop, foreach_start_stop,
	undef_start_stop, lang_undef_start_stop, lang_init_startof_sizeof,
	set_start_stop, lang_finalize_start_stop): New functions.
	(lang_process): Call _start_stop functions.
	* testsuite/ld-elf/pr21562a.d: Use xfail rather than notarget.
	Correct typos and list of xfail targets.
	* testsuite/ld-elf/pr21562b.d: Likewise.
	* testsuite/ld-elf/pr21562c.d: Likewise.
	* testsuite/ld-elf/pr21562d.d: 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-elf/sizeofa.d: Likewise.  Adjust to pass for generic ELF.
	* testsuite/ld-elf/sizeofb.d: Likewise.
	* testsuite/ld-elf/startofa.d: Likewise.
	* testsuite/ld-elf/startofb.d: Likewise.
This commit is contained in:
Alan Modra 2017-06-16 19:41:41 +09:30
parent d68f19767d
commit 7dba9362c1
59 changed files with 492 additions and 242 deletions

View file

@ -5878,97 +5878,173 @@ section_for_dot (void)
return bfd_abs_section_ptr;
}
/* 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. 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. */
/* Array of __start/__stop/.startof./.sizeof/ symbols. */
static struct bfd_link_hash_entry **start_stop_syms;
static size_t start_stop_count = 0;
static size_t start_stop_alloc = 0;
/* Give start/stop SYMBOL for SEC a preliminary definition, and add it
to start_stop_syms. */
static void
lang_set_startof (void)
lang_define_start_stop (const char *symbol, asection *sec)
{
asection *s;
char leading_char;
bfd_boolean is_elf;
bfd_boolean is_relocatable;
struct bfd_link_hash_entry *h;
if (!config.build_constructors)
h = bfd_define_start_stop (link_info.output_bfd, &link_info, symbol, sec);
if (h != NULL)
{
if (start_stop_count == start_stop_alloc)
{
start_stop_alloc = 2 * start_stop_alloc + 10;
start_stop_syms
= xrealloc (start_stop_syms,
start_stop_alloc * sizeof (*start_stop_syms));
}
start_stop_syms[start_stop_count++] = h;
}
}
/* Check for input sections whose names match references to
__start_SECNAME or __stop_SECNAME symbols. Give the symbols
preliminary definitions. */
static void
lang_init_start_stop (void)
{
bfd *abfd;
asection *s;
char leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
for (s = abfd->sections; s != NULL; s = s->next)
{
const char *ps;
const char *secname = s->name;
for (ps = secname; *ps != '\0'; ps++)
if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symbol = (char *) xmalloc (10 + strlen (secname));
symbol[0] = leading_char;
sprintf (symbol + (leading_char != 0), "__start_%s", secname);
lang_define_start_stop (symbol, s);
symbol[1] = leading_char;
memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
lang_define_start_stop (symbol + 1, s);
free (symbol);
}
}
}
/* Iterate over start_stop_syms. */
static void
foreach_start_stop (void (*func) (struct bfd_link_hash_entry *))
{
size_t i;
for (i = 0; i < start_stop_count; ++i)
func (start_stop_syms[i]);
}
/* __start and __stop symbols are only supposed to be defined by the
linker for orphan sections, but we now extend that to sections that
map to an output section of the same name. The symbols were
defined early for --gc-sections, before we mapped input to output
sections, so undo those that don't satisfy this rule. */
static void
undef_start_stop (struct bfd_link_hash_entry *h)
{
if (h->ldscript_def)
return;
is_elf = (bfd_get_flavour (link_info.output_bfd)
== bfd_target_elf_flavour);
is_relocatable = bfd_link_relocatable (&link_info);
if (h->u.def.section->output_section == NULL
|| h->u.def.section->output_section->owner != link_info.output_bfd
|| strcmp (h->u.def.section->name,
h->u.def.section->output_section->name) != 0)
{
h->type = bfd_link_hash_undefined;
h->u.undef.abfd = NULL;
}
}
leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
static void
lang_undef_start_stop (void)
{
foreach_start_stop (undef_start_stop);
}
/* Check for output sections whose names match references to
.startof.SECNAME or .sizeof.SECNAME symbols. Give the symbols
preliminary definitions. */
static void
lang_init_startof_sizeof (void)
{
asection *s;
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
{
const char *secname;
char *buf;
struct bfd_link_hash_entry *h;
const char *secname = s->name;
char *symbol = (char *) xmalloc (10 + strlen (secname));
secname = bfd_get_section_name (link_info.output_bfd, s);
buf = (char *) xmalloc (10 + strlen (secname));
sprintf (symbol, ".startof.%s", secname);
lang_define_start_stop (symbol, s);
if (!is_relocatable)
{
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;
}
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 = s;
if (is_elf)
((struct elf_link_hash_entry *) h)->def_regular = 1;
}
free (buf);
memcpy (symbol + 1, ".size", 5);
lang_define_start_stop (symbol + 1, s);
free (symbol);
}
}
/* Set .startof., .sizeof., __start and __stop symbols final values. */
static void
set_start_stop (struct bfd_link_hash_entry *h)
{
if (h->ldscript_def
|| h->type != bfd_link_hash_defined)
return;
if (h->root.string[0] == '.')
{
/* .startof. or .sizeof. symbol.
.startof. already has final value. */
if (h->root.string[2] == 'i')
{
/* .sizeof. */
h->u.def.value = TO_ADDR (h->u.def.section->size);
h->u.def.section = bfd_abs_section_ptr;
}
}
else
{
/* __start or __stop symbol. */
int has_lead = bfd_get_symbol_leading_char (link_info.output_bfd) != 0;
h->u.def.section = h->u.def.section->output_section;
if (h->root.string[4 + has_lead] == 'o')
{
/* __stop_ */
h->u.def.value = TO_ADDR (h->u.def.section->size);
}
}
}
static void
lang_finalize_start_stop (void)
{
foreach_start_stop (set_start_stop);
}
static void
lang_end (void)
{
@ -7035,6 +7111,12 @@ lang_process (void)
files. */
ldctor_build_sets ();
/* Give initial values for __start and __stop symbols, so that ELF
gc_sections will keep sections referenced by these symbols. Must
be done before lang_do_assignments below. */
if (config.build_constructors)
lang_init_start_stop ();
/* PR 13683: We must rerun the assignments prior to running garbage
collection in order to make sure that all symbol aliases are resolved. */
lang_do_assignments (lang_mark_phase_enum);
@ -7089,6 +7171,17 @@ lang_process (void)
/* Copy forward lma regions for output sections in same lma region. */
lang_propagate_lma_regions ();
/* Defining __start/__stop symbols early for --gc-sections to work
around a glibc build problem can result in these symbols being
defined when they should not be. Fix them now. */
if (config.build_constructors)
lang_undef_start_stop ();
/* Define .startof./.sizeof. symbols with preliminary values before
dynamic symbols are created. */
if (!bfd_link_relocatable (&link_info))
lang_init_startof_sizeof ();
/* Do anything special before sizing sections. This is where ELF
and other back-ends size dynamic sections. */
ldemul_before_allocation ();
@ -7108,8 +7201,8 @@ lang_process (void)
everything is. This is where relaxation is done. */
ldemul_after_allocation ();
/* Fix any .startof. or .sizeof. symbols. */
lang_set_startof ();
/* Fix any __start, __stop, .startof. or .sizeof. symbols. */
lang_finalize_start_stop ();
/* Do all the assignments, now that we know the final resting places
of all the symbols. */