aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-10-10 18:54:06 +0000
committerIan Lance Taylor <iant@google.com>2006-10-10 18:54:06 +0000
commita783673bd6247d3fcbf2cfe54fe7574d36b97691 (patch)
tree382ad6bd357c8bd20581d864b0f2c4ada8d303b7 /gold
parent774a49c04797335bacdeb48d2438dc2863c8a9fe (diff)
downloadfsf-binutils-gdb-a783673bd6247d3fcbf2cfe54fe7574d36b97691.zip
fsf-binutils-gdb-a783673bd6247d3fcbf2cfe54fe7574d36b97691.tar.gz
fsf-binutils-gdb-a783673bd6247d3fcbf2cfe54fe7574d36b97691.tar.bz2
Avoid multiple definition errors from linkonce sections.
Diffstat (limited to 'gold')
-rw-r--r--gold/object.cc6
-rw-r--r--gold/object.h35
-rw-r--r--gold/po/gold.pot6
-rw-r--r--gold/symtab.cc49
-rw-r--r--gold/target-reloc.h1
5 files changed, 64 insertions, 33 deletions
diff --git a/gold/object.cc b/gold/object.cc
index d8658e9..8f1241a 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -346,9 +346,9 @@ Sized_object<size, big_endian>::include_linkonce_section(
const elfcpp::Shdr<size, big_endian>&)
{
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 dfcb944..ca227c5 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<Sized_target<size, big_endian>*>(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<int size, bool big_endian>
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index 48bc987..f086e6d 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 2251ea7..748218d 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<size>::sym_size;
+
const unsigned char* p = reinterpret_cast<const unsigned char*>(syms);
- for (size_t i = 0; i < count; ++i)
+ for (size_t i = 0; i < count; ++i, p += sym_size)
{
elfcpp::Sym<size, big_endian> sym(p);
+ elfcpp::Sym<size, big_endian>* 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<size, big_endian> 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<size, big_endian> 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<size>::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<size, big_endian> 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 66ff78c..f972b11 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);