Add support for SHF_MERGE sections.

This commit is contained in:
Ian Lance Taylor 2007-05-16 17:42:48 +00:00
parent 60dfee7299
commit b8e6aad960
18 changed files with 1451 additions and 267 deletions

View File

@ -30,6 +30,7 @@ CCFILES = \
gold.cc \
gold-threads.cc \
layout.cc \
merge.cc \
object.cc \
options.cc \
output.cc \
@ -52,6 +53,7 @@ HFILES = \
gold.h \
gold-threads.h \
layout.h \
merge.h \
object.h \
options.h \
output.h \

View File

@ -71,10 +71,11 @@ libgold_a_LIBADD =
am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \
dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \
gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \
script.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
target-select.$(OBJEXT) workqueue.$(OBJEXT)
merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
resolve.$(OBJEXT) script.$(OBJEXT) symtab.$(OBJEXT) \
stringpool.$(OBJEXT) target-select.$(OBJEXT) \
workqueue.$(OBJEXT)
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
@ -256,6 +257,7 @@ CCFILES = \
gold.cc \
gold-threads.cc \
layout.cc \
merge.cc \
object.cc \
options.cc \
output.cc \
@ -278,6 +280,7 @@ HFILES = \
gold.h \
gold-threads.h \
layout.h \
merge.h \
object.h \
options.h \
output.h \
@ -398,6 +401,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@

View File

@ -12,7 +12,6 @@ namespace gold
{
class General_options;
class Stringpool;
// A dynamic object (ET_DYN). This is an abstract base class itself.
// The implementations is the template class Sized_dynobj.

View File

@ -109,7 +109,7 @@ class Target_i386 : public Sized_target<32, false>
relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
const elfcpp::Rel<32, false>&,
unsigned int r_type, const Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
const Symbol_value<32>*,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
off_t);
@ -119,7 +119,7 @@ class Target_i386 : public Sized_target<32, false>
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&,
unsigned int r_type, const Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
const Symbol_value<32>*,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
// Do a TLS Initial-Exec to Local-Exec transition.
@ -1027,7 +1027,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
const Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
const Symbol_value<32>* psymval,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
@ -1050,14 +1050,19 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
}
// Pick the value to use for symbols defined in shared objects.
Symbol_value<32> symval;
if (gsym != NULL && gsym->is_from_dynobj())
{
if (gsym->has_plt_offset())
value = target->plt_section()->address() + gsym->plt_offset();
else
if (!gsym->has_plt_offset())
gold_unreachable();
symval.set_output_value(target->plt_section()->address()
+ gsym->plt_offset());
psymval = &symval;
}
const Sized_relobj<32, false>* object = relinfo->object;
switch (r_type)
{
case elfcpp::R_386_NONE:
@ -1066,51 +1071,57 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
break;
case elfcpp::R_386_32:
Relocate_functions<32, false>::rel32(view, value);
Relocate_functions<32, false>::rel32(view, object, psymval);
break;
case elfcpp::R_386_PC32:
Relocate_functions<32, false>::pcrel32(view, value, address);
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
break;
case elfcpp::R_386_16:
Relocate_functions<32, false>::rel16(view, value);
Relocate_functions<32, false>::rel16(view, object, psymval);
break;
case elfcpp::R_386_PC16:
Relocate_functions<32, false>::pcrel16(view, value, address);
Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
break;
case elfcpp::R_386_8:
Relocate_functions<32, false>::rel8(view, value);
Relocate_functions<32, false>::rel8(view, object, psymval);
break;
case elfcpp::R_386_PC8:
Relocate_functions<32, false>::pcrel8(view, value, address);
Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
break;
case elfcpp::R_386_PLT32:
gold_assert(gsym->has_plt_offset()
|| gsym->final_value_is_known(relinfo->options));
Relocate_functions<32, false>::pcrel32(view, value, address);
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
break;
case elfcpp::R_386_GOT32:
// Local GOT offsets not yet supported.
gold_assert(gsym);
gold_assert(gsym->has_got_offset());
value = gsym->got_offset();
Relocate_functions<32, false>::rel32(view, value);
Relocate_functions<32, false>::rel32(view, gsym->got_offset());
break;
case elfcpp::R_386_GOTOFF:
value -= target->got_section(NULL, NULL, NULL)->address();
Relocate_functions<32, false>::rel32(view, value);
{
elfcpp::Elf_types<32>::Elf_Addr value;
value = (psymval->value(object, 0)
- target->got_section(NULL, NULL, NULL)->address());
Relocate_functions<32, false>::rel32(view, value);
}
break;
case elfcpp::R_386_GOTPC:
value = target->got_section(NULL, NULL, NULL)->address();
Relocate_functions<32, false>::pcrel32(view, value, address);
{
elfcpp::Elf_types<32>::Elf_Addr value;
value = target->got_section(NULL, NULL, NULL)->address();
Relocate_functions<32, false>::pcrel32(view, value, address);
}
break;
case elfcpp::R_386_COPY:
@ -1139,7 +1150,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view,
this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view,
address, view_size);
break;
@ -1173,7 +1184,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
const Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
const Symbol_value<32>* psymval,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr,
off_t view_size)
@ -1187,6 +1198,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
gold_exit(false);
}
elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
const bool is_final = (gsym == NULL
? !relinfo->options->is_shared()
: gsym->final_value_is_known(relinfo->options));

View File

@ -133,7 +133,9 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key,
// We should ignore some flags.
flags &= ~ (elfcpp::SHF_INFO_LINK
| elfcpp::SHF_LINK_ORDER
| elfcpp::SHF_GROUP);
| elfcpp::SHF_GROUP
| elfcpp::SHF_MERGE
| elfcpp::SHF_STRINGS);
const Key key(name_key, std::make_pair(type, flags));
const std::pair<Key, Output_section*> v(key, NULL);
@ -224,7 +226,7 @@ Output_section*
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
Output_section* os = new Output_section(name, type, flags, true);
Output_section* os = new Output_section(name, type, flags);
this->section_list_.push_back(os);
if ((flags & elfcpp::SHF_ALLOC) == 0)
@ -466,7 +468,6 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
off_t off = this->set_segment_offsets(target, load_seg, &shndx);
// Create the symbol table sections.
// FIXME: We don't need to do this if we are stripping symbols.
this->create_symtab_sections(size, input_objects, symtab, &off);
// Create the .shstrtab section.
@ -690,7 +691,9 @@ Layout::set_section_offsets(off_t off, unsigned int* pshndx)
return off;
}
// Create the symbol table sections.
// Create the symbol table sections. Here we also set the final
// values of the symbols. At this point all the loadable sections are
// fully laid out.
void
Layout::create_symtab_sections(int size, const Input_objects* input_objects,

333
gold/merge.cc Normal file
View File

@ -0,0 +1,333 @@
// merge.cc -- handle section merging for gold
#include "gold.h"
#include <cstdlib>
#include "merge.h"
namespace gold
{
// Sort the entries in a merge mapping. The key is an input object, a
// section index in that object, and an offset in that section.
bool
Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1,
const Merge_key& mk2) const
{
// The order of different objects and different sections doesn't
// matter. We want to get consistent results across links so we
// don't use pointer comparison.
if (mk1.object != mk2.object)
return mk1.object->name() < mk2.object->name();
if (mk1.shndx != mk2.shndx)
return mk1.shndx < mk2.shndx;
return mk1.offset < mk2.offset;
}
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in a merged output section. This
// manages the mapping used to resolve relocations against merged
// sections.
void
Output_merge_base::add_mapping(Relobj* object, unsigned int shndx,
off_t offset, off_t output_offset)
{
Merge_key mk;
mk.object = object;
mk.shndx = shndx;
mk.offset = offset;
std::pair<Merge_map::iterator, bool> ins =
this->merge_map_.insert(std::make_pair(mk, output_offset));
gold_assert(ins.second);
}
// Return the output address for an input address. The input address
// is at offset OFFSET in section SHNDX in OBJECT.
// OUTPUT_SECTION_ADDRESS is the address of the output section. If we
// know the address, set *POUTPUT and return true. Otherwise return
// false.
bool
Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx,
off_t offset,
uint64_t output_section_address,
uint64_t* poutput) const
{
gold_assert(output_section_address == this->address());
Merge_key mk;
mk.object = object;
mk.shndx = shndx;
mk.offset = offset;
Merge_map::const_iterator p = this->merge_map_.lower_bound(mk);
// If MK is not in the map, lower_bound returns the next iterator
// larger than it.
if (p->first.object != object
|| p->first.shndx != shndx
|| p->first.offset != offset)
{
if (p == this->merge_map_.begin())
return false;
--p;
}
if (p->first.object != object || p->first.shndx != shndx)
return false;
// Any input section is fully mapped: we don't need to know the size
// of the range starting at P->FIRST.OFFSET.
*poutput = output_section_address + p->second + (offset - p->first.offset);
return true;
}
// Compute the hash code for a fixed-size constant.
size_t
Output_merge_data::Merge_data_hash::operator()(Merge_data_key k) const
{
const unsigned char* p = this->pomd_->constant(k);
uint64_t entsize = this->pomd_->entsize();
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
if (sizeof(size_t) == 8)
{
size_t result = static_cast<size_t>(14695981039346656037ULL);
for (uint64_t i = 0; i < entsize; ++i)
{
result &= (size_t) *p++;
result *= 1099511628211ULL;
}
return result;
}
else
{
size_t result = 2166136261UL;
for (uint64_t i = 0; i < entsize; ++i)
{
result ^= (size_t) *p++;
result *= 16777619UL;
}
return result;
}
}
// Return whether one hash table key equals another.
bool
Output_merge_data::Merge_data_eq::operator()(Merge_data_key k1,
Merge_data_key k2) const
{
const unsigned char* p1 = this->pomd_->constant(k1);
const unsigned char* p2 = this->pomd_->constant(k2);
return memcmp(p1, p2, this->pomd_->entsize()) == 0;
}
// Add a constant to the end of the section contents.
void
Output_merge_data::add_constant(const unsigned char* p)
{
uint64_t entsize = this->entsize();
if (this->len_ + entsize > this->alc_)
{
if (this->alc_ == 0)
this->alc_ = 128 * entsize;
else
this->alc_ *= 2;
this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->alc_));
if (this->p_ == NULL)
gold_fatal("out of memory", true);
}
memcpy(this->p_ + this->len_, p, entsize);
this->len_ += entsize;
}
// Add the input section SHNDX in OBJECT to a merged output section
// which holds fixed length constants. Return whether we were able to
// handle the section; if not, it will be linked as usual without
// constant merging.
bool
Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
{
off_t len;
const unsigned char* p = object->section_contents(shndx, &len);
uint64_t entsize = this->entsize();
if (len % entsize != 0)
return false;
for (off_t i = 0; i < len; i += entsize, p += entsize)
{
// Add the constant to the section contents. If we find that it
// is already in the hash table, we will remove it again.
Merge_data_key k = this->len_;
this->add_constant(p);
std::pair<Merge_data_hashtable::iterator, bool> ins =
this->hashtable_.insert(k);
if (!ins.second)
{
// Key was already present. Remove the copy we just added.
this->len_ -= entsize;
k = *ins.first;
}
// Record the offset of this constant in the output section.
this->add_mapping(object, shndx, i, k);
}
return true;
}
// Set the final data size in a merged output section with fixed size
// constants.
void
Output_merge_data::do_set_address(uint64_t, off_t)
{
// Release the memory we don't need.
this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_));
gold_assert(this->p_ != NULL);
this->set_data_size(this->len_);
}
// Write the data of a merged output section with fixed size constants
// to the file.
void
Output_merge_data::do_write(Output_file* of)
{
of->write(this->offset(), this->p_, this->len_);
}
// Compute a hash code for a Merge_string_key, which is an object, a
// section index, and an offset.
template<typename Char_type>
size_t
Output_merge_string<Char_type>::Merge_string_key_hash::operator()(
const Merge_string_key& key) const
{
// This is a very simple minded hash code. Fix it if it we get too
// many collisions.
const std::string& oname(key.object->name());
return oname[0] + oname.length() + key.shndx + key.offset;
}
// Compare two Merge_string_keys for equality.
template<typename Char_type>
bool
Output_merge_string<Char_type>::Merge_string_key_eq::operator()(
const Merge_string_key& k1, const Merge_string_key& k2) const
{
return (k1.object == k2.object
&& k1.shndx == k2.shndx
&& k1.offset == k2.offset);
}
// Add an input section to a merged string section.
template<typename Char_type>
bool
Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
unsigned int shndx)
{
off_t len;
const unsigned char* pdata = object->section_contents(shndx, &len);
const Char_type* p = reinterpret_cast<const Char_type*>(pdata);
if (len % sizeof(Char_type) != 0)
{
fprintf(stderr,
_("%s: %s: mergeable string section length not multiple of "
"character size\n"),
program_name, object->name().c_str());
gold_exit(false);
}
len /= sizeof(Char_type);
off_t i = 0;
while (i < len)
{
off_t plen = 0;
for (const Char_type* pl = p; *pl != 0; ++pl)
{
++plen;
if (i + plen >= len)
{
fprintf(stderr,
_("%s: %s: entry in mergeable string section "
"not null terminated\n"),
program_name, object->name().c_str());
gold_exit(false);
}
}
const Char_type* str = this->stringpool_.add(p, NULL);
Merge_string_key k(object, shndx, i);
typename Merge_string_hashtable::value_type v(k, str);
bool b = this->hashtable_.insert(v).second;
gold_assert(b);
p += plen + 1;
i += plen + 1;
}
return true;
}
// Set the final data size of a merged string section. This is where
// we finalize the mappings from the input sections to the output
// section.
template<typename Char_type>
void
Output_merge_string<Char_type>::do_set_address(uint64_t, off_t)
{
this->stringpool_.set_string_offsets();
for (typename Merge_string_hashtable::const_iterator p =
this->hashtable_.begin();
p != this->hashtable_.end();
++p)
this->add_mapping(p->first.object, p->first.shndx, p->first.offset,
this->stringpool_.get_offset(p->second));
this->set_data_size(this->stringpool_.get_strtab_size());
// Save some memory.
this->hashtable_.clear();
}
// Write out a merged string section.
template<typename Char_type>
void
Output_merge_string<Char_type>::do_write(Output_file* of)
{
this->stringpool_.write(of, this->offset());
}
// Instantiate the templates we need.
template
class Output_merge_string<char>;
template
class Output_merge_string<uint16_t>;
template
class Output_merge_string<uint32_t>;
} // End namespace gold.

226
gold/merge.h Normal file
View File

@ -0,0 +1,226 @@
// merge.h -- handle section merging for gold -*- C++ -*-
#ifndef GOLD_MERGE_H
#define GOLD_MERGE_H
#include <climits>
#include "stringpool.h"
#include "output.h"
namespace gold
{
// A general class for SHF_MERGE data, to hold functions shared by
// fixed-size constant data and string data.
class Output_merge_base : public Output_section_data
{
public:
Output_merge_base(uint64_t entsize)
: Output_section_data(1), merge_map_(), entsize_(entsize)
{ }
// Return the output address for an input address.
bool
do_output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t* poutput) const;
protected:
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section.
void
add_mapping(Relobj* object, unsigned int shndx, off_t offset,
off_t output_offset);
private:
// We build a mapping from OBJECT/SHNDX/OFFSET to an offset in the
// output section.
struct Merge_key
{
const Relobj* object;
unsigned int shndx;
off_t offset;
};
struct Merge_key_less
{
bool
operator()(const Merge_key&, const Merge_key&) const;
};
typedef std::map<Merge_key, off_t, Merge_key_less> Merge_map;
// A mapping from input object/section/offset to offset in output
// section.
Merge_map merge_map_;
// The entry size. For fixed-size constants, this is the size of
// the constants. For strings, this is the size of a character.
uint64_t entsize_;
};
// Handle SHF_MERGE sections with fixed-size constant data.
class Output_merge_data : public Output_merge_base
{
public:
Output_merge_data(uint64_t entsize)
: Output_merge_base(entsize), p_(NULL), len_(0), alc_(0),
hashtable_(128, Merge_data_hash(this), Merge_data_eq(this))
{ }
// Add an input section.
bool
do_add_input_section(Relobj* object, unsigned int shndx);
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Write the data to the file.
void
do_write(Output_file*);
private:
// We build a hash table of the fixed-size constants. Each constant
// is stored as a pointer into the section data we are accumulating.
// A key in the hash table. This is an offset in the section
// contents we are building.
typedef off_t Merge_data_key;
// Compute the hash code. To do this we need a pointer back to the
// object holding the data.
class Merge_data_hash
{
public:
Merge_data_hash(const Output_merge_data* pomd)
: pomd_(pomd)
{ }
size_t
operator()(Merge_data_key) const;
private:
const Output_merge_data* pomd_;
};
friend class Merge_data_hash;
// Compare two entries in the hash table for equality. To do this
// we need a pointer back to the object holding the data. Note that
// we now have a pointer to the object stored in two places in the
// hash table. Fixing this would require specializing the hash
// table, which would be hard to do portably.
class Merge_data_eq
{
public:
Merge_data_eq(const Output_merge_data* pomd)
: pomd_(pomd)
{ }
bool
operator()(Merge_data_key k1, Merge_data_key k2) const;
private:
const Output_merge_data* pomd_;
};
friend class Merge_data_eq;
// The type of the hash table.
typedef Unordered_set<Merge_data_key, Merge_data_hash, Merge_data_eq>
Merge_data_hashtable;
// Given a hash table key, which is just an offset into the section
// data, return a pointer to the corresponding constant.
const unsigned char*
constant(Merge_data_key k) const
{
gold_assert(k >= 0 && k < this->len_);
return this->p_ + k;
}
// Add a constant to the output.
void
add_constant(const unsigned char*);
// The accumulated data.
unsigned char* p_;
// The length of the accumulated data.
off_t len_;
// The size of the allocated buffer.
size_t alc_;
// The hash table.
Merge_data_hashtable hashtable_;
};
// Handle SHF_MERGE sections with string data. This is a template
// based on the type of the characters in the string.
template<typename Char_type>
class Output_merge_string : public Output_merge_base
{
public:
Output_merge_string()
: Output_merge_base(sizeof(Char_type)), stringpool_(false), hashtable_()
{ }
// Add an input section.
bool
do_add_input_section(Relobj* object, unsigned int shndx);
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Write the data to the file.
void
do_write(Output_file*);
private:
// As we see input sections, we build a mapping from object, section
// index and offset to strings.
struct Merge_string_key
{
Relobj* object;
unsigned int shndx;
off_t offset;
Merge_string_key(Relobj *objecta, unsigned int shndxa, off_t offseta)
: object(objecta), shndx(shndxa), offset(offseta)
{ }
};
struct Merge_string_key_hash
{
size_t
operator()(const Merge_string_key&) const;
};
struct Merge_string_key_eq
{
bool
operator()(const Merge_string_key&, const Merge_string_key&) const;
};
typedef Unordered_map<Merge_string_key, const Char_type*,
Merge_string_key_hash, Merge_string_key_eq>
Merge_string_hashtable;
// As we see the strings, we add them to a Stringpool.
Stringpool_template<Char_type> stringpool_;
// Map from a location in an input object to an entry in the
// Stringpool.
Merge_string_hashtable hashtable_;
};
} // End namespace gold.
#endif // !defined(GOLD_MERGE_H)

View File

@ -127,8 +127,7 @@ Sized_relobj<size, big_endian>::Sized_relobj(
output_local_symbol_count_(0),
symbols_(NULL),
local_symbol_offset_(0),
local_values_(),
local_indexes_()
local_values_()
{
}
@ -505,10 +504,9 @@ 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->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.
// add their values to THIS->LOCAL_VALUES_. 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>
unsigned int
@ -542,7 +540,6 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
locsize);
this->local_values_.resize(loccount);
this->local_indexes_.resize(loccount);
// Read the symbol names.
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
@ -562,12 +559,15 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
{
elfcpp::Sym<size, big_endian> sym(psyms);
Symbol_value<size>& lv(this->local_values_[i]);
unsigned int shndx = sym.get_st_shndx();
lv.set_input_shndx(shndx);
if (shndx >= elfcpp::SHN_LORESERVE)
{
if (shndx == elfcpp::SHN_ABS)
this->local_values_[i] = sym.get_st_value();
lv.set_output_value(sym.get_st_value());
else
{
// FIXME: Handle SHN_XINDEX.
@ -589,23 +589,28 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
gold_exit(false);
}
if (mo[shndx].output_section == NULL)
Output_section* os = mo[shndx].output_section;
if (os == NULL)
{
this->local_values_[i] = 0;
this->local_indexes_[i] = -1U;
lv.set_output_value(0);
lv.set_no_output_symtab_entry();
continue;
}
this->local_values_[i] = (mo[shndx].output_section->address()
+ mo[shndx].offset
+ sym.get_st_value());
if (mo[shndx].offset == -1)
lv.set_input_value(sym.get_st_value());
else
lv.set_output_value(mo[shndx].output_section->address()
+ mo[shndx].offset
+ sym.get_st_value());
}
// Decide whether this symbol should go into the output file.
if (sym.get_st_type() == elfcpp::STT_SECTION)
{
this->local_indexes_[i] = -1U;
lv.set_no_output_symtab_entry();
continue;
}
@ -622,9 +627,8 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
const char* name = pnames + sym.get_st_name();
pool->add(name, NULL);
this->local_indexes_[i] = index;
lv.set_output_symtab_index(index);
++index;
off += sym_size;
++count;
}
@ -633,6 +637,23 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
return index;
}
// Return the value of a local symbol defined in input section SHNDX,
// with value VALUE, adding addend ADDEND. This handles SHF_MERGE
// sections.
template<int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
Sized_relobj<size, big_endian>::local_value(unsigned int shndx,
Address value,
Address addend) const
{
const std::vector<Map_to_output>& mo(this->map_to_output());
Output_section* os = mo[shndx].output_section;
if (os == NULL)
return addend;
gold_assert(mo[shndx].offset == -1);
return os->output_address(this, shndx, value + addend);
}
// Write out the local symbols.
template<int size, bool big_endian>
@ -676,7 +697,6 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
const std::vector<Map_to_output>& mo(this->map_to_output());
gold_assert(this->local_values_.size() == loccount);
gold_assert(this->local_indexes_.size() == loccount);
unsigned char* ov = oview;
psyms += sym_size;
@ -684,9 +704,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
{
elfcpp::Sym<size, big_endian> isym(psyms);
if (this->local_indexes_[i] == -1U)
if (!this->local_values_[i].needs_output_symtab_entry())
continue;
gold_assert(this->local_indexes_[i] != 0);
unsigned int st_shndx = isym.get_st_shndx();
if (st_shndx < elfcpp::SHN_LORESERVE)
@ -702,7 +721,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
gold_assert(isym.get_st_name() < strtab_size);
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_value(this->local_values_[i].value(this, 0));
osym.put_st_size(isym.get_st_size());
osym.put_st_info(isym.get_st_info());
osym.put_st_other(isym.get_st_other());

View File

@ -15,12 +15,14 @@ namespace gold
{
class General_options;
class Stringpool;
class Layout;
class Output_section;
class Output_file;
class Dynobj;
template<typename Stringpool_char>
class Stringpool_template;
// Data to pass from read_symbols() to add_symbols().
struct Read_symbols_data
@ -338,7 +340,7 @@ Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY)
}
// A regular object (ET_REL). This is an abstract base class itself.
// The implementations is the template class Sized_relobj.
// The implementation is the template class Sized_relobj.
class Relobj : public Object
{
@ -362,7 +364,8 @@ class Relobj : public Object
// symbol information will be stored; add local symbol names to
// *POOL; return the new local symbol index.
unsigned int
finalize_local_symbols(unsigned int index, off_t off, Stringpool* pool)
finalize_local_symbols(unsigned int index, off_t off,
Stringpool_template<char>* pool)
{ return this->do_finalize_local_symbols(index, off, pool); }
// Relocate the input sections and write out the local symbols.
@ -383,7 +386,7 @@ class Relobj : public Object
// (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 shndx, off_t* poff);
output_section(unsigned int shndx, off_t* poff) const;
// Set the offset of an input section within its output section.
void
@ -402,7 +405,8 @@ class Relobj : public Object
// The output section. This is NULL if the input section is to be
// discarded.
Output_section* output_section;
// The offset within the output section.
// The offset within the output section. This is -1 if the
// section requires special handling.
off_t offset;
};
@ -417,7 +421,8 @@ class Relobj : public Object
// Finalize local symbols--implemented by child class.
virtual unsigned int
do_finalize_local_symbols(unsigned int, off_t, Stringpool*) = 0;
do_finalize_local_symbols(unsigned int, off_t,
Stringpool_template<char>*) = 0;
// Relocate the input sections and write out the local
// symbols--implemented by child class.
@ -430,6 +435,10 @@ class Relobj : public Object
map_to_output()
{ return this->map_to_output_; }
const std::vector<Map_to_output>&
map_to_output() const
{ return this->map_to_output_; }
private:
// Mapping from input sections to output section.
std::vector<Map_to_output> map_to_output_;
@ -437,7 +446,7 @@ class Relobj : public Object
// Implement Object::output_section inline for efficiency.
inline Output_section*
Relobj::output_section(unsigned int shndx, off_t* poff)
Relobj::output_section(unsigned int shndx, off_t* poff) const
{
gold_assert(shndx < this->map_to_output_.size());
const Map_to_output& mo(this->map_to_output_[shndx]);
@ -445,6 +454,108 @@ Relobj::output_section(unsigned int shndx, off_t* poff)
return mo.output_section;
}
// This POD class is holds the value of a symbol. This is used for
// local symbols, and for all symbols during relocation processing.
// In order to process relocs we need to be able to handle SHF_MERGE
// sections correctly.
template<int size>
class Symbol_value
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
Symbol_value()
: output_symtab_index_(0), input_shndx_(0), needs_output_address_(false),
value_(0)
{ }
// Get the value of this symbol. OBJECT is the object in which this
// symbol is defined, and ADDEND is an addend to add to the value.
template<bool big_endian>
Value
value(const Sized_relobj<size, big_endian>* object, Value addend) const
{
if (!this->needs_output_address_)
return this->value_ + addend;
return object->local_value(this->input_shndx_, this->value_, addend);
}
// Set the value of this symbol in the output symbol table.
void
set_output_value(Value value)
{
this->value_ = value;
this->needs_output_address_ = false;
}
// If this symbol is mapped to an output section which requires
// special handling to determine the output value, we store the
// value of the symbol in the input file. This is used for
// SHF_MERGE sections.
void
set_input_value(Value value)
{
this->value_ = value;
this->needs_output_address_ = true;
}
// Return whether this symbol should go into the output symbol
// table.
bool
needs_output_symtab_entry() const
{
gold_assert(this->output_symtab_index_ != 0);
return this->output_symtab_index_ != -1U;
}
// Return the index in the output symbol table.
unsigned int
output_symtab_index() const
{
gold_assert(this->output_symtab_index_ != 0);
return this->output_symtab_index_;
}
// Set the index in the output symbol table.
void
set_output_symtab_index(unsigned int i)
{
gold_assert(this->output_symtab_index_ == 0);
this->output_symtab_index_ = i;
}
// Record that this symbol should not go into the output symbol
// table.
void
set_no_output_symtab_entry()
{
gold_assert(this->output_symtab_index_ == 0);
this->output_symtab_index_ = -1U;
}
// Set the index of the input section in the input file.
void
set_input_shndx(unsigned int i)
{ this->input_shndx_ = i; }
private:
// The index of this local symbol in the output symbol table. This
// will be -1 if the symbol should not go into the symbol table.
unsigned int output_symtab_index_;
// The section index in the input file in which this symbol is
// defined.
unsigned int input_shndx_ : 31;
// Whether getting the value of this symbol requires calling an
// Output_section method. For example, this will be true of a
// STT_SECTION symbol in a SHF_MERGE section.
bool needs_output_address_ : 1;
// The value of the symbol. If !needs_output_address_, this is the
// value in the output file. If needs_output_address_, this is the
// value in the input file.
Value value_;
};
// A regular object file. This is size and endian specific.
template<int size, bool big_endian>
@ -452,7 +563,7 @@ class Sized_relobj : public Relobj
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef std::vector<Address> Local_values;
typedef std::vector<Symbol_value<size> > Local_values;
Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>&);
@ -468,9 +579,8 @@ class Sized_relobj : public Relobj
unsigned int
symtab_index(unsigned int sym) const
{
gold_assert(sym < this->local_indexes_.size());
gold_assert(this->local_indexes_[sym] != 0);
return this->local_indexes_[sym];
gold_assert(sym < this->local_values_.size());
return this->local_values_[sym].output_symtab_index();
}
// Read the symbols.
@ -497,7 +607,8 @@ class Sized_relobj : public Relobj
// Finalize the local symbols.
unsigned int
do_finalize_local_symbols(unsigned int, off_t, Stringpool*);
do_finalize_local_symbols(unsigned int, off_t,
Stringpool_template<char>*);
// Relocate the input sections and write out the local symbols.
void
@ -528,6 +639,12 @@ class Sized_relobj : public Relobj
SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
}
// Return the value of a local symbol define in input section SHNDX,
// with value VALUE, adding addend ADDEND. This handles SHF_MERGE
// sections.
Address
local_value(unsigned int shndx, Address value, Address addend) const;
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;
@ -574,7 +691,8 @@ class Sized_relobj : public Relobj
// Write out the local symbols.
void
write_local_symbols(Output_file*, const Stringpool*);
write_local_symbols(Output_file*,
const Stringpool_template<char>*);
// General access to the ELF file.
elfcpp::Elf_file<size, big_endian, Object> elf_file_;
@ -590,8 +708,6 @@ class Sized_relobj : public Relobj
off_t local_symbol_offset_;
// Values of local symbols.
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.

View File

@ -12,6 +12,7 @@
#include "object.h"
#include "symtab.h"
#include "reloc.h"
#include "merge.h"
#include "output.h"
namespace gold
@ -790,9 +791,9 @@ off_t
Output_section::Input_section::data_size() const
{
if (this->is_input_section())
return this->data_size_;
return this->u1_.data_size;
else
return this->u_.posd->data_size();
return this->u2_.posd->data_size();
}
// Set the address and file offset.
@ -802,9 +803,33 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off,
off_t secoff)
{
if (this->is_input_section())
this->u_.object->set_section_offset(this->shndx_, off - secoff);
this->u2_.object->set_section_offset(this->shndx_, off - secoff);
else
this->u_.posd->set_address(addr, off);
this->u2_.posd->set_address(addr, off);
}
// Try to turn an input address into an output address.
bool
Output_section::Input_section::output_address(const Relobj* object,
unsigned int shndx,
off_t offset,
uint64_t output_section_address,
uint64_t *poutput) const
{
if (!this->is_input_section())
return this->u2_.posd->output_address(object, shndx, offset,
output_section_address, poutput);
else
{
if (this->u2_.object != object)
return false;
off_t output_offset;
Output_section* os = object->output_section(shndx, &output_offset);
gold_assert(os != NULL);
*poutput = output_section_address + output_offset + offset;
return true;
}
}
// Write out the data. We don't have to do anything for an input
@ -815,7 +840,7 @@ void
Output_section::Input_section::write(Output_file* of)
{
if (!this->is_input_section())
this->u_.posd->write(of);
this->u2_.posd->write(of);
}
// Output_section methods.
@ -823,7 +848,7 @@ Output_section::Input_section::write(Output_file* of)
// Construct an Output_section. NAME will point into a Stringpool.
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags, bool may_add_data)
elfcpp::Elf_Xword flags)
: name_(name),
addralign_(0),
entsize_(0),
@ -838,7 +863,6 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
dynsym_index_(0),
input_sections_(),
first_input_offset_(0),
may_add_data_(may_add_data),
needs_symtab_index_(false),
needs_dynsym_index_(false),
should_link_to_symtab_(false),
@ -873,8 +897,6 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr)
{
gold_assert(this->may_add_data_);
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
{
@ -887,6 +909,20 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
if (addralign > this->addralign_)
this->addralign_ = addralign;
// If this is a SHF_MERGE section, we pass all the input sections to
// a Output_data_merge.
if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0)
{
if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(),
shdr.get_sh_entsize(),
addralign))
{
// Tell the relocation routines that they need to call the
// output_address method to determine the final address.
return -1;
}
}
off_t ssize = this->data_size();
ssize = align_address(ssize, addralign);
this->set_data_size(ssize + shdr.get_sh_size());
@ -907,18 +943,107 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
void
Output_section::add_output_section_data(Output_section_data* posd)
{
gold_assert(this->may_add_data_);
Input_section inp(posd);
this->add_output_section_data(&inp);
}
// Add arbitrary data to an output section by Input_section.
void
Output_section::add_output_section_data(Input_section* inp)
{
if (this->input_sections_.empty())
this->first_input_offset_ = this->data_size();
this->input_sections_.push_back(Input_section(posd));
this->input_sections_.push_back(*inp);
uint64_t addralign = posd->addralign();
uint64_t addralign = inp->addralign();
if (addralign > this->addralign_)
this->addralign_ = addralign;
posd->set_output_section(this);
inp->set_output_section(this);
}
// Add a merge section to an output section.
void
Output_section::add_output_merge_section(Output_section_data* posd,
bool is_string, uint64_t entsize)
{
Input_section inp(posd, is_string, entsize);
this->add_output_section_data(&inp);
}
// Add an input section to a SHF_MERGE section.
bool
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
uint64_t flags, uint64_t entsize,
uint64_t addralign)
{
// We only merge constants if the alignment is not more than the
// entry size. This could be handled, but it's unusual.
if (addralign > entsize)
return false;
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
Input_section_list::iterator p;
for (p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
if (p->is_merge_section(is_string, entsize))
break;
// We handle the actual constant merging in Output_merge_data or
// Output_merge_string_data.
if (p != this->input_sections_.end())
p->add_input_section(object, shndx);
else
{
Output_section_data* posd;
if (!is_string)
posd = new Output_merge_data(entsize);
else if (entsize == 1)
posd = new Output_merge_string<char>();
else if (entsize == 2)
posd = new Output_merge_string<uint16_t>();
else if (entsize == 4)
posd = new Output_merge_string<uint32_t>();
else
return false;
this->add_output_merge_section(posd, is_string, entsize);
posd->add_input_section(object, shndx);
}
return true;
}
// Return the output virtual address of OFFSET relative to the start
// of input section SHNDX in object OBJECT.
uint64_t
Output_section::output_address(const Relobj* object, unsigned int shndx,
off_t offset) const
{
uint64_t addr = this->address() + this->first_input_offset_;
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
addr = align_address(addr, p->addralign());
uint64_t output;
if (p->output_address(object, shndx, offset, addr, &output))
return output;
addr += p->data_size();
}
// If we get here, it means that we don't know the mapping for this
// input section. This might happen in principle if
// add_input_section were called before add_output_section_data.
// But it should never actually happen.
gold_unreachable();
}
// Set the address of an Output_section. This is where we handle
@ -1189,7 +1314,8 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
return ret;
}
// Set the addresses in a list of Output_data structures.
// Set the addresses and file offsets in a list of Output_data
// structures.
uint64_t
Output_segment::set_section_list_addresses(Output_data_list* pdl,
@ -1541,3 +1667,4 @@ template
class Output_data_got<64, true>;
} // End namespace gold.

View File

@ -314,6 +314,26 @@ class Output_section_data : public Output_data
void
set_output_section(Output_section* os);
// Add an input section, for SHF_MERGE sections. This returns true
// if the section was handled.
bool
add_input_section(Relobj* object, unsigned int shndx)
{ return this->do_add_input_section(object, shndx); }
// Given an input OBJECT, an input section index SHNDX within that
// object, and an OFFSET relative to the start of that input
// section, return whether or not the output address is known.
// OUTPUT_SECTION_ADDRESS is the address of the output section which
// this is a part of. If this function returns true, it sets
// *POUTPUT to the output address.
virtual bool
output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t *poutput) const
{
return this->do_output_address(object, shndx, offset,
output_section_address, poutput);
}
protected:
// The child class must implement do_write.
@ -323,6 +343,18 @@ class Output_section_data : public Output_data
do_adjust_output_section(Output_section*)
{ }
// May be implemented by child class. Return true if the section
// was handled.
virtual bool
do_add_input_section(Relobj*, unsigned int)
{ gold_unreachable(); }
// The child class may implement output_address.
virtual bool
do_output_address(const Relobj*, unsigned int, off_t, uint64_t,
uint64_t*) const
{ return false; }
// Return the required alignment.
uint64_t
do_addralign() const
@ -1114,8 +1146,7 @@ class Output_section : public Output_data
{
public:
// Create an output section, giving the name, type, and flags.
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
bool may_add_data);
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
virtual ~Output_section();
// Add a new input section SHNDX, named NAME, with header SHDR, from
@ -1125,7 +1156,7 @@ class Output_section : public Output_data
add_input_section(Relobj* object, unsigned int shndx, const char *name,
const elfcpp::Shdr<size, big_endian>& shdr);
// Add generated data ODATA to this output section.
// Add generated data POSD to this output section.
void
add_output_section_data(Output_section_data* posd);
@ -1284,6 +1315,12 @@ class Output_section : public Output_data
this->dynsym_index_ = index;
}
// Return the output virtual address of OFFSET relative to the start
// of input section SHNDX in object OBJECT.
uint64_t
output_address(const Relobj* object, unsigned int shndx,
off_t offset) const;
// 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
@ -1339,24 +1376,44 @@ class Output_section : public Output_data
{
public:
Input_section()
: shndx_(0), p2align_(0), data_size_(0)
{ this->u_.object = NULL; }
: shndx_(0), p2align_(0)
{
this->u1_.data_size = 0;
this->u2_.object = NULL;
}
// For an ordinary input section.
Input_section(Relobj* object, unsigned int shndx, off_t data_size,
uint64_t addralign)
: shndx_(shndx),
p2align_(ffsll(static_cast<long long>(addralign))),
data_size_(data_size)
p2align_(ffsll(static_cast<long long>(addralign)))
{
gold_assert(shndx != -1U);
this->u_.object = object;
gold_assert(shndx != OUTPUT_SECTION_CODE
&& shndx != MERGE_DATA_SECTION_CODE
&& shndx != MERGE_STRING_SECTION_CODE);
this->u1_.data_size = data_size;
this->u2_.object = object;
}
// For a non-merge output section.
Input_section(Output_section_data* posd)
: shndx_(-1U),
p2align_(ffsll(static_cast<long long>(posd->addralign()))),
data_size_(0)
{ this->u_.posd = posd; }
: shndx_(OUTPUT_SECTION_CODE),
p2align_(ffsll(static_cast<long long>(posd->addralign())))
{
this->u1_.data_size = 0;
this->u2_.posd = posd;
}
// For a merge section.
Input_section(Output_section_data* posd, bool is_string, uint64_t entsize)
: shndx_(is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE),
p2align_(ffsll(static_cast<long long>(posd->addralign())))
{
this->u1_.entsize = entsize;
this->u2_.posd = posd;
}
// The required alignment.
uint64_t
@ -1371,41 +1428,125 @@ class Output_section : public Output_data
off_t
data_size() const;
// Return whether this is a merge section which matches the
// parameters.
bool
is_merge_section(bool is_string, uint64_t entsize) const
{
return (this->shndx_ == (is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE)
&& this->u1_.entsize == entsize);
}
// Set the output section.
void
set_output_section(Output_section* os)
{
gold_assert(!this->is_input_section());
this->u2_.posd->set_output_section(os);
}
// Set the address and file offset. This is called during
// Layout::finalize. SECOFF is the file offset of the enclosing
// section.
void
set_address(uint64_t addr, off_t off, off_t secoff);
// Add an input section, for SHF_MERGE sections.
bool
add_input_section(Relobj* object, unsigned int shndx)
{
gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
|| this->shndx_ == MERGE_STRING_SECTION_CODE);
return this->u2_.posd->add_input_section(object, shndx);
}
// Given an input OBJECT, an input section index SHNDX within that
// object, and an OFFSET relative to the start of that input
// section, return whether or not the output address is known.
// OUTPUT_SECTION_ADDRESS is the address of the output section
// which this is a part of. If this function returns true, it
// sets *POUTPUT to the output address.
bool
output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t *poutput) const;
// Write out the data. This does nothing for an input section.
void
write(Output_file*);
private:
// Code values which appear in shndx_. If the value is not one of
// these codes, it is the input section index in the object file.
enum
{
// An Output_section_data.
OUTPUT_SECTION_CODE = -1U,
// An Output_section_data for an SHF_MERGE section with
// SHF_STRINGS not set.
MERGE_DATA_SECTION_CODE = -2U,
// An Output_section_data for an SHF_MERGE section with
// SHF_STRINGS set.
MERGE_STRING_SECTION_CODE = -3U
};
// Whether this is an input section.
bool
is_input_section() const
{ return this->shndx_ != -1U; }
{
return (this->shndx_ != OUTPUT_SECTION_CODE
&& this->shndx_ != MERGE_DATA_SECTION_CODE
&& this->shndx_ != MERGE_STRING_SECTION_CODE);
}
// For an ordinary input section, this is the section index in
// the input file. For an Output_section_data, this is -1U.
// For an ordinary input section, this is the section index in the
// input file. For an Output_section_data, this is
// OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
// MERGE_STRING_SECTION_CODE.
unsigned int shndx_;
// The required alignment, stored as a power of 2.
unsigned int p2align_;
// For an ordinary input section, the section size.
off_t data_size_;
union
{
// If shndx_ != -1U, this points to the object which holds the
// For an ordinary input section, the section size.
off_t data_size;
// For OUTPUT_SECTION_CODE, this is not used. For
// MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
// entity size.
uint64_t entsize;
} u1_;
union
{
// For an ordinary input section, the object which holds the
// input section.
Relobj* object;
// If shndx_ == -1U, this is the data to write out.
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
// MERGE_STRING_SECTION_CODE, the data.
Output_section_data* posd;
} u_;
} u2_;
};
typedef std::vector<Input_section> Input_section_list;
// Add a new output section by Input_section.
void
add_output_section_data(Input_section*);
// Add an SHF_MERGE input section. Returns true if the section was
// handled.
bool
add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
uint64_t entsize, uint64_t addralign);
// Add an output SHF_MERGE section POSD to this output section.
// IS_STRING indicates whether it is a SHF_STRINGS section, and
// ENTSIZE is the entity size. This returns the entry added to
// input_sections_.
void
add_output_merge_section(Output_section_data* posd, bool is_string,
uint64_t entsize);
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
@ -1445,8 +1586,6 @@ class Output_section : public Output_data
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_ : 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.

View File

@ -17,6 +17,8 @@ gold-threads.h
i386.cc
layout.cc
layout.h
merge.cc
merge.h
object.cc
object.h
options.cc

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-12-05 17:51-0800\n"
"POT-Creation-Date: 2007-05-16 10: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"
@ -101,7 +101,7 @@ msgstr ""
msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
msgstr ""
#: dynobj.cc:368 object.cc:421
#: dynobj.cc:368 object.cc:420
#, c-format
msgid "%s: %s: bad section name offset for section %u: %lu\n"
msgstr ""
@ -255,7 +255,7 @@ msgstr ""
msgid "%s: missing expected TLS relocation\n"
msgstr ""
#: i386.cc:729 i386.cc:870 i386.cc:1125
#: i386.cc:729 i386.cc:870 i386.cc:1136
#, c-format
msgid "%s: %s: unexpected reloc %u in object file\n"
msgstr ""
@ -280,31 +280,42 @@ msgstr ""
msgid "%s: %s: missing expected TLS relocation\n"
msgstr ""
#: i386.cc:1157 i386.cc:1232 i386.cc:1243
#: i386.cc:1168 i386.cc:1245 i386.cc:1256
#, c-format
msgid "%s: %s: unsupported reloc %u\n"
msgstr ""
#: i386.cc:1184
#: i386.cc:1195
#, c-format
msgid "%s: %s: TLS reloc but no TLS segment\n"
msgstr ""
#: i386.cc:1217
#: i386.cc:1230
#, c-format
msgid "%s: %s: unsupported reloc type %u\n"
msgstr ""
#: i386.cc:1426
#: i386.cc:1439
#, c-format
msgid "%s: %s: TLS relocation out of range\n"
msgstr ""
#: i386.cc:1444
#: i386.cc:1457
#, c-format
msgid "%s: %s: TLS relocation against invalid instruction\n"
msgstr ""
#: merge.cc:252
#, c-format
msgid ""
"%s: %s: mergeable string section length not multiple of character size\n"
msgstr ""
#: merge.cc:269
#, c-format
msgid "%s: %s: entry in mergeable string section not null terminated\n"
msgstr ""
#: object.cc:30
#, c-format
msgid "%s: %s: unsupported ELF machine number %d\n"
@ -315,32 +326,32 @@ msgstr ""
msgid "%s: %s: section name section has wrong type: %u\n"
msgstr ""
#: object.cc:229
#: object.cc:228
#, c-format
msgid "%s: %s: invalid symbol table name index: %u\n"
msgstr ""
#: object.cc:237
#: object.cc:236
#, c-format
msgid "%s: %s: symbol table name section has wrong type: %u\n"
msgstr ""
#: object.cc:293
#: object.cc:292
#, c-format
msgid "%s: %s: section group %u info %u out of range\n"
msgstr ""
#: object.cc:310
#: object.cc:309
#, c-format
msgid "%s: %s: symbol %u name offset %u out of range\n"
msgstr ""
#: object.cc:344
#: object.cc:343
#, c-format
msgid "%s: %s: section %u in section group %u out of range"
msgstr ""
#: object.cc:488
#: object.cc:487
#, c-format
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
msgstr ""
@ -355,47 +366,47 @@ msgstr ""
msgid "%s: %s: local symbol %u section index %u out of range\n"
msgstr ""
#: object.cc:615
#: object.cc:620
#, c-format
msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
msgstr ""
#: object.cc:815
#: object.cc:834
#, c-format
msgid "%s: %s: unsupported ELF file type %d\n"
msgstr ""
#: object.cc:834 object.cc:887 object.cc:908
#: object.cc:853 object.cc:906 object.cc:927
#, c-format
msgid "%s: %s: ELF file too short\n"
msgstr ""
#: object.cc:843
#: object.cc:862
#, c-format
msgid "%s: %s: invalid ELF version 0\n"
msgstr ""
#: object.cc:846
#: object.cc:865
#, c-format
msgid "%s: %s: unsupported ELF version %d\n"
msgstr ""
#: object.cc:854
#: object.cc:873
#, c-format
msgid "%s: %s: invalid ELF class 0\n"
msgstr ""
#: object.cc:861
#: object.cc:880
#, c-format
msgid "%s: %s: unsupported ELF class %d\n"
msgstr ""
#: object.cc:869
#: object.cc:888
#, c-format
msgid "%s: %s: invalid ELF data encoding\n"
msgstr ""
#: object.cc:876
#: object.cc:895
#, c-format
msgid "%s: %s: unsupported ELF data encoding %d\n"
msgstr ""
@ -511,37 +522,37 @@ msgstr ""
msgid "%s: -%c: %s\n"
msgstr ""
#: output.cc:881
#: output.cc:903
#, c-format
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
msgstr ""
#: output.cc:1393
#: output.cc:1519
#, c-format
msgid "%s: %s: open: %s\n"
msgstr ""
#: output.cc:1402
#: output.cc:1528
#, c-format
msgid "%s: %s: lseek: %s\n"
msgstr ""
#: output.cc:1409
#: output.cc:1535
#, c-format
msgid "%s: %s: write: %s\n"
msgstr ""
#: output.cc:1419
#: output.cc:1545
#, c-format
msgid "%s: %s: mmap: %s\n"
msgstr ""
#: output.cc:1433
#: output.cc:1559
#, c-format
msgid "%s: %s: munmap: %s\n"
msgstr ""
#: output.cc:1441
#: output.cc:1567
#, c-format
msgid "%s: %s: close: %s\n"
msgstr ""
@ -562,22 +573,22 @@ msgstr ""
msgid "%s: %s: not an object or archive\n"
msgstr ""
#: reloc.cc:169 reloc.cc:410
#: reloc.cc:169 reloc.cc:413
#, c-format
msgid "%s: %s: relocation section %u has bad info %u\n"
msgstr ""
#: reloc.cc:188 reloc.cc:427
#: reloc.cc:188 reloc.cc:430
#, c-format
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
msgstr ""
#: reloc.cc:204 reloc.cc:446
#: reloc.cc:204 reloc.cc:449
#, c-format
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
msgstr ""
#: reloc.cc:215 reloc.cc:457
#: reloc.cc:215 reloc.cc:460
#, c-format
msgid "%s: %s: reloc section %u size %lu uneven"
msgstr ""
@ -632,12 +643,12 @@ msgstr ""
msgid "%s: %s: warning: %s\n"
msgstr ""
#: target-reloc.h:164
#: target-reloc.h:170
#, c-format
msgid "%s: %s: reloc has bad offset %zu\n"
msgstr ""
#: target-reloc.h:174
#: target-reloc.h:180
#, c-format
msgid "%s: %s: undefined reference to '%s'\n"
msgstr ""

View File

@ -343,6 +343,9 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
pvs->view = NULL;
if (map_sections[i].offset == -1)
continue;
const Output_section* os = map_sections[i].output_section;
if (os == NULL)
continue;

View File

@ -13,13 +13,18 @@ namespace gold
class General_options;
class Relobj;
class Read_relocs_data;
class Stringpool;
class Symbol;
class Layout;
template<int size>
class Sized_symbol;
template<int size, bool big_endian>
class Sized_relobj;
template<int size>
class Symbol_value;
template<int sh_type, bool dynamic, int size, bool big_endian>
class Output_data_reloc;
@ -151,6 +156,22 @@ private:
elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value);
}
// Do a simple relocation using a Symbol_value with the addend in
// the section contents. VALSIZE is the size of the value to
// relocate.
template<int valsize>
static inline void
rel(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
x = psymval->value(object, x);
elfcpp::Swap<valsize, big_endian>::writeval(wv, x);
}
// Do a simple PC relative relocation with the addend in the section
// contents. VALSIZE is the size of the value.
template<int valsize>
@ -165,76 +186,129 @@ private:
elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value - address);
}
// Do a simple PC relative relocation with a Symbol_value with the
// addend in the section contents. VALSIZE is the size of the
// value.
template<int valsize>
static inline void
pcrel(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
x = psymval->value(object, x);
elfcpp::Swap<valsize, big_endian>::writeval(wv, x - address);
}
typedef Relocate_functions<size, big_endian> This;
public:
// Do a simple 8-bit REL relocation with the addend in the object
// file data.
// Do a simple 8-bit REL relocation with the addend in the section
// contents.
static inline void
rel8(unsigned char* view, unsigned char value)
{
This::template rel<8>(view, value);
}
{ This::template rel<8>(view, value); }
static inline void
rel8(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<8>(view, object, psymval); }
// Do a simple 8-bit PC relative relocation with the addend in the
// object file data.
// section contents.
static inline void
pcrel8(unsigned char* view, unsigned char value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<8>(view, value, address);
}
{ This::template pcrel<8>(view, value, address); }
// Do a simple 16-bit REL relocation with the addend in the object
// file data.
static inline void
pcrel8(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{ This::template pcrel<8>(view, object, psymval, address); }
// Do a simple 16-bit REL relocation with the addend in the section
// contents.
static inline void
rel16(unsigned char* view, elfcpp::Elf_Half value)
{
This::template rel<16>(view, value);
}
{ This::template rel<16>(view, value); }
static inline void
rel16(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<16>(view, object, psymval); }
// Do a simple 32-bit PC relative REL relocation with the addend in
// the object file data.
// the section contents.
static inline void
pcrel16(unsigned char* view, elfcpp::Elf_Word value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<16>(view, value, address);
}
{ This::template pcrel<16>(view, value, address); }
static inline void
pcrel16(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{ This::template pcrel<16>(view, object, psymval, address); }
// Do a simple 32-bit REL relocation with the addend in the section
// contents.
static inline void
rel32(unsigned char* view, elfcpp::Elf_Word value)
{
This::template rel<32>(view, value);
}
{ This::template rel<32>(view, value); }
static inline void
rel32(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<32>(view, object, psymval); }
// Do a simple 32-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel32(unsigned char* view, elfcpp::Elf_Word value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<32>(view, value, address);
}
{ This::template pcrel<32>(view, value, address); }
static inline void
pcrel32(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{ This::template pcrel<32>(view, object, psymval, address); }
// Do a simple 64-bit REL relocation with the addend in the section
// contents.
static inline void
rel64(unsigned char* view, elfcpp::Elf_Xword value)
{
This::template rel<64>(view, value);
}
{ This::template rel<64>(view, value); }
static inline void
rel64(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<64>(view, object, psymval); }
// Do a simple 64-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel64(unsigned char* view, elfcpp::Elf_Xword value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<64>(view, value, address);
}
{ This::template pcrel<64>(view, value, address); }
static inline void
pcrel64(unsigned char* view,
const Sized_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{ This::template pcrel<64>(view, object, psymval, address); }
};
// We try to avoid COPY relocations when possible. A COPY relocation

View File

@ -12,42 +12,103 @@
namespace gold
{
Stringpool::Stringpool()
: string_set_(), strings_(), strtab_size_(0), next_index_(1)
template<typename Stringpool_char>
Stringpool_template<Stringpool_char>::Stringpool_template(bool zero_null)
: string_set_(), strings_(), strtab_size_(0), next_index_(1),
zero_null_(zero_null)
{
}
Stringpool::~Stringpool()
template<typename Stringpool_char>
Stringpool_template<Stringpool_char>::~Stringpool_template()
{
for (std::list<Stringdata*>::iterator p = this->strings_.begin();
for (typename std::list<Stringdata*>::iterator p = this->strings_.begin();
p != this->strings_.end();
++p)
delete[] reinterpret_cast<char*>(*p);
}
// Return the length of a string of arbitrary character type.
template<typename Stringpool_char>
size_t
Stringpool_template<Stringpool_char>::string_length(const Stringpool_char* p)
{
size_t len = 0;
for (; *p != 0; ++p)
++len;
return len;
}
// Specialize string_length for char. Maybe we could just use
// std::char_traits<>::length?
template<>
inline size_t
Stringpool_template<char>::string_length(const char* p)
{
return strlen(p);
}
// Equality comparison function.
template<typename Stringpool_char>
bool
Stringpool_template<Stringpool_char>::Stringpool_eq::operator()(
const Stringpool_char* s1,
const Stringpool_char* s2) const
{
while (*s1 != 0)
if (*s1++ != *s2++)
return false;
return *s2 == 0;
}
// Specialize equality comparison for char.
template<>
bool
Stringpool_template<char>::Stringpool_eq::operator()(const char* s1,
const char* s2) const
{
return strcmp(s1, s2) == 0;
}
// Hash function.
template<typename Stringpool_char>
size_t
Stringpool::Stringpool_hash::operator()(const char* s) const
Stringpool_template<Stringpool_char>::Stringpool_hash::operator()(
const Stringpool_char* s) const
{
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
if (sizeof(size_t) == 8)
{
size_t result = static_cast<size_t>(14695981039346656037ULL);
while (*s != '\0')
while (*s != 0)
{
result &= (size_t) *s++;
result *= 1099511628211ULL;
const char* p = reinterpret_cast<const char*>(s);
for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
{
result &= (size_t) *p++;
result *= 1099511628211ULL;
}
++s;
}
return result;
}
else
{
size_t result = 2166136261UL;
while (*s != '\0')
while (*s != 0)
{
result ^= (size_t) *s++;
result *= 16777619UL;
const char* p = reinterpret_cast<const char*>(s);
for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
{
result ^= (size_t) *p++;
result *= 16777619UL;
}
++s;
}
return result;
}
@ -56,8 +117,10 @@ Stringpool::Stringpool_hash::operator()(const char* s) const
// Add a string to the list of canonical strings. Return a pointer to
// the canonical string. If PKEY is not NULL, set *PKEY to the key.
const char*
Stringpool::add_string(const char* s, Key* pkey)
template<typename Stringpool_char>
const Stringpool_char*
Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s,
Key* pkey)
{
// We are in trouble if we've already computed the string offsets.
gold_assert(this->strtab_size_ == 0);
@ -69,11 +132,11 @@ Stringpool::add_string(const char* s, Key* pkey)
const size_t key_mult = 1024;
gold_assert(key_mult >= buffer_size);
size_t len = strlen(s);
size_t len = (string_length(s) + 1) * sizeof(Stringpool_char);
size_t alc;
bool front = true;
if (len >= buffer_size)
if (len > buffer_size)
{
alc = sizeof(Stringdata) + len;
front = false;
@ -83,26 +146,26 @@ Stringpool::add_string(const char* s, Key* pkey)
else
{
Stringdata *psd = this->strings_.front();
if (len >= psd->alc - psd->len)
if (len > psd->alc - psd->len)
alc = sizeof(Stringdata) + buffer_size;
else
{
char* ret = psd->data + psd->len;
memcpy(ret, s, len + 1);
memcpy(ret, s, len);
if (pkey != NULL)
*pkey = psd->index * key_mult + psd->len;
psd->len += len + 1;
psd->len += len;
return ret;
return reinterpret_cast<const Stringpool_char*>(ret);
}
}
Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
psd->alc = alc - sizeof(Stringdata);
memcpy(psd->data, s, len + 1);
psd->len = len + 1;
memcpy(psd->data, s, len);
psd->len = len;
psd->index = this->next_index_;
++this->next_index_;
@ -114,13 +177,14 @@ Stringpool::add_string(const char* s, Key* pkey)
else
this->strings_.push_back(psd);
return psd->data;
return reinterpret_cast<const Stringpool_char*>(psd->data);
}
// Add a string to a string pool.
const char*
Stringpool::add(const char* s, Key* pkey)
template<typename Stringpool_char>
const Stringpool_char*
Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, Key* pkey)
{
// FIXME: This will look up the entry twice in the hash table. The
// problem is that we can't insert S before we canonicalize it. I
@ -128,7 +192,7 @@ Stringpool::add(const char* s, Key* pkey)
// unordered_map, so this should be replaced with custom code to do
// what we need, which is to return the empty slot.
String_set_type::const_iterator p = this->string_set_.find(s);
typename String_set_type::const_iterator p = this->string_set_.find(s);
if (p != this->string_set_.end())
{
if (pkey != NULL)
@ -137,11 +201,12 @@ Stringpool::add(const char* s, Key* pkey)
}
Key k;
const char* ret = this->add_string(s, &k);
const Stringpool_char* ret = this->add_string(s, &k);
const off_t ozero = 0;
std::pair<const char*, Val> element(ret, std::make_pair(k, ozero));
std::pair<String_set_type::iterator, bool> ins =
std::pair<const Stringpool_char*, Val> element(ret,
std::make_pair(k, ozero));
std::pair<typename String_set_type::iterator, bool> ins =
this->string_set_.insert(element);
gold_assert(ins.second);
@ -153,19 +218,23 @@ Stringpool::add(const char* s, Key* pkey)
// Add a prefix of a string to a string pool.
const char*
Stringpool::add(const char* s, size_t len, Key* pkey)
template<typename Stringpool_char>
const Stringpool_char*
Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, size_t len,
Key* pkey)
{
// FIXME: This implementation should be rewritten when we rewrite
// the hash table to avoid copying.
std::string st(s, len);
std::basic_string<Stringpool_char> st(s, len);
return this->add(st, pkey);
}
const char*
Stringpool::find(const char* s, Key* pkey) const
template<typename Stringpool_char>
const Stringpool_char*
Stringpool_template<Stringpool_char>::find(const Stringpool_char* s,
Key* pkey) const
{
String_set_type::const_iterator p = this->string_set_.find(s);
typename String_set_type::const_iterator p = this->string_set_.find(s);
if (p == this->string_set_.end())
return NULL;
@ -186,19 +255,20 @@ Stringpool::find(const char* s, Key* pkey) const
// in, but we need to ensure that suffixes wind up next to each other.
// So we do a reversed lexicographic sort on the reversed string.
template<typename Stringpool_char>
bool
Stringpool::Stringpool_sort_comparison::operator()(
String_set_type::iterator it1,
String_set_type::iterator it2) const
Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()(
typename String_set_type::iterator it1,
typename String_set_type::iterator it2) const
{
const char* s1 = it1->first;
const char* s2 = it2->first;
int len1 = strlen(s1);
int len2 = strlen(s2);
int minlen = len1 < len2 ? len1 : len2;
const char* p1 = s1 + len1 - 1;
const char* p2 = s2 + len2 - 1;
for (int i = minlen - 1; i >= 0; --i, --p1, --p2)
const Stringpool_char* s1 = it1->first;
const Stringpool_char* s2 = it2->first;
size_t len1 = string_length(s1);
size_t len2 = string_length(s2);
size_t minlen = len1 < len2 ? len1 : len2;
const Stringpool_char* p1 = s1 + len1 - 1;
const Stringpool_char* p2 = s2 + len2 - 1;
for (size_t i = minlen; i > 0; --i, --p1, --p2)
{
if (*p1 != *p2)
return *p1 > *p2;
@ -208,21 +278,24 @@ Stringpool::Stringpool_sort_comparison::operator()(
// Return whether s1 is a suffix of s2.
template<typename Stringpool_char>
bool
Stringpool::is_suffix(const char* s1, const char* s2)
Stringpool_template<Stringpool_char>::is_suffix(const Stringpool_char* s1,
const Stringpool_char* s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
size_t len1 = string_length(s1);
size_t len2 = string_length(s2);
if (len1 > len2)
return false;
return strcmp(s1, s2 + len2 - len1) == 0;
return memcmp(s1, s2 + len2 - len1, len1 * sizeof(Stringpool_char)) == 0;
}
// Turn the stringpool into an ELF strtab: determine the offsets of
// each string in the table.
template<typename Stringpool_char>
void
Stringpool::set_string_offsets()
Stringpool_template<Stringpool_char>::set_string_offsets()
{
if (this->strtab_size_ != 0)
{
@ -232,30 +305,33 @@ Stringpool::set_string_offsets()
size_t count = this->string_set_.size();
std::vector<String_set_type::iterator> v;
std::vector<typename String_set_type::iterator> v;
v.reserve(count);
for (String_set_type::iterator p = this->string_set_.begin();
for (typename String_set_type::iterator p = this->string_set_.begin();
p != this->string_set_.end();
++p)
v.push_back(p);
std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
// Offset 0 is reserved for the empty string.
off_t offset = 1;
const size_t charsize = sizeof(Stringpool_char);
// Offset 0 may be reserved for the empty string.
off_t offset = this->zero_null_ ? charsize : 0;
for (size_t i = 0; i < count; ++i)
{
if (v[i]->first[0] == '\0')
if (this->zero_null_ && v[i]->first[0] == 0)
v[i]->second.second = 0;
else if (i > 0 && Stringpool::is_suffix(v[i]->first, v[i - 1]->first))
else if (i > 0 && is_suffix(v[i]->first, v[i - 1]->first))
v[i]->second.second = (v[i - 1]->second.second
+ strlen(v[i - 1]->first)
- strlen(v[i]->first));
+ ((string_length(v[i - 1]->first)
- string_length(v[i]->first))
* charsize));
else
{
v[i]->second.second = offset;
offset += strlen(v[i]->first) + 1;
offset += (string_length(v[i]->first) + 1) * charsize;
}
}
@ -265,11 +341,13 @@ Stringpool::set_string_offsets()
// Get the offset of a string in the ELF strtab. The string must
// exist.
template<typename Stringpool_char>
off_t
Stringpool::get_offset(const char* s) const
Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s)
const
{
gold_assert(this->strtab_size_ != 0);
String_set_type::const_iterator p = this->string_set_.find(s);
typename String_set_type::const_iterator p = this->string_set_.find(s);
if (p != this->string_set_.end())
return p->second.second;
gold_unreachable();
@ -277,18 +355,32 @@ Stringpool::get_offset(const char* s) const
// Write the ELF strtab into the output file at the specified offset.
template<typename Stringpool_char>
void
Stringpool::write(Output_file* of, off_t offset)
Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset)
{
gold_assert(this->strtab_size_ != 0);
unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
char* view = reinterpret_cast<char*>(viewu);
view[0] = '\0';
for (String_set_type::const_iterator p = this->string_set_.begin();
if (this->zero_null_)
view[0] = '\0';
for (typename String_set_type::const_iterator p = this->string_set_.begin();
p != this->string_set_.end();
++p)
strcpy(view + p->second.second, p->first);
memcpy(view + p->second.second, p->first,
(string_length(p->first) + 1) * sizeof(Stringpool_char));
of->write_output_view(offset, this->strtab_size_, viewu);
}
// Instantiate the templates we need.
template
class Stringpool_template<char>;
template
class Stringpool_template<uint16_t>;
template
class Stringpool_template<uint32_t>;
} // End namespace gold.

View File

@ -14,7 +14,8 @@ namespace gold
class Output_file;
class Stringpool
template<typename Stringpool_char>
class Stringpool_template
{
public:
// The type of a key into the stringpool. A key value will always
@ -24,43 +25,47 @@ class Stringpool
// into an unordered hash table. Zero is never a valid key.
typedef size_t Key;
Stringpool();
// Create a Stringpool. ZERO_NULL is true if we should reserve
// offset 0 to hold the empty string.
Stringpool_template(bool zero_null = true);
~Stringpool();
~Stringpool_template();
// Add a string to the pool. This returns a canonical permanent
// pointer to the string. If PKEY is not NULL, this sets *PKEY to
// the key for the string.
const char*
add(const char*, Key* pkey);
const Stringpool_char*
add(const Stringpool_char*, Key* pkey);
const char*
add(const std::string& s, Key* pkey)
const Stringpool_char*
add(const std::basic_string<Stringpool_char>& s, Key* pkey)
{ return this->add(s.c_str(), pkey); }
// Add the prefix of a string to the pool.
const char*
add(const char *, size_t, Key* pkey);
const Stringpool_char*
add(const Stringpool_char*, size_t, Key* pkey);
// If a string is present, return the canonical string. Otherwise,
// return NULL. If PKEY is not NULL, set *PKEY to the key.
const char*
find(const char*, Key* pkey) const;
const Stringpool_char*
find(const Stringpool_char*, Key* pkey) const;
// Turn the stringpool into an ELF strtab: determine the offsets of
// all the strings.
void
set_string_offsets();
// Get the offset of a string in an ELF strtab.
// Get the offset of a string in an ELF strtab. This returns the
// offset in bytes, not characters.
off_t
get_offset(const char*) const;
get_offset(const Stringpool_char*) const;
off_t
get_offset(const std::string& s) const
get_offset(const std::basic_string<Stringpool_char>& s) const
{ return this->get_offset(s.c_str()); }
// Get the size of the ELF strtab.
// Get the size of the ELF strtab. This returns the number of
// bytes, not characters.
off_t
get_strtab_size() const
{
@ -73,8 +78,12 @@ class Stringpool
write(Output_file*, off_t offset);
private:
Stringpool(const Stringpool&);
Stringpool& operator=(const Stringpool&);
Stringpool_template(const Stringpool_template&);
Stringpool_template& operator=(const Stringpool_template&);
// Return the length of a string.
static size_t
string_length(const Stringpool_char*);
// We store the actual data in a list of these buffers.
struct Stringdata
@ -90,24 +99,24 @@ class Stringpool
};
// Copy a string into the buffers, returning a canonical string.
const char*
add_string(const char*, Key*);
const Stringpool_char*
add_string(const Stringpool_char*, Key*);
struct Stringpool_hash
{
size_t
operator()(const char*) const;
operator()(const Stringpool_char*) const;
};
struct Stringpool_eq
{
bool
operator()(const char* p1, const char* p2) const
{ return strcmp(p1, p2) == 0; }
operator()(const Stringpool_char* p1, const Stringpool_char* p2) const;
};
// Return whether s1 is a suffix of s2.
static bool is_suffix(const char* s1, const char* s2);
static bool
is_suffix(const Stringpool_char* s1, const Stringpool_char* s2);
// The hash table is a map from string names to a pair of Key and
// ELF strtab offsets. We only use the offsets if we turn this into
@ -116,12 +125,13 @@ class Stringpool
typedef std::pair<Key, off_t> Val;
#ifdef HAVE_TR1_UNORDERED_SET
typedef Unordered_map<const char*, Val, Stringpool_hash,
typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
Stringpool_eq,
std::allocator<std::pair<const char* const, Val> >,
std::allocator<std::pair<const Stringpool_char* const,
Val> >,
true> String_set_type;
#else
typedef Unordered_map<const char*, Val, Stringpool_hash,
typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
Stringpool_eq> String_set_type;
#endif
@ -130,8 +140,8 @@ class Stringpool
struct Stringpool_sort_comparison
{
bool
operator()(String_set_type::iterator,
String_set_type::iterator) const;
operator()(typename String_set_type::iterator,
typename String_set_type::iterator) const;
};
// List of Stringdata structures.
@ -145,8 +155,13 @@ class Stringpool
off_t strtab_size_;
// Next Stringdata index.
unsigned int next_index_;
// Whether to reserve offset 0 to hold the null string.
bool zero_null_;
};
// The most common type of Stringpool.
typedef Stringpool_template<char> Stringpool;
} // End namespace gold.
#endif // !defined(GOLD_STRINGPOOL_H)

View File

@ -137,12 +137,13 @@ relocate_section(
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
const Sized_symbol<size>* sym;
typename elfcpp::Elf_types<size>::Elf_Addr value;
Symbol_value<size> symval;
const Symbol_value<size> *psymval;
if (r_sym < local_count)
{
sym = NULL;
value = (*local_values)[r_sym];
psymval = &(*local_values)[r_sym];
}
else
{
@ -152,10 +153,15 @@ relocate_section(
gsym = relinfo->symtab->resolve_forwards(gsym);
sym = static_cast<const Sized_symbol<size>*>(gsym);
value = sym->value();
if (sym->has_symtab_index())
symval.set_output_symtab_index(sym->symtab_index());
else
symval.set_no_output_symtab_entry();
symval.set_output_value(sym->value());
psymval = &symval;
}
if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, value,
if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
view + offset, view_address + offset, view_size))
continue;