aboutsummaryrefslogtreecommitdiff
path: root/gold/object.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/object.cc')
-rw-r--r--gold/object.cc236
1 files changed, 199 insertions, 37 deletions
diff --git a/gold/object.cc b/gold/object.cc
index 2849093..19d9185 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -40,6 +40,93 @@
namespace gold
{
+// Class Xindex.
+
+// Initialize the symtab_xindex_ array. Find the SHT_SYMTAB_SHNDX
+// section and read it in. SYMTAB_SHNDX is the index of the symbol
+// table we care about.
+
+template<int size, bool big_endian>
+void
+Xindex::initialize_symtab_xindex(Object* object, unsigned int symtab_shndx)
+{
+ if (!this->symtab_xindex_.empty())
+ return;
+
+ gold_assert(symtab_shndx != 0);
+
+ // Look through the sections in reverse order, on the theory that it
+ // is more likely to be near the end than the beginning.
+ unsigned int i = object->shnum();
+ while (i > 0)
+ {
+ --i;
+ if (object->section_type(i) == elfcpp::SHT_SYMTAB_SHNDX
+ && this->adjust_shndx(object->section_link(i)) == symtab_shndx)
+ {
+ this->read_symtab_xindex<size, big_endian>(object, i, NULL);
+ return;
+ }
+ }
+
+ object->error(_("missing SHT_SYMTAB_SHNDX section"));
+}
+
+// Read in the symtab_xindex_ array, given the section index of the
+// SHT_SYMTAB_SHNDX section. If PSHDRS is not NULL, it points at the
+// section headers.
+
+template<int size, bool big_endian>
+void
+Xindex::read_symtab_xindex(Object* object, unsigned int xindex_shndx,
+ const unsigned char* pshdrs)
+{
+ section_size_type bytecount;
+ const unsigned char* contents;
+ if (pshdrs == NULL)
+ contents = object->section_contents(xindex_shndx, &bytecount, false);
+ else
+ {
+ const unsigned char* p = (pshdrs
+ + (xindex_shndx
+ * elfcpp::Elf_sizes<size>::shdr_size));
+ typename elfcpp::Shdr<size, big_endian> shdr(p);
+ bytecount = convert_to_section_size_type(shdr.get_sh_size());
+ contents = object->get_view(shdr.get_sh_offset(), bytecount, true, false);
+ }
+
+ gold_assert(this->symtab_xindex_.empty());
+ this->symtab_xindex_.reserve(bytecount / 4);
+ for (section_size_type i = 0; i < bytecount; i += 4)
+ {
+ unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(contents + i);
+ // We preadjust the section indexes we save.
+ this->symtab_xindex_.push_back(this->adjust_shndx(shndx));
+ }
+}
+
+// Symbol symndx has a section of SHN_XINDEX; return the real section
+// index.
+
+unsigned int
+Xindex::sym_xindex_to_shndx(Object* object, unsigned int symndx)
+{
+ if (symndx >= this->symtab_xindex_.size())
+ {
+ object->error(_("symbol %u out of range for SHT_SYMTAB_SHNDX section"),
+ symndx);
+ return elfcpp::SHN_UNDEF;
+ }
+ unsigned int shndx = this->symtab_xindex_[symndx];
+ if (shndx < elfcpp::SHN_LORESERVE || shndx >= object->shnum())
+ {
+ object->error(_("extended index for symbol %u out of range: %u"),
+ symndx, shndx);
+ return elfcpp::SHN_UNDEF;
+ }
+ return shndx;
+}
+
// Class Object.
// Set the target based on fields in the ELF file header.
@@ -204,6 +291,8 @@ Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
// to put the symbol table at the end.
const unsigned char* p = pshdrs + shnum * This::shdr_size;
unsigned int i = shnum;
+ unsigned int xindex_shndx = 0;
+ unsigned int xindex_link = 0;
while (i > 0)
{
--i;
@@ -212,12 +301,43 @@ Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
{
this->symtab_shndx_ = i;
+ if (xindex_shndx > 0 && xindex_link == i)
+ {
+ Xindex* xindex =
+ new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->read_symtab_xindex<size, big_endian>(this,
+ xindex_shndx,
+ pshdrs);
+ this->set_xindex(xindex);
+ }
break;
}
+
+ // Try to pick up the SHT_SYMTAB_SHNDX section, if there is
+ // one. This will work if it follows the SHT_SYMTAB
+ // section.
+ if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB_SHNDX)
+ {
+ xindex_shndx = i;
+ xindex_link = this->adjust_shndx(shdr.get_sh_link());
+ }
}
}
}
+// Return the Xindex structure to use for object with lots of
+// sections.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_relobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_assert(this->symtab_shndx_ != -1U);
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->initialize_symtab_xindex<size, big_endian>(this, this->symtab_shndx_);
+ return xindex;
+}
+
// Return whether SHDR has the right type and flags to be a GNU
// .eh_frame section.
@@ -323,7 +443,7 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
File_view* fvsymtab = this->get_lasting_view(readoff, readsize, true, false);
// Read the section header for the symbol names.
- unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ unsigned int strtab_shndx = this->adjust_shndx(symtabshdr.get_sh_link());
if (strtab_shndx >= this->shnum())
{
this->error(_("invalid symbol table name index: %u"), strtab_shndx);
@@ -351,14 +471,17 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
}
// Return the section index of symbol SYM. Set *VALUE to its value in
-// the object file. Note that for a symbol which is not defined in
-// this object file, this will set *VALUE to 0 and return SHN_UNDEF;
-// it will not return the final value of the symbol in the link.
+// the object file. Set *IS_ORDINARY if this is an ordinary section
+// index. not a special cod between SHN_LORESERVE and SHN_HIRESERVE.
+// Note that for a symbol which is not defined in this object file,
+// this will set *VALUE to 0 and return SHN_UNDEF; it will not return
+// the final value of the symbol in the link.
template<int size, bool big_endian>
unsigned int
Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
- Address* value)
+ Address* value,
+ bool* is_ordinary)
{
section_size_type symbols_size;
const unsigned char* symbols = this->section_contents(this->symtab_shndx_,
@@ -370,8 +493,8 @@ Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
elfcpp::Sym<size, big_endian> elfsym(symbols + sym * This::sym_size);
*value = elfsym.get_st_value();
- // FIXME: Handle SHN_XINDEX.
- return elfsym.get_st_shndx();
+
+ return this->adjust_sym_shndx(sym, elfsym.get_st_shndx(), is_ordinary);
}
// Return whether to include a section group in the link. LAYOUT is
@@ -408,17 +531,18 @@ Sized_relobj<size, big_endian>::include_section_group(
// Get the appropriate symbol table header (this will normally be
// the single SHT_SYMTAB section, but in principle it need not be).
- const unsigned int link = shdr.get_sh_link();
+ const unsigned int link = this->adjust_shndx(shdr.get_sh_link());
typename This::Shdr symshdr(this, this->elf_file_.section_header(link));
// Read the symbol table entry.
- if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
+ unsigned int symndx = shdr.get_sh_info();
+ if (symndx >= symshdr.get_sh_size() / This::sym_size)
{
this->error(_("section group %u info %u out of range"),
- index, shdr.get_sh_info());
+ index, symndx);
return false;
}
- off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
+ off_t symoff = symshdr.get_sh_offset() + symndx * This::sym_size;
const unsigned char* psym = this->get_view(symoff, This::sym_size, true,
false);
elfcpp::Sym<size, big_endian> sym(psym);
@@ -426,15 +550,15 @@ Sized_relobj<size, big_endian>::include_section_group(
// Read the symbol table names.
section_size_type symnamelen;
const unsigned char* psymnamesu;
- psymnamesu = this->section_contents(symshdr.get_sh_link(), &symnamelen,
- true);
+ psymnamesu = this->section_contents(this->adjust_shndx(symshdr.get_sh_link()),
+ &symnamelen, true);
const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
// Get the section group signature.
if (sym.get_st_name() >= symnamelen)
{
this->error(_("symbol %u name offset %u out of range"),
- shdr.get_sh_info(), sym.get_st_name());
+ symndx, sym.get_st_name());
return false;
}
@@ -443,11 +567,20 @@ Sized_relobj<size, big_endian>::include_section_group(
// It seems that some versions of gas will create a section group
// associated with a section symbol, and then fail to give a name to
// the section symbol. In such a case, use the name of the section.
- // FIXME.
std::string secname;
if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
{
- secname = this->section_name(sym.get_st_shndx());
+ bool is_ordinary;
+ unsigned int sym_shndx = this->adjust_sym_shndx(symndx,
+ sym.get_st_shndx(),
+ &is_ordinary);
+ if (!is_ordinary || sym_shndx >= this->shnum())
+ {
+ this->error(_("symbol %u invalid section index %u"),
+ symndx, sym_shndx);
+ return false;
+ }
+ secname = this->section_name(sym_shndx);
signature = secname.c_str();
}
@@ -559,7 +692,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
unsigned int sh_type = shdr.get_sh_type();
if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA)
{
- unsigned int target_shndx = shdr.get_sh_info();
+ unsigned int target_shndx = this->adjust_shndx(shdr.get_sh_info());
if (target_shndx == 0 || target_shndx >= shnum)
{
this->error(_("relocation section %u has bad info %u"),
@@ -723,7 +856,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
pshdr = sd->section_headers->data() + i * This::shdr_size;
typename This::Shdr shdr(pshdr);
- unsigned int data_shndx = shdr.get_sh_info();
+ unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
if (data_shndx >= shnum)
{
// We already warned about this above.
@@ -813,7 +946,11 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
reinterpret_cast<const char*>(sd->symbol_names->data());
symtab->add_from_relobj(this,
sd->symbols->data() + sd->external_symbols_offset,
- symcount, sym_names, sd->symbol_names_size,
+ symcount,
+ (sd->external_symbols_offset == 0
+ ? this->local_symbol_count_
+ : 0),
+ sym_names, sd->symbol_names_size,
&this->symbols_);
delete sd->symbols;
@@ -855,7 +992,8 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
locsize, true, true);
// Read the symbol names.
- const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ const unsigned int strtab_shndx =
+ this->adjust_shndx(symtabshdr.get_sh_link());
section_size_type strtab_size;
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
&strtab_size,
@@ -876,8 +1014,10 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
Symbol_value<size>& lv(this->local_values_[i]);
- unsigned int shndx = sym.get_st_shndx();
- lv.set_input_shndx(shndx);
+ bool is_ordinary;
+ unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
+ &is_ordinary);
+ lv.set_input_shndx(shndx, is_ordinary);
if (sym.get_st_type() == elfcpp::STT_SECTION)
lv.set_is_section_symbol();
@@ -937,7 +1077,7 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
template<int size, bool big_endian>
unsigned int
Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
- off_t off)
+ off_t off)
{
gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
@@ -951,17 +1091,17 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
{
Symbol_value<size>& lv(this->local_values_[i]);
- unsigned int shndx = lv.input_shndx();
+ bool is_ordinary;
+ unsigned int shndx = lv.input_shndx(&is_ordinary);
// Set the output symbol value.
- if (shndx >= elfcpp::SHN_LORESERVE)
+ if (!is_ordinary)
{
if (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON)
lv.set_output_value(lv.input_value());
else
{
- // FIXME: Handle SHN_XINDEX.
this->error(_("unknown section index %u for local symbol %u"),
shndx, i);
lv.set_output_value(0);
@@ -1062,7 +1202,9 @@ void
Sized_relobj<size, big_endian>::write_local_symbols(
Output_file* of,
const Stringpool* sympool,
- const Stringpool* dynpool)
+ const Stringpool* dynpool,
+ Output_symtab_xindex* symtab_xindex,
+ Output_symtab_xindex* dynsym_xindex)
{
if (parameters->options().strip_all()
&& this->output_local_dynsym_count_ == 0)
@@ -1090,7 +1232,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(
locsize, true, false);
// Read the symbol names.
- const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ const unsigned int strtab_shndx =
+ this->adjust_shndx(symtabshdr.get_sh_link());
section_size_type strtab_size;
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
&strtab_size,
@@ -1121,18 +1264,30 @@ Sized_relobj<size, big_endian>::write_local_symbols(
{
elfcpp::Sym<size, big_endian> isym(psyms);
- unsigned int st_shndx = isym.get_st_shndx();
- if (st_shndx < elfcpp::SHN_LORESERVE)
+ Symbol_value<size>& lv(this->local_values_[i]);
+
+ bool is_ordinary;
+ unsigned int st_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+ &is_ordinary);
+ if (is_ordinary)
{
gold_assert(st_shndx < mo.size());
if (mo[st_shndx].output_section == NULL)
continue;
st_shndx = mo[st_shndx].output_section->out_shndx();
+ if (st_shndx >= elfcpp::SHN_LORESERVE)
+ {
+ if (lv.needs_output_symtab_entry())
+ symtab_xindex->add(lv.output_symtab_index(), st_shndx);
+ if (lv.needs_output_dynsym_entry())
+ dynsym_xindex->add(lv.output_dynsym_index(), st_shndx);
+ st_shndx = elfcpp::SHN_XINDEX;
+ }
}
// Write the symbol to the output symbol table.
if (!parameters->options().strip_all()
- && this->local_values_[i].needs_output_symtab_entry())
+ && lv.needs_output_symtab_entry())
{
elfcpp::Sym_write<size, big_endian> osym(ov);
@@ -1149,7 +1304,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(
}
// Write the symbol to the output dynamic symbol table.
- if (this->local_values_[i].needs_output_dynsym_entry())
+ if (lv.needs_output_dynsym_entry())
{
gold_assert(dyn_ov < dyn_oview + dyn_output_size);
elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
@@ -1201,7 +1356,8 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
&symbols_size,
false);
- unsigned int symbol_names_shndx = this->section_link(this->symtab_shndx_);
+ unsigned int symbol_names_shndx =
+ this->adjust_shndx(this->section_link(this->symtab_shndx_));
section_size_type names_size;
const unsigned char* symbol_names_u =
this->section_contents(symbol_names_shndx, &names_size, false);
@@ -1221,11 +1377,17 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
info->source_file = "(invalid)";
else
info->source_file = symbol_names + sym.get_st_name();
+ continue;
}
- else if (sym.get_st_shndx() == shndx
- && static_cast<off_t>(sym.get_st_value()) <= offset
- && (static_cast<off_t>(sym.get_st_value() + sym.get_st_size())
- > offset))
+
+ bool is_ordinary;
+ unsigned int st_shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
+ &is_ordinary);
+ if (is_ordinary
+ && st_shndx == shndx
+ && static_cast<off_t>(sym.get_st_value()) <= offset
+ && (static_cast<off_t>(sym.get_st_value() + sym.get_st_size())
+ > offset))
{
if (sym.get_st_name() > names_size)
info->enclosing_symbol_name = "(invalid)";