aboutsummaryrefslogtreecommitdiff
path: root/gold/object.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/object.cc')
-rw-r--r--gold/object.cc124
1 files changed, 112 insertions, 12 deletions
diff --git a/gold/object.cc b/gold/object.cc
index 85019fb..6186f65 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -9,6 +9,7 @@
#include "object.h"
#include "target-select.h"
#include "layout.h"
+#include "output.h"
namespace gold
{
@@ -47,8 +48,11 @@ Sized_object<size, big_endian>::Sized_object(
shoff_(ehdr.get_e_shoff()),
shstrndx_(0),
symtab_shnum_(0),
+ local_symbol_count_(0),
+ output_local_symbol_count_(0),
symbols_(NULL),
- local_symbol_offset_(0)
+ local_symbol_offset_(0),
+ values_(NULL)
{
if (ehdr.get_e_ehsize() != This::ehdr_size)
{
@@ -77,6 +81,7 @@ template<int size, bool big_endian>
const unsigned char*
Sized_object<size, big_endian>::section_header(unsigned int shnum)
{
+ assert(shnum < this->shnum());
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
return this->get_view(symtabshdroff, This::shdr_size);
}
@@ -393,7 +398,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
const char* pnames = reinterpret_cast<const char*>(pnamesu);
std::vector<Map_to_output>& map_sections(this->map_to_output());
- map_sections.reserve(shnum);
+ map_sections.resize(shnum);
// Keep track of which sections to omit.
std::vector<bool> omit(shnum, false);
@@ -446,16 +451,24 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
}
// Finalize the local symbols. Here we record the file offset at
-// which they should be output and we add their names to *POOL.
-// Return the new file offset. This function is always called from
-// the main thread. The actual output of the local symbols will occur
-// in a separate task.
+// which they should be output, we add their names to *POOL, and we
+// add their values to THIS->VALUES_. Return the new file offset.
+// This function is always called from the main thread. The actual
+// output of the local symbols will occur in a separate task.
template<int size, bool big_endian>
off_t
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
Stringpool* pool)
{
+ if (this->symtab_shnum_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return off;
+ }
+
+ off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
+
this->local_symbol_offset_ = off;
// Read the symbol table section header.
@@ -469,6 +482,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
+ this->local_symbol_count_ = loccount;
+
+ this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
+
// Read the section header for the symbol names.
typename This::Shdr strtabshdr(
this->section_header(symtabshdr.get_sh_link()));
@@ -483,9 +500,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
std::vector<Map_to_output>& mo(this->map_to_output());
unsigned int shnum = this->shnum();
+ unsigned int count = 0;
// Skip the first, dummy, symbol.
psyms += sym_size;
- for (unsigned int i = 1; i < loccount; ++i)
+ for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> sym(psyms);
@@ -493,15 +511,17 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
if (shndx >= elfcpp::SHN_LORESERVE)
{
- if (shndx != elfcpp::SHN_ABS)
+ if (shndx == elfcpp::SHN_ABS)
+ this->values_[i] = sym.get_st_value();
+ else
{
+ // FIXME: Handle SHN_XINDEX.
fprintf(stderr,
_("%s: %s: unknown section index %u "
"for local symbol %u\n"),
program_name, this->name().c_str(), shndx, i);
gold_exit(false);
}
- // FIXME: Handle SHN_XINDEX.
}
else
{
@@ -515,18 +535,98 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
}
if (mo[shndx].output_section == NULL)
- continue;
+ {
+ this->values_[i] = 0;
+ continue;
+ }
+
+ this->values_[i] = (mo[shndx].output_section->address()
+ + sym.get_st_value());
}
pool->add(pnames + sym.get_st_name());
off += sym_size;
-
- psyms += sym_size;
+ ++count;
}
+ this->output_local_symbol_count_ = count;
+
return off;
}
+// Write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
+ const Stringpool* sympool)
+{
+ if (this->symtab_shnum_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return;
+ }
+
+ // Read the symbol table section header.
+ typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
+ assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+ unsigned int local_symbol_count = this->local_symbol_count_;
+ assert(local_symbol_count == symtabshdr.get_sh_info());
+
+ // Read the local symbols.
+ const int sym_size = This::sym_size;
+ off_t locsize = local_symbol_count * sym_size;
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ locsize);
+
+ // Read the section header for the symbol names.
+ typename This::Shdr strtabshdr(
+ this->section_header(symtabshdr.get_sh_link()));
+ assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB);
+
+ // Read the symbol names.
+ const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(),
+ strtabshdr.get_sh_size());
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Get a view into the output file.
+ off_t output_size = this->output_local_symbol_count_ * sym_size;
+ unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
+ output_size);
+
+ std::vector<Map_to_output>& mo(this->map_to_output());
+
+ psyms += sym_size;
+ unsigned char* ov = oview;
+ for (unsigned int i = 1; i < local_symbol_count; ++i, psyms += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> isym(psyms);
+ elfcpp::Sym_write<size, big_endian> osym(ov);
+
+ unsigned int st_shndx = isym.get_st_shndx();
+ if (st_shndx < elfcpp::SHN_LORESERVE)
+ {
+ assert(st_shndx < mo.size());
+ if (mo[st_shndx].output_section == NULL)
+ continue;
+ st_shndx = mo[st_shndx].output_section->shndx();
+ }
+
+ osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
+ osym.put_st_value(this->values_[i]);
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }
+
+ assert(ov - oview == output_size);
+
+ of->write_output_view(this->local_symbol_offset_, output_size, oview);
+}
+
// Input_objects methods.
void