diff options
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 233 |
1 files changed, 163 insertions, 70 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index eb4ba9e..726bc8e 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -5878,98 +5878,174 @@ 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_define_start_stop (const char *symbol, asection *sec) +{ + struct bfd_link_hash_entry *h; + + 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_set_startof (void) +lang_init_start_stop (void) { + bfd *abfd; asection *s; - char leading_char; - bfd_boolean is_elf; - bfd_boolean is_relocatable; + 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)); - if (!config.build_constructors) + 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; + } +} + +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. */ - leading_char = bfd_get_symbol_leading_char (link_info.output_bfd); +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; - } + memcpy (symbol + 1, ".size", 5); + lang_define_start_stop (symbol + 1, s); + free (symbol); + } +} - 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; - } - } +/* Set .startof., .sizeof., __start and __stop symbols final values. */ - 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)) +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') { - 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; + /* .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; - 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->u.def.section = h->u.def.section->output_section; + if (h->root.string[4 + has_lead] == 'o') { - 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; + /* __stop_ */ + h->u.def.value = TO_ADDR (h->u.def.section->size); } - free (buf); } } static void +lang_finalize_start_stop (void) +{ + foreach_start_stop (set_start_stop); +} + +static void lang_end (void) { struct bfd_link_hash_entry *h; @@ -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. */ |