diff options
author | Alan Modra <amodra@gmail.com> | 2011-07-09 06:20:52 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2011-07-09 06:20:52 +0000 |
commit | 0c51100021bb287449cd0796586a7495d76e14bf (patch) | |
tree | 65bbc32ae045206821bd4d2de8a5473adc6071fb /bfd | |
parent | beabb2c68ff9e09a1141cafd6f0b11ed98343290 (diff) | |
download | gdb-0c51100021bb287449cd0796586a7495d76e14bf.zip gdb-0c51100021bb287449cd0796586a7495d76e14bf.tar.gz gdb-0c51100021bb287449cd0796586a7495d76e14bf.tar.bz2 |
PR ld/12942
bfd/
* elflink.c (elf_link_add_object_symbols): Use elf_discarded_section
rather than kept_section to determine whether a symbol is from
a discarded section.
* cofflink.c (coff_link_add_symbols): Make symbols from discarded
sections appear undefined.
* elf-bfd.h (_bfd_elf_section_already_linked): Replace
"asection *" with "struct already_linked *".
* libbfd-in.h (_bfd_nolink_section_already_linked): Likewise.
(_bfd_generic_section_already_linked): Likewise.
(bfd_section_already_linked_table_insert): Likewise.
(struct already_linked): New.
(struct bfd_section_already_linked): Use it.
* elflink.c (_bfd_elf_section_already_linked): Replace.
"asection *" with "struct already_linked *". Replace the plugin
dummy with the LTO output.
* linker.c (_bfd_generic_section_already_linked): Likewise.
* targets.c (struct already_linked): Add forward declaration.
(bfd_target): Replace "struct bfd_section *" with
"struct already_linked *" in _section_already_linked.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
include/
* bfdlink.h (bfd_link_info): Add loading_lto_outputs.
ld/
* ldlang.c (section_already_linked): Pass "struct already_linked *"
to bfd_section_already_linked.
(lang_process): Set link_info.loading_lto_outputs before
loading LTO outputs.
* plugin.c: Include "libbfd.h".
(add_symbols): Call bfd_section_already_linked with comdat_key.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 29 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 10 | ||||
-rw-r--r-- | bfd/cofflink.c | 6 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 2 | ||||
-rw-r--r-- | bfd/elflink.c | 329 | ||||
-rw-r--r-- | bfd/libbfd-in.h | 19 | ||||
-rw-r--r-- | bfd/libbfd.h | 19 | ||||
-rw-r--r-- | bfd/linker.c | 127 | ||||
-rw-r--r-- | bfd/targets.c | 3 |
9 files changed, 371 insertions, 173 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9a3dafb..a1b9197 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,32 @@ +2011-07-09 Alan Modra <amodra@gmail.com> + + PR ld/12942 + * elflink.c (elf_link_add_object_symbols): Use elf_discarded_section + rather than kept_section to determine whether a symbol is from + a discarded section. + * cofflink.c (coff_link_add_symbols): Make symbols from discarded + sections appear undefined. + +2011-07-09 H.J. Lu <hongjiu.lu@intel.com> + + PR ld/12942 + * elf-bfd.h (_bfd_elf_section_already_linked): Replace + "asection *" with "struct already_linked *". + * libbfd-in.h (_bfd_nolink_section_already_linked): Likewise. + (_bfd_generic_section_already_linked): Likewise. + (bfd_section_already_linked_table_insert): Likewise. + (struct already_linked): New. + (struct bfd_section_already_linked): Use it. + * elflink.c (_bfd_elf_section_already_linked): Replace. + "asection *" with "struct already_linked *". Replace the plugin + dummy with the LTO output. + * linker.c (_bfd_generic_section_already_linked): Likewise. + * targets.c (struct already_linked): Add forward declaration. + (bfd_target): Replace "struct bfd_section *" with + "struct already_linked *" in _section_already_linked. + * bfd-in2.h: Regenerate. + * libbfd.h: Regenerate. + 2011-07-06 Tristan Gingold <gingold@adacore.com> * mach-o.h: Move loader related definitions to diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 672c293..da4688c 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5726,6 +5726,7 @@ enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; /* Forward declaration. */ typedef struct bfd_link_info _bfd_link_info; +struct already_linked; typedef struct bfd_target { @@ -6051,7 +6052,7 @@ typedef struct bfd_target /* Check if SEC has been already linked during a reloceatable or final link. */ - void (*_section_already_linked) (bfd *, struct bfd_section *, + void (*_section_already_linked) (bfd *, struct already_linked *, struct bfd_link_info *); /* Define a common symbol. */ @@ -6121,11 +6122,12 @@ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); #define bfd_link_split_section(abfd, sec) \ BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) -void bfd_section_already_linked (bfd *abfd, asection *sec, +void bfd_section_already_linked (bfd *abfd, + struct already_linked *data, struct bfd_link_info *info); -#define bfd_section_already_linked(abfd, sec, info) \ - BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) +#define bfd_section_already_linked(abfd, data, info) \ + BFD_SEND (abfd, _section_already_linked, (abfd, data, info)) bfd_boolean bfd_generic_define_common_symbol (bfd *output_bfd, struct bfd_link_info *info, diff --git a/bfd/cofflink.c b/bfd/cofflink.c index bca1364..27257ba 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -392,7 +392,11 @@ coff_link_add_symbols (bfd *abfd, section = coff_section_from_bfd_index (abfd, sym.n_scnum); if (! obj_pe (abfd)) value -= section->vma; - break; + /* Treat a symbol from a discarded section as undefined. */ + if (bfd_is_abs_section (section) + || !bfd_is_abs_section (section->output_section)) + break; + /* Fall thru */ case COFF_SYMBOL_UNDEFINED: flags = 0; diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 64a9dc0..b2075a5 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1793,7 +1793,7 @@ extern bfd_boolean _bfd_elf_match_sections_by_type extern bfd_boolean bfd_elf_is_group_section (bfd *, const struct bfd_section *); extern void _bfd_elf_section_already_linked - (bfd *, struct bfd_section *, struct bfd_link_info *); + (bfd *, struct already_linked *, struct bfd_link_info *); extern void bfd_elf_set_group_contents (bfd *, asection *, void *); extern asection *_bfd_elf_check_kept_section diff --git a/bfd/elflink.c b/bfd/elflink.c index b518da8..238a4aa 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -3900,7 +3900,7 @@ error_free_dyn: sec = bfd_section_from_elf_index (abfd, isym->st_shndx); if (sec == NULL) sec = bfd_abs_section_ptr; - else if (sec->kept_section) + else if (elf_discarded_section (sec)) { /* Symbols from discarded section are undefined. We keep its visibility. */ @@ -12438,63 +12438,100 @@ section_signature (asection *sec) } void -_bfd_elf_section_already_linked (bfd *abfd, asection *sec, +_bfd_elf_section_already_linked (bfd *abfd, + struct already_linked *linked, struct bfd_link_info *info) { flagword flags; const char *name, *p; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; + asection *sec, *l_sec; - if (sec->output_section == bfd_abs_section_ptr) - return; - - flags = sec->flags; - - /* Return if it isn't a linkonce section. A comdat group section - also has SEC_LINK_ONCE set. */ - if ((flags & SEC_LINK_ONCE) == 0) - return; - - /* Don't put group member sections on our list of already linked - sections. They are handled as a group via their group section. */ - if (elf_sec_group (sec) != NULL) - return; - - /* FIXME: When doing a relocatable link, we may have trouble - copying relocations in other sections that refer to local symbols - in the section being discarded. Those relocations will have to - be converted somehow; as of this writing I'm not sure that any of - the backends handle that correctly. - - It is tempting to instead not discard link once sections when - doing a relocatable link (technically, they should be discarded - whenever we are building constructors). However, that fails, - because the linker winds up combining all the link once sections - into a single large link once section, which defeats the purpose - of having link once sections in the first place. - - Also, not merging link once sections in a relocatable link - causes trouble for MIPS ELF, which relies on link once semantics - to handle the .reginfo section correctly. */ - - name = section_signature (sec); - - if (CONST_STRNEQ (name, ".gnu.linkonce.") - && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) - p++; + p = name = linked->comdat_key; + if (name) + { + sec = NULL; + flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + } else - p = name; + { + sec = linked->u.sec; + if (sec->output_section == bfd_abs_section_ptr) + return; + + flags = sec->flags; + + /* Return if it isn't a linkonce section. A comdat group section + also has SEC_LINK_ONCE set. */ + if ((flags & SEC_LINK_ONCE) == 0) + return; + + /* Don't put group member sections on our list of already linked + sections. They are handled as a group via their group section. + */ + if (elf_sec_group (sec) != NULL) + return; + + /* FIXME: When doing a relocatable link, we may have trouble + copying relocations in other sections that refer to local symbols + in the section being discarded. Those relocations will have to + be converted somehow; as of this writing I'm not sure that any of + the backends handle that correctly. + + It is tempting to instead not discard link once sections when + doing a relocatable link (technically, they should be discarded + whenever we are building constructors). However, that fails, + because the linker winds up combining all the link once sections + into a single large link once section, which defeats the purpose + of having link once sections in the first place. + + Also, not merging link once sections in a relocatable link + causes trouble for MIPS ELF, which relies on link once semantics + to handle the .reginfo section correctly. */ + + name = section_signature (sec); + + if (CONST_STRNEQ (name, ".gnu.linkonce.") + && ((p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) + != NULL)) + p++; + else + p = name; + } already_linked_list = bfd_section_already_linked_table_lookup (p); for (l = already_linked_list->entry; l != NULL; l = l->next) { + bfd_boolean l_coff_comdat_sec; + flagword l_flags; + bfd *l_owner; + const char *l_name = l->linked.comdat_key; + if (l_name) + { + l_sec = NULL; + l_owner = l->linked.u.abfd; + l_flags = (SEC_GROUP + | SEC_LINK_ONCE + | SEC_LINK_DUPLICATES_DISCARD); + l_coff_comdat_sec = FALSE; + } + else + { + l_sec = l->linked.u.sec; + l_owner = l_sec->owner; + l_flags = l_sec->flags; + l_coff_comdat_sec + = !!bfd_coff_get_comdat_section (l_sec->owner, l_sec); + l_name = section_signature (l_sec); + } + /* We may have 2 different types of sections on the list: group sections and linkonce sections. Match like sections. */ - if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) - && strcmp (name, section_signature (l->sec)) == 0 - && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL) + if ((flags & SEC_GROUP) == (l_flags & SEC_GROUP) + && strcmp (name, l_name) == 0 + && !l_coff_comdat_sec) { /* The section has already been linked. See if we should issue a warning. */ @@ -12504,6 +12541,18 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec, abort (); case SEC_LINK_DUPLICATES_DISCARD: + /* If we found an LTO IR match for this comdat group on + the first pass, replace it with the LTO output on the + second pass. We can't simply choose real object + files over IR because the first pass may contain a + mix of LTO and normal objects and we must keep the + first match, be it IR or real. */ + if (info->loading_lto_outputs + && (l_owner->flags & BFD_PLUGIN) != 0) + { + l->linked = *linked; + return; + } break; case SEC_LINK_DUPLICATES_ONE_ONLY: @@ -12513,14 +12562,20 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec, break; case SEC_LINK_DUPLICATES_SAME_SIZE: - if (sec->size != l->sec->size) + if (!sec || !l_sec) + abort (); + + if (sec->size != l_sec->size) (*_bfd_error_handler) (_("%B: duplicate section `%A' has different size"), abfd, sec); break; case SEC_LINK_DUPLICATES_SAME_CONTENTS: - if (sec->size != l->sec->size) + if (!sec || !l_sec) + abort (); + + if (sec->size != l_sec->size) (*_bfd_error_handler) (_("%B: duplicate section `%A' has different size"), abfd, sec); @@ -12532,11 +12587,11 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec, (*_bfd_error_handler) (_("%B: warning: could not read contents of section `%A'"), abfd, sec); - else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec, + else if (!bfd_malloc_and_get_section (l_sec->owner, l_sec, &l_sec_contents)) (*_bfd_error_handler) (_("%B: warning: could not read contents of section `%A'"), - l->sec->owner, l->sec); + l_sec->owner, l_sec); else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) (*_bfd_error_handler) (_("%B: warning: duplicate section `%A' has different contents"), @@ -12550,28 +12605,31 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec, break; } - /* Set the output_section field so that lang_add_section - does not create a lang_input_section structure for this - section. Since there might be a symbol in the section - being discarded, we must retain a pointer to the section - which we are really going to use. */ - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = l->sec; - - if (flags & SEC_GROUP) + if (sec) { - asection *first = elf_next_in_group (sec); - asection *s = first; + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. Since there might be a symbol in the section + being discarded, we must retain a pointer to the section + which we are really going to use. */ + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l_sec; - while (s != NULL) + if (flags & SEC_GROUP) { - s->output_section = bfd_abs_section_ptr; - /* Record which group discards it. */ - s->kept_section = l->sec; - s = elf_next_in_group (s); - /* These lists are circular. */ - if (s == first) - break; + asection *first = elf_next_in_group (sec); + asection *s = first; + + while (s != NULL) + { + s->output_section = bfd_abs_section_ptr; + /* Record which group discards it. */ + s->kept_section = l_sec; + s = elf_next_in_group (s); + /* These lists are circular. */ + if (s == first) + break; + } } } @@ -12579,67 +12637,100 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec, } } - /* A single member comdat group section may be discarded by a - linkonce section and vice versa. */ - - if ((flags & SEC_GROUP) != 0) + if (sec) { - asection *first = elf_next_in_group (sec); + /* A single member comdat group section may be discarded by a + linkonce section and vice versa. */ - if (first != NULL && elf_next_in_group (first) == first) - /* Check this single member group against linkonce sections. */ - for (l = already_linked_list->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP) == 0 - && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL - && bfd_elf_match_symbols_in_sections (l->sec, first, info)) - { - first->output_section = bfd_abs_section_ptr; - first->kept_section = l->sec; - sec->output_section = bfd_abs_section_ptr; - break; - } - } - else - /* Check this linkonce section against single member groups. */ - for (l = already_linked_list->entry; l != NULL; l = l->next) - if (l->sec->flags & SEC_GROUP) + if ((flags & SEC_GROUP) != 0) { - asection *first = elf_next_in_group (l->sec); + asection *first = elf_next_in_group (sec); - if (first != NULL - && elf_next_in_group (first) == first - && bfd_elf_match_symbols_in_sections (first, sec, info)) - { - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = first; - break; - } + if (first != NULL && elf_next_in_group (first) == first) + /* Check this single member group against linkonce sections. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + if (l->linked.comdat_key == NULL) + { + l_sec = l->linked.u.sec; + + if ((l_sec->flags & SEC_GROUP) == 0 + && bfd_coff_get_comdat_section (l_sec->owner, + l_sec) == NULL + && bfd_elf_match_symbols_in_sections (l_sec, + first, + info)) + { + first->output_section = bfd_abs_section_ptr; + first->kept_section = l_sec; + sec->output_section = bfd_abs_section_ptr; + break; + } + } + } } + else + /* Check this linkonce section against single member groups. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + if (l->linked.comdat_key == NULL) + { + l_sec = l->linked.u.sec; - /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' - referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4 - specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce' - prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its - matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded - but its `.gnu.linkonce.t.F' is discarded means we chose one-only - `.gnu.linkonce.t.F' section from a different bfd not requiring any - `.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded. - The reverse order cannot happen as there is never a bfd with only the - `.gnu.linkonce.r.F' section. The order of sections in a bfd does not - matter as here were are looking only for cross-bfd sections. */ - - if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r.")) - for (l = already_linked_list->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP) == 0 - && CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t.")) - { - if (abfd != l->sec->owner) - sec->output_section = bfd_abs_section_ptr; - break; - } + if (l_sec->flags & SEC_GROUP) + { + asection *first = elf_next_in_group (l_sec); + + if (first != NULL + && elf_next_in_group (first) == first + && bfd_elf_match_symbols_in_sections (first, + sec, + info)) + { + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = first; + break; + } + } + } + } + + /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' + referencing its discarded `.gnu.linkonce.t.F' counterpart - + g++-3.4 specific as g++-4.x is using COMDAT groups (without the + `.gnu.linkonce' prefix) instead. `.gnu.linkonce.r.*' were the + `.rodata' part of its matching `.gnu.linkonce.t.*'. If + `.gnu.linkonce.r.F' is not discarded but its `.gnu.linkonce.t.F' + is discarded means we chose one-only `.gnu.linkonce.t.F' section + from a different bfd not requiring any `.gnu.linkonce.r.F'. + Thus `.gnu.linkonce.r.F' should be discarded. The reverse order + cannot happen as there is never a bfd with only the + `.gnu.linkonce.r.F' section. The order of sections in a bfd + does not matter as here were are looking only for cross-bfd + sections. */ + + if ((flags & SEC_GROUP) == 0 + && CONST_STRNEQ (name, ".gnu.linkonce.r.")) + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + if (l->linked.comdat_key == NULL) + { + l_sec = l->linked.u.sec; + + if ((l_sec->flags & SEC_GROUP) == 0 + && CONST_STRNEQ (l_sec->name, ".gnu.linkonce.t.")) + { + if (abfd != l_sec->owner) + sec->output_section = bfd_abs_section_ptr; + break; + } + } + } + } /* This is the first section with this name. Record it. */ - if (! bfd_section_already_linked_table_insert (already_linked_list, sec)) + if (! bfd_section_already_linked_table_insert (already_linked_list, + linked)) info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); } diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index ad45ba3..a80687e 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -478,7 +478,8 @@ extern bfd_boolean _bfd_generic_set_section_contents #define _bfd_nolink_bfd_link_split_section \ ((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false) #define _bfd_nolink_section_already_linked \ - ((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void) + ((void (*) (bfd *, struct already_linked*, \ + struct bfd_link_info *)) bfd_void) #define _bfd_nolink_bfd_define_common_symbol \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, \ struct bfd_link_hash_entry *)) bfd_false) @@ -599,7 +600,7 @@ extern bfd_boolean _bfd_generic_link_split_section (bfd *, struct bfd_section *); extern void _bfd_generic_section_already_linked - (bfd *, struct bfd_section *, struct bfd_link_info *); + (bfd *, struct already_linked *, struct bfd_link_info *); /* Generic reloc_link_order processing routine. */ extern bfd_boolean _bfd_generic_reloc_link_order @@ -791,16 +792,26 @@ struct bfd_section_already_linked_hash_entry struct bfd_section_already_linked *entry; }; +struct already_linked +{ + const char *comdat_key; + union + { + asection *sec; + bfd *abfd; + } u; +}; + struct bfd_section_already_linked { struct bfd_section_already_linked *next; - asection *sec; + struct already_linked linked; }; extern struct bfd_section_already_linked_hash_entry * bfd_section_already_linked_table_lookup (const char *); extern bfd_boolean bfd_section_already_linked_table_insert - (struct bfd_section_already_linked_hash_entry *, asection *); + (struct bfd_section_already_linked_hash_entry *, struct already_linked *); extern void bfd_section_already_linked_table_traverse (bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *, void *), void *); diff --git a/bfd/libbfd.h b/bfd/libbfd.h index dd4cc94..c72ff16 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -483,7 +483,8 @@ extern bfd_boolean _bfd_generic_set_section_contents #define _bfd_nolink_bfd_link_split_section \ ((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false) #define _bfd_nolink_section_already_linked \ - ((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void) + ((void (*) (bfd *, struct already_linked*, \ + struct bfd_link_info *)) bfd_void) #define _bfd_nolink_bfd_define_common_symbol \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, \ struct bfd_link_hash_entry *)) bfd_false) @@ -604,7 +605,7 @@ extern bfd_boolean _bfd_generic_link_split_section (bfd *, struct bfd_section *); extern void _bfd_generic_section_already_linked - (bfd *, struct bfd_section *, struct bfd_link_info *); + (bfd *, struct already_linked *, struct bfd_link_info *); /* Generic reloc_link_order processing routine. */ extern bfd_boolean _bfd_generic_reloc_link_order @@ -796,16 +797,26 @@ struct bfd_section_already_linked_hash_entry struct bfd_section_already_linked *entry; }; +struct already_linked +{ + const char *comdat_key; + union + { + asection *sec; + bfd *abfd; + } u; +}; + struct bfd_section_already_linked { struct bfd_section_already_linked *next; - asection *sec; + struct already_linked linked; }; extern struct bfd_section_already_linked_hash_entry * bfd_section_already_linked_table_lookup (const char *); extern bfd_boolean bfd_section_already_linked_table_insert - (struct bfd_section_already_linked_hash_entry *, asection *); + (struct bfd_section_already_linked_hash_entry *, struct already_linked *); extern void bfd_section_already_linked_table_traverse (bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *, void *), void *); diff --git a/bfd/linker.c b/bfd/linker.c index e472317..492e774 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -2888,15 +2888,16 @@ FUNCTION bfd_section_already_linked SYNOPSIS - void bfd_section_already_linked (bfd *abfd, asection *sec, + void bfd_section_already_linked (bfd *abfd, + struct already_linked *data, struct bfd_link_info *info); DESCRIPTION - Check if @var{sec} has been already linked during a reloceatable + Check if @var{data} has been already linked during a reloceatable or final link. -.#define bfd_section_already_linked(abfd, sec, info) \ -. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) +.#define bfd_section_already_linked(abfd, data, info) \ +. BFD_SEND (abfd, _section_already_linked, (abfd, data, info)) . */ @@ -2939,7 +2940,7 @@ bfd_section_already_linked_table_lookup (const char *name) bfd_boolean bfd_section_already_linked_table_insert (struct bfd_section_already_linked_hash_entry *already_linked_list, - asection *sec) + struct already_linked *data) { struct bfd_section_already_linked *l; @@ -2949,7 +2950,7 @@ bfd_section_already_linked_table_insert bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l); if (l == NULL) return FALSE; - l->sec = sec; + l->linked = *data; l->next = already_linked_list->entry; already_linked_list->entry = l; return TRUE; @@ -2990,42 +2991,74 @@ bfd_section_already_linked_table_free (void) /* This is used on non-ELF inputs. */ void -_bfd_generic_section_already_linked (bfd *abfd, asection *sec, +_bfd_generic_section_already_linked (bfd *abfd, + struct already_linked *linked, struct bfd_link_info *info) { flagword flags; const char *name; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; + struct coff_comdat_info *s_comdat; + asection *sec; - flags = sec->flags; - if ((flags & SEC_LINK_ONCE) == 0) - return; - - /* FIXME: When doing a relocatable link, we may have trouble - copying relocations in other sections that refer to local symbols - in the section being discarded. Those relocations will have to - be converted somehow; as of this writing I'm not sure that any of - the backends handle that correctly. - - It is tempting to instead not discard link once sections when - doing a relocatable link (technically, they should be discarded - whenever we are building constructors). However, that fails, - because the linker winds up combining all the link once sections - into a single large link once section, which defeats the purpose - of having link once sections in the first place. */ - - name = bfd_get_section_name (abfd, sec); + name = linked->comdat_key; + if (name) + { + sec = NULL; + flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + s_comdat = NULL; + } + else + { + sec = linked->u.sec; + flags = sec->flags; + if ((flags & SEC_LINK_ONCE) == 0) + return; + + s_comdat = bfd_coff_get_comdat_section (abfd, sec); + + /* FIXME: When doing a relocatable link, we may have trouble + copying relocations in other sections that refer to local symbols + in the section being discarded. Those relocations will have to + be converted somehow; as of this writing I'm not sure that any of + the backends handle that correctly. + + It is tempting to instead not discard link once sections when + doing a relocatable link (technically, they should be discarded + whenever we are building constructors). However, that fails, + because the linker winds up combining all the link once sections + into a single large link once section, which defeats the purpose + of having link once sections in the first place. */ + + name = bfd_get_section_name (abfd, sec); + } already_linked_list = bfd_section_already_linked_table_lookup (name); for (l = already_linked_list->entry; l != NULL; l = l->next) { bfd_boolean skip = FALSE; - struct coff_comdat_info *s_comdat - = bfd_coff_get_comdat_section (abfd, sec); - struct coff_comdat_info *l_comdat - = bfd_coff_get_comdat_section (l->sec->owner, l->sec); + bfd *l_owner; + flagword l_flags; + struct coff_comdat_info *l_comdat; + asection *l_sec; + + if (l->linked.comdat_key) + { + l_sec = NULL; + l_owner = l->linked.u.abfd; + l_comdat = NULL; + l_flags = (SEC_GROUP + | SEC_LINK_ONCE + | SEC_LINK_DUPLICATES_DISCARD); + } + else + { + l_sec = l->linked.u.sec; + l_owner = l_sec->owner; + l_comdat = bfd_coff_get_comdat_section (l_sec->owner, l_sec); + } /* We may have 3 different sections on the list: group section, comdat section and linkonce section. SEC may be a linkonce or @@ -3034,7 +3067,7 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, FIXME: Is that safe to match a linkonce section with a comdat section for COFF inputs? */ - if ((l->sec->flags & SEC_GROUP) != 0) + if ((l_flags & SEC_GROUP) != 0) skip = TRUE; else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) { @@ -3056,6 +3089,18 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, abort (); case SEC_LINK_DUPLICATES_DISCARD: + /* If we found an LTO IR match for this comdat group on + the first pass, replace it with the LTO output on the + second pass. We can't simply choose real object + files over IR because the first pass may contain a + mix of LTO and normal objects and we must keep the + first match, be it IR or real. */ + if (info->loading_lto_outputs + && (l_owner->flags & BFD_PLUGIN) != 0) + { + l->linked = *linked; + return; + } break; case SEC_LINK_DUPLICATES_ONE_ONLY: @@ -3072,27 +3117,31 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, either. */ /* Fall through. */ case SEC_LINK_DUPLICATES_SAME_SIZE: - if (sec->size != l->sec->size) + if (sec->size != l_sec->size) (*_bfd_error_handler) (_("%B: warning: duplicate section `%A' has different size\n"), abfd, sec); break; } - /* Set the output_section field so that lang_add_section - does not create a lang_input_section structure for this - section. Since there might be a symbol in the section - being discarded, we must retain a pointer to the section - which we are really going to use. */ - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = l->sec; + if (sec) + { + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. Since there might be a symbol in the section + being discarded, we must retain a pointer to the section + which we are really going to use. */ + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l_sec; + } return; } } /* This is the first section with this name. Record it. */ - if (! bfd_section_already_linked_table_insert (already_linked_list, sec)) + if (! bfd_section_already_linked_table_insert (already_linked_list, + linked)) info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); } diff --git a/bfd/targets.c b/bfd/targets.c index 52dcd6b..ac978a1 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -176,6 +176,7 @@ DESCRIPTION . .{* Forward declaration. *} .typedef struct bfd_link_info _bfd_link_info; +.struct already_linked; . .typedef struct bfd_target .{ @@ -503,7 +504,7 @@ BFD_JUMP_TABLE macros. . . {* Check if SEC has been already linked during a reloceatable or . final link. *} -. void (*_section_already_linked) (bfd *, struct bfd_section *, +. void (*_section_already_linked) (bfd *, struct already_linked *, . struct bfd_link_info *); . . {* Define a common symbol. *} |