Add support for SHF_MERGE sections.
This commit is contained in:
parent
60dfee7299
commit
b8e6aad960
|
@ -30,6 +30,7 @@ CCFILES = \
|
||||||
gold.cc \
|
gold.cc \
|
||||||
gold-threads.cc \
|
gold-threads.cc \
|
||||||
layout.cc \
|
layout.cc \
|
||||||
|
merge.cc \
|
||||||
object.cc \
|
object.cc \
|
||||||
options.cc \
|
options.cc \
|
||||||
output.cc \
|
output.cc \
|
||||||
|
@ -52,6 +53,7 @@ HFILES = \
|
||||||
gold.h \
|
gold.h \
|
||||||
gold-threads.h \
|
gold-threads.h \
|
||||||
layout.h \
|
layout.h \
|
||||||
|
merge.h \
|
||||||
object.h \
|
object.h \
|
||||||
options.h \
|
options.h \
|
||||||
output.h \
|
output.h \
|
||||||
|
|
|
@ -71,10 +71,11 @@ libgold_a_LIBADD =
|
||||||
am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \
|
am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \
|
||||||
dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \
|
dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \
|
||||||
gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
|
gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
|
||||||
object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
|
merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
|
||||||
readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \
|
output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
|
||||||
script.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
|
resolve.$(OBJEXT) script.$(OBJEXT) symtab.$(OBJEXT) \
|
||||||
target-select.$(OBJEXT) workqueue.$(OBJEXT)
|
stringpool.$(OBJEXT) target-select.$(OBJEXT) \
|
||||||
|
workqueue.$(OBJEXT)
|
||||||
am__objects_2 =
|
am__objects_2 =
|
||||||
am__objects_3 = yyscript.$(OBJEXT)
|
am__objects_3 = yyscript.$(OBJEXT)
|
||||||
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
|
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
|
||||||
|
@ -256,6 +257,7 @@ CCFILES = \
|
||||||
gold.cc \
|
gold.cc \
|
||||||
gold-threads.cc \
|
gold-threads.cc \
|
||||||
layout.cc \
|
layout.cc \
|
||||||
|
merge.cc \
|
||||||
object.cc \
|
object.cc \
|
||||||
options.cc \
|
options.cc \
|
||||||
output.cc \
|
output.cc \
|
||||||
|
@ -278,6 +280,7 @@ HFILES = \
|
||||||
gold.h \
|
gold.h \
|
||||||
gold-threads.h \
|
gold-threads.h \
|
||||||
layout.h \
|
layout.h \
|
||||||
|
merge.h \
|
||||||
object.h \
|
object.h \
|
||||||
options.h \
|
options.h \
|
||||||
output.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)/i386.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.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)/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)/object.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.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@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
|
||||||
|
|
|
@ -12,7 +12,6 @@ namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
class General_options;
|
class General_options;
|
||||||
class Stringpool;
|
|
||||||
|
|
||||||
// A dynamic object (ET_DYN). This is an abstract base class itself.
|
// A dynamic object (ET_DYN). This is an abstract base class itself.
|
||||||
// The implementations is the template class Sized_dynobj.
|
// The implementations is the template class Sized_dynobj.
|
||||||
|
|
55
gold/i386.cc
55
gold/i386.cc
|
@ -109,7 +109,7 @@ class Target_i386 : public Sized_target<32, false>
|
||||||
relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
|
relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
|
||||||
const elfcpp::Rel<32, false>&,
|
const elfcpp::Rel<32, false>&,
|
||||||
unsigned int r_type, const Sized_symbol<32>*,
|
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,
|
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
|
||||||
off_t);
|
off_t);
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ class Target_i386 : public Sized_target<32, false>
|
||||||
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
|
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
|
||||||
const elfcpp::Rel<32, false>&,
|
const elfcpp::Rel<32, false>&,
|
||||||
unsigned int r_type, const Sized_symbol<32>*,
|
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);
|
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
|
||||||
|
|
||||||
// Do a TLS Initial-Exec to Local-Exec transition.
|
// 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,
|
const elfcpp::Rel<32, false>& rel,
|
||||||
unsigned int r_type,
|
unsigned int r_type,
|
||||||
const Sized_symbol<32>* gsym,
|
const Sized_symbol<32>* gsym,
|
||||||
elfcpp::Elf_types<32>::Elf_Addr value,
|
const Symbol_value<32>* psymval,
|
||||||
unsigned char* view,
|
unsigned char* view,
|
||||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||||
off_t view_size)
|
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.
|
// Pick the value to use for symbols defined in shared objects.
|
||||||
|
Symbol_value<32> symval;
|
||||||
if (gsym != NULL && gsym->is_from_dynobj())
|
if (gsym != NULL && gsym->is_from_dynobj())
|
||||||
{
|
{
|
||||||
if (gsym->has_plt_offset())
|
if (!gsym->has_plt_offset())
|
||||||
value = target->plt_section()->address() + gsym->plt_offset();
|
|
||||||
else
|
|
||||||
gold_unreachable();
|
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)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case elfcpp::R_386_NONE:
|
case elfcpp::R_386_NONE:
|
||||||
|
@ -1066,51 +1071,57 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_32:
|
case elfcpp::R_386_32:
|
||||||
Relocate_functions<32, false>::rel32(view, value);
|
Relocate_functions<32, false>::rel32(view, object, psymval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_PC32:
|
case elfcpp::R_386_PC32:
|
||||||
Relocate_functions<32, false>::pcrel32(view, value, address);
|
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_16:
|
case elfcpp::R_386_16:
|
||||||
Relocate_functions<32, false>::rel16(view, value);
|
Relocate_functions<32, false>::rel16(view, object, psymval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_PC16:
|
case elfcpp::R_386_PC16:
|
||||||
Relocate_functions<32, false>::pcrel16(view, value, address);
|
Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_8:
|
case elfcpp::R_386_8:
|
||||||
Relocate_functions<32, false>::rel8(view, value);
|
Relocate_functions<32, false>::rel8(view, object, psymval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_PC8:
|
case elfcpp::R_386_PC8:
|
||||||
Relocate_functions<32, false>::pcrel8(view, value, address);
|
Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_PLT32:
|
case elfcpp::R_386_PLT32:
|
||||||
gold_assert(gsym->has_plt_offset()
|
gold_assert(gsym->has_plt_offset()
|
||||||
|| gsym->final_value_is_known(relinfo->options));
|
|| 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;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_GOT32:
|
case elfcpp::R_386_GOT32:
|
||||||
// Local GOT offsets not yet supported.
|
// Local GOT offsets not yet supported.
|
||||||
gold_assert(gsym);
|
gold_assert(gsym);
|
||||||
gold_assert(gsym->has_got_offset());
|
gold_assert(gsym->has_got_offset());
|
||||||
value = gsym->got_offset();
|
Relocate_functions<32, false>::rel32(view, gsym->got_offset());
|
||||||
Relocate_functions<32, false>::rel32(view, value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_GOTOFF:
|
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;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_GOTPC:
|
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;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_386_COPY:
|
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_LE_32:
|
||||||
case elfcpp::R_386_TLS_GOTDESC:
|
case elfcpp::R_386_TLS_GOTDESC:
|
||||||
case elfcpp::R_386_TLS_DESC_CALL:
|
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);
|
address, view_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1173,7 +1184,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
|
||||||
const elfcpp::Rel<32, false>& rel,
|
const elfcpp::Rel<32, false>& rel,
|
||||||
unsigned int r_type,
|
unsigned int r_type,
|
||||||
const Sized_symbol<32>* gsym,
|
const Sized_symbol<32>* gsym,
|
||||||
elfcpp::Elf_types<32>::Elf_Addr value,
|
const Symbol_value<32>* psymval,
|
||||||
unsigned char* view,
|
unsigned char* view,
|
||||||
elfcpp::Elf_types<32>::Elf_Addr,
|
elfcpp::Elf_types<32>::Elf_Addr,
|
||||||
off_t view_size)
|
off_t view_size)
|
||||||
|
@ -1187,6 +1198,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
|
||||||
gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
|
||||||
|
|
||||||
const bool is_final = (gsym == NULL
|
const bool is_final = (gsym == NULL
|
||||||
? !relinfo->options->is_shared()
|
? !relinfo->options->is_shared()
|
||||||
: gsym->final_value_is_known(relinfo->options));
|
: gsym->final_value_is_known(relinfo->options));
|
||||||
|
|
|
@ -133,7 +133,9 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key,
|
||||||
// We should ignore some flags.
|
// We should ignore some flags.
|
||||||
flags &= ~ (elfcpp::SHF_INFO_LINK
|
flags &= ~ (elfcpp::SHF_INFO_LINK
|
||||||
| elfcpp::SHF_LINK_ORDER
|
| 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 Key key(name_key, std::make_pair(type, flags));
|
||||||
const std::pair<Key, Output_section*> v(key, NULL);
|
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,
|
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
elfcpp::Elf_Xword flags)
|
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);
|
this->section_list_.push_back(os);
|
||||||
|
|
||||||
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
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);
|
off_t off = this->set_segment_offsets(target, load_seg, &shndx);
|
||||||
|
|
||||||
// Create the symbol table sections.
|
// 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);
|
this->create_symtab_sections(size, input_objects, symtab, &off);
|
||||||
|
|
||||||
// Create the .shstrtab section.
|
// Create the .shstrtab section.
|
||||||
|
@ -690,7 +691,9 @@ Layout::set_section_offsets(off_t off, unsigned int* pshndx)
|
||||||
return off;
|
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
|
void
|
||||||
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
|
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
|
||||||
|
|
|
@ -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.
|
|
@ -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)
|
|
@ -127,8 +127,7 @@ Sized_relobj<size, big_endian>::Sized_relobj(
|
||||||
output_local_symbol_count_(0),
|
output_local_symbol_count_(0),
|
||||||
symbols_(NULL),
|
symbols_(NULL),
|
||||||
local_symbol_offset_(0),
|
local_symbol_offset_(0),
|
||||||
local_values_(),
|
local_values_()
|
||||||
local_indexes_()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
// Finalize the local symbols. Here we record the file offset at
|
||||||
// which they should be output, we add their names to *POOL, and we
|
// 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
|
// add their values to THIS->LOCAL_VALUES_. Return the symbol index.
|
||||||
// output symbol table to THIS->LOCAL_INDEXES_. Return the symbol
|
// This function is always called from the main thread. The actual
|
||||||
// index. This function is always called from the main thread. The
|
// output of the local symbols will occur in a separate task.
|
||||||
// actual output of the local symbols will occur in a separate task.
|
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
unsigned int
|
unsigned int
|
||||||
|
@ -542,7 +540,6 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
|
||||||
locsize);
|
locsize);
|
||||||
|
|
||||||
this->local_values_.resize(loccount);
|
this->local_values_.resize(loccount);
|
||||||
this->local_indexes_.resize(loccount);
|
|
||||||
|
|
||||||
// Read the symbol names.
|
// Read the symbol names.
|
||||||
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
|
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);
|
elfcpp::Sym<size, big_endian> sym(psyms);
|
||||||
|
|
||||||
|
Symbol_value<size>& lv(this->local_values_[i]);
|
||||||
|
|
||||||
unsigned int shndx = sym.get_st_shndx();
|
unsigned int shndx = sym.get_st_shndx();
|
||||||
|
lv.set_input_shndx(shndx);
|
||||||
|
|
||||||
if (shndx >= elfcpp::SHN_LORESERVE)
|
if (shndx >= elfcpp::SHN_LORESERVE)
|
||||||
{
|
{
|
||||||
if (shndx == elfcpp::SHN_ABS)
|
if (shndx == elfcpp::SHN_ABS)
|
||||||
this->local_values_[i] = sym.get_st_value();
|
lv.set_output_value(sym.get_st_value());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// FIXME: Handle SHN_XINDEX.
|
// FIXME: Handle SHN_XINDEX.
|
||||||
|
@ -589,23 +589,28 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
|
||||||
gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mo[shndx].output_section == NULL)
|
Output_section* os = mo[shndx].output_section;
|
||||||
|
|
||||||
|
if (os == NULL)
|
||||||
{
|
{
|
||||||
this->local_values_[i] = 0;
|
lv.set_output_value(0);
|
||||||
this->local_indexes_[i] = -1U;
|
lv.set_no_output_symtab_entry();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->local_values_[i] = (mo[shndx].output_section->address()
|
if (mo[shndx].offset == -1)
|
||||||
+ mo[shndx].offset
|
lv.set_input_value(sym.get_st_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.
|
// Decide whether this symbol should go into the output file.
|
||||||
|
|
||||||
if (sym.get_st_type() == elfcpp::STT_SECTION)
|
if (sym.get_st_type() == elfcpp::STT_SECTION)
|
||||||
{
|
{
|
||||||
this->local_indexes_[i] = -1U;
|
lv.set_no_output_symtab_entry();
|
||||||
continue;
|
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();
|
const char* name = pnames + sym.get_st_name();
|
||||||
pool->add(name, NULL);
|
pool->add(name, NULL);
|
||||||
this->local_indexes_[i] = index;
|
lv.set_output_symtab_index(index);
|
||||||
++index;
|
++index;
|
||||||
off += sym_size;
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +637,23 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
|
||||||
return 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.
|
// Write out the local symbols.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
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());
|
const std::vector<Map_to_output>& mo(this->map_to_output());
|
||||||
|
|
||||||
gold_assert(this->local_values_.size() == loccount);
|
gold_assert(this->local_values_.size() == loccount);
|
||||||
gold_assert(this->local_indexes_.size() == loccount);
|
|
||||||
|
|
||||||
unsigned char* ov = oview;
|
unsigned char* ov = oview;
|
||||||
psyms += sym_size;
|
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);
|
elfcpp::Sym<size, big_endian> isym(psyms);
|
||||||
|
|
||||||
if (this->local_indexes_[i] == -1U)
|
if (!this->local_values_[i].needs_output_symtab_entry())
|
||||||
continue;
|
continue;
|
||||||
gold_assert(this->local_indexes_[i] != 0);
|
|
||||||
|
|
||||||
unsigned int st_shndx = isym.get_st_shndx();
|
unsigned int st_shndx = isym.get_st_shndx();
|
||||||
if (st_shndx < elfcpp::SHN_LORESERVE)
|
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);
|
gold_assert(isym.get_st_name() < strtab_size);
|
||||||
const char* name = pnames + isym.get_st_name();
|
const char* name = pnames + isym.get_st_name();
|
||||||
osym.put_st_name(sympool->get_offset(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_size(isym.get_st_size());
|
||||||
osym.put_st_info(isym.get_st_info());
|
osym.put_st_info(isym.get_st_info());
|
||||||
osym.put_st_other(isym.get_st_other());
|
osym.put_st_other(isym.get_st_other());
|
||||||
|
|
146
gold/object.h
146
gold/object.h
|
@ -15,12 +15,14 @@ namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
class General_options;
|
class General_options;
|
||||||
class Stringpool;
|
|
||||||
class Layout;
|
class Layout;
|
||||||
class Output_section;
|
class Output_section;
|
||||||
class Output_file;
|
class Output_file;
|
||||||
class Dynobj;
|
class Dynobj;
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
|
class Stringpool_template;
|
||||||
|
|
||||||
// Data to pass from read_symbols() to add_symbols().
|
// Data to pass from read_symbols() to add_symbols().
|
||||||
|
|
||||||
struct Read_symbols_data
|
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.
|
// 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
|
class Relobj : public Object
|
||||||
{
|
{
|
||||||
|
@ -362,7 +364,8 @@ class Relobj : public Object
|
||||||
// symbol information will be stored; add local symbol names to
|
// symbol information will be stored; add local symbol names to
|
||||||
// *POOL; return the new local symbol index.
|
// *POOL; return the new local symbol index.
|
||||||
unsigned int
|
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); }
|
{ return this->do_finalize_local_symbols(index, off, pool); }
|
||||||
|
|
||||||
// Relocate the input sections and write out the local symbols.
|
// 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)
|
// (which will be NULL if the section is not included in the link)
|
||||||
// and set *POFF to the offset within that section.
|
// and set *POFF to the offset within that section.
|
||||||
inline Output_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.
|
// Set the offset of an input section within its output section.
|
||||||
void
|
void
|
||||||
|
@ -402,7 +405,8 @@ class Relobj : public Object
|
||||||
// The output section. This is NULL if the input section is to be
|
// The output section. This is NULL if the input section is to be
|
||||||
// discarded.
|
// discarded.
|
||||||
Output_section* output_section;
|
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;
|
off_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -417,7 +421,8 @@ class Relobj : public Object
|
||||||
|
|
||||||
// Finalize local symbols--implemented by child class.
|
// Finalize local symbols--implemented by child class.
|
||||||
virtual unsigned int
|
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
|
// Relocate the input sections and write out the local
|
||||||
// symbols--implemented by child class.
|
// symbols--implemented by child class.
|
||||||
|
@ -430,6 +435,10 @@ class Relobj : public Object
|
||||||
map_to_output()
|
map_to_output()
|
||||||
{ return this->map_to_output_; }
|
{ return this->map_to_output_; }
|
||||||
|
|
||||||
|
const std::vector<Map_to_output>&
|
||||||
|
map_to_output() const
|
||||||
|
{ return this->map_to_output_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Mapping from input sections to output section.
|
// Mapping from input sections to output section.
|
||||||
std::vector<Map_to_output> map_to_output_;
|
std::vector<Map_to_output> map_to_output_;
|
||||||
|
@ -437,7 +446,7 @@ class Relobj : public Object
|
||||||
|
|
||||||
// Implement Object::output_section inline for efficiency.
|
// Implement Object::output_section inline for efficiency.
|
||||||
inline Output_section*
|
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());
|
gold_assert(shndx < this->map_to_output_.size());
|
||||||
const Map_to_output& mo(this->map_to_output_[shndx]);
|
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;
|
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.
|
// A regular object file. This is size and endian specific.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -452,7 +563,7 @@ class Sized_relobj : public Relobj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
|
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,
|
Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
|
||||||
const typename elfcpp::Ehdr<size, big_endian>&);
|
const typename elfcpp::Ehdr<size, big_endian>&);
|
||||||
|
@ -468,9 +579,8 @@ class Sized_relobj : public Relobj
|
||||||
unsigned int
|
unsigned int
|
||||||
symtab_index(unsigned int sym) const
|
symtab_index(unsigned int sym) const
|
||||||
{
|
{
|
||||||
gold_assert(sym < this->local_indexes_.size());
|
gold_assert(sym < this->local_values_.size());
|
||||||
gold_assert(this->local_indexes_[sym] != 0);
|
return this->local_values_[sym].output_symtab_index();
|
||||||
return this->local_indexes_[sym];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the symbols.
|
// Read the symbols.
|
||||||
|
@ -497,7 +607,8 @@ class Sized_relobj : public Relobj
|
||||||
|
|
||||||
// Finalize the local symbols.
|
// Finalize the local symbols.
|
||||||
unsigned int
|
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.
|
// Relocate the input sections and write out the local symbols.
|
||||||
void
|
void
|
||||||
|
@ -528,6 +639,12 @@ class Sized_relobj : public Relobj
|
||||||
SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
|
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:
|
private:
|
||||||
// For convenience.
|
// For convenience.
|
||||||
typedef Sized_relobj<size, big_endian> This;
|
typedef Sized_relobj<size, big_endian> This;
|
||||||
|
@ -574,7 +691,8 @@ class Sized_relobj : public Relobj
|
||||||
|
|
||||||
// Write out the local symbols.
|
// Write out the local symbols.
|
||||||
void
|
void
|
||||||
write_local_symbols(Output_file*, const Stringpool*);
|
write_local_symbols(Output_file*,
|
||||||
|
const Stringpool_template<char>*);
|
||||||
|
|
||||||
// General access to the ELF file.
|
// General access to the ELF file.
|
||||||
elfcpp::Elf_file<size, big_endian, Object> 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_;
|
off_t local_symbol_offset_;
|
||||||
// Values of local symbols.
|
// Values of local symbols.
|
||||||
Local_values local_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.
|
// A class to manage the list of all objects.
|
||||||
|
|
155
gold/output.cc
155
gold/output.cc
|
@ -12,6 +12,7 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "reloc.h"
|
#include "reloc.h"
|
||||||
|
#include "merge.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
|
@ -790,9 +791,9 @@ off_t
|
||||||
Output_section::Input_section::data_size() const
|
Output_section::Input_section::data_size() const
|
||||||
{
|
{
|
||||||
if (this->is_input_section())
|
if (this->is_input_section())
|
||||||
return this->data_size_;
|
return this->u1_.data_size;
|
||||||
else
|
else
|
||||||
return this->u_.posd->data_size();
|
return this->u2_.posd->data_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the address and file offset.
|
// 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)
|
off_t secoff)
|
||||||
{
|
{
|
||||||
if (this->is_input_section())
|
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
|
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
|
// 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)
|
Output_section::Input_section::write(Output_file* of)
|
||||||
{
|
{
|
||||||
if (!this->is_input_section())
|
if (!this->is_input_section())
|
||||||
this->u_.posd->write(of);
|
this->u2_.posd->write(of);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output_section methods.
|
// 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.
|
// Construct an Output_section. NAME will point into a Stringpool.
|
||||||
|
|
||||||
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
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),
|
: name_(name),
|
||||||
addralign_(0),
|
addralign_(0),
|
||||||
entsize_(0),
|
entsize_(0),
|
||||||
|
@ -838,7 +863,6 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
dynsym_index_(0),
|
dynsym_index_(0),
|
||||||
input_sections_(),
|
input_sections_(),
|
||||||
first_input_offset_(0),
|
first_input_offset_(0),
|
||||||
may_add_data_(may_add_data),
|
|
||||||
needs_symtab_index_(false),
|
needs_symtab_index_(false),
|
||||||
needs_dynsym_index_(false),
|
needs_dynsym_index_(false),
|
||||||
should_link_to_symtab_(false),
|
should_link_to_symtab_(false),
|
||||||
|
@ -873,8 +897,6 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
|
||||||
const char* secname,
|
const char* secname,
|
||||||
const elfcpp::Shdr<size, big_endian>& shdr)
|
const elfcpp::Shdr<size, big_endian>& shdr)
|
||||||
{
|
{
|
||||||
gold_assert(this->may_add_data_);
|
|
||||||
|
|
||||||
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
|
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
|
||||||
if ((addralign & (addralign - 1)) != 0)
|
if ((addralign & (addralign - 1)) != 0)
|
||||||
{
|
{
|
||||||
|
@ -887,6 +909,20 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
|
||||||
if (addralign > this->addralign_)
|
if (addralign > this->addralign_)
|
||||||
this->addralign_ = 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();
|
off_t ssize = this->data_size();
|
||||||
ssize = align_address(ssize, addralign);
|
ssize = align_address(ssize, addralign);
|
||||||
this->set_data_size(ssize + shdr.get_sh_size());
|
this->set_data_size(ssize + shdr.get_sh_size());
|
||||||
|
@ -907,18 +943,107 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
|
||||||
void
|
void
|
||||||
Output_section::add_output_section_data(Output_section_data* posd)
|
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())
|
if (this->input_sections_.empty())
|
||||||
this->first_input_offset_ = this->data_size();
|
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_)
|
if (addralign > this->addralign_)
|
||||||
this->addralign_ = 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
|
// 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;
|
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
|
uint64_t
|
||||||
Output_segment::set_section_list_addresses(Output_data_list* pdl,
|
Output_segment::set_section_list_addresses(Output_data_list* pdl,
|
||||||
|
@ -1541,3 +1667,4 @@ template
|
||||||
class Output_data_got<64, true>;
|
class Output_data_got<64, true>;
|
||||||
|
|
||||||
} // End namespace gold.
|
} // End namespace gold.
|
||||||
|
|
||||||
|
|
185
gold/output.h
185
gold/output.h
|
@ -314,6 +314,26 @@ class Output_section_data : public Output_data
|
||||||
void
|
void
|
||||||
set_output_section(Output_section* os);
|
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:
|
protected:
|
||||||
// The child class must implement do_write.
|
// The child class must implement do_write.
|
||||||
|
|
||||||
|
@ -323,6 +343,18 @@ class Output_section_data : public Output_data
|
||||||
do_adjust_output_section(Output_section*)
|
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.
|
// Return the required alignment.
|
||||||
uint64_t
|
uint64_t
|
||||||
do_addralign() const
|
do_addralign() const
|
||||||
|
@ -1114,8 +1146,7 @@ class Output_section : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Create an output section, giving the name, type, and flags.
|
// Create an output section, giving the name, type, and flags.
|
||||||
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
|
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
|
||||||
bool may_add_data);
|
|
||||||
virtual ~Output_section();
|
virtual ~Output_section();
|
||||||
|
|
||||||
// Add a new input section SHNDX, named NAME, with header SHDR, from
|
// 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,
|
add_input_section(Relobj* object, unsigned int shndx, const char *name,
|
||||||
const elfcpp::Shdr<size, big_endian>& shdr);
|
const elfcpp::Shdr<size, big_endian>& shdr);
|
||||||
|
|
||||||
// Add generated data ODATA to this output section.
|
// Add generated data POSD to this output section.
|
||||||
void
|
void
|
||||||
add_output_section_data(Output_section_data* posd);
|
add_output_section_data(Output_section_data* posd);
|
||||||
|
|
||||||
|
@ -1284,6 +1315,12 @@ class Output_section : public Output_data
|
||||||
this->dynsym_index_ = index;
|
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
|
// Set the address of the Output_section. For a typical
|
||||||
// Output_section, there is nothing to do, but if there are any
|
// Output_section, there is nothing to do, but if there are any
|
||||||
// Output_section_data objects we need to set the final addresses
|
// Output_section_data objects we need to set the final addresses
|
||||||
|
@ -1339,24 +1376,44 @@ class Output_section : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Input_section()
|
Input_section()
|
||||||
: shndx_(0), p2align_(0), data_size_(0)
|
: shndx_(0), p2align_(0)
|
||||||
{ this->u_.object = NULL; }
|
{
|
||||||
|
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,
|
Input_section(Relobj* object, unsigned int shndx, off_t data_size,
|
||||||
uint64_t addralign)
|
uint64_t addralign)
|
||||||
: shndx_(shndx),
|
: shndx_(shndx),
|
||||||
p2align_(ffsll(static_cast<long long>(addralign))),
|
p2align_(ffsll(static_cast<long long>(addralign)))
|
||||||
data_size_(data_size)
|
|
||||||
{
|
{
|
||||||
gold_assert(shndx != -1U);
|
gold_assert(shndx != OUTPUT_SECTION_CODE
|
||||||
this->u_.object = object;
|
&& 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)
|
Input_section(Output_section_data* posd)
|
||||||
: shndx_(-1U),
|
: shndx_(OUTPUT_SECTION_CODE),
|
||||||
p2align_(ffsll(static_cast<long long>(posd->addralign()))),
|
p2align_(ffsll(static_cast<long long>(posd->addralign())))
|
||||||
data_size_(0)
|
{
|
||||||
{ this->u_.posd = posd; }
|
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.
|
// The required alignment.
|
||||||
uint64_t
|
uint64_t
|
||||||
|
@ -1371,41 +1428,125 @@ class Output_section : public Output_data
|
||||||
off_t
|
off_t
|
||||||
data_size() const;
|
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
|
// Set the address and file offset. This is called during
|
||||||
// Layout::finalize. SECOFF is the file offset of the enclosing
|
// Layout::finalize. SECOFF is the file offset of the enclosing
|
||||||
// section.
|
// section.
|
||||||
void
|
void
|
||||||
set_address(uint64_t addr, off_t off, off_t secoff);
|
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.
|
// Write out the data. This does nothing for an input section.
|
||||||
void
|
void
|
||||||
write(Output_file*);
|
write(Output_file*);
|
||||||
|
|
||||||
private:
|
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.
|
// Whether this is an input section.
|
||||||
bool
|
bool
|
||||||
is_input_section() const
|
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
|
// For an ordinary input section, this is the section index in the
|
||||||
// the input file. For an Output_section_data, this is -1U.
|
// 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_;
|
unsigned int shndx_;
|
||||||
// The required alignment, stored as a power of 2.
|
// The required alignment, stored as a power of 2.
|
||||||
unsigned int p2align_;
|
unsigned int p2align_;
|
||||||
// For an ordinary input section, the section size.
|
|
||||||
off_t data_size_;
|
|
||||||
union
|
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.
|
// input section.
|
||||||
Relobj* object;
|
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;
|
Output_section_data* posd;
|
||||||
} u_;
|
} u2_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Input_section> Input_section_list;
|
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.
|
// Most of these fields are only valid after layout.
|
||||||
|
|
||||||
// The name of the section. This will point into a Stringpool.
|
// 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_;
|
Input_section_list input_sections_;
|
||||||
// The offset of the first entry in input_sections_.
|
// The offset of the first entry in input_sections_.
|
||||||
off_t first_input_offset_;
|
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
|
// Whether this output section needs a STT_SECTION symbol in the
|
||||||
// normal symbol table. This will be true if there is a relocation
|
// normal symbol table. This will be true if there is a relocation
|
||||||
// which needs it.
|
// which needs it.
|
||||||
|
|
|
@ -17,6 +17,8 @@ gold-threads.h
|
||||||
i386.cc
|
i386.cc
|
||||||
layout.cc
|
layout.cc
|
||||||
layout.h
|
layout.h
|
||||||
|
merge.cc
|
||||||
|
merge.h
|
||||||
object.cc
|
object.cc
|
||||||
object.h
|
object.h
|
||||||
options.cc
|
options.cc
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\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"
|
msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: dynobj.cc:368 object.cc:421
|
#: dynobj.cc:368 object.cc:420
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -255,7 +255,7 @@ msgstr ""
|
||||||
msgid "%s: missing expected TLS relocation\n"
|
msgid "%s: missing expected TLS relocation\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:729 i386.cc:870 i386.cc:1125
|
#: i386.cc:729 i386.cc:870 i386.cc:1136
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unexpected reloc %u in object file\n"
|
msgid "%s: %s: unexpected reloc %u in object file\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -280,31 +280,42 @@ msgstr ""
|
||||||
msgid "%s: %s: missing expected TLS relocation\n"
|
msgid "%s: %s: missing expected TLS relocation\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:1157 i386.cc:1232 i386.cc:1243
|
#: i386.cc:1168 i386.cc:1245 i386.cc:1256
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported reloc %u\n"
|
msgid "%s: %s: unsupported reloc %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:1184
|
#: i386.cc:1195
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: TLS reloc but no TLS segment\n"
|
msgid "%s: %s: TLS reloc but no TLS segment\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:1217
|
#: i386.cc:1230
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported reloc type %u\n"
|
msgid "%s: %s: unsupported reloc type %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:1426
|
#: i386.cc:1439
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: TLS relocation out of range\n"
|
msgid "%s: %s: TLS relocation out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: i386.cc:1444
|
#: i386.cc:1457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: TLS relocation against invalid instruction\n"
|
msgid "%s: %s: TLS relocation against invalid instruction\n"
|
||||||
msgstr ""
|
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
|
#: object.cc:30
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
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"
|
msgid "%s: %s: section name section has wrong type: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:229
|
#: object.cc:228
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:237
|
#: object.cc:236
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:293
|
#: object.cc:292
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: section group %u info %u out of range\n"
|
msgid "%s: %s: section group %u info %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:310
|
#: object.cc:309
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:344
|
#: object.cc:343
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: section %u in section group %u out of range"
|
msgid "%s: %s: section %u in section group %u out of range"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:488
|
#: object.cc:487
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -355,47 +366,47 @@ msgstr ""
|
||||||
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:615
|
#: object.cc:620
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
|
msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:815
|
#: object.cc:834
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF file type %d\n"
|
msgid "%s: %s: unsupported ELF file type %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:834 object.cc:887 object.cc:908
|
#: object.cc:853 object.cc:906 object.cc:927
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: ELF file too short\n"
|
msgid "%s: %s: ELF file too short\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:843
|
#: object.cc:862
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF version 0\n"
|
msgid "%s: %s: invalid ELF version 0\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:846
|
#: object.cc:865
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF version %d\n"
|
msgid "%s: %s: unsupported ELF version %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:854
|
#: object.cc:873
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF class 0\n"
|
msgid "%s: %s: invalid ELF class 0\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:861
|
#: object.cc:880
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF class %d\n"
|
msgid "%s: %s: unsupported ELF class %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:869
|
#: object.cc:888
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF data encoding\n"
|
msgid "%s: %s: invalid ELF data encoding\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:876
|
#: object.cc:895
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -511,37 +522,37 @@ msgstr ""
|
||||||
msgid "%s: -%c: %s\n"
|
msgid "%s: -%c: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:881
|
#: output.cc:903
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1393
|
#: output.cc:1519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: open: %s\n"
|
msgid "%s: %s: open: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1402
|
#: output.cc:1528
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: lseek: %s\n"
|
msgid "%s: %s: lseek: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1409
|
#: output.cc:1535
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: write: %s\n"
|
msgid "%s: %s: write: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1419
|
#: output.cc:1545
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: mmap: %s\n"
|
msgid "%s: %s: mmap: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1433
|
#: output.cc:1559
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: munmap: %s\n"
|
msgid "%s: %s: munmap: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:1441
|
#: output.cc:1567
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: close: %s\n"
|
msgid "%s: %s: close: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -562,22 +573,22 @@ msgstr ""
|
||||||
msgid "%s: %s: not an object or archive\n"
|
msgid "%s: %s: not an object or archive\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: reloc.cc:169 reloc.cc:410
|
#: reloc.cc:169 reloc.cc:413
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: relocation section %u has bad info %u\n"
|
msgid "%s: %s: relocation section %u has bad info %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: reloc.cc:188 reloc.cc:427
|
#: reloc.cc:188 reloc.cc:430
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
|
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: reloc.cc:204 reloc.cc:446
|
#: reloc.cc:204 reloc.cc:449
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
|
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: reloc.cc:215 reloc.cc:457
|
#: reloc.cc:215 reloc.cc:460
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: reloc section %u size %lu uneven"
|
msgid "%s: %s: reloc section %u size %lu uneven"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -632,12 +643,12 @@ msgstr ""
|
||||||
msgid "%s: %s: warning: %s\n"
|
msgid "%s: %s: warning: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: target-reloc.h:164
|
#: target-reloc.h:170
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: reloc has bad offset %zu\n"
|
msgid "%s: %s: reloc has bad offset %zu\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: target-reloc.h:174
|
#: target-reloc.h:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: undefined reference to '%s'\n"
|
msgid "%s: %s: undefined reference to '%s'\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -343,6 +343,9 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
|
||||||
|
|
||||||
pvs->view = NULL;
|
pvs->view = NULL;
|
||||||
|
|
||||||
|
if (map_sections[i].offset == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
const Output_section* os = map_sections[i].output_section;
|
const Output_section* os = map_sections[i].output_section;
|
||||||
if (os == NULL)
|
if (os == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
136
gold/reloc.h
136
gold/reloc.h
|
@ -13,13 +13,18 @@ namespace gold
|
||||||
class General_options;
|
class General_options;
|
||||||
class Relobj;
|
class Relobj;
|
||||||
class Read_relocs_data;
|
class Read_relocs_data;
|
||||||
class Stringpool;
|
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class Layout;
|
class Layout;
|
||||||
|
|
||||||
template<int size>
|
template<int size>
|
||||||
class Sized_symbol;
|
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>
|
template<int sh_type, bool dynamic, int size, bool big_endian>
|
||||||
class Output_data_reloc;
|
class Output_data_reloc;
|
||||||
|
|
||||||
|
@ -151,6 +156,22 @@ private:
|
||||||
elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value);
|
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
|
// Do a simple PC relative relocation with the addend in the section
|
||||||
// contents. VALSIZE is the size of the value.
|
// contents. VALSIZE is the size of the value.
|
||||||
template<int valsize>
|
template<int valsize>
|
||||||
|
@ -165,76 +186,129 @@ private:
|
||||||
elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value - address);
|
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;
|
typedef Relocate_functions<size, big_endian> This;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Do a simple 8-bit REL relocation with the addend in the object
|
// Do a simple 8-bit REL relocation with the addend in the section
|
||||||
// file data.
|
// contents.
|
||||||
static inline void
|
static inline void
|
||||||
rel8(unsigned char* view, unsigned char value)
|
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
|
// Do a simple 8-bit PC relative relocation with the addend in the
|
||||||
// object file data.
|
// section contents.
|
||||||
static inline void
|
static inline void
|
||||||
pcrel8(unsigned char* view, unsigned char value,
|
pcrel8(unsigned char* view, unsigned char value,
|
||||||
typename elfcpp::Elf_types<size>::Elf_Addr address)
|
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
|
static inline void
|
||||||
// file data.
|
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
|
static inline void
|
||||||
rel16(unsigned char* view, elfcpp::Elf_Half value)
|
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
|
// Do a simple 32-bit PC relative REL relocation with the addend in
|
||||||
// the object file data.
|
// the section contents.
|
||||||
static inline void
|
static inline void
|
||||||
pcrel16(unsigned char* view, elfcpp::Elf_Word value,
|
pcrel16(unsigned char* view, elfcpp::Elf_Word value,
|
||||||
typename elfcpp::Elf_types<size>::Elf_Addr address)
|
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
|
// Do a simple 32-bit REL relocation with the addend in the section
|
||||||
// contents.
|
// contents.
|
||||||
static inline void
|
static inline void
|
||||||
rel32(unsigned char* view, elfcpp::Elf_Word value)
|
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
|
// Do a simple 32-bit PC relative REL relocation with the addend in
|
||||||
// the section contents.
|
// the section contents.
|
||||||
static inline void
|
static inline void
|
||||||
pcrel32(unsigned char* view, elfcpp::Elf_Word value,
|
pcrel32(unsigned char* view, elfcpp::Elf_Word value,
|
||||||
typename elfcpp::Elf_types<size>::Elf_Addr address)
|
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
|
// Do a simple 64-bit REL relocation with the addend in the section
|
||||||
// contents.
|
// contents.
|
||||||
static inline void
|
static inline void
|
||||||
rel64(unsigned char* view, elfcpp::Elf_Xword value)
|
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
|
// Do a simple 64-bit PC relative REL relocation with the addend in
|
||||||
// the section contents.
|
// the section contents.
|
||||||
static inline void
|
static inline void
|
||||||
pcrel64(unsigned char* view, elfcpp::Elf_Xword value,
|
pcrel64(unsigned char* view, elfcpp::Elf_Xword value,
|
||||||
typename elfcpp::Elf_types<size>::Elf_Addr address)
|
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
|
// We try to avoid COPY relocations when possible. A COPY relocation
|
||||||
|
|
|
@ -12,42 +12,103 @@
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
Stringpool::Stringpool()
|
template<typename Stringpool_char>
|
||||||
: string_set_(), strings_(), strtab_size_(0), next_index_(1)
|
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 != this->strings_.end();
|
||||||
++p)
|
++p)
|
||||||
delete[] reinterpret_cast<char*>(*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.
|
// Hash function.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
size_t
|
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).
|
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
|
||||||
if (sizeof(size_t) == 8)
|
if (sizeof(size_t) == 8)
|
||||||
{
|
{
|
||||||
size_t result = static_cast<size_t>(14695981039346656037ULL);
|
size_t result = static_cast<size_t>(14695981039346656037ULL);
|
||||||
while (*s != '\0')
|
while (*s != 0)
|
||||||
{
|
{
|
||||||
result &= (size_t) *s++;
|
const char* p = reinterpret_cast<const char*>(s);
|
||||||
result *= 1099511628211ULL;
|
for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
|
||||||
|
{
|
||||||
|
result &= (size_t) *p++;
|
||||||
|
result *= 1099511628211ULL;
|
||||||
|
}
|
||||||
|
++s;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t result = 2166136261UL;
|
size_t result = 2166136261UL;
|
||||||
while (*s != '\0')
|
while (*s != 0)
|
||||||
{
|
{
|
||||||
result ^= (size_t) *s++;
|
const char* p = reinterpret_cast<const char*>(s);
|
||||||
result *= 16777619UL;
|
for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
|
||||||
|
{
|
||||||
|
result ^= (size_t) *p++;
|
||||||
|
result *= 16777619UL;
|
||||||
|
}
|
||||||
|
++s;
|
||||||
}
|
}
|
||||||
return result;
|
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
|
// 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.
|
// the canonical string. If PKEY is not NULL, set *PKEY to the key.
|
||||||
|
|
||||||
const char*
|
template<typename Stringpool_char>
|
||||||
Stringpool::add_string(const char* s, Key* pkey)
|
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.
|
// We are in trouble if we've already computed the string offsets.
|
||||||
gold_assert(this->strtab_size_ == 0);
|
gold_assert(this->strtab_size_ == 0);
|
||||||
|
@ -69,11 +132,11 @@ Stringpool::add_string(const char* s, Key* pkey)
|
||||||
const size_t key_mult = 1024;
|
const size_t key_mult = 1024;
|
||||||
gold_assert(key_mult >= buffer_size);
|
gold_assert(key_mult >= buffer_size);
|
||||||
|
|
||||||
size_t len = strlen(s);
|
size_t len = (string_length(s) + 1) * sizeof(Stringpool_char);
|
||||||
|
|
||||||
size_t alc;
|
size_t alc;
|
||||||
bool front = true;
|
bool front = true;
|
||||||
if (len >= buffer_size)
|
if (len > buffer_size)
|
||||||
{
|
{
|
||||||
alc = sizeof(Stringdata) + len;
|
alc = sizeof(Stringdata) + len;
|
||||||
front = false;
|
front = false;
|
||||||
|
@ -83,26 +146,26 @@ Stringpool::add_string(const char* s, Key* pkey)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stringdata *psd = this->strings_.front();
|
Stringdata *psd = this->strings_.front();
|
||||||
if (len >= psd->alc - psd->len)
|
if (len > psd->alc - psd->len)
|
||||||
alc = sizeof(Stringdata) + buffer_size;
|
alc = sizeof(Stringdata) + buffer_size;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* ret = psd->data + psd->len;
|
char* ret = psd->data + psd->len;
|
||||||
memcpy(ret, s, len + 1);
|
memcpy(ret, s, len);
|
||||||
|
|
||||||
if (pkey != NULL)
|
if (pkey != NULL)
|
||||||
*pkey = psd->index * key_mult + psd->len;
|
*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]);
|
Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
|
||||||
psd->alc = alc - sizeof(Stringdata);
|
psd->alc = alc - sizeof(Stringdata);
|
||||||
memcpy(psd->data, s, len + 1);
|
memcpy(psd->data, s, len);
|
||||||
psd->len = len + 1;
|
psd->len = len;
|
||||||
psd->index = this->next_index_;
|
psd->index = this->next_index_;
|
||||||
++this->next_index_;
|
++this->next_index_;
|
||||||
|
|
||||||
|
@ -114,13 +177,14 @@ Stringpool::add_string(const char* s, Key* pkey)
|
||||||
else
|
else
|
||||||
this->strings_.push_back(psd);
|
this->strings_.push_back(psd);
|
||||||
|
|
||||||
return psd->data;
|
return reinterpret_cast<const Stringpool_char*>(psd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a string to a string pool.
|
// Add a string to a string pool.
|
||||||
|
|
||||||
const char*
|
template<typename Stringpool_char>
|
||||||
Stringpool::add(const char* s, Key* pkey)
|
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
|
// 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
|
// 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
|
// unordered_map, so this should be replaced with custom code to do
|
||||||
// what we need, which is to return the empty slot.
|
// 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 (p != this->string_set_.end())
|
||||||
{
|
{
|
||||||
if (pkey != NULL)
|
if (pkey != NULL)
|
||||||
|
@ -137,11 +201,12 @@ Stringpool::add(const char* s, Key* pkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
Key k;
|
Key k;
|
||||||
const char* ret = this->add_string(s, &k);
|
const Stringpool_char* ret = this->add_string(s, &k);
|
||||||
|
|
||||||
const off_t ozero = 0;
|
const off_t ozero = 0;
|
||||||
std::pair<const char*, Val> element(ret, std::make_pair(k, ozero));
|
std::pair<const Stringpool_char*, Val> element(ret,
|
||||||
std::pair<String_set_type::iterator, bool> ins =
|
std::make_pair(k, ozero));
|
||||||
|
std::pair<typename String_set_type::iterator, bool> ins =
|
||||||
this->string_set_.insert(element);
|
this->string_set_.insert(element);
|
||||||
gold_assert(ins.second);
|
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.
|
// Add a prefix of a string to a string pool.
|
||||||
|
|
||||||
const char*
|
template<typename Stringpool_char>
|
||||||
Stringpool::add(const char* s, size_t len, Key* pkey)
|
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
|
// FIXME: This implementation should be rewritten when we rewrite
|
||||||
// the hash table to avoid copying.
|
// the hash table to avoid copying.
|
||||||
std::string st(s, len);
|
std::basic_string<Stringpool_char> st(s, len);
|
||||||
return this->add(st, pkey);
|
return this->add(st, pkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
template<typename Stringpool_char>
|
||||||
Stringpool::find(const char* s, Key* pkey) const
|
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())
|
if (p == this->string_set_.end())
|
||||||
return NULL;
|
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.
|
// 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.
|
// So we do a reversed lexicographic sort on the reversed string.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
bool
|
bool
|
||||||
Stringpool::Stringpool_sort_comparison::operator()(
|
Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()(
|
||||||
String_set_type::iterator it1,
|
typename String_set_type::iterator it1,
|
||||||
String_set_type::iterator it2) const
|
typename String_set_type::iterator it2) const
|
||||||
{
|
{
|
||||||
const char* s1 = it1->first;
|
const Stringpool_char* s1 = it1->first;
|
||||||
const char* s2 = it2->first;
|
const Stringpool_char* s2 = it2->first;
|
||||||
int len1 = strlen(s1);
|
size_t len1 = string_length(s1);
|
||||||
int len2 = strlen(s2);
|
size_t len2 = string_length(s2);
|
||||||
int minlen = len1 < len2 ? len1 : len2;
|
size_t minlen = len1 < len2 ? len1 : len2;
|
||||||
const char* p1 = s1 + len1 - 1;
|
const Stringpool_char* p1 = s1 + len1 - 1;
|
||||||
const char* p2 = s2 + len2 - 1;
|
const Stringpool_char* p2 = s2 + len2 - 1;
|
||||||
for (int i = minlen - 1; i >= 0; --i, --p1, --p2)
|
for (size_t i = minlen; i > 0; --i, --p1, --p2)
|
||||||
{
|
{
|
||||||
if (*p1 != *p2)
|
if (*p1 != *p2)
|
||||||
return *p1 > *p2;
|
return *p1 > *p2;
|
||||||
|
@ -208,21 +278,24 @@ Stringpool::Stringpool_sort_comparison::operator()(
|
||||||
|
|
||||||
// Return whether s1 is a suffix of s2.
|
// Return whether s1 is a suffix of s2.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
bool
|
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 len1 = string_length(s1);
|
||||||
size_t len2 = strlen(s2);
|
size_t len2 = string_length(s2);
|
||||||
if (len1 > len2)
|
if (len1 > len2)
|
||||||
return false;
|
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
|
// Turn the stringpool into an ELF strtab: determine the offsets of
|
||||||
// each string in the table.
|
// each string in the table.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
void
|
void
|
||||||
Stringpool::set_string_offsets()
|
Stringpool_template<Stringpool_char>::set_string_offsets()
|
||||||
{
|
{
|
||||||
if (this->strtab_size_ != 0)
|
if (this->strtab_size_ != 0)
|
||||||
{
|
{
|
||||||
|
@ -232,30 +305,33 @@ Stringpool::set_string_offsets()
|
||||||
|
|
||||||
size_t count = this->string_set_.size();
|
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);
|
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 != this->string_set_.end();
|
||||||
++p)
|
++p)
|
||||||
v.push_back(p);
|
v.push_back(p);
|
||||||
|
|
||||||
std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
|
std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
|
||||||
|
|
||||||
// Offset 0 is reserved for the empty string.
|
const size_t charsize = sizeof(Stringpool_char);
|
||||||
off_t offset = 1;
|
|
||||||
|
// 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)
|
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;
|
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
|
v[i]->second.second = (v[i - 1]->second.second
|
||||||
+ strlen(v[i - 1]->first)
|
+ ((string_length(v[i - 1]->first)
|
||||||
- strlen(v[i]->first));
|
- string_length(v[i]->first))
|
||||||
|
* charsize));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
v[i]->second.second = offset;
|
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
|
// Get the offset of a string in the ELF strtab. The string must
|
||||||
// exist.
|
// exist.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
off_t
|
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);
|
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())
|
if (p != this->string_set_.end())
|
||||||
return p->second.second;
|
return p->second.second;
|
||||||
gold_unreachable();
|
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.
|
// Write the ELF strtab into the output file at the specified offset.
|
||||||
|
|
||||||
|
template<typename Stringpool_char>
|
||||||
void
|
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);
|
gold_assert(this->strtab_size_ != 0);
|
||||||
unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
|
unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
|
||||||
char* view = reinterpret_cast<char*>(viewu);
|
char* view = reinterpret_cast<char*>(viewu);
|
||||||
view[0] = '\0';
|
if (this->zero_null_)
|
||||||
for (String_set_type::const_iterator p = this->string_set_.begin();
|
view[0] = '\0';
|
||||||
|
for (typename String_set_type::const_iterator p = this->string_set_.begin();
|
||||||
p != this->string_set_.end();
|
p != this->string_set_.end();
|
||||||
++p)
|
++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);
|
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.
|
} // End namespace gold.
|
||||||
|
|
|
@ -14,7 +14,8 @@ namespace gold
|
||||||
|
|
||||||
class Output_file;
|
class Output_file;
|
||||||
|
|
||||||
class Stringpool
|
template<typename Stringpool_char>
|
||||||
|
class Stringpool_template
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// The type of a key into the stringpool. A key value will always
|
// 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.
|
// into an unordered hash table. Zero is never a valid key.
|
||||||
typedef size_t 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
|
// Add a string to the pool. This returns a canonical permanent
|
||||||
// pointer to the string. If PKEY is not NULL, this sets *PKEY to
|
// pointer to the string. If PKEY is not NULL, this sets *PKEY to
|
||||||
// the key for the string.
|
// the key for the string.
|
||||||
const char*
|
const Stringpool_char*
|
||||||
add(const char*, Key* pkey);
|
add(const Stringpool_char*, Key* pkey);
|
||||||
|
|
||||||
const char*
|
const Stringpool_char*
|
||||||
add(const std::string& s, Key* pkey)
|
add(const std::basic_string<Stringpool_char>& s, Key* pkey)
|
||||||
{ return this->add(s.c_str(), pkey); }
|
{ return this->add(s.c_str(), pkey); }
|
||||||
|
|
||||||
// Add the prefix of a string to the pool.
|
// Add the prefix of a string to the pool.
|
||||||
const char*
|
const Stringpool_char*
|
||||||
add(const char *, size_t, Key* pkey);
|
add(const Stringpool_char*, size_t, Key* pkey);
|
||||||
|
|
||||||
// If a string is present, return the canonical string. Otherwise,
|
// If a string is present, return the canonical string. Otherwise,
|
||||||
// return NULL. If PKEY is not NULL, set *PKEY to the key.
|
// return NULL. If PKEY is not NULL, set *PKEY to the key.
|
||||||
const char*
|
const Stringpool_char*
|
||||||
find(const char*, Key* pkey) const;
|
find(const Stringpool_char*, Key* pkey) const;
|
||||||
|
|
||||||
// Turn the stringpool into an ELF strtab: determine the offsets of
|
// Turn the stringpool into an ELF strtab: determine the offsets of
|
||||||
// all the strings.
|
// all the strings.
|
||||||
void
|
void
|
||||||
set_string_offsets();
|
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
|
off_t
|
||||||
get_offset(const char*) const;
|
get_offset(const Stringpool_char*) const;
|
||||||
|
|
||||||
off_t
|
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()); }
|
{ 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
|
off_t
|
||||||
get_strtab_size() const
|
get_strtab_size() const
|
||||||
{
|
{
|
||||||
|
@ -73,8 +78,12 @@ class Stringpool
|
||||||
write(Output_file*, off_t offset);
|
write(Output_file*, off_t offset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Stringpool(const Stringpool&);
|
Stringpool_template(const Stringpool_template&);
|
||||||
Stringpool& operator=(const Stringpool&);
|
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.
|
// We store the actual data in a list of these buffers.
|
||||||
struct Stringdata
|
struct Stringdata
|
||||||
|
@ -90,24 +99,24 @@ class Stringpool
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy a string into the buffers, returning a canonical string.
|
// Copy a string into the buffers, returning a canonical string.
|
||||||
const char*
|
const Stringpool_char*
|
||||||
add_string(const char*, Key*);
|
add_string(const Stringpool_char*, Key*);
|
||||||
|
|
||||||
struct Stringpool_hash
|
struct Stringpool_hash
|
||||||
{
|
{
|
||||||
size_t
|
size_t
|
||||||
operator()(const char*) const;
|
operator()(const Stringpool_char*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stringpool_eq
|
struct Stringpool_eq
|
||||||
{
|
{
|
||||||
bool
|
bool
|
||||||
operator()(const char* p1, const char* p2) const
|
operator()(const Stringpool_char* p1, const Stringpool_char* p2) const;
|
||||||
{ return strcmp(p1, p2) == 0; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return whether s1 is a suffix of s2.
|
// 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
|
// 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
|
// 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;
|
typedef std::pair<Key, off_t> Val;
|
||||||
|
|
||||||
#ifdef HAVE_TR1_UNORDERED_SET
|
#ifdef HAVE_TR1_UNORDERED_SET
|
||||||
typedef Unordered_map<const char*, Val, Stringpool_hash,
|
typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
|
||||||
Stringpool_eq,
|
Stringpool_eq,
|
||||||
std::allocator<std::pair<const char* const, Val> >,
|
std::allocator<std::pair<const Stringpool_char* const,
|
||||||
|
Val> >,
|
||||||
true> String_set_type;
|
true> String_set_type;
|
||||||
#else
|
#else
|
||||||
typedef Unordered_map<const char*, Val, Stringpool_hash,
|
typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
|
||||||
Stringpool_eq> String_set_type;
|
Stringpool_eq> String_set_type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -130,8 +140,8 @@ class Stringpool
|
||||||
struct Stringpool_sort_comparison
|
struct Stringpool_sort_comparison
|
||||||
{
|
{
|
||||||
bool
|
bool
|
||||||
operator()(String_set_type::iterator,
|
operator()(typename String_set_type::iterator,
|
||||||
String_set_type::iterator) const;
|
typename String_set_type::iterator) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// List of Stringdata structures.
|
// List of Stringdata structures.
|
||||||
|
@ -145,8 +155,13 @@ class Stringpool
|
||||||
off_t strtab_size_;
|
off_t strtab_size_;
|
||||||
// Next Stringdata index.
|
// Next Stringdata index.
|
||||||
unsigned int next_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.
|
} // End namespace gold.
|
||||||
|
|
||||||
#endif // !defined(GOLD_STRINGPOOL_H)
|
#endif // !defined(GOLD_STRINGPOOL_H)
|
||||||
|
|
|
@ -137,12 +137,13 @@ relocate_section(
|
||||||
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
|
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
|
||||||
|
|
||||||
const Sized_symbol<size>* sym;
|
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)
|
if (r_sym < local_count)
|
||||||
{
|
{
|
||||||
sym = NULL;
|
sym = NULL;
|
||||||
value = (*local_values)[r_sym];
|
psymval = &(*local_values)[r_sym];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -152,10 +153,15 @@ relocate_section(
|
||||||
gsym = relinfo->symtab->resolve_forwards(gsym);
|
gsym = relinfo->symtab->resolve_forwards(gsym);
|
||||||
|
|
||||||
sym = static_cast<const Sized_symbol<size>*>(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))
|
view + offset, view_address + offset, view_size))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue