From: Ian Lance Taylor Date: Tue, 10 Oct 2006 18:54:06 +0000 (+0000) Subject: Avoid multiple definition errors from linkonce sections. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a783673bd6247d3fcbf2cfe54fe7574d36b97691;p=binutils-gdb.git Avoid multiple definition errors from linkonce sections. --- diff --git a/gold/object.cc b/gold/object.cc index d8658e920c9..8f1241ad879 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -346,9 +346,9 @@ Sized_object::include_linkonce_section( const elfcpp::Shdr&) { const char* symname = strrchr(name, '.') + 1; - bool omit1 = layout->add_comdat(symname, false); - bool omit2 = layout->add_comdat(name, true); - return omit1 || omit2; + bool include1 = layout->add_comdat(symname, false); + bool include2 = layout->add_comdat(name, true); + return include1 && include2; } // Lay out the input sections. We walk through the sections and check diff --git a/gold/object.h b/gold/object.h index dfcb94410d1..ca227c5d880 100644 --- a/gold/object.h +++ b/gold/object.h @@ -127,6 +127,21 @@ class Object const Stringpool* sympool, Output_file* of) { return this->do_relocate(options, symtab, sympool, of); } + // Return whether an input section is being included in the link. + bool + is_section_included(unsigned int shnum) const + { + assert(shnum < this->map_to_output_.size()); + return this->map_to_output_[shnum].output_section != NULL; + } + + // Given a section index, return the corresponding Output_section + // (which will be NULL if the section is not included in the link) + // and set *POFF to the offset within that section. + inline Output_section* + output_section(unsigned int shnum, off_t* poff); + + protected: // What we need to know to map an input section to an output // section. We keep an array of these, one for each input section, // indexed by the input section number. @@ -139,16 +154,6 @@ class Object off_t offset; }; - // Given a section index, return the corresponding Map_to_output - // information. - const Map_to_output* - section_output_info(unsigned int shnum) const - { - assert(shnum < this->map_to_output_.size()); - return &this->map_to_output_[shnum]; - } - - protected: // Read the symbols--implemented by child class. virtual void do_read_symbols(Read_symbols_data*) = 0; @@ -248,6 +253,16 @@ Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY) return static_cast*>(this->target_); } +// Implement Object::output_section inline for efficiency. +inline Output_section* +Object::output_section(unsigned int shnum, off_t* poff) +{ + assert(shnum < this->map_to_output_.size()); + const Map_to_output& mo(this->map_to_output_[shnum]); + *poff = mo.offset; + return mo.output_section; +} + // A regular object file. This is size and endian specific. template diff --git a/gold/po/gold.pot b/gold/po/gold.pot index 48bc987867a..f086e6d40cc 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-10-04 08:37-0700\n" +"POT-Creation-Date: 2006-10-10 11:40-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -403,7 +403,7 @@ msgstr "" msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n" msgstr "" -#: symtab.cc:317 +#: symtab.cc:320 #, c-format msgid "%s: %s: bad global symbol name offset %u at %lu\n" msgstr "" @@ -413,7 +413,7 @@ msgstr "" msgid "%s: %s: reloc %zu has bad offset %lu\n" msgstr "" -#: target-reloc.h:106 +#: target-reloc.h:107 #, c-format msgid "%s: %s: undefined reference to '%s'\n" msgstr "" diff --git a/gold/symtab.cc b/gold/symtab.cc index 2251ea76c7d..748218d843f 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -305,12 +305,15 @@ Symbol_table::add_from_object( gold_exit(false); } + const int sym_size = elfcpp::Elf_sizes::sym_size; + const unsigned char* p = reinterpret_cast(syms); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i, p += sym_size) { elfcpp::Sym sym(p); + elfcpp::Sym* psym = &sym; - unsigned int st_name = sym.get_st_name(); + unsigned int st_name = psym->get_st_name(); if (st_name >= sym_name_size) { fprintf(stderr, @@ -320,6 +323,21 @@ Symbol_table::add_from_object( gold_exit(false); } + // A symbol defined in a section which we are not including must + // be treated as an undefined symbol. + unsigned char symbuf[sym_size]; + elfcpp::Sym sym2(symbuf); + unsigned int st_shndx = psym->get_st_shndx(); + if (st_shndx != elfcpp::SHN_UNDEF + && st_shndx < elfcpp::SHN_LORESERVE + && !object->is_section_included(st_shndx)) + { + memcpy(symbuf, p, sym_size); + elfcpp::Sym_write sw(symbuf); + sw.put_st_shndx(elfcpp::SHN_UNDEF); + psym = &sym2; + } + const char* name = sym_names + st_name; // In an object file, an '@' in the name separates the symbol @@ -331,7 +349,7 @@ Symbol_table::add_from_object( if (ver == NULL) { name = this->namepool_.add(name); - res = this->add_from_object(object, name, NULL, false, sym); + res = this->add_from_object(object, name, NULL, false, *psym); } else { @@ -344,12 +362,10 @@ Symbol_table::add_from_object( ++ver; } ver = this->namepool_.add(ver); - res = this->add_from_object(object, name, ver, def, sym); + res = this->add_from_object(object, name, ver, def, *psym); } *sympointers++ = res; - - p += elfcpp::Elf_sizes::sym_size; } } @@ -393,10 +409,11 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool) continue; } - const Object::Map_to_output* mo = - sym->object()->section_output_info(sym->shnum()); + off_t secoff; + Output_section* os = sym->object()->output_section(sym->shnum(), + &secoff); - if (mo->output_section == NULL) + if (os == NULL) { // We should be able to erase this symbol from the symbol // table, but at least with gcc 4.0.2 @@ -407,9 +424,7 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool) } else { - sym->set_value(sym->value() - + mo->output_section->address() - + mo->offset); + sym->set_value(sym->value() + os->address() + secoff); pool->add(sym->name()); ++p; ++count; @@ -470,10 +485,10 @@ Symbol_table::sized_write_globals(const Target*, if (sym->shnum() >= elfcpp::SHN_LORESERVE) continue; - const Object::Map_to_output* mo = - sym->object()->section_output_info(sym->shnum()); - - if (mo->output_section == NULL) + off_t secoff; + Output_section* os = sym->object()->output_section(sym->shnum(), + &secoff); + if (os == NULL) continue; elfcpp::Sym_write osym(ps); @@ -482,7 +497,7 @@ Symbol_table::sized_write_globals(const Target*, osym.put_st_size(sym->symsize()); osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type())); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->other())); - osym.put_st_shndx(mo->output_section->shndx()); + osym.put_st_shndx(os->shndx()); ps += sym_size; } diff --git a/gold/target-reloc.h b/gold/target-reloc.h index 66ff78cf101..f972b117d9a 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -94,6 +94,7 @@ relocate_section( else { Symbol* gsym = global_syms[r_sym - local_count]; + assert(gsym != NULL); if (gsym->is_forwarder()) gsym = symtab->resolve_forwards(gsym);