From bcacc0f587e22ba46333d9377e7e9e4576c90f74 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 3 Oct 2008 09:40:49 +0000 Subject: [PATCH] bfd/ * elf.c (bfd_elf_set_group_contents): Assign sh_info for ld -r when the signature symbol is global. * elflink.c (elf_link_input_bfd): Ensure group signature symbol is output when ld -r. Set group sh_info when local. * linker.c (default_indirect_link_order): Handle group sections specially. ld/ * ldemul.c (ldemul_place_orphan): Add "name" param. * ldemul.h (ldemul_place_orphan): Update prototype. (struct ld_emulation_xfer_struct ): Likewise. * ldlang.c (lang_place_orphans): Generate unique section names here.. * emultempl/elf32.em (place_orphan): ..rather than here. Don't directly use an existing output section statement that has no bfd section. * emultempl/pe.em (place_orphan): Likewise. * emultempl/pep.em (place_orphan): Likewise. * emultempl/beos.em (place_orphan): Adjust. * emultempl/spuelf.em (spu_place_special_section): Adjust place_orphan call. * emultempl/genelf.em (gld${EMULATION_NAME}_after_open): New function. (LDEMUL_AFTER_OPEN): Define. --- bfd/ChangeLog | 9 +++++++ bfd/elf.c | 57 ++++++++++++++++++++++++++++++---------- bfd/elflink.c | 57 ++++++++++++++++++++++++++++++++++++++++ bfd/linker.c | 42 +++++++++++++++++++++--------- ld/ChangeLog | 17 ++++++++++++ ld/emultempl/beos.em | 5 +--- ld/emultempl/elf32.em | 59 ++++++++++++++---------------------------- ld/emultempl/genelf.em | 20 ++++++++++++++ ld/emultempl/pe.em | 30 +++++---------------- ld/emultempl/pep.em | 30 +++++---------------- ld/emultempl/spuelf.em | 7 +---- ld/ldemul.c | 4 +-- ld/ldemul.h | 4 +-- ld/ldlang.c | 25 ++++++++++++++---- 14 files changed, 237 insertions(+), 129 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f7755361553..b95f32212ae 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2008-10-03 Alan Modra + + * elf.c (bfd_elf_set_group_contents): Assign sh_info for ld -r when + the signature symbol is global. + * elflink.c (elf_link_input_bfd): Ensure group signature symbol + is output when ld -r. Set group sh_info when local. + * linker.c (default_indirect_link_order): Handle group sections + specially. + 2008-09-30 Wesley W. Terpstra Nick Clifton diff --git a/bfd/elf.c b/bfd/elf.c index 763750b8827..e9d0af302a5 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -2681,13 +2681,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) *failedptr = TRUE; } -/* Fill in the contents of a SHT_GROUP section. */ +/* Fill in the contents of a SHT_GROUP section. Called from + _bfd_elf_compute_section_file_positions for gas, objcopy, and + when ELF targets use the generic linker, ld. Called for ld -r + from bfd_elf_final_link. */ void bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) { bfd_boolean *failedptr = failedptrarg; - unsigned long symindx; asection *elt, *first; unsigned char *loc; bfd_boolean gas; @@ -2698,20 +2700,49 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) || *failedptr) return; - symindx = 0; - if (elf_group_id (sec) != NULL) - symindx = elf_group_id (sec)->udata.i; + if (elf_section_data (sec)->this_hdr.sh_info == 0) + { + unsigned long symindx = 0; + + /* elf_group_id will have been set up by objcopy and the + generic linker. */ + if (elf_group_id (sec) != NULL) + symindx = elf_group_id (sec)->udata.i; - if (symindx == 0) + if (symindx == 0) + { + /* If called from the assembler, swap_out_syms will have set up + elf_section_syms. */ + BFD_ASSERT (elf_section_syms (abfd) != NULL); + symindx = elf_section_syms (abfd)[sec->index]->udata.i; + } + elf_section_data (sec)->this_hdr.sh_info = symindx; + } + else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2) { - /* If called from the assembler, swap_out_syms will have set up - elf_section_syms; If called for "ld -r", use target_index. */ - if (elf_section_syms (abfd) != NULL) - symindx = elf_section_syms (abfd)[sec->index]->udata.i; - else - symindx = sec->target_index; + /* The ELF backend linker sets sh_info to -2 when the group + signature symbol is global, and thus the index can't be + set until all local symbols are output. */ + asection *igroup = elf_sec_group (elf_next_in_group (sec)); + struct bfd_elf_section_data *sec_data = elf_section_data (igroup); + unsigned long symndx = sec_data->this_hdr.sh_info; + unsigned long extsymoff = 0; + struct elf_link_hash_entry *h; + + if (!elf_bad_symtab (igroup->owner)) + { + Elf_Internal_Shdr *symtab_hdr; + + symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr; + extsymoff = symtab_hdr->sh_info; + } + h = elf_sym_hashes (igroup->owner)[symndx - extsymoff]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + elf_section_data (sec)->this_hdr.sh_info = h->indx; } - elf_section_data (sec)->this_hdr.sh_info = symindx; /* The contents won't be allocated for "ld -r" or objcopy. */ gas = TRUE; diff --git a/bfd/elflink.c b/bfd/elflink.c index 8e59383aae6..d2dc17d3747 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -9062,6 +9062,63 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) continue; } + if (finfo->info->relocatable + && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP) + { + /* Deal with the group signature symbol. */ + struct bfd_elf_section_data *sec_data = elf_section_data (o); + unsigned long symndx = sec_data->this_hdr.sh_info; + asection *osec = o->output_section; + + if (symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[symndx] == NULL)) + { + struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + /* Arrange for symbol to be output. */ + h->indx = -2; + elf_section_data (osec)->this_hdr.sh_info = -2; + } + else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION) + { + /* We'll use the output section target_index. */ + asection *sec = finfo->sections[symndx]->output_section; + elf_section_data (osec)->this_hdr.sh_info = sec->target_index; + } + else + { + if (finfo->indices[symndx] == -1) + { + /* Otherwise output the local symbol now. */ + Elf_Internal_Sym sym = isymbuf[symndx]; + asection *sec = finfo->sections[symndx]->output_section; + const char *name; + + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym.st_name); + if (name == NULL) + return FALSE; + + sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, + sec); + if (sym.st_shndx == SHN_BAD) + return FALSE; + + sym.st_value += o->output_offset; + + finfo->indices[symndx] = bfd_get_symcount (output_bfd); + if (! elf_link_output_sym (finfo, name, &sym, o, NULL)) + return FALSE; + } + elf_section_data (osec)->this_hdr.sh_info + = finfo->indices[symndx]; + } + } + if ((o->flags & SEC_HAS_CONTENTS) == 0 || (o->size == 0 && (o->flags & SEC_RELOC) == 0)) continue; diff --git a/bfd/linker.c b/bfd/linker.c index baf280c7a24..5080d7d44cb 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -2796,18 +2796,36 @@ default_indirect_link_order (bfd *output_bfd, } } - /* Get and relocate the section contents. */ - sec_size = (input_section->rawsize > input_section->size - ? input_section->rawsize - : input_section->size); - contents = bfd_malloc (sec_size); - if (contents == NULL && sec_size != 0) - goto error_return; - new_contents = (bfd_get_relocated_section_contents - (output_bfd, info, link_order, contents, info->relocatable, - _bfd_generic_link_get_symbols (input_bfd))); - if (!new_contents) - goto error_return; + if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP + && input_section->size != 0) + { + /* Group section contents are set by bfd_elf_set_group_contents. */ + if (!output_bfd->output_has_begun) + { + /* FIXME: This hack ensures bfd_elf_set_group_contents is called. */ + if (!bfd_set_section_contents (output_bfd, output_section, "", 0, 1)) + goto error_return; + } + new_contents = output_section->contents; + BFD_ASSERT (new_contents != NULL); + BFD_ASSERT (input_section->output_offset == 0); + } + else + { + /* Get and relocate the section contents. */ + sec_size = (input_section->rawsize > input_section->size + ? input_section->rawsize + : input_section->size); + contents = bfd_malloc (sec_size); + if (contents == NULL && sec_size != 0) + goto error_return; + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, + info->relocatable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + } /* Output the section contents. */ loc = input_section->output_offset * bfd_octets_per_byte (output_bfd); diff --git a/ld/ChangeLog b/ld/ChangeLog index 25debe5ef6c..f957395ed09 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,20 @@ +2008-10-03 Alan Modra + + * ldemul.c (ldemul_place_orphan): Add "name" param. + * ldemul.h (ldemul_place_orphan): Update prototype. + (struct ld_emulation_xfer_struct ): Likewise. + * ldlang.c (lang_place_orphans): Generate unique section names here.. + * emultempl/elf32.em (place_orphan): ..rather than here. Don't + directly use an existing output section statement that has no + bfd section. + * emultempl/pe.em (place_orphan): Likewise. + * emultempl/pep.em (place_orphan): Likewise. + * emultempl/beos.em (place_orphan): Adjust. + * emultempl/spuelf.em (spu_place_special_section): Adjust + place_orphan call. + * emultempl/genelf.em (gld${EMULATION_NAME}_after_open): New function. + (LDEMUL_AFTER_OPEN): Define. + 2008-09-30 Joseph Myers * emulparams/elf64ppc.sh (OTHER_GOT_RELOC_SECTIONS): Add .rela.opd diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em index fac0c893c67..997f3a63cec 100644 --- a/ld/emultempl/beos.em +++ b/ld/emultempl/beos.em @@ -665,9 +665,8 @@ gld_${EMULATION_NAME}_before_allocation (void) which are not mentioned in the linker script. */ static bfd_boolean -gld${EMULATION_NAME}_place_orphan (asection *s) +gld${EMULATION_NAME}_place_orphan (asection *s, const char *secname) { - const char *secname; char *output_secname, *ps; lang_output_section_statement_type *os; lang_statement_union_type *l; @@ -682,8 +681,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s) if (link_info.relocatable) return FALSE; - secname = bfd_get_section_name (s->owner, s); - /* Everything from the '\$' on gets deleted so don't allow '\$' as the first character. */ if (*secname == '\$') diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index be9d78d2eff..65ad4f13461 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -62,7 +62,7 @@ fragment <owner->xvec->flavour == bfd_target_elf_flavour; unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL; - secname = bfd_get_section_name (s->owner, s); - if (! link_info.relocatable && link_info.combreloc && (s->flags & SEC_ALLOC)) @@ -1707,28 +1704,24 @@ gld${EMULATION_NAME}_place_orphan (asection *s) } } - if (isdyn || (!config.unique_orphan_sections && !unique_section_p (s))) + /* Look through the script to see where to place this section. */ + os = lang_output_section_find (secname); + + if (os != NULL + && os->bfd_section != NULL + && (os->bfd_section->flags == 0 + || (_bfd_elf_match_sections_by_type (link_info.output_bfd, + os->bfd_section, s->owner, s) + && ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0))) { - /* Look through the script to see where to place this section. */ - os = lang_output_section_find (secname); - - if (os != NULL - && (os->bfd_section == NULL - || os->bfd_section->flags == 0 - || (_bfd_elf_match_sections_by_type (link_info.output_bfd, - os->bfd_section, - s->owner, s) - && ((s->flags ^ os->bfd_section->flags) - & (SEC_LOAD | SEC_ALLOC)) == 0))) - { - /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. - If the section already exists but does not have any flags - set, then it has been created by the linker, probably as a - result of a --section-start command line switch. */ - lang_add_section (&os->children, s, os); - return TRUE; - } + /* We already have an output section statement with this + name, and its bfd section has compatible flags. + If the section already exists but does not have any flags + set, then it has been created by the linker, probably as a + result of a --section-start command line switch. */ + lang_add_section (&os->children, s, os); + return TRUE; } if (!orphan_init_done) @@ -1748,7 +1741,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s) sections into the .text section to get them out of the way. */ if (link_info.executable && ! link_info.relocatable - && CONST_STRNEQ (secname, ".gnu.warning.") + && CONST_STRNEQ (s->name, ".gnu.warning.") && hold[orphan_text].os != NULL) { lang_add_section (&hold[orphan_text].os->children, s, @@ -1803,18 +1796,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s) after = &lang_output_section_statement.head->output_section_statement; } - /* Choose a unique name for the section. This will be needed if the - same section name appears in the input file with different - loadable or allocatable characteristics. */ - if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL) - { - static int count = 1; - secname = bfd_get_unique_section_name (link_info.output_bfd, - secname, &count); - if (secname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } - lang_insert_orphan (s, secname, after, place, NULL, NULL); return TRUE; diff --git a/ld/emultempl/genelf.em b/ld/emultempl/genelf.em index e44bb9b9e10..e6e8841f0d3 100644 --- a/ld/emultempl/genelf.em +++ b/ld/emultempl/genelf.em @@ -34,7 +34,27 @@ gld${EMULATION_NAME}_finish (void) gld${EMULATION_NAME}_map_segments (FALSE); finish_default (); } + +static void +gld${EMULATION_NAME}_after_open (void) +{ + bfd *ibfd; + asection *sec; + asymbol **syms; + + if (link_info.relocatable) + for (ibfd = link_info.input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + if ((syms = bfd_get_outsymbols (ibfd)) != NULL + && bfd_get_flavour (ibfd) == bfd_target_elf_flavour) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP) + { + struct bfd_elf_section_data *sec_data = elf_section_data (sec); + elf_group_id (sec) = syms[sec_data->this_hdr.sh_info - 1]; + } +} EOF # Put these extra routines in ld_${EMULATION_NAME}_emulation # LDEMUL_FINISH=gld${EMULATION_NAME}_finish +LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index cec399a052b..89c521d9e9e 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -1613,24 +1613,20 @@ gld_${EMULATION_NAME}_finish (void) sort_sections. */ static bfd_boolean -gld_${EMULATION_NAME}_place_orphan (asection *s) +gld_${EMULATION_NAME}_place_orphan (asection *s, const char *secname) { - const char *secname; - const char *orig_secname; + const char *orig_secname = secname; char *dollar = NULL; lang_output_section_statement_type *os; lang_statement_list_type add_child; - secname = bfd_get_section_name (s->owner, s); - /* Look through the script to see where to place this section. */ - orig_secname = secname; if (!link_info.relocatable && (dollar = strchr (secname, '$')) != NULL) { - size_t len = dollar - orig_secname; + size_t len = dollar - secname; char *newname = xmalloc (len + 1); - memcpy (newname, orig_secname, len); + memcpy (newname, secname, len); newname[len] = '\0'; secname = newname; } @@ -1640,13 +1636,13 @@ gld_${EMULATION_NAME}_place_orphan (asection *s) lang_list_init (&add_child); if (os != NULL - && (os->bfd_section == NULL - || os->bfd_section->flags == 0 + && os->bfd_section != NULL + && (os->bfd_section->flags == 0 || ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)) { /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. + name, and its bfd section has compatible flags. If the section already exists but does not have any flags set, then it has been created by the linker, probably as a result of a --section-start command line switch. */ @@ -1723,18 +1719,6 @@ gld_${EMULATION_NAME}_place_orphan (asection *s) ->output_section_statement); } - /* Choose a unique name for the section. This will be needed if the - same section name appears in the input file with different - loadable or allocatable characteristics. */ - if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL) - { - static int count = 1; - secname = bfd_get_unique_section_name (link_info.output_bfd, - secname, &count); - if (secname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } - /* All sections in an executable must be aligned to a page boundary. */ address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); os = lang_insert_orphan (s, secname, after, place, address, &add_child); diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em index 0b9bf402b5f..4afac022b6d 100644 --- a/ld/emultempl/pep.em +++ b/ld/emultempl/pep.em @@ -1372,24 +1372,20 @@ gld_${EMULATION_NAME}_finish (void) sort_sections. */ static bfd_boolean -gld_${EMULATION_NAME}_place_orphan (asection *s) +gld_${EMULATION_NAME}_place_orphan (asection *s, const char *secname) { - const char *secname; - const char *orig_secname; + const char *orig_secname = secname; char *dollar = NULL; lang_output_section_statement_type *os; lang_statement_list_type add_child; - secname = bfd_get_section_name (s->owner, s); - /* Look through the script to see where to place this section. */ - orig_secname = secname; if (!link_info.relocatable && (dollar = strchr (secname, '$')) != NULL) { - size_t len = dollar - orig_secname; + size_t len = dollar - secname; char *newname = xmalloc (len + 1); - memcpy (newname, orig_secname, len); + memcpy (newname, secname, len); newname[len] = '\0'; secname = newname; } @@ -1399,13 +1395,13 @@ gld_${EMULATION_NAME}_place_orphan (asection *s) lang_list_init (&add_child); if (os != NULL - && (os->bfd_section == NULL - || os->bfd_section->flags == 0 + && os->bfd_section != NULL + && (os->bfd_section->flags == 0 || ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)) { /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. + name, and its bfd section has compatible flags. If the section already exists but does not have any flags set, then it has been created by the linker, probably as a result of a --section-start command line switch. */ @@ -1482,18 +1478,6 @@ gld_${EMULATION_NAME}_place_orphan (asection *s) ->output_section_statement); } - /* Choose a unique name for the section. This will be needed if the - same section name appears in the input file with different - loadable or allocatable characteristics. */ - if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL) - { - static int count = 1; - secname = bfd_get_unique_section_name (link_info.output_bfd, - secname, &count); - if (secname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } - /* All sections in an executable must be aligned to a page boundary. */ address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); os = lang_insert_orphan (s, secname, after, place, address, &add_child); diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em index 116a0cc9851..bc2f6b548fc 100644 --- a/ld/emultempl/spuelf.em +++ b/ld/emultempl/spuelf.em @@ -114,12 +114,7 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) os = lang_output_section_find (o != NULL ? o->name : output_name); if (os == NULL) - { - const char *save = s->name; - s->name = output_name; - gld${EMULATION_NAME}_place_orphan (s); - s->name = save; - } + gld${EMULATION_NAME}_place_orphan (s, output_name); else if (o != NULL && os->children.head != NULL) { lang_statement_list_type add; diff --git a/ld/ldemul.c b/ld/ldemul.c index 6b86ddfce48..68e1de26210 100644 --- a/ld/ldemul.c +++ b/ld/ldemul.c @@ -120,10 +120,10 @@ ldemul_open_dynamic_archive (const char *arch, search_dirs_type *search, } bfd_boolean -ldemul_place_orphan (asection *s) +ldemul_place_orphan (asection *s, const char *name) { if (ld_emulation->place_orphan) - return (*ld_emulation->place_orphan) (s); + return (*ld_emulation->place_orphan) (s, name); return FALSE; } diff --git a/ld/ldemul.h b/ld/ldemul.h index cc817286094..6c95a9d9a16 100644 --- a/ld/ldemul.h +++ b/ld/ldemul.h @@ -59,7 +59,7 @@ extern void ldemul_set_symbols extern void ldemul_create_output_section_statements (void); extern bfd_boolean ldemul_place_orphan - (asection *); + (asection *, const char *); extern bfd_boolean ldemul_parse_args (int, char **); extern void ldemul_add_options @@ -152,7 +152,7 @@ typedef struct ld_emulation_xfer_struct { the default action should be taken. This field may be NULL, in which case the default action will always be taken. */ bfd_boolean (*place_orphan) - (asection *); + (asection *, const char *); /* Run after assigning parsing with the args, but before reading the script. Used to initialize symbols used in the script. */ diff --git a/ld/ldlang.c b/ld/ldlang.c index b1b88062b02..44fb136d84b 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -5652,14 +5652,29 @@ lang_place_orphans (void) default_common_section); } } - else if (ldemul_place_orphan (s)) - ; else { - lang_output_section_statement_type *os; + const char *name = s->name; - os = lang_output_section_statement_lookup (s->name, 0, TRUE); - lang_add_section (&os->children, s, os); + if ((config.unique_orphan_sections + || unique_section_p (s)) + && bfd_get_section_by_name (link_info.output_bfd, + name) != NULL) + { + static int count = 1; + name = bfd_get_unique_section_name (link_info.output_bfd, + name, &count); + if (name == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); + } + + if (!ldemul_place_orphan (s, name)) + { + lang_output_section_statement_type *os; + os = lang_output_section_statement_lookup (name, 0, + TRUE); + lang_add_section (&os->children, s, os); + } } } } -- 2.30.2