aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elfcpp/elfcpp.h52
-rw-r--r--gold/Makefile.am2
-rw-r--r--gold/Makefile.in2
-rw-r--r--gold/i386.cc8
-rw-r--r--gold/layout.cc11
-rw-r--r--gold/object.cc88
-rw-r--r--gold/object.h37
-rw-r--r--gold/output.cc181
-rw-r--r--gold/output.h367
-rw-r--r--gold/po/POTFILES.in2
-rw-r--r--gold/po/gold.pot76
-rw-r--r--gold/reloc-types.h36
-rw-r--r--gold/reloc.cc2
-rw-r--r--gold/resolve.cc12
-rw-r--r--gold/symtab.cc64
-rw-r--r--gold/symtab.h88
-rw-r--r--gold/target-reloc.h34
17 files changed, 884 insertions, 178 deletions
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index e106fab..afbd74d 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -1163,7 +1163,7 @@ class Sym_write
internal::Sym_data<size>* p_;
};
-// Accessor classes for Elf relocation table entries.
+// Accessor classes for an ELF REL relocation entry.
template<int size, bool big_endian>
class Rel
@@ -1191,6 +1191,30 @@ class Rel
const internal::Rel_data<size>* p_;
};
+// Writer class for an ELF Rel relocation.
+
+template<int size, bool big_endian>
+class Rel_write
+{
+ public:
+ Rel_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Rel_data<size>*>(p))
+ { }
+
+ void
+ put_r_offset(typename Elf_types<size>::Elf_Addr v)
+ { this->p_->r_offset = Convert<size, big_endian>::convert_host(v); }
+
+ void
+ put_r_info(typename Elf_types<size>::Elf_WXword v)
+ { this->p_->r_info = Convert<size, big_endian>::convert_host(v); }
+
+ private:
+ internal::Rel_data<size>* p_;
+};
+
+// Accessor class for an ELF Rela relocation.
+
template<int size, bool big_endian>
class Rela
{
@@ -1221,6 +1245,32 @@ class Rela
const internal::Rela_data<size>* p_;
};
+// Writer class for an ELF Rela relocation.
+
+template<int size, bool big_endian>
+class Rela_write
+{
+ public:
+ Rela_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Rela_data<size>*>(p))
+ { }
+
+ void
+ put_r_offset(typename Elf_types<size>::Elf_Addr v)
+ { this->p_->r_offset = Convert<size, big_endian>::convert_host(v); }
+
+ void
+ put_r_info(typename Elf_types<size>::Elf_WXword v)
+ { this->p_->r_info = Convert<size, big_endian>::convert_host(v); }
+
+ void
+ put_r_addend(typename Elf_types<size>::Elf_Swxword v)
+ { this->p_->r_addend = Convert<size, big_endian>::convert_host(v); }
+
+ private:
+ internal::Rela_data<size>* p_;
+};
+
// Accessor classes for entries in the ELF SHT_DYNAMIC section aka
// PT_DYNAMIC segment.
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 12ec749..f76ee5b 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -56,7 +56,9 @@ HFILES = \
output.h \
readsyms.h \
reloc.h \
+ reloc-types.h \
script.h \
+ script-c.h \
stringpool.h \
symtab.h \
target.h \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index deef51c..560f481 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -272,7 +272,9 @@ HFILES = \
output.h \
readsyms.h \
reloc.h \
+ reloc-types.h \
script.h \
+ script-c.h \
stringpool.h \
symtab.h \
target.h \
diff --git a/gold/i386.cc b/gold/i386.cc
index dc13dca..e6522e3 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -96,7 +96,7 @@ class Target_i386 : public Sized_target<32, false>
inline bool
relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
const elfcpp::Rel<32, false>&,
- unsigned int r_type, Sized_symbol<32>*,
+ unsigned int r_type, const Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
off_t);
@@ -106,7 +106,7 @@ class Target_i386 : public Sized_target<32, false>
inline void
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&,
- unsigned int r_type, Sized_symbol<32>*,
+ unsigned int r_type, const Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
@@ -529,7 +529,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
- Sized_symbol<32>* gsym,
+ const Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
@@ -670,7 +670,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
- Sized_symbol<32>* gsym,
+ const Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr,
diff --git a/gold/layout.cc b/gold/layout.cc
index bcb1029..f9f5548 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -676,19 +676,24 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
// Save space for the dummy symbol at the start of the section. We
// never bother to write this out--it will just be left as zero.
off += symsize;
+ unsigned int local_symbol_index = 1;
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
Task_lock_obj<Object> tlo(**p);
- off = (*p)->finalize_local_symbols(off, &this->sympool_);
+ unsigned int index = (*p)->finalize_local_symbols(local_symbol_index,
+ off,
+ &this->sympool_);
+ off += (index - local_symbol_index) * symsize;
+ local_symbol_index = index;
}
- unsigned int local_symcount = (off - startoff) / symsize;
+ unsigned int local_symcount = local_symbol_index;
assert(local_symcount * symsize == off - startoff);
- off = symtab->finalize(off, &this->sympool_);
+ off = symtab->finalize(local_symcount, off, &this->sympool_);
this->sympool_.set_string_offsets();
diff --git a/gold/object.cc b/gold/object.cc
index 1bfd969..74c1347 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -128,7 +128,8 @@ Sized_relobj<size, big_endian>::Sized_relobj(
output_local_symbol_count_(0),
symbols_(NULL),
local_symbol_offset_(0),
- values_(NULL)
+ local_values_(),
+ local_indexes_()
{
}
@@ -505,23 +506,25 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
// Finalize the local symbols. Here we record the file offset at
// 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.
+// add their values to THIS->LOCAL_VALUES_ and their indexes in the
+// output symbol table to THIS->LOCAL_INDEXES_. Return the symbol
+// index. 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_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
+unsigned int
+Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
+ off_t off,
Stringpool* pool)
{
assert(this->symtab_shndx_ != -1U);
if (this->symtab_shndx_ == 0)
{
// This object has no symbols. Weird but legal.
- return off;
+ return index;
}
- off = align_address(off, size >> 3);
+ assert(off == static_cast<off_t>(align_address(off, size >> 3)));
this->local_symbol_offset_ = off;
@@ -539,7 +542,8 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
- this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
+ this->local_values_.resize(loccount);
+ this->local_indexes_.resize(loccount);
// Read the symbol names.
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
@@ -550,7 +554,7 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
// Loop over the local symbols.
- std::vector<Map_to_output>& mo(this->map_to_output());
+ const std::vector<Map_to_output>& mo(this->map_to_output());
unsigned int shnum = this->shnum();
unsigned int count = 0;
// Skip the first, dummy, symbol.
@@ -564,7 +568,7 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
if (shndx >= elfcpp::SHN_LORESERVE)
{
if (shndx == elfcpp::SHN_ABS)
- this->values_[i] = sym.get_st_value();
+ this->local_values_[i] = sym.get_st_value();
else
{
// FIXME: Handle SHN_XINDEX.
@@ -588,37 +592,46 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
if (mo[shndx].output_section == NULL)
{
- this->values_[i] = 0;
+ this->local_values_[i] = 0;
+ this->local_indexes_[i] = -1U;
continue;
}
- this->values_[i] = (mo[shndx].output_section->address()
- + mo[shndx].offset
- + sym.get_st_value());
+ this->local_values_[i] = (mo[shndx].output_section->address()
+ + mo[shndx].offset
+ + sym.get_st_value());
}
- if (sym.get_st_type() != elfcpp::STT_SECTION)
+ // Decide whether this symbol should go into the output file.
+
+ if (sym.get_st_type() == elfcpp::STT_SECTION)
{
- if (sym.get_st_name() >= strtab_size)
- {
- fprintf(stderr,
- _("%s: %s: local symbol %u section name "
- "out of range: %u >= %u\n"),
- program_name, this->name().c_str(),
- i, sym.get_st_name(),
- static_cast<unsigned int>(strtab_size));
- gold_exit(false);
- }
+ this->local_indexes_[i] = -1U;
+ continue;
+ }
- pool->add(pnames + sym.get_st_name(), NULL);
- off += sym_size;
- ++count;
+ if (sym.get_st_name() >= strtab_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: local symbol %u section name "
+ "out of range: %u >= %u\n"),
+ program_name, this->name().c_str(),
+ i, sym.get_st_name(),
+ static_cast<unsigned int>(strtab_size));
+ gold_exit(false);
}
+
+ const char* name = pnames + sym.get_st_name();
+ pool->add(name, NULL);
+ this->local_indexes_[i] = index;
+ ++index;
+ off += sym_size;
+ ++count;
}
this->output_local_symbol_count_ = count;
- return off;
+ return index;
}
// Write out the local symbols.
@@ -661,16 +674,20 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
output_size);
- std::vector<Map_to_output>& mo(this->map_to_output());
+ const std::vector<Map_to_output>& mo(this->map_to_output());
+
+ assert(this->local_values_.size() == loccount);
+ assert(this->local_indexes_.size() == loccount);
- psyms += sym_size;
unsigned char* ov = oview;
+ psyms += sym_size;
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> isym(psyms);
- if (isym.get_st_type() == elfcpp::STT_SECTION)
+ if (this->local_indexes_[i] == -1U)
continue;
+ assert(this->local_indexes_[i] != 0);
unsigned int st_shndx = isym.get_st_shndx();
if (st_shndx < elfcpp::SHN_LORESERVE)
@@ -684,8 +701,9 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
elfcpp::Sym_write<size, big_endian> osym(ov);
assert(isym.get_st_name() < strtab_size);
- osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
- osym.put_st_value(this->values_[i]);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_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());
diff --git a/gold/object.h b/gold/object.h
index 6361356..b2f4706 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -352,10 +352,10 @@ class Relobj : public Object
// Initial local symbol processing: set the offset where local
// symbol information will be stored; add local symbol names to
- // *POOL; return the offset following the local symbols.
- off_t
- finalize_local_symbols(off_t off, Stringpool* pool)
- { return this->do_finalize_local_symbols(off, pool); }
+ // *POOL; return the new local symbol index.
+ unsigned int
+ finalize_local_symbols(unsigned int index, off_t off, Stringpool* pool)
+ { return this->do_finalize_local_symbols(index, off, pool); }
// Relocate the input sections and write out the local symbols.
void
@@ -408,8 +408,8 @@ class Relobj : public Object
Read_relocs_data*) = 0;
// Finalize local symbols--implemented by child class.
- virtual off_t
- do_finalize_local_symbols(off_t, Stringpool*) = 0;
+ virtual unsigned int
+ do_finalize_local_symbols(unsigned int, off_t, Stringpool*) = 0;
// Relocate the input sections and write out the local
// symbols--implemented by child class.
@@ -443,6 +443,9 @@ template<int size, bool big_endian>
class Sized_relobj : public Relobj
{
public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef std::vector<Address> Local_values;
+
Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>&);
@@ -452,6 +455,16 @@ class Sized_relobj : public Relobj
void
setup(const typename elfcpp::Ehdr<size, big_endian>&);
+ // Return the index of local symbol SYM in the ordinary symbol
+ // table. A value of -1U means that the symbol is not being output.
+ unsigned int
+ symtab_index(unsigned int sym) const
+ {
+ assert(sym < this->local_indexes_.size());
+ assert(this->local_indexes_[sym] != 0);
+ return this->local_indexes_[sym];
+ }
+
// Read the symbols.
void
do_read_symbols(Read_symbols_data*);
@@ -475,8 +488,8 @@ class Sized_relobj : public Relobj
Read_relocs_data*);
// Finalize the local symbols.
- off_t
- do_finalize_local_symbols(off_t, Stringpool*);
+ unsigned int
+ do_finalize_local_symbols(unsigned int, off_t, Stringpool*);
// Relocate the input sections and write out the local symbols.
void
@@ -563,7 +576,9 @@ class Sized_relobj : public Relobj
// File offset for local symbols.
off_t local_symbol_offset_;
// Values of local symbols.
- typename elfcpp::Elf_types<size>::Elf_Addr *values_;
+ Local_values local_values_;
+ // Indexes of local symbols in the output file; -1U if not present.
+ std::vector<unsigned int> local_indexes_;
};
// A class to manage the list of all objects.
@@ -643,9 +658,9 @@ struct Relocate_info
// Number of local symbols.
unsigned int local_symbol_count;
// Values of local symbols.
- typename elfcpp::Elf_types<size>::Elf_Addr *values;
+ const typename Sized_relobj<size, big_endian>::Local_values* local_values;
// Global symbols.
- Symbol** symbols;
+ const Symbol* const * symbols;
// Section index of relocation section.
unsigned int reloc_shndx;
// Section index of section being relocated.
diff --git a/gold/output.cc b/gold/output.cc
index aba8ee1..0330384 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -366,6 +366,120 @@ Output_section_data::do_out_shndx() const
return this->output_section_->out_shndx();
}
+// Output_reloc methods.
+
+// Get the symbol index of a relocation.
+
+template<bool dynamic, int size, bool big_endian>
+unsigned int
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
+ const
+{
+ unsigned int index;
+ switch (this->local_sym_index_)
+ {
+ case INVALID_CODE:
+ abort();
+
+ case GSYM_CODE:
+ if (this->u_.gsym == NULL)
+ index = 0;
+ else if (dynamic)
+ index = this->u_.gsym->dynsym_index();
+ else
+ index = this->u_.gsym->symtab_index();
+ break;
+
+ case SECTION_CODE:
+ if (dynamic)
+ index = this->u_.os->dynsym_index();
+ else
+ index = this->u_.os->symtab_index();
+ break;
+
+ default:
+ if (dynamic)
+ {
+ // FIXME: It seems that some targets may need to generate
+ // dynamic relocations against local symbols for some
+ // reasons. This will have to be addressed at some point.
+ abort();
+ }
+ else
+ index = this->u_.object->symtab_index(this->local_sym_index_);
+ break;
+ }
+ assert(index != -1U);
+ return index;
+}
+
+// Write out the offset and info fields of a Rel or Rela relocation
+// entry.
+
+template<bool dynamic, int size, bool big_endian>
+template<typename Write_rel>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
+ Write_rel* wr) const
+{
+ wr->put_r_offset(this->address_);
+ wr->put_r_info(elfcpp::elf_r_info<size>(this->get_symbol_index(),
+ this->type_));
+}
+
+// Write out a Rel relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rel_write<size, big_endian> orel(pov);
+ this->write_rel(&orel);
+}
+
+// Write out a Rela relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rela_write<size, big_endian> orel(pov);
+ this->rel_.write_rel(&orel);
+ orel.put_r_addend(this->addend_);
+}
+
+// Output_data_reloc_base methods.
+
+// Write out relocation data.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
+ Output_file* of)
+{
+ const off_t off = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+
+ unsigned char* pov = oview;
+ for (typename Relocs::const_iterator p = this->relocs_.begin();
+ p != this->relocs_.end();
+ ++p)
+ {
+ p->write(pov);
+ pov += reloc_size;
+ }
+
+ assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the relocation entries.
+ this->relocs_.clear();
+}
+
// Output_data_got::Got_entry methods.
// Write out the entry.
@@ -439,7 +553,7 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
const int add = size / 8;
const off_t off = this->offset();
- const off_t oview_size = this->entries_.size() * add;
+ const off_t oview_size = this->data_size();
unsigned char* const oview = of->get_output_view(off, oview_size);
unsigned char* pov = oview;
@@ -451,6 +565,8 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
pov += add;
}
+ assert(pov - oview == oview_size);
+
of->write_output_view(off, oview_size, oview);
// We no longer need the GOT entries.
@@ -508,6 +624,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
type_(type),
flags_(flags),
out_shndx_(0),
+ symtab_index_(0),
+ dynsym_index_(0),
input_sections_(),
first_input_offset_(0),
may_add_data_(may_add_data)
@@ -564,12 +682,17 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
void
Output_section::add_output_section_data(Output_section_data* posd)
{
+ assert(this->may_add_data_);
+
if (this->input_sections_.empty())
this->first_input_offset_ = this->data_size();
+
this->input_sections_.push_back(Input_section(posd));
+
uint64_t addralign = posd->addralign();
if (addralign > this->addralign_)
this->addralign_ = addralign;
+
posd->set_output_section(this);
}
@@ -627,14 +750,6 @@ Output_section::do_write(Output_file* of)
p->write(of);
}
-// Output_section_symtab methods.
-
-Output_section_symtab::Output_section_symtab(const char* name, off_t size)
- : Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
-{
- this->set_data_size(size);
-}
-
// Output_section_strtab methods.
Output_section_strtab::Output_section_strtab(const char* name,
@@ -1144,6 +1259,54 @@ Output_section::add_input_section<64, true>(
const elfcpp::Shdr<64, true>& shdr);
template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
+
+template
class Output_data_got<32, false>;
template
diff --git a/gold/output.h b/gold/output.h
index 9763d74..c31640f 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -9,6 +9,7 @@
#include "elfcpp.h"
#include "layout.h"
+#include "reloc-types.h"
namespace gold
{
@@ -16,9 +17,11 @@ namespace gold
class General_options;
class Object;
class Output_file;
-
+class Output_section;
template<int size, bool big_endian>
class Sized_target;
+template<int size, bool big_endian>
+class Sized_relobj;
// An abtract class for data which has to go into the output file.
@@ -361,6 +364,262 @@ class Output_data_common : public Output_section_data
{ }
};
+// This POD class is used to represent a single reloc in the output
+// file. This could be a private class within Output_data_reloc, but
+// the templatization is complex enough that I broke it out into a
+// separate class. The class is templatized on either elfcpp::SHT_REL
+// or elfcpp::SHT_RELA, and also on whether this is a dynamic
+// relocation or an ordinary relocation.
+
+// A relocation can be against a global symbol, a local symbol, an
+// output section, or the undefined symbol at index 0. We represent
+// the latter by using a NULL global symbol.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_reloc;
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ // An uninitialized entry. We need this because we want to put
+ // instances of this class into an STL container.
+ Output_reloc()
+ : local_sym_index_(INVALID_CODE)
+ { }
+
+ // A reloc against a global symbol.
+ Output_reloc(Symbol* gsym, unsigned int type, Address address)
+ : local_sym_index_(GSYM_CODE), type_(type), address_(address)
+ { this->u_.gsym = gsym; }
+
+ // A reloc against a local symbol.
+ Output_reloc(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index,
+ unsigned int type, Address address)
+ : local_sym_index_(local_sym_index), type_(type), address_(address)
+ {
+ assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE);
+ this->u_.object = object;
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ Output_reloc(Output_section* os, unsigned int type, Address address)
+ : local_sym_index_(SECTION_CODE), type_(type), address_(address)
+ { this->u_.os = os; }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ // Write the offset and info fields to Write_rel.
+ template<typename Write_rel>
+ void write_rel(Write_rel*) const;
+
+ private:
+ // Return the symbol index. We can't do a double template
+ // specialization, so we do a secondary template here.
+ unsigned int
+ get_symbol_index() const;
+
+ // Codes for local_sym_index_.
+ enum
+ {
+ // Global symbol.
+ GSYM_CODE = -1U,
+ // Output section.
+ SECTION_CODE = -2U,
+ // Invalid uninitialized entry.
+ INVALID_CODE = -3U
+ };
+
+ union
+ {
+ // For a local symbol, the object. We will never generate a
+ // relocation against a local symbol in a dynamic object; that
+ // doesn't make sense. And our callers will always be
+ // templatized, so we use Sized_relobj here.
+ Sized_relobj<size, big_endian>* object;
+ // For a global symbol, the symbol. If this is NULL, it indicates
+ // a relocation against the undefined 0 symbol.
+ Symbol* gsym;
+ // For a relocation against an output section, the output section.
+ Output_section* os;
+ } u_;
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or INVALID_CODE for an uninitialized value.
+ unsigned int local_sym_index_;
+ unsigned int type_;
+ Address address_;
+};
+
+// The SHT_RELA version of Output_reloc<>. This is just derived from
+// the SHT_REL version of Output_reloc, but it adds an addend.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+ // An uninitialized entry.
+ Output_reloc()
+ : rel_()
+ { }
+
+ // A reloc against a global symbol.
+ Output_reloc(Symbol* gsym, unsigned int type, Address address, Addend addend)
+ : rel_(gsym, type, address), addend_(addend)
+ { }
+
+ // A reloc against a local symbol.
+ Output_reloc(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index,
+ unsigned int type, Address address, Addend addend)
+ : rel_(object, local_sym_index, type, address), addend_(addend)
+ { }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ Output_reloc(Output_section* os, unsigned int type, Address address,
+ Addend addend)
+ : rel_(os, type, address), addend_(addend)
+ { }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ private:
+ // The basic reloc.
+ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+ // The addend.
+ Addend addend_;
+};
+
+// Output_data_reloc is used to manage a section containing relocs.
+// SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA. DYNAMIC
+// indicates whether this is a dynamic relocation or a normal
+// relocation. Output_data_reloc_base is a base class.
+// Output_data_reloc is the real class, which we specialize based on
+// the reloc type.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc_base : public Output_section_data
+{
+ public:
+ typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ static const int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ // Construct the section.
+ Output_data_reloc_base()
+ : Output_section_data(Output_data::default_alignment(size))
+ { }
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ protected:
+ // Add a relocation entry.
+ void
+ add(const Output_reloc_type& reloc)
+ {
+ this->relocs_.push_back(reloc);
+ this->set_data_size(this->relocs_.size() * reloc_size);
+ }
+
+ private:
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ Relocs relocs_;
+};
+
+// The class which callers actually create.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc;
+
+// The SHT_REL version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>()
+ { }
+
+ // Add a reloc against a global symbol.
+ void
+ add_global(Symbol* gsym, unsigned int type, Address address)
+ { this->add(Output_reloc_type(gsym, type, address)); }
+
+ // Add a reloc against a local symbol.
+ void
+ add_local(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index, unsigned int type, Address address)
+ { this->add(Output_reloc_type(object, local_sym_index, type, address)); }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ void
+ add_output_section(Output_section* os, unsigned int type, Address address)
+ { this->add(Output_reloc_type(os, type, address)); }
+};
+
+// The SHT_RELA version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ typedef typename Output_reloc_type::Addend Addend;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+ { }
+
+ // Add a reloc against a global symbol.
+ void
+ add_global(Symbol* gsym, unsigned int type, Address address, Addend addend)
+ { this->add(Output_reloc_type(gsym, type, address, addend)); }
+
+ // Add a reloc against a local symbol.
+ void
+ add_local(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index, unsigned int type,
+ Address address, Addend addend)
+ {
+ this->add(Output_reloc_type(object, local_sym_index, type, address,
+ addend));
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ void
+ add_output_section(Output_section* os, unsigned int type, Address address,
+ Addend addend)
+ { this->add(Output_reloc_type(os, type, address, addend)); }
+};
+
// Output_data_got is used to manage a GOT. Each entry in the GOT is
// for one symbol--either a global symbol or a local symbol in an
// object. The target specific code adds entries to the GOT as
@@ -456,8 +715,8 @@ class Output_data_got : public Output_section_data
// For a constant, the constant.
Valtype constant;
} u_;
- // For a local symbol, the local symbol index. This is -1U for a
- // global symbol, or -2U for a constant.
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or CONSTANT_CODE for a constant.
unsigned int local_sym_index_;
};
@@ -501,7 +760,7 @@ class Output_section : public Output_data
const elfcpp::Shdr<size, big_endian>& shdr);
// Add generated data ODATA to this output section.
- virtual void
+ void
add_output_section_data(Output_section_data* posd);
// Return the section name.
@@ -549,6 +808,58 @@ class Output_section : public Output_data
set_addralign(uint64_t v)
{ this->addralign_ = v; }
+ // Indicate that we need a symtab index.
+ void
+ set_needs_symtab_index()
+ { this->needs_symtab_index_ = true; }
+
+ // Return whether we need a symtab index.
+ bool
+ needs_symtab_index() const
+ { return this->needs_symtab_index_; }
+
+ // Get the symtab index.
+ unsigned int
+ symtab_index() const
+ {
+ assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the symtab index.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Indicate that we need a dynsym index.
+ void
+ set_needs_dynsym_index()
+ { this->needs_dynsym_index_ = true; }
+
+ // Return whether we need a dynsym index.
+ bool
+ needs_dynsym_index() const
+ { return this->needs_dynsym_index_; }
+
+ // Get the dynsym index.
+ unsigned int
+ dynsym_index() const
+ {
+ assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the dynsym index.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
// Set the address of the Output_section. For a typical
// Output_section, there is nothing to do, but if there are any
// Output_section_data objects we need to set the final addresses
@@ -686,13 +997,31 @@ class Output_section : public Output_data
elfcpp::Elf_Xword flags_;
// The section index.
unsigned int out_shndx_;
+ // If there is a STT_SECTION for this output section in the normal
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int symtab_index_;
+ // If there is a STT_SECTION for this output section in the dynamic
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int dynsym_index_;
// The input sections. This will be empty in cases where we don't
// need to keep track of them.
Input_section_list input_sections_;
// The offset of the first entry in input_sections_.
off_t first_input_offset_;
// Whether we permit adding data.
- bool may_add_data_;
+ bool may_add_data_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // normal symbol table. This will be true if there is a relocation
+ // which needs it.
+ bool needs_symtab_index_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // dynamic symbol table. This will be true if there is a dynamic
+ // relocation which needs it.
+ bool needs_dynsym_index_ : 1;
};
// A special Output_section which represents the symbol table
@@ -702,18 +1031,33 @@ class Output_section : public Output_data
class Output_section_symtab : public Output_section
{
public:
- Output_section_symtab(const char* name, off_t size);
+ Output_section_symtab(const char* name, off_t data_size)
+ : Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
+ { this->set_data_size(data_size); }
// The data is written out by Symbol_table::write_globals. We don't
// do anything here.
void
do_write(Output_file*)
{ }
+};
+
+// A special Output_section which represents the dynamic symbol table
+// (SHT_DYNSYM). The actual data is written out by
+// Symbol_table::write_globals.
+
+class Output_section_dynsym : public Output_section
+{
+ public:
+ Output_section_dynsym(const char* name, off_t data_size)
+ : Output_section(name, elfcpp::SHT_DYNSYM, 0, false)
+ { this->set_data_size(data_size); }
- // We don't expect to see any input sections or data here.
+ // The data is written out by Symbol_table::write_globals. We don't
+ // do anything here.
void
- add_output_section_data(Output_section_data*)
- { abort(); }
+ do_write(Output_file*)
+ { }
};
// A special Output_section which holds a string table.
@@ -727,11 +1071,6 @@ class Output_section_strtab : public Output_section
void
do_write(Output_file*);
- // We don't expect to see any input sections or data here.
- void
- add_output_section_data(Output_section_data*)
- { abort(); }
-
private:
Stringpool* contents_;
};
diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in
index d13ddf5..834e31a 100644
--- a/gold/po/POTFILES.in
+++ b/gold/po/POTFILES.in
@@ -27,8 +27,10 @@ readsyms.cc
readsyms.h
reloc.cc
reloc.h
+reloc-types.h
resolve.cc
script.cc
+script-c.h
script.h
stringpool.cc
stringpool.h
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index c002c5c..b5725e5 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-11-14 11:17-0800\n"
+"POT-Creation-Date: 2006-11-15 16:35-0800\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"
@@ -101,7 +101,7 @@ msgstr ""
msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
msgstr ""
-#: dynobj.cc:356 object.cc:421
+#: dynobj.cc:356 object.cc:422
#, c-format
msgid "%s: %s: bad section name offset for section %u: %lu\n"
msgstr ""
@@ -300,87 +300,87 @@ msgstr ""
msgid "%s: %s: section name section has wrong type: %u\n"
msgstr ""
-#: object.cc:229
+#: object.cc:230
#, c-format
msgid "%s: %s: invalid symbol table name index: %u\n"
msgstr ""
-#: object.cc:237
+#: object.cc:238
#, c-format
msgid "%s: %s: symbol table name section has wrong type: %u\n"
msgstr ""
-#: object.cc:293
+#: object.cc:294
#, c-format
msgid "%s: %s: section group %u info %u out of range\n"
msgstr ""
-#: object.cc:310
+#: object.cc:311
#, c-format
msgid "%s: %s: symbol %u name offset %u out of range\n"
msgstr ""
-#: object.cc:344
+#: object.cc:345
#, c-format
msgid "%s: %s: section %u in section group %u out of range"
msgstr ""
-#: object.cc:488
+#: object.cc:489
#, c-format
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
msgstr ""
-#: object.cc:572
+#: object.cc:576
#, c-format
msgid "%s: %s: unknown section index %u for local symbol %u\n"
msgstr ""
-#: object.cc:583
+#: object.cc:587
#, c-format
msgid "%s: %s: local symbol %u section index %u out of range\n"
msgstr ""
-#: object.cc:605
+#: object.cc:616
#, c-format
msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
msgstr ""
-#: object.cc:782
+#: object.cc:800
#, c-format
msgid "%s: %s: unsupported ELF file type %d\n"
msgstr ""
-#: object.cc:801 object.cc:854 object.cc:875
+#: object.cc:819 object.cc:872 object.cc:893
#, c-format
msgid "%s: %s: ELF file too short\n"
msgstr ""
-#: object.cc:810
+#: object.cc:828
#, c-format
msgid "%s: %s: invalid ELF version 0\n"
msgstr ""
-#: object.cc:813
+#: object.cc:831
#, c-format
msgid "%s: %s: unsupported ELF version %d\n"
msgstr ""
-#: object.cc:821
+#: object.cc:839
#, c-format
msgid "%s: %s: invalid ELF class 0\n"
msgstr ""
-#: object.cc:828
+#: object.cc:846
#, c-format
msgid "%s: %s: unsupported ELF class %d\n"
msgstr ""
-#: object.cc:836
+#: object.cc:854
#, c-format
msgid "%s: %s: invalid ELF data encoding\n"
msgstr ""
-#: object.cc:843
+#: object.cc:861
#, c-format
msgid "%s: %s: unsupported ELF data encoding %d\n"
msgstr ""
@@ -496,37 +496,37 @@ msgstr ""
msgid "%s: -%c: %s\n"
msgstr ""
-#: output.cc:538
+#: output.cc:656
#, c-format
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
msgstr ""
-#: output.cc:1056
+#: output.cc:1171
#, c-format
msgid "%s: %s: open: %s\n"
msgstr ""
-#: output.cc:1065
+#: output.cc:1180
#, c-format
msgid "%s: %s: lseek: %s\n"
msgstr ""
-#: output.cc:1072
+#: output.cc:1187
#, c-format
msgid "%s: %s: write: %s\n"
msgstr ""
-#: output.cc:1082
+#: output.cc:1197
#, c-format
msgid "%s: %s: mmap: %s\n"
msgstr ""
-#: output.cc:1096
+#: output.cc:1211
#, c-format
msgid "%s: %s: munmap: %s\n"
msgstr ""
-#: output.cc:1104
+#: output.cc:1219
#, c-format
msgid "%s: %s: close: %s\n"
msgstr ""
@@ -567,62 +567,62 @@ msgstr ""
msgid "%s: %s: reloc section %u size %lu uneven"
msgstr ""
-#: resolve.cc:141
+#: resolve.cc:142
#, c-format
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
msgstr ""
-#: resolve.cc:147
+#: resolve.cc:148
#, c-format
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
msgstr ""
-#: symtab.cc:443 symtab.cc:540
+#: symtab.cc:446 symtab.cc:543
#, c-format
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
msgstr ""
-#: symtab.cc:460
+#: symtab.cc:463
#, c-format
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
msgstr ""
-#: symtab.cc:547
+#: symtab.cc:550
#, c-format
msgid "%s: %s: too few symbol versions\n"
msgstr ""
-#: symtab.cc:567
+#: symtab.cc:570
#, c-format
msgid "%s: %s: bad symbol name offset %u at %lu\n"
msgstr ""
-#: symtab.cc:611
+#: symtab.cc:614
#, c-format
msgid "%s: %s: versym for symbol %zu out of range: %u\n"
msgstr ""
-#: symtab.cc:619
+#: symtab.cc:622
#, c-format
msgid "%s: %s: versym for symbol %zu has no name: %u\n"
msgstr ""
-#: symtab.cc:1010 symtab.cc:1149
+#: symtab.cc:1019 symtab.cc:1158
#, c-format
msgid "%s: %s: unsupported symbol section 0x%x\n"
msgstr ""
-#: symtab.cc:1262
+#: symtab.cc:1274
#, c-format
msgid "%s: %s: warning: %s\n"
msgstr ""
-#: target-reloc.h:181
+#: target-reloc.h:163
#, c-format
msgid "%s: %s: reloc has bad offset %zu\n"
msgstr ""
-#: target-reloc.h:191
+#: target-reloc.h:173
#, c-format
msgid "%s: %s: undefined reference to '%s'\n"
msgstr ""
diff --git a/gold/reloc-types.h b/gold/reloc-types.h
new file mode 100644
index 0000000..62538d6
--- /dev/null
+++ b/gold/reloc-types.h
@@ -0,0 +1,36 @@
+// reloc-types.h -- ELF relocation templates for gold -*- C++ -*-
+
+// This header files defines a few convenient templated types for use
+// when handling ELF relocations.
+
+#ifndef GOLD_RELOC_TYPES_H
+#define GOLD_RELOC_TYPES_H
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+// Pick the ELF relocation accessor class and the size based on
+// SH_TYPE, which is either elfcpp::SHT_REL or elfcpp::SHT_RELA.
+
+template<int sh_type, int size, bool big_endian>
+struct Reloc_types;
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
+{
+ typedef typename elfcpp::Rel<size, big_endian> Reloc;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+};
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
+{
+ typedef typename elfcpp::Rela<size, big_endian> Reloc;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+};
+
+}; // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_TYPE_SH)
diff --git a/gold/reloc.cc b/gold/reloc.cc
index dd3eef1..ce6af0b 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -391,7 +391,7 @@ Sized_relobj<size, big_endian>::relocate_sections(
relinfo.layout = layout;
relinfo.object = this;
relinfo.local_symbol_count = this->local_symbol_count_;
- relinfo.values = this->values_;
+ relinfo.local_values = &this->local_values_;
relinfo.symbols = this->symbols_;
const unsigned char* p = pshdrs + This::shdr_size;
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 86645a4..2b6d65c 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -106,7 +106,8 @@ Symbol_table::resolve(Sized_symbol<size>* to,
abort();
}
- if (to->object() != NULL && to->object()->is_dynamic())
+ if (to->source() == Symbol::FROM_OBJECT
+ && to->object()->is_dynamic())
tobits |= (1 << 1);
switch (to->shnum())
@@ -174,6 +175,15 @@ Symbol_table::resolve(Sized_symbol<size>* to,
break;
}
+ if ((tobits & (1 << 1)) != (frombits & (1 << 1)))
+ {
+ // This symbol is seen in both a dynamic object and a regular
+ // object. That means that we need the symbol to go into the
+ // dynamic symbol table, so that the dynamic linker can use the
+ // regular symbol to override or define the dynamic symbol.
+ to->set_needs_dynsym_entry();
+ }
+
// FIXME: Warn if either but not both of TO and SYM are STT_TLS.
// We use a giant switch table for symbol resolution. This code is
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 9279d26..92d5583 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -29,6 +29,8 @@ Symbol::init_fields(const char* name, const char* version,
{
this->name_ = name;
this->version_ = version;
+ this->symtab_index_ = 0;
+ this->dynsym_index_ = 0;
this->got_offset_ = 0;
this->type_ = type;
this->binding_ = binding;
@@ -37,6 +39,7 @@ Symbol::init_fields(const char* name, const char* version,
this->is_target_special_ = false;
this->is_def_ = false;
this->is_forwarder_ = false;
+ this->needs_dynsym_entry_ = false;
this->in_dyn_ = false;
this->has_got_offset_ = false;
this->has_warning_ = false;
@@ -204,10 +207,10 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
// Resolve the forwards from FROM, returning the real symbol.
Symbol*
-Symbol_table::resolve_forwards(Symbol* from) const
+Symbol_table::resolve_forwards(const Symbol* from) const
{
assert(from->is_forwarder());
- Unordered_map<Symbol*, Symbol*>::const_iterator p =
+ Unordered_map<const Symbol*, Symbol*>::const_iterator p =
this->forwarders_.find(from);
assert(p != this->forwarders_.end());
return p->second;
@@ -952,18 +955,22 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
}
}
-// Set the final values for all the symbols. Record the file offset
+// Set the final values for all the symbols. The index of the first
+// global symbol in the output file is INDEX. Record the file offset
// OFF. Add their names to POOL. Return the new file offset.
off_t
-Symbol_table::finalize(off_t off, Stringpool* pool)
+Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
{
off_t ret;
+ assert(index != 0);
+ this->first_global_index_ = index;
+
if (this->size_ == 32)
- ret = this->sized_finalize<32>(off, pool);
+ ret = this->sized_finalize<32>(index, off, pool);
else if (this->size_ == 64)
- ret = this->sized_finalize<64>(off, pool);
+ ret = this->sized_finalize<64>(index, off, pool);
else
abort();
@@ -980,15 +987,17 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
template<int size>
off_t
-Symbol_table::sized_finalize(off_t off, Stringpool* pool)
+Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
{
off = align_address(off, size >> 3);
this->offset_ = off;
+ size_t orig_index = index;
+
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
- Symbol_table_type::iterator p = this->table_.begin();
- size_t count = 0;
- while (p != this->table_.end())
+ for (Symbol_table_type::iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
{
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
@@ -1030,12 +1039,7 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
if (os == NULL)
{
- // We should be able to erase this symbol from the
- // symbol table, but at least with gcc 4.0.2
- // std::unordered_map::erase doesn't appear to return
- // the new iterator.
- // p = this->table_.erase(p);
- ++p;
+ sym->set_symtab_index(-1U);
continue;
}
@@ -1082,13 +1086,13 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
}
sym->set_value(value);
+ sym->set_symtab_index(index);
pool->add(sym->name(), NULL);
- ++count;
+ ++index;
off += sym_size;
- ++p;
}
- this->output_count_ = count;
+ this->output_count_ = index - orig_index;
return off;
}
@@ -1126,8 +1130,10 @@ Symbol_table::sized_write_globals(const Target*,
Output_file* of) const
{
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
- unsigned char* psyms = of->get_output_view(this->offset_,
- this->output_count_ * sym_size);
+ unsigned int index = this->first_global_index_;
+ const off_t oview_size = this->output_count_ * sym_size;
+ unsigned char* psyms = of->get_output_view(this->offset_, oview_size);
+
unsigned char* ps = psyms;
for (Symbol_table_type::const_iterator p = this->table_.begin();
p != this->table_.end();
@@ -1135,6 +1141,9 @@ Symbol_table::sized_write_globals(const Target*,
{
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+ if (sym->symtab_index() == -1U)
+ continue;
+
unsigned int shndx;
switch (sym->source())
{
@@ -1164,9 +1173,7 @@ Symbol_table::sized_write_globals(const Target*,
Relobj* relobj = static_cast<Relobj*>(symobj);
off_t secoff;
Output_section* os = relobj->output_section(shnum, &secoff);
- if (os == NULL)
- continue;
-
+ assert(os != NULL);
shndx = os->out_shndx();
}
}
@@ -1188,6 +1195,9 @@ Symbol_table::sized_write_globals(const Target*,
abort();
}
+ assert(sym->symtab_index() == index);
+ ++index;
+
elfcpp::Sym_write<size, big_endian> osym(ps);
osym.put_st_name(sympool->get_offset(sym->name()));
osym.put_st_value(sym->value());
@@ -1200,7 +1210,9 @@ Symbol_table::sized_write_globals(const Target*,
ps += sym_size;
}
- of->write_output_view(this->offset_, this->output_count_ * sym_size, psyms);
+ assert(ps - psyms == oview_size);
+
+ of->write_output_view(this->offset_, oview_size, psyms);
}
// Warnings functions.
@@ -1254,7 +1266,7 @@ Warnings::note_warnings(Symbol_table* symtab)
// symbol for which has a warning.
void
-Warnings::issue_warning(Symbol* sym, const std::string& location) const
+Warnings::issue_warning(const Symbol* sym, const std::string& location) const
{
assert(sym->has_warning());
Warning_table::const_iterator p = this->warnings_.find(sym->name());
diff --git a/gold/symtab.h b/gold/symtab.h
index e972600..06a4b6b 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -173,6 +173,17 @@ class Symbol
set_forwarder()
{ this->is_forwarder_ = true; }
+ // Return whether this symbol needs an entry in the dynamic symbol
+ // table.
+ bool
+ needs_dynsym_entry() const
+ { return this->needs_dynsym_entry_; }
+
+ // Mark this symbol as needing an entry in the dynamic symbol table.
+ void
+ set_needs_dynsym_entry()
+ { this->needs_dynsym_entry_ = true; }
+
// Return whether this symbol was ever seen in a dynamic object.
bool
in_dyn() const
@@ -183,6 +194,46 @@ class Symbol
set_in_dyn()
{ this->in_dyn_ = true; }
+ // Return the index of this symbol in the output file symbol table.
+ // A value of -1U means that this symbol is not going into the
+ // output file. This starts out as zero, and is set to a non-zero
+ // value by Symbol_table::finalize. It is an error to ask for the
+ // symbol table index before it has been set.
+ unsigned int
+ symtab_index() const
+ {
+ assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the index of the symbol in the output file symbol table.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Return the index of this symbol in the dynamic symbol table. A
+ // value of -1U means that this symbol is not going into the dynamic
+ // symbol table. This starts out as zero, and is set to a non-zero
+ // during Layout::finalize. It is an error to ask for the dynamic
+ // symbol table index before it has been set.
+ unsigned int
+ dynsym_index() const
+ {
+ assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the index of the symbol in the dynamic symbol table.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
// Return whether this symbol has an entry in the GOT section.
bool
has_got_offset() const
@@ -334,9 +385,22 @@ class Symbol
} in_output_segment;
} u_;
+ // The index of this symbol in the output file. If the symbol is
+ // not going into the output file, this value is -1U. This field
+ // starts as always holding zero. It is set to a non-zero value by
+ // Symbol_table::finalize.
+ unsigned int symtab_index_;
+
+ // The index of this symbol in the dynamic symbol table. If the
+ // symbol is not going into the dynamic symbol table, this value is
+ // -1U. This field starts as always holding zero. It is set to a
+ // non-zero value during Layout::finalize.
+ unsigned int dynsym_index_;
+
// If this symbol has an entry in the GOT section (has_got_offset_
- // is true), this is the offset.
+ // is true), this is the offset from the start of the GOT section.
unsigned int got_offset_;
+
// Symbol type.
elfcpp::STT type_ : 4;
// Symbol binding.
@@ -360,6 +424,8 @@ class Symbol
// It forwards to the symbol found in the forwarders_ map of
// Symbol_table.
bool is_forwarder_ : 1;
+ // True if this symbol needs to be in the dynamic symbol table.
+ bool needs_dynsym_entry_ : 1;
// True if we've seen this symbol in a dynamic object.
bool in_dyn_ : 1;
// True if the symbol has an entry in the GOT section.
@@ -548,7 +614,7 @@ class Warnings
// Issue a warning for a reference to SYM at LOCATION.
void
- issue_warning(Symbol* sym, const std::string& location) const;
+ issue_warning(const Symbol* sym, const std::string& location) const;
private:
Warnings(const Warnings&);
@@ -667,7 +733,7 @@ class Symbol_table
// Return the real symbol associated with the forwarder symbol FROM.
Symbol*
- resolve_forwards(Symbol* from) const;
+ resolve_forwards(const Symbol* from) const;
// Return the size of the symbols in the table.
int
@@ -705,15 +771,16 @@ class Symbol_table
// Possibly issue a warning for a reference to SYM at LOCATION which
// is in OBJ.
void
- issue_warning(Symbol* sym, const std::string& location) const
+ issue_warning(const Symbol* sym, const std::string& location) const
{ this->warnings_.issue_warning(sym, location); }
// Finalize the symbol table after we have set the final addresses
- // of all the input sections. This sets the final symbol values and
- // adds the names to *POOL. It records the file offset OFF, and
+ // of all the input sections. This sets the final symbol indexes,
+ // values and adds the names to *POOL. INDEX is the index of the
+ // first global symbol. This records the file offset OFF, and
// returns the new file offset.
off_t
- finalize(off_t, Stringpool*);
+ finalize(unsigned int index, off_t off, Stringpool* pool);
// Write out the global symbols.
void
@@ -791,7 +858,7 @@ class Symbol_table
// Finalize symbols specialized for size.
template<int size>
off_t
- sized_finalize(off_t, Stringpool*);
+ sized_finalize(unsigned int, off_t, Stringpool*);
// Write globals specialized for size and endianness.
template<int size, bool big_endian>
@@ -828,6 +895,9 @@ class Symbol_table
// use in archive groups.
int saw_undefined_;
+ // The index of the first global symbol in the output file.
+ unsigned int first_global_index_;
+
// The file offset within the output symtab section where we should
// write the table.
off_t offset_;
@@ -843,7 +913,7 @@ class Symbol_table
Stringpool namepool_;
// Forwarding symbols.
- Unordered_map<Symbol*, Symbol*> forwarders_;
+ Unordered_map<const Symbol*, Symbol*> forwarders_;
// We don't expect there to be very many common symbols, so we keep
// a list of them. When we find a common symbol we add it to this
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
index 7069278..5b057ac 100644
--- a/gold/target-reloc.h
+++ b/gold/target-reloc.h
@@ -6,30 +6,11 @@
#include "elfcpp.h"
#include "object.h"
#include "symtab.h"
+#include "reloc-types.h"
namespace gold
{
-// Pick the ELF relocation accessor class and the size based on
-// SH_TYPE, which is either SHT_REL or SHT_RELA.
-
-template<int sh_type, int size, bool big_endian>
-struct Reloc_types;
-
-template<int size, bool big_endian>
-struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
-{
- typedef typename elfcpp::Rel<size, big_endian> Reloc;
- static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
-};
-
-template<int size, bool big_endian>
-struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
-{
- typedef typename elfcpp::Rela<size, big_endian> Reloc;
- static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
-};
-
// This function implements the generic part of reloc scanning. This
// is an inline function which takes a class whose operator()
// implements the machine specific part of scanning. We do it this
@@ -140,8 +121,9 @@ relocate_section(
Relocate relocate;
unsigned int local_count = relinfo->local_symbol_count;
- typename elfcpp::Elf_types<size>::Elf_Addr *local_values = relinfo->values;
- Symbol** global_syms = relinfo->symbols;
+ const typename Sized_relobj<size, big_endian>::Local_values* local_values =
+ relinfo->local_values;
+ const Symbol* const * global_syms = relinfo->symbols;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
@@ -153,22 +135,22 @@ relocate_section(
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
- Sized_symbol<size>* sym;
+ const Sized_symbol<size>* sym;
typename elfcpp::Elf_types<size>::Elf_Addr value;
if (r_sym < local_count)
{
sym = NULL;
- value = local_values[r_sym];
+ value = (*local_values)[r_sym];
}
else
{
- Symbol* gsym = global_syms[r_sym - local_count];
+ const Symbol* gsym = global_syms[r_sym - local_count];
assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = relinfo->symtab->resolve_forwards(gsym);
- sym = static_cast<Sized_symbol<size>*>(gsym);
+ sym = static_cast<const Sized_symbol<size>*>(gsym);
value = sym->value();
}