New drop, with first cut of section layout code.
This commit is contained in:
parent
5ffff7c1d1
commit
a2fb1b05e4
19 changed files with 1479 additions and 171 deletions
|
@ -22,8 +22,10 @@ CCFILES = \
|
|||
fileread.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
layout.cc \
|
||||
object.cc \
|
||||
options.cc \
|
||||
output.cc \
|
||||
readsyms.cc \
|
||||
resolve.cc \
|
||||
symtab.cc \
|
||||
|
@ -36,13 +38,14 @@ HFILES = \
|
|||
fileread.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
layout.h \
|
||||
object.h \
|
||||
options.h \
|
||||
output.h \
|
||||
readsyms.h \
|
||||
stringpool.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
target-select.h \
|
||||
workqueue.h
|
||||
|
||||
|
|
|
@ -66,10 +66,10 @@ CONFIG_HEADER = config.h
|
|||
CONFIG_CLEAN_FILES = po/Makefile.in
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
|
||||
gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
|
||||
readsyms.$(OBJEXT) resolve.$(OBJEXT) symtab.$(OBJEXT) \
|
||||
stringpool.$(OBJEXT) target-select.$(OBJEXT) \
|
||||
workqueue.$(OBJEXT)
|
||||
gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
|
||||
options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
|
||||
resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
|
||||
target-select.$(OBJEXT) workqueue.$(OBJEXT)
|
||||
am__objects_2 =
|
||||
am__objects_3 = i386.$(OBJEXT)
|
||||
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
|
||||
|
@ -233,8 +233,10 @@ CCFILES = \
|
|||
fileread.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
layout.cc \
|
||||
object.cc \
|
||||
options.cc \
|
||||
output.cc \
|
||||
readsyms.cc \
|
||||
resolve.cc \
|
||||
symtab.cc \
|
||||
|
@ -247,13 +249,14 @@ HFILES = \
|
|||
fileread.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
layout.h \
|
||||
object.h \
|
||||
options.h \
|
||||
output.h \
|
||||
readsyms.h \
|
||||
stringpool.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
target-select.h \
|
||||
workqueue.h
|
||||
|
||||
|
@ -340,8 +343,10 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.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)/object.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
|
||||
|
|
|
@ -173,22 +173,6 @@ class File_view
|
|||
const unsigned char* data_;
|
||||
};
|
||||
|
||||
// An object which locks a file using RAII.
|
||||
|
||||
class File_read_lock
|
||||
{
|
||||
public:
|
||||
File_read_lock(File_read& file)
|
||||
: file_(file)
|
||||
{ this->file_.lock(); }
|
||||
|
||||
~File_read_lock()
|
||||
{ this->file_.unlock(); }
|
||||
|
||||
private:
|
||||
File_read& file_;
|
||||
};
|
||||
|
||||
// All the information we hold for a single input file. This can be
|
||||
// an object file, a shared library, or an archive.
|
||||
|
||||
|
|
17
gold/gold.cc
17
gold/gold.cc
|
@ -12,6 +12,7 @@
|
|||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
#include "symtab.h"
|
||||
#include "layout.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -66,7 +67,8 @@ void
|
|||
queue_initial_tasks(const General_options& options,
|
||||
const Dirsearch& search_path,
|
||||
const Command_line::Input_argument_list& inputs,
|
||||
Workqueue* workqueue, Symbol_table* symtab)
|
||||
Workqueue* workqueue, Object_list* input_objects,
|
||||
Symbol_table* symtab)
|
||||
{
|
||||
if (inputs.empty())
|
||||
gold_fatal(_("no input files"), false);
|
||||
|
@ -82,12 +84,13 @@ queue_initial_tasks(const General_options& options,
|
|||
{
|
||||
Task_token* next_blocker = new Task_token();
|
||||
next_blocker->add_blocker();
|
||||
workqueue->queue(new Read_symbols(options, symtab, search_path,
|
||||
*p, this_blocker, next_blocker));
|
||||
workqueue->queue(new Read_symbols(options, input_objects, symtab,
|
||||
search_path, *p, this_blocker,
|
||||
next_blocker));
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
|
||||
// workqueue->queue(new Layout(options, inputs, this_blocker));
|
||||
workqueue->queue(new Layout_task(options, input_objects, this_blocker));
|
||||
}
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
@ -113,6 +116,9 @@ main(int argc, char** argv)
|
|||
// The work queue.
|
||||
gold::Workqueue workqueue(command_line.options());
|
||||
|
||||
// The list of input objects.
|
||||
Object_list input_objects;
|
||||
|
||||
// The symbol table.
|
||||
Symbol_table symtab;
|
||||
|
||||
|
@ -122,7 +128,8 @@ main(int argc, char** argv)
|
|||
|
||||
// Queue up the first set of tasks.
|
||||
queue_initial_tasks(command_line.options(), search_path,
|
||||
command_line.inputs(), &workqueue, &symtab);
|
||||
command_line.inputs(), &workqueue, &input_objects,
|
||||
&symtab);
|
||||
|
||||
// Run the main task processing loop.
|
||||
workqueue.process();
|
||||
|
|
432
gold/layout.cc
Normal file
432
gold/layout.cc
Normal file
|
@ -0,0 +1,432 @@
|
|||
// layout.cc -- lay out output file sections for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "output.h"
|
||||
#include "layout.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Layout_task methods.
|
||||
|
||||
Layout_task::~Layout_task()
|
||||
{
|
||||
}
|
||||
|
||||
// This task can be run when it is unblocked.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Layout_task::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->this_blocker_->is_blocked())
|
||||
return IS_BLOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
// We don't need to hold any locks for the duration of this task. In
|
||||
// fact this task will be the only one running.
|
||||
|
||||
Task_locker*
|
||||
Layout_task::locks(Workqueue*)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Lay out the sections. This is called after all the input objects
|
||||
// have been read.
|
||||
|
||||
void
|
||||
Layout_task::run(Workqueue*)
|
||||
{
|
||||
Layout layout(this->options_);
|
||||
for (Object_list::const_iterator p = this->input_objects_->begin();
|
||||
p != this->input_objects_->end();
|
||||
++p)
|
||||
(*p)->layout(&layout);
|
||||
}
|
||||
|
||||
// Layout methods.
|
||||
|
||||
// Hash a key we use to look up an output section mapping.
|
||||
|
||||
size_t
|
||||
Layout::Hash_key::operator()(const Layout::Key& k) const
|
||||
{
|
||||
return reinterpret_cast<size_t>(k.first) + k.second.first + k.second.second;
|
||||
}
|
||||
|
||||
// Whether to include this section in the link.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
Layout::include_section(Object*, const char*,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr)
|
||||
{
|
||||
// Some section types are never linked. Some are only linked when
|
||||
// doing a relocateable link.
|
||||
switch (shdr.get_sh_type())
|
||||
{
|
||||
case elfcpp::SHT_NULL:
|
||||
case elfcpp::SHT_SYMTAB:
|
||||
case elfcpp::SHT_DYNSYM:
|
||||
case elfcpp::SHT_STRTAB:
|
||||
case elfcpp::SHT_HASH:
|
||||
case elfcpp::SHT_DYNAMIC:
|
||||
case elfcpp::SHT_SYMTAB_SHNDX:
|
||||
return false;
|
||||
|
||||
case elfcpp::SHT_RELA:
|
||||
case elfcpp::SHT_REL:
|
||||
case elfcpp::SHT_GROUP:
|
||||
return this->options_.is_relocatable();
|
||||
|
||||
default:
|
||||
// FIXME: Handle stripping debug sections here.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the output section to use for input section NAME, with
|
||||
// header HEADER, from object OBJECT. Set *OFF to the offset of this
|
||||
// input section without the output section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
Layout::layout(Object* object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
|
||||
{
|
||||
if (!this->include_section(object, name, shdr))
|
||||
return NULL;
|
||||
|
||||
// Unless we are doing a relocateable link, .gnu.linkonce sections
|
||||
// are laid out as though they were named for the sections are
|
||||
// placed into.
|
||||
if (!this->options_.is_relocatable() && Layout::is_linkonce(name))
|
||||
name = Layout::linkonce_output_name(name);
|
||||
|
||||
// FIXME: Handle SHF_OS_NONCONFORMING here.
|
||||
|
||||
// Canonicalize the section name.
|
||||
name = this->namepool_.add(name);
|
||||
|
||||
// Find the output section. The output section is selected based on
|
||||
// the section name, type, and flags.
|
||||
|
||||
// FIXME: If we want to do relaxation, we need to modify this
|
||||
// algorithm. We also build a list of input sections for each
|
||||
// output section. Then we relax all the input sections. Then we
|
||||
// walk down the list and adjust all the offsets.
|
||||
|
||||
elfcpp::Elf_Word type = shdr.get_sh_type();
|
||||
elfcpp::Elf_Xword flags = shdr.get_sh_flags();
|
||||
const Key key(name, std::make_pair(type, flags));
|
||||
const std::pair<Key, Output_section*> v(key, NULL);
|
||||
std::pair<Section_name_map::iterator, bool> ins(
|
||||
this->section_name_map_.insert(v));
|
||||
|
||||
Output_section* os;
|
||||
if (!ins.second)
|
||||
os = ins.first->second;
|
||||
else
|
||||
{
|
||||
// This is the first time we've seen this name/type/flags
|
||||
// combination.
|
||||
os = this->make_output_section(name, type, flags);
|
||||
ins.first->second = os;
|
||||
}
|
||||
|
||||
// FIXME: Handle SHF_LINK_ORDER somewhere.
|
||||
|
||||
*off = os->add_input_section(object, name, shdr);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Return whether SEG1 should be before SEG2 in the output file. This
|
||||
// is based entirely on the segment type and flags. When this is
|
||||
// called the segment addresses has normally not yet been set.
|
||||
|
||||
bool
|
||||
Layout::segment_precedes(const Output_segment* seg1,
|
||||
const Output_segment* seg2)
|
||||
{
|
||||
elfcpp::Elf_Word type1 = seg1->type();
|
||||
elfcpp::Elf_Word type2 = seg2->type();
|
||||
|
||||
// The single PT_PHDR segment is required to precede any loadable
|
||||
// segment. We simply make it always first.
|
||||
if (type1 == elfcpp::PT_PHDR)
|
||||
{
|
||||
assert(type2 != elfcpp::PT_PHDR);
|
||||
return true;
|
||||
}
|
||||
if (type2 == elfcpp::PT_PHDR)
|
||||
return false;
|
||||
|
||||
// The single PT_INTERP segment is required to precede any loadable
|
||||
// segment. We simply make it always second.
|
||||
if (type1 == elfcpp::PT_INTERP)
|
||||
{
|
||||
assert(type2 != elfcpp::PT_INTERP);
|
||||
return true;
|
||||
}
|
||||
if (type2 == elfcpp::PT_INTERP)
|
||||
return false;
|
||||
|
||||
// We then put PT_LOAD segments before any other segments.
|
||||
if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD)
|
||||
return true;
|
||||
if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
|
||||
return false;
|
||||
|
||||
const elfcpp::Elf_Word flags1 = seg1->flags();
|
||||
const elfcpp::Elf_Word flags2 = seg2->flags();
|
||||
|
||||
// The order of non-PT_LOAD segments is unimportant. We simply sort
|
||||
// by the numeric segment type and flags values. There should not
|
||||
// be more than one segment with the same type and flags.
|
||||
if (type1 != elfcpp::PT_LOAD)
|
||||
{
|
||||
if (type1 != type2)
|
||||
return type1 < type2;
|
||||
assert(flags1 != flags2);
|
||||
return flags1 < flags2;
|
||||
}
|
||||
|
||||
// We sort PT_LOAD segments based on the flags. Readonly segments
|
||||
// come before writable segments. Then executable segments come
|
||||
// before non-executable segments. Then the unlikely case of a
|
||||
// non-readable segment comes before the normal case of a readable
|
||||
// segment. If there are multiple segments with the same type and
|
||||
// flags, we require that the address be set, and we sort by
|
||||
// virtual address and then physical address.
|
||||
if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W))
|
||||
return (flags1 & elfcpp::PF_W) == 0;
|
||||
if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X))
|
||||
return (flags1 & elfcpp::PF_X) != 0;
|
||||
if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
|
||||
return (flags1 & elfcpp::PF_R) == 0;
|
||||
|
||||
uint64_t vaddr1 = seg1->vaddr();
|
||||
uint64_t vaddr2 = seg2->vaddr();
|
||||
if (vaddr1 != vaddr2)
|
||||
return vaddr1 < vaddr2;
|
||||
|
||||
uint64_t paddr1 = seg1->paddr();
|
||||
uint64_t paddr2 = seg2->paddr();
|
||||
assert(paddr1 != paddr2);
|
||||
return paddr1 < paddr2;
|
||||
}
|
||||
|
||||
// Map section flags to segment flags.
|
||||
|
||||
elfcpp::Elf_Word
|
||||
Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
|
||||
{
|
||||
elfcpp::Elf_Word ret = elfcpp::PF_R;
|
||||
if ((flags & elfcpp::SHF_WRITE) != 0)
|
||||
ret |= elfcpp::PF_W;
|
||||
if ((flags & elfcpp::SHF_EXECINSTR) != 0)
|
||||
ret |= elfcpp::PF_X;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Make a new Output_section, and attach it to segments as
|
||||
// appropriate.
|
||||
|
||||
Output_section*
|
||||
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags)
|
||||
{
|
||||
Output_section* os = new Output_section(name, type, flags);
|
||||
|
||||
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
||||
this->section_list_.push_back(os);
|
||||
else
|
||||
{
|
||||
// This output section goes into a PT_LOAD segment.
|
||||
|
||||
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
|
||||
|
||||
// The only thing we really care about for PT_LOAD segments is
|
||||
// whether or not they are writable, so that is how we search
|
||||
// for them. People who need segments sorted on some other
|
||||
// basis will have to wait until we implement a mechanism for
|
||||
// them to describe the segments they want.
|
||||
|
||||
Segment_list::const_iterator p;
|
||||
for (p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_LOAD
|
||||
&& ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
|
||||
{
|
||||
(*p)->add_output_section(os);
|
||||
if ((*p)->flags() != seg_flags)
|
||||
(*p)->update_flags(seg_flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
oseg->add_output_section(os);
|
||||
}
|
||||
|
||||
// If we see a loadable SHT_NOTE section, we create a PT_NOTE
|
||||
// segment.
|
||||
if (type == elfcpp::SHT_NOTE)
|
||||
{
|
||||
// See if we already have an equivalent PT_NOTE segment.
|
||||
for (p = this->segment_list_.begin();
|
||||
p != segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_NOTE
|
||||
&& (((*p)->flags() & elfcpp::PF_W)
|
||||
== (seg_flags & elfcpp::PF_W)))
|
||||
{
|
||||
(*p)->add_output_section(os);
|
||||
if ((*p)->flags() != seg_flags)
|
||||
(*p)->update_flags(seg_flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
oseg->add_output_section(os);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// The mapping of .gnu.linkonce section names to real section names.
|
||||
|
||||
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t }
|
||||
const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
|
||||
{
|
||||
MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Must be before "d".
|
||||
MAPPING_INIT("t", ".text"),
|
||||
MAPPING_INIT("r", ".rodata"),
|
||||
MAPPING_INIT("d", ".data"),
|
||||
MAPPING_INIT("b", ".bss"),
|
||||
MAPPING_INIT("s", ".sdata"),
|
||||
MAPPING_INIT("sb", ".sbss"),
|
||||
MAPPING_INIT("s2", ".sdata2"),
|
||||
MAPPING_INIT("sb2", ".sbss2"),
|
||||
MAPPING_INIT("wi", ".debug_info"),
|
||||
MAPPING_INIT("td", ".tdata"),
|
||||
MAPPING_INIT("tb", ".tbss"),
|
||||
MAPPING_INIT("lr", ".lrodata"),
|
||||
MAPPING_INIT("l", ".ldata"),
|
||||
MAPPING_INIT("lb", ".lbss"),
|
||||
};
|
||||
#undef MAPPING_INIT
|
||||
|
||||
const int Layout::linkonce_mapping_count =
|
||||
sizeof(Layout::linkonce_mapping) / sizeof(Layout::linkonce_mapping[0]);
|
||||
|
||||
// Return the name of the output section to use for a .gnu.linkonce
|
||||
// section. This is based on the default ELF linker script of the old
|
||||
// GNU linker. For example, we map a name like ".gnu.linkonce.t.foo"
|
||||
// to ".text".
|
||||
|
||||
const char*
|
||||
Layout::linkonce_output_name(const char* name)
|
||||
{
|
||||
const char* s = name + sizeof(".gnu.linkonce") - 1;
|
||||
if (*s != '.')
|
||||
return name;
|
||||
++s;
|
||||
const Linkonce_mapping* plm = linkonce_mapping;
|
||||
for (int i = 0; i < linkonce_mapping_count; ++i, ++plm)
|
||||
{
|
||||
if (strncmp(s, plm->from, plm->fromlen) == 0 && s[plm->fromlen] == '.')
|
||||
return plm->to;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// Record the signature of a comdat section, and return whether to
|
||||
// include it in the link. If GROUP is true, this is a regular
|
||||
// section group. If GROUP is false, this is a group signature
|
||||
// derived from the name of a linkonce section. We want linkonce
|
||||
// signatures and group signatures to block each other, but we don't
|
||||
// want a linkonce signature to block another linkonce signature.
|
||||
|
||||
bool
|
||||
Layout::add_comdat(const char* signature, bool group)
|
||||
{
|
||||
std::string sig(signature);
|
||||
std::pair<Signatures::iterator, bool> ins(
|
||||
this->signatures_.insert(std::make_pair(signature, group)));
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
// This is the first time we've seen this signature.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ins.first->second)
|
||||
{
|
||||
// We've already seen a real section group with this signature.
|
||||
return false;
|
||||
}
|
||||
else if (group)
|
||||
{
|
||||
// This is a real section group, and we've already seen a
|
||||
// linkonce section with tihs signature. Record that we've seen
|
||||
// a section group, and don't include this section group.
|
||||
ins.first->second = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've already seen a linkonce section and this is a linkonce
|
||||
// section. These don't block each other--this may be the same
|
||||
// symbol name with different section types.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones for implemented targets.
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<32, false>(Object* object, const char* name,
|
||||
const elfcpp::Shdr<32, false>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<32, true>(Object* object, const char* name,
|
||||
const elfcpp::Shdr<32, true>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<64, false>(Object* object, const char* name,
|
||||
const elfcpp::Shdr<64, false>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<64, true>(Object* object, const char* name,
|
||||
const elfcpp::Shdr<64, true>& shdr, off_t*);
|
||||
|
||||
|
||||
} // End namespace gold.
|
181
gold/layout.h
Normal file
181
gold/layout.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
// layout.h -- lay out output file sections for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_LAYOUT_H
|
||||
#define GOLD_LAYOUT_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "options.h"
|
||||
#include "workqueue.h"
|
||||
#include "object.h"
|
||||
#include "stringpool.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Output_section;
|
||||
class Output_segment;
|
||||
|
||||
// This Task handles mapping the input sections to output sections and
|
||||
// laying them out in memory.
|
||||
|
||||
class Layout_task : public Task
|
||||
{
|
||||
public:
|
||||
// OPTIONS is the command line options, INPUT_OBJECTS is the list of
|
||||
// input objects, THIS_BLOCKER is a token which blocks this task
|
||||
// from executing until all the input symbols have been read.
|
||||
Layout_task(const General_options& options, const Object_list* input_objects,
|
||||
Task_token* this_blocker)
|
||||
: options_(options), input_objects_(input_objects),
|
||||
this_blocker_(this_blocker)
|
||||
{ }
|
||||
|
||||
~Layout_task();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
Layout_task(const Layout_task&);
|
||||
Layout_task& operator=(const Layout_task&);
|
||||
|
||||
const General_options& options_;
|
||||
const Object_list* input_objects_;
|
||||
Task_token* this_blocker_;
|
||||
};
|
||||
|
||||
// This class handles the details of laying out input sections.
|
||||
|
||||
class Layout
|
||||
{
|
||||
public:
|
||||
Layout(const General_options& options)
|
||||
: options_(options), namepool_(), signatures_(),
|
||||
section_name_map_(), segment_list_()
|
||||
{ }
|
||||
|
||||
// Given an input section named NAME with data in SHDR from the
|
||||
// object file OBJECT, return the output section where this input
|
||||
// section should go. Set *OFFSET to the offset within the output
|
||||
// section.
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
layout(Object *object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
|
||||
|
||||
// Return whether a section is a .gnu.linkonce section, given the
|
||||
// section name.
|
||||
static inline bool
|
||||
is_linkonce(const char* name)
|
||||
{ return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
|
||||
|
||||
// Record the signature of a comdat section, and return whether to
|
||||
// include it in the link. The GROUP parameter is true for a
|
||||
// section group signature, false for a signature derived from a
|
||||
// .gnu.linkonce section.
|
||||
bool
|
||||
add_comdat(const char*, bool group);
|
||||
|
||||
private:
|
||||
Layout(const Layout&);
|
||||
Layout& operator=(const Layout&);
|
||||
|
||||
// Mapping from .gnu.linkonce section names to output section names.
|
||||
struct Linkonce_mapping
|
||||
{
|
||||
const char* from;
|
||||
int fromlen;
|
||||
const char* to;
|
||||
};
|
||||
static const Linkonce_mapping linkonce_mapping[];
|
||||
static const int linkonce_mapping_count;
|
||||
|
||||
// Return whether to include this section in the link.
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
include_section(Object* object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>&);
|
||||
|
||||
// Return the output section name to use for a linkonce section
|
||||
// name.
|
||||
static const char*
|
||||
linkonce_output_name(const char* name);
|
||||
|
||||
// Create a new Output_section.
|
||||
Output_section*
|
||||
make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags);
|
||||
|
||||
// Return whether SEG1 comes before SEG2 in the output file.
|
||||
static bool
|
||||
Layout::segment_precedes(const Output_segment* seg1,
|
||||
const Output_segment* seg2);
|
||||
|
||||
// Map from section flags to segment flags.
|
||||
static elfcpp::Elf_Word
|
||||
section_flags_to_segment(elfcpp::Elf_Xword flags);
|
||||
|
||||
// A mapping used for group signatures.
|
||||
typedef Unordered_map<std::string, bool> Signatures;
|
||||
|
||||
// Mapping from input section name/type/flags to output section. We
|
||||
// use canonicalized strings here.
|
||||
|
||||
typedef std::pair<const char*,
|
||||
std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key;
|
||||
|
||||
struct Hash_key
|
||||
{
|
||||
size_t
|
||||
operator()(const Key& k) const;
|
||||
};
|
||||
|
||||
typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
|
||||
|
||||
// A comparison class for segments.
|
||||
|
||||
struct Compare_segments
|
||||
{
|
||||
bool
|
||||
operator()(const Output_segment* seg1, const Output_segment* seg2)
|
||||
{ return Layout::segment_precedes(seg1, seg2); }
|
||||
};
|
||||
|
||||
// The list of segments.
|
||||
|
||||
typedef std::list<Output_segment*> Segment_list;
|
||||
|
||||
// The list of sections not attached to a segment.
|
||||
|
||||
typedef std::list<Output_section*> Section_list;
|
||||
|
||||
// A reference to the options on the command line.
|
||||
const General_options& options_;
|
||||
// The output section names.
|
||||
Stringpool namepool_;
|
||||
// The list of group sections and linkonce sections which we have seen.
|
||||
Signatures signatures_;
|
||||
// The mapping from input section name/type/flags to output sections.
|
||||
Section_name_map section_name_map_;
|
||||
// The list of output segments.
|
||||
Segment_list segment_list_;
|
||||
// The list of output sections which are not attached to any output
|
||||
// segment.
|
||||
Section_list section_list_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_LAYOUT_H)
|
262
gold/object.cc
262
gold/object.cc
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "object.h"
|
||||
#include "target-select.h"
|
||||
#include "layout.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -42,28 +43,24 @@ Sized_object<size, big_endian>::Sized_object(
|
|||
off_t offset,
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Object(name, input_file, false, offset),
|
||||
osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
|
||||
abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
|
||||
machine_(ehdr.get_e_machine()),
|
||||
flags_(ehdr.get_e_flags()),
|
||||
shoff_(ehdr.get_e_shoff()),
|
||||
shnum_(0),
|
||||
shstrndx_(0),
|
||||
symtab_shnum_(0),
|
||||
symbols_(NULL)
|
||||
{
|
||||
if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
|
||||
if (ehdr.get_e_ehsize() != This::ehdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad e_ehsize field (%d != %d)\n"),
|
||||
program_name, this->name().c_str(), ehdr.get_e_ehsize(),
|
||||
elfcpp::Elf_sizes<size>::ehdr_size);
|
||||
This::ehdr_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
if (ehdr.get_e_shentsize() != elfcpp::Elf_sizes<size>::shdr_size)
|
||||
if (ehdr.get_e_shentsize() != This::shdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad e_shentsize field (%d != %d)\n"),
|
||||
program_name, this->name().c_str(), ehdr.get_e_shentsize(),
|
||||
elfcpp::Elf_sizes<size>::shdr_size);
|
||||
This::shdr_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
@ -81,12 +78,14 @@ void
|
|||
Sized_object<size, big_endian>::setup(
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
{
|
||||
Target* target = select_target(this->machine_, size, big_endian,
|
||||
this->osabi_, this->abiversion_);
|
||||
int machine = ehdr.get_e_machine();
|
||||
Target* target = select_target(machine, size, big_endian,
|
||||
ehdr.get_e_ident()[elfcpp::EI_OSABI],
|
||||
ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
|
||||
if (target == NULL)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported ELF machine number %d\n"),
|
||||
program_name, this->name().c_str(), this->machine_);
|
||||
program_name, this->name().c_str(), machine);
|
||||
gold_exit(false);
|
||||
}
|
||||
this->set_target(target);
|
||||
|
@ -95,25 +94,24 @@ Sized_object<size, big_endian>::setup(
|
|||
if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
|
||||
&& this->shoff_ != 0)
|
||||
{
|
||||
const unsigned char* p = this->get_view
|
||||
(this->shoff_, elfcpp::Elf_sizes<size>::shdr_size);
|
||||
const unsigned char* p = this->get_view (this->shoff_, This::shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
if (shnum == 0)
|
||||
shnum = shdr.get_sh_size();
|
||||
if (shstrndx == elfcpp::SHN_XINDEX)
|
||||
shstrndx = shdr.get_sh_link();
|
||||
}
|
||||
this->shnum_ = shnum;
|
||||
this->set_shnum(shnum);
|
||||
this->shstrndx_ = shstrndx;
|
||||
|
||||
if (shnum == 0)
|
||||
return;
|
||||
|
||||
// Find the SHT_SYMTAB section.
|
||||
const unsigned char* p = this->get_view
|
||||
(this->shoff_, shnum * elfcpp::Elf_sizes<size>::shdr_size);
|
||||
const unsigned char* p = this->get_view (this->shoff_,
|
||||
shnum * This::shdr_size);
|
||||
// Skip the first section, which is always empty.
|
||||
p += elfcpp::Elf_sizes<size>::shdr_size;
|
||||
p += This::shdr_size;
|
||||
for (unsigned int i = 1; i < shnum; ++i)
|
||||
{
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
|
@ -122,7 +120,7 @@ Sized_object<size, big_endian>::setup(
|
|||
this->symtab_shnum_ = i;
|
||||
break;
|
||||
}
|
||||
p += elfcpp::Elf_sizes<size>::shdr_size;
|
||||
p += This::shdr_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,7 +141,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
|||
return ret;
|
||||
}
|
||||
|
||||
int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
const int shdr_size = This::shdr_size;
|
||||
|
||||
// Read the symbol table section header.
|
||||
off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
|
||||
|
@ -152,7 +150,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
|||
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// We only need the external symbols.
|
||||
int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
const int sym_size = This::sym_size;
|
||||
off_t locsize = symtabshdr.get_sh_info() * sym_size;
|
||||
off_t extoff = symtabshdr.get_sh_offset() + locsize;
|
||||
off_t extsize = symtabshdr.get_sh_size() - locsize;
|
||||
|
@ -162,7 +160,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
|||
|
||||
// Read the section header for the symbol names.
|
||||
unsigned int strtab_shnum = symtabshdr.get_sh_link();
|
||||
if (strtab_shnum == 0 || strtab_shnum >= this->shnum_)
|
||||
if (strtab_shnum == 0 || strtab_shnum >= this->shnum())
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
|
||||
program_name, this->name().c_str(), strtab_shnum);
|
||||
|
@ -206,7 +204,7 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
|||
return;
|
||||
}
|
||||
|
||||
unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
const int sym_size = This::sym_size;
|
||||
size_t symcount = sd.symbols_size / sym_size;
|
||||
if (symcount * sym_size != sd.symbols_size)
|
||||
{
|
||||
|
@ -224,6 +222,226 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
|||
reinterpret_cast<const char*>(sd.symbol_names->data());
|
||||
symtab->add_from_object(this, syms, symcount, sym_names,
|
||||
sd.symbol_names_size, this->symbols_);
|
||||
|
||||
delete sd.symbols;
|
||||
delete sd.symbol_names;
|
||||
}
|
||||
|
||||
// Return whether to include a section group in the link. LAYOUT is
|
||||
// used to keep track of which section groups we have already seen.
|
||||
// INDEX is the index of the section group and SHDR is the section
|
||||
// header. If we do not want to include this group, we set bits in
|
||||
// OMIT for each section which should be discarded.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
Sized_object<size, big_endian>::include_section_group(
|
||||
Layout* layout,
|
||||
unsigned int index,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
std::vector<bool>* omit)
|
||||
{
|
||||
// Read the section contents.
|
||||
const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
|
||||
shdr.get_sh_size());
|
||||
const elfcpp::Elf_Word* pword =
|
||||
reinterpret_cast<const elfcpp::Elf_Word*>(pcon);
|
||||
|
||||
// The first word contains flags. We only care about COMDAT section
|
||||
// groups. Other section groups are always included in the link
|
||||
// just like ordinary sections.
|
||||
elfcpp::Elf_Word flags = elfcpp::read_elf_word<big_endian>(pword);
|
||||
if ((flags & elfcpp::GRP_COMDAT) == 0)
|
||||
return true;
|
||||
|
||||
// Look up the group signature, which is the name of a symbol. This
|
||||
// is a lot of effort to go to to read a string. Why didn't they
|
||||
// just use the name of the SHT_GROUP section as the group
|
||||
// signature?
|
||||
|
||||
// Get the appropriate symbol table header (this will normally be
|
||||
// the single SHT_SYMTAB section, but in principle it need not be).
|
||||
if (shdr.get_sh_link() >= this->shnum())
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: section group %u link %u out of range\n"),
|
||||
program_name, this->name().c_str(), index, shdr.get_sh_link());
|
||||
gold_exit(false);
|
||||
}
|
||||
off_t off = this->shoff_ + shdr.get_sh_link() * This::shdr_size;
|
||||
const unsigned char* psymshdr = this->get_view(off, This::shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> symshdr(psymshdr);
|
||||
|
||||
// Read the symbol table entry.
|
||||
if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: section group %u info %u out of range\n"),
|
||||
program_name, this->name().c_str(), index, shdr.get_sh_info());
|
||||
gold_exit(false);
|
||||
}
|
||||
off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
|
||||
const unsigned char* psym = this->get_view(symoff, This::sym_size);
|
||||
elfcpp::Sym<size, big_endian> sym(psym);
|
||||
|
||||
// Read the section header for the symbol table names.
|
||||
if (symshdr.get_sh_link() >= this->shnum())
|
||||
{
|
||||
fprintf(stderr, _("%s; %s: symtab section %u link %u out of range\n"),
|
||||
program_name, this->name().c_str(), shdr.get_sh_link(),
|
||||
symshdr.get_sh_link());
|
||||
gold_exit(false);
|
||||
}
|
||||
off_t symnameoff = this->shoff_ + symshdr.get_sh_link() * This::shdr_size;
|
||||
const unsigned char* psymnamehdr = this->get_view(symnameoff,
|
||||
This::shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> symnamehdr(psymnamehdr);
|
||||
|
||||
// Read the symbol table names.
|
||||
const unsigned char *psymnamesu = this->get_view(symnamehdr.get_sh_offset(),
|
||||
symnamehdr.get_sh_size());
|
||||
const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
|
||||
|
||||
// Get the section group signature.
|
||||
if (sym.get_st_name() >= symnamehdr.get_sh_size())
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: symbol %u name offset %u out of range\n"),
|
||||
program_name, this->name().c_str(), shdr.get_sh_info(),
|
||||
sym.get_st_name());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
const char* signature = psymnames + sym.get_st_name();
|
||||
|
||||
// Record this section group, and see whether we've already seen one
|
||||
// with the same signature.
|
||||
if (layout->add_comdat(signature, true))
|
||||
return true;
|
||||
|
||||
// This is a duplicate. We want to discard the sections in this
|
||||
// group.
|
||||
size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
|
||||
for (size_t i = 1; i < count; ++i)
|
||||
{
|
||||
elfcpp::Elf_Word secnum = elfcpp::read_elf_word<big_endian>(pword + i);
|
||||
if (secnum >= this->shnum())
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: section %u in section group %u out of range"),
|
||||
program_name, this->name().c_str(), secnum,
|
||||
index);
|
||||
gold_exit(false);
|
||||
}
|
||||
(*omit)[secnum] = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Whether to include a linkonce section in the link. NAME is the
|
||||
// name of the section and SHDR is the section header.
|
||||
|
||||
// Linkonce sections are a GNU extension implemented in the original
|
||||
// GNU linker before section groups were defined. The semantics are
|
||||
// that we only include one linkonce section with a given name. The
|
||||
// name of a linkonce section is normally .gnu.linkonce.T.SYMNAME,
|
||||
// where T is the type of section and SYMNAME is the name of a symbol.
|
||||
// In an attempt to make linkonce sections interact well with section
|
||||
// groups, we try to identify SYMNAME and use it like a section group
|
||||
// signature. We want to block section groups with that signature,
|
||||
// but not other linkonce sections with that signature. We also use
|
||||
// the full name of the linkonce section as a normal section group
|
||||
// signature.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
Sized_object<size, big_endian>::include_linkonce_section(
|
||||
Layout* layout,
|
||||
const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>&)
|
||||
{
|
||||
const char* symname = strrchr(name, '.') + 1;
|
||||
bool omit1 = layout->add_comdat(symname, false);
|
||||
bool omit2 = layout->add_comdat(name, true);
|
||||
return omit1 || omit2;
|
||||
}
|
||||
|
||||
// Lay out the input sections. We walk through the sections and check
|
||||
// whether they should be included in the link. If they should, we
|
||||
// pass them to the Layout object, which will return an output section
|
||||
// and an offset.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_object<size, big_endian>::do_layout(Layout* layout)
|
||||
{
|
||||
// This is always called from the main thread. Lock the file to
|
||||
// keep the error checks happy.
|
||||
Task_locker_obj<File_read> frl(this->input_file()->file());
|
||||
|
||||
// Get the section headers.
|
||||
unsigned int shnum = this->shnum();
|
||||
const unsigned char* pshdrs = this->get_view(this->shoff_,
|
||||
shnum * This::shdr_size);
|
||||
|
||||
// Get the section names.
|
||||
const unsigned char* pshdrnames = pshdrs + this->shstrndx_ * This::shdr_size;
|
||||
elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword names_size =
|
||||
shdrnames.get_sh_size();
|
||||
const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(),
|
||||
shdrnames.get_sh_size());
|
||||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||
|
||||
std::vector<Map_to_output>& map_sections(this->map_to_output());
|
||||
map_sections.reserve(shnum);
|
||||
|
||||
// Keep track of which sections to omit.
|
||||
std::vector<bool> omit(shnum, false);
|
||||
|
||||
for (unsigned int i = 0; i < shnum; ++i)
|
||||
{
|
||||
elfcpp::Shdr<size, big_endian> shdr(pshdrs);
|
||||
|
||||
if (shdr.get_sh_name() >= names_size)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: bad section name offset for section %u: %lu\n"),
|
||||
program_name, this->name().c_str(), i,
|
||||
static_cast<unsigned long>(shdr.get_sh_name()));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
const char* name = pnames + shdr.get_sh_name();
|
||||
|
||||
bool discard = omit[i];
|
||||
if (!discard)
|
||||
{
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
|
||||
{
|
||||
if (!this->include_section_group(layout, i, shdr, &omit))
|
||||
discard = true;
|
||||
}
|
||||
else if (Layout::is_linkonce(name))
|
||||
{
|
||||
if (!this->include_linkonce_section(layout, name, shdr))
|
||||
discard = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (discard)
|
||||
{
|
||||
// Do not include this section in the link.
|
||||
map_sections[i].output_section = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
off_t offset;
|
||||
Output_section* os = layout->layout(this, name, shdr, &offset);
|
||||
|
||||
map_sections[i].output_section = os;
|
||||
map_sections[i].offset = offset;
|
||||
|
||||
pshdrs += This::shdr_size;
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
|
122
gold/object.h
122
gold/object.h
|
@ -4,6 +4,7 @@
|
|||
#define GOLD_OBJECT_H
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "fileread.h"
|
||||
|
@ -13,6 +14,9 @@
|
|||
namespace gold
|
||||
{
|
||||
|
||||
class Output_section;
|
||||
class Layout;
|
||||
|
||||
// Data to pass from read_symbols() to add_symbols().
|
||||
|
||||
struct Read_symbols_data
|
||||
|
@ -42,7 +46,8 @@ class Object
|
|||
Object(const std::string& name, Input_file* input_file, bool is_dynamic,
|
||||
off_t offset = 0)
|
||||
: name_(name), input_file_(input_file), offset_(offset),
|
||||
is_dynamic_(is_dynamic), target_(NULL)
|
||||
shnum_(0), is_dynamic_(is_dynamic), target_(NULL),
|
||||
map_to_output_()
|
||||
{ }
|
||||
|
||||
virtual ~Object()
|
||||
|
@ -58,6 +63,33 @@ class Object
|
|||
is_dynamic() const
|
||||
{ return this->is_dynamic_; }
|
||||
|
||||
// Return the target structure associated with this object.
|
||||
Target*
|
||||
target() const
|
||||
{ return this->target_; }
|
||||
|
||||
// Lock the underlying file.
|
||||
void
|
||||
lock()
|
||||
{ this->input_file_->file().lock(); }
|
||||
|
||||
// Unlock the underlying file.
|
||||
void
|
||||
unlock()
|
||||
{ this->input_file_->file().unlock(); }
|
||||
|
||||
// Return whether the underlying file is locked.
|
||||
bool
|
||||
is_locked() const
|
||||
{ return this->input_file_->file().is_locked(); }
|
||||
|
||||
// Return the sized target structure associated with this object.
|
||||
// This is like the target method but it returns a pointer of
|
||||
// appropriate checked type.
|
||||
template<int size, bool big_endian>
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target();
|
||||
|
||||
// Read the symbol and relocation information.
|
||||
Read_symbols_data
|
||||
read_symbols()
|
||||
|
@ -68,19 +100,25 @@ class Object
|
|||
add_symbols(Symbol_table* symtab, Read_symbols_data rd)
|
||||
{ this->do_add_symbols(symtab, rd); }
|
||||
|
||||
// Return the target structure associated with this object.
|
||||
Target*
|
||||
target()
|
||||
{ return this->target_; }
|
||||
|
||||
// Return the sized target structure associated with this object.
|
||||
// This is like the target method but it returns a pointer of
|
||||
// appropriate checked type.
|
||||
template<int size, bool big_endian>
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target();
|
||||
// Pass sections which should be included in the link to the Layout
|
||||
// object, and record where the sections go in the output file.
|
||||
void
|
||||
layout(Layout* lay)
|
||||
{ this->do_layout(lay); }
|
||||
|
||||
protected:
|
||||
// What we need to know to map an input section to an output
|
||||
// section. We keep an array of these, one for each input section,
|
||||
// indexed by the input section number.
|
||||
struct Map_to_output
|
||||
{
|
||||
// The output section. This is NULL if the input section is to be
|
||||
// discarded.
|
||||
Output_section* output_section;
|
||||
// The offset within the output section.
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
// Read the symbols--implemented by child class.
|
||||
virtual Read_symbols_data
|
||||
do_read_symbols() = 0;
|
||||
|
@ -90,6 +128,10 @@ class Object
|
|||
virtual void
|
||||
do_add_symbols(Symbol_table*, Read_symbols_data) = 0;
|
||||
|
||||
// Lay out sections--implemented by child class.
|
||||
virtual void
|
||||
do_layout(Layout*) = 0;
|
||||
|
||||
// Get the file.
|
||||
Input_file*
|
||||
input_file() const
|
||||
|
@ -104,6 +146,16 @@ class Object
|
|||
const unsigned char*
|
||||
get_view(off_t start, off_t size);
|
||||
|
||||
// Get the number of sections.
|
||||
unsigned int
|
||||
shnum(void) const
|
||||
{ return this->shnum_; }
|
||||
|
||||
// Set the number of sections.
|
||||
void
|
||||
set_shnum(int shnum)
|
||||
{ this->shnum_ = shnum; }
|
||||
|
||||
// Set the target.
|
||||
void
|
||||
set_target(Target* target)
|
||||
|
@ -117,6 +169,11 @@ class Object
|
|||
File_view*
|
||||
get_lasting_view(off_t start, off_t size);
|
||||
|
||||
// Return the vector mapping input sections to output sections.
|
||||
std::vector<Map_to_output>&
|
||||
map_to_output()
|
||||
{ return this->map_to_output_; }
|
||||
|
||||
private:
|
||||
// This class may not be copied.
|
||||
Object(const Object&);
|
||||
|
@ -129,10 +186,14 @@ class Object
|
|||
// Offset within the file--0 for an object file, non-0 for an
|
||||
// archive.
|
||||
off_t offset_;
|
||||
// Number of input sections.
|
||||
unsigned int shnum_;
|
||||
// Whether this is a dynamic object.
|
||||
bool is_dynamic_;
|
||||
// Target functions--may be NULL if the target is not known.
|
||||
Target* target_;
|
||||
// Mapping from input sections to output section.
|
||||
std::vector<Map_to_output> map_to_output_;
|
||||
};
|
||||
|
||||
// Implement sized_target inline for efficiency. This approach breaks
|
||||
|
@ -158,15 +219,23 @@ class Sized_object : public Object
|
|||
|
||||
~Sized_object();
|
||||
|
||||
// Set up the object file based on the ELF header.
|
||||
void
|
||||
setup(const typename elfcpp::Ehdr<size, big_endian>&);
|
||||
|
||||
// Read the symbols.
|
||||
Read_symbols_data
|
||||
do_read_symbols();
|
||||
|
||||
// Add the symbols to the symbol table.
|
||||
void
|
||||
do_add_symbols(Symbol_table*, Read_symbols_data);
|
||||
|
||||
// Lay out the input sections.
|
||||
void
|
||||
do_layout(Layout*);
|
||||
|
||||
// Return the appropriate Sized_target structure.
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target()
|
||||
{ return this->Object::sized_target<size, big_endian>(); }
|
||||
|
@ -176,18 +245,27 @@ class Sized_object : public Object
|
|||
Sized_object(const Sized_object&);
|
||||
Sized_object& operator=(const Sized_object&);
|
||||
|
||||
// ELF file header EI_OSABI field.
|
||||
unsigned char osabi_;
|
||||
// ELF file header EI_ABIVERSION field.
|
||||
unsigned char abiversion_;
|
||||
// ELF file header e_machine field.
|
||||
elfcpp::Elf_Half machine_;
|
||||
// For convenience.
|
||||
typedef Sized_object<size, big_endian> This;
|
||||
static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
|
||||
static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
|
||||
// Whether to include a section group in the link.
|
||||
bool
|
||||
include_section_group(Layout*, unsigned int,
|
||||
const elfcpp::Shdr<size, big_endian>&,
|
||||
std::vector<bool>*);
|
||||
|
||||
// Whether to include a linkonce section in the link.
|
||||
bool
|
||||
include_linkonce_section(Layout*, const char*,
|
||||
const elfcpp::Shdr<size, big_endian>&);
|
||||
|
||||
// ELF file header e_flags field.
|
||||
unsigned int flags_;
|
||||
// File offset of section header table.
|
||||
off_t shoff_;
|
||||
// Number of input sections.
|
||||
unsigned int shnum_;
|
||||
// Offset of SHT_STRTAB section holding section names.
|
||||
unsigned int shstrndx_;
|
||||
// Index of SHT_SYMTAB section.
|
||||
|
@ -196,6 +274,10 @@ class Sized_object : public Object
|
|||
Symbol** symbols_;
|
||||
};
|
||||
|
||||
// The type of the list of input objects.
|
||||
|
||||
typedef std::list<Object*> Object_list;
|
||||
|
||||
// Return an Object appropriate for the input file. P is BYTES long,
|
||||
// and holds the ELF header.
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include <list>
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
|
|
159
gold/output.cc
Normal file
159
gold/output.cc
Normal file
|
@ -0,0 +1,159 @@
|
|||
// output.cc -- manage the output file for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "object.h"
|
||||
#include "output.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Output_data methods.
|
||||
|
||||
Output_data::~Output_data()
|
||||
{
|
||||
}
|
||||
|
||||
// Output_data_const methods.
|
||||
|
||||
void
|
||||
Output_data_const::write(Output_file* output, off_t off)
|
||||
{
|
||||
output->write(off, data_.data(), data_.size());
|
||||
}
|
||||
|
||||
// Output_section methods.
|
||||
|
||||
// Construct an Output_section. NAME will point into a Stringpool.
|
||||
|
||||
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags)
|
||||
: name_(name),
|
||||
addr_(0),
|
||||
addralign_(0),
|
||||
entsize_(0),
|
||||
offset_(0),
|
||||
size_(0),
|
||||
link_(0),
|
||||
info_(0),
|
||||
type_(type),
|
||||
flags_(flags)
|
||||
{
|
||||
}
|
||||
|
||||
// Add an input section to an Output_section. We don't keep track of
|
||||
// input sections for an Output_section. Instead, each Object keeps
|
||||
// track of the Output_section for each of its input sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
Output_section::add_input_section(Object* object, const char* secname,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr)
|
||||
{
|
||||
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
|
||||
if ((addralign & (addralign - 1)) != 0)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: invalid alignment %lu for section \"%s\"\n"),
|
||||
program_name, object->name().c_str(),
|
||||
static_cast<unsigned long>(addralign), secname);
|
||||
gold_exit(false);
|
||||
}
|
||||
this->size_ = (this->size_ + addralign - 1) &~ (addralign - 1);
|
||||
|
||||
if (addralign > this->addralign_)
|
||||
this->addralign_ = addralign;
|
||||
|
||||
off_t ret = this->size_;
|
||||
this->size_ += shdr.get_sh_size();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Output segment methods.
|
||||
|
||||
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
||||
: output_sections_(),
|
||||
vaddr_(0),
|
||||
paddr_(0),
|
||||
memsz_(0),
|
||||
align_(0),
|
||||
offset_(0),
|
||||
filesz_(0),
|
||||
type_(type),
|
||||
flags_(flags)
|
||||
{
|
||||
}
|
||||
|
||||
// Add an Output_section to an Output_segment.
|
||||
|
||||
void
|
||||
Output_segment::add_output_section(Output_section* os)
|
||||
{
|
||||
// So that PT_NOTE segments will work correctly, we need to ensure
|
||||
// that all SHT_NOTE sections are adjacent. This will normally
|
||||
// happen automatically, because all the SHT_NOTE input sections
|
||||
// will wind up in the same output section. However, it is possible
|
||||
// for multiple SHT_NOTE input sections to have different section
|
||||
// flags, and thus be in different output sections, but for the
|
||||
// different section flags to map into the same segment flags and
|
||||
// thus the same output segment.
|
||||
if (os->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
for (Section_list::iterator p = this->output_sections_.begin();
|
||||
p != this->output_sections_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
++p;
|
||||
this->output_sections_.insert(p, os);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->output_sections_.push_back(os);
|
||||
}
|
||||
|
||||
// Output_file methods.
|
||||
|
||||
void
|
||||
Output_file::write(off_t, const void*, off_t)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones for implemented targets.
|
||||
|
||||
template
|
||||
off_t
|
||||
Output_section::add_input_section<32, false>(
|
||||
Object* object,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<32, false>& shdr);
|
||||
|
||||
template
|
||||
off_t
|
||||
Output_section::add_input_section<32, true>(
|
||||
Object* object,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<32, true>& shdr);
|
||||
|
||||
template
|
||||
off_t
|
||||
Output_section::add_input_section<64, false>(
|
||||
Object* object,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<64, false>& shdr);
|
||||
|
||||
template
|
||||
off_t
|
||||
Output_section::add_input_section<64, true>(
|
||||
Object* object,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<64, true>& shdr);
|
||||
|
||||
} // End namespace gold.
|
214
gold/output.h
Normal file
214
gold/output.h
Normal file
|
@ -0,0 +1,214 @@
|
|||
// output.h -- manage the output file for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_OUTPUT_H
|
||||
#define GOLD_OUTPUT_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "elfcpp.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Object;
|
||||
class Output_file;
|
||||
|
||||
// An abtract class for data which has to go into the output file
|
||||
// which is not associated with any input section.
|
||||
|
||||
class Output_data
|
||||
{
|
||||
public:
|
||||
Output_data(off_t size = 0)
|
||||
: size_(size)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
~Output_data();
|
||||
|
||||
// Return the size of the data.
|
||||
off_t
|
||||
size()
|
||||
{ return this->size_; }
|
||||
|
||||
// Write the data to the output file at the specified offset. This
|
||||
// must be implemented by the real class.
|
||||
virtual void
|
||||
write(Output_file*, off_t off) = 0;
|
||||
|
||||
protected:
|
||||
// Set the size of the data.
|
||||
void
|
||||
set_size(off_t size)
|
||||
{ this->size_ = size; }
|
||||
|
||||
private:
|
||||
Output_data(const Output_data&);
|
||||
Output_data& operator=(const Output_data&);
|
||||
|
||||
// Size of data in file.
|
||||
off_t size_;
|
||||
};
|
||||
|
||||
// A simple cass of Output_data in which we have constant data to
|
||||
// output.
|
||||
|
||||
class Output_data_const : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_data_const(const std::string& data)
|
||||
: Output_data(data.size()), data_(data)
|
||||
{ }
|
||||
|
||||
Output_data_const(const char* p, off_t len)
|
||||
: Output_data(len), data_(p, len)
|
||||
{ }
|
||||
|
||||
void
|
||||
write(Output_file* output, off_t off);
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
};
|
||||
|
||||
// An output section. We don't expect to have too many output
|
||||
// sections, so we don't bother to do a template on the size.
|
||||
|
||||
class Output_section
|
||||
{
|
||||
public:
|
||||
// Create an output section, giving the name, type, and flags.
|
||||
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
|
||||
~Output_section();
|
||||
|
||||
// Add a new input section named NAME with header SHDR from object
|
||||
// OBJECT. Return the offset within the output section.
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
add_input_section(Object* object, const char *name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr);
|
||||
|
||||
// Return the section name.
|
||||
const char*
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Return the section type.
|
||||
elfcpp::Elf_Word
|
||||
type() const
|
||||
{ return this->type_; }
|
||||
|
||||
// Return the section flags.
|
||||
elfcpp::Elf_Xword
|
||||
flags() const
|
||||
{ return this->flags_; }
|
||||
|
||||
private:
|
||||
// Most of these fields are only valid after layout.
|
||||
|
||||
// The name of the section. This will point into a Stringpool.
|
||||
const char* name_;
|
||||
// The section address.
|
||||
uint64_t addr_;
|
||||
// The section alignment.
|
||||
uint64_t addralign_;
|
||||
// The section entry size.
|
||||
uint64_t entsize_;
|
||||
// The file offset.
|
||||
off_t offset_;
|
||||
// The section size.
|
||||
off_t size_;
|
||||
// The section link field.
|
||||
unsigned int link_;
|
||||
// The section info field.
|
||||
unsigned int info_;
|
||||
// The section type.
|
||||
elfcpp::Elf_Word type_;
|
||||
// The section flags.
|
||||
elfcpp::Elf_Xword flags_;
|
||||
};
|
||||
|
||||
// An output segment. PT_LOAD segments are built from collections of
|
||||
// output sections. Other segments typically point within PT_LOAD
|
||||
// segments, and are built directly as needed.
|
||||
|
||||
class Output_segment
|
||||
{
|
||||
public:
|
||||
// Create an output segment, specifying the type and flags.
|
||||
Output_segment(elfcpp::Elf_Word, elfcpp::Elf_Word);
|
||||
|
||||
// Return the virtual address.
|
||||
uint64_t
|
||||
vaddr() const
|
||||
{ return this->vaddr_; }
|
||||
|
||||
// Return the physical address.
|
||||
uint64_t
|
||||
paddr() const
|
||||
{ return this->paddr_; }
|
||||
|
||||
// Return the segment type.
|
||||
elfcpp::Elf_Word
|
||||
type() const
|
||||
{ return this->type_; }
|
||||
|
||||
// Return the segment flags.
|
||||
elfcpp::Elf_Word
|
||||
flags() const
|
||||
{ return this->flags_; }
|
||||
|
||||
// Add an Output_section to this segment.
|
||||
void
|
||||
add_output_section(Output_section*);
|
||||
|
||||
// Update the segment flags to be compatible with FLAGS.
|
||||
void
|
||||
update_flags(elfcpp::Elf_Word flags)
|
||||
{ this->flags_ |= flags & (elfcpp::PF_R | elfcpp::PF_W | elfcpp::PF_X); }
|
||||
|
||||
private:
|
||||
Output_segment(const Output_segment&);
|
||||
Output_segment& operator=(const Output_segment&);
|
||||
|
||||
typedef std::list<Output_section*> Section_list;
|
||||
|
||||
// The list of output sections attached to this segment. This is
|
||||
// cleared after layout.
|
||||
Section_list output_sections_;
|
||||
// The segment virtual address.
|
||||
uint64_t vaddr_;
|
||||
// The segment physical address.
|
||||
uint64_t paddr_;
|
||||
// The size of the segment in memory.
|
||||
uint64_t memsz_;
|
||||
// The segment alignment.
|
||||
uint64_t align_;
|
||||
// The offset of the segment data within the file.
|
||||
off_t offset_;
|
||||
// The size of the segment data in the file.
|
||||
off_t filesz_;
|
||||
// The segment type;
|
||||
elfcpp::Elf_Word type_;
|
||||
// The segment flags.
|
||||
elfcpp::Elf_Word flags_;
|
||||
};
|
||||
|
||||
// This class represents the output file. The output file is a
|
||||
// collection of output segments and a collection of output sections
|
||||
// which are not associated with segments.
|
||||
|
||||
class Output_file
|
||||
{
|
||||
public:
|
||||
Output_file();
|
||||
~Output_file();
|
||||
|
||||
// Write data to the output file.
|
||||
void
|
||||
write(off_t off, const void* data, off_t len);
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_OUTPUT_H)
|
|
@ -7,10 +7,14 @@ gold.h
|
|||
gold-threads.cc
|
||||
gold-threads.h
|
||||
i386.cc
|
||||
layout.cc
|
||||
layout.h
|
||||
object.cc
|
||||
object.h
|
||||
options.cc
|
||||
options.h
|
||||
output.cc
|
||||
output.h
|
||||
readsyms.cc
|
||||
readsyms.h
|
||||
resolve.cc
|
||||
|
@ -21,6 +25,5 @@ symtab.h
|
|||
target.h
|
||||
target-select.cc
|
||||
target-select.h
|
||||
targetsize.h
|
||||
workqueue.cc
|
||||
workqueue.h
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-09-07 14:17-0700\n"
|
||||
"POT-Creation-Date: 2006-09-21 13:30-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -51,7 +51,7 @@ msgstr ""
|
|||
msgid "%s: cannot open %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: gold.cc:72
|
||||
#: gold.cc:74
|
||||
msgid "no input files"
|
||||
msgstr ""
|
||||
|
||||
|
@ -99,73 +99,103 @@ msgstr ""
|
|||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:57
|
||||
#: object.cc:54
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:64
|
||||
#: object.cc:61
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:88
|
||||
#: object.cc:87
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:167
|
||||
#: object.cc:165
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:177
|
||||
#: object.cc:175
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:214
|
||||
#: object.cc:212
|
||||
#, c-format
|
||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:262
|
||||
#: object.cc:266
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:286 object.cc:339 object.cc:360
|
||||
#: object.cc:277
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:295
|
||||
#: object.cc:288
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:298
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:306
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:328
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:407
|
||||
#, c-format
|
||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:480
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:504 object.cc:557 object.cc:578
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:513
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:516
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:524
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:313
|
||||
#: object.cc:531
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:321
|
||||
#: object.cc:539
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:328
|
||||
#: object.cc:546
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
|
@ -220,6 +250,11 @@ msgstr ""
|
|||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:58
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:135
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "options.h"
|
||||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
#include "object.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -49,8 +50,6 @@ Read_symbols::locks(Workqueue*)
|
|||
void
|
||||
Read_symbols::run(Workqueue* workqueue)
|
||||
{
|
||||
// We don't keep track of Input_file objects, so this is a memory
|
||||
// leak.
|
||||
Input_file* input_file = new Input_file(this->input_);
|
||||
input_file->open(this->options_, this->dirpath_);
|
||||
|
||||
|
@ -72,6 +71,8 @@ Read_symbols::run(Workqueue* workqueue)
|
|||
Object* obj = make_elf_object(this->input_.name(), input_file, 0,
|
||||
p, bytes);
|
||||
|
||||
this->input_objects_->push_back(obj);
|
||||
|
||||
Read_symbols_data sd = obj->read_symbols();
|
||||
workqueue->queue(new Add_symbols(this->symtab_, obj, sd,
|
||||
this->this_blocker_,
|
||||
|
@ -99,20 +100,37 @@ Add_symbols::~Add_symbols()
|
|||
// input file.
|
||||
}
|
||||
|
||||
// We are blocked by this_blocker_. We block next_blocker_.
|
||||
// We are blocked by this_blocker_. We block next_blocker_. We also
|
||||
// lock the file.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Add_symbols::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return IS_BLOCKED;
|
||||
if (this->object_->is_locked())
|
||||
return IS_LOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
class Add_symbols::Add_symbols_locker : public Task_locker
|
||||
{
|
||||
public:
|
||||
Add_symbols_locker(Task_token& token, Workqueue* workqueue,
|
||||
Object* object)
|
||||
: blocker_(token, workqueue), objlock_(*object)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_block blocker_;
|
||||
Task_locker_obj<Object> objlock_;
|
||||
};
|
||||
|
||||
Task_locker*
|
||||
Add_symbols::locks(Workqueue* workqueue)
|
||||
{
|
||||
return new Task_locker_block(*this->next_blocker_, workqueue);
|
||||
return new Add_symbols_locker(*this->next_blocker_, workqueue,
|
||||
this->object_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#ifndef GOLD_READSYMS_H
|
||||
#define GOLD_READSYMS_H
|
||||
|
||||
#include "targetsize.h"
|
||||
#include "workqueue.h"
|
||||
#include "object.h"
|
||||
|
||||
|
@ -26,11 +25,13 @@ class Read_symbols : public Task
|
|||
// associated Add_symbols task from running before the previous one
|
||||
// has completed; it will be NULL for the first task. NEXT_BLOCKER
|
||||
// is used to block the next input file from adding symbols.
|
||||
Read_symbols(const General_options& options, Symbol_table* symtab,
|
||||
const Dirsearch& dirpath, const Input_argument& input,
|
||||
Read_symbols(const General_options& options, Object_list* input_objects,
|
||||
Symbol_table* symtab, const Dirsearch& dirpath,
|
||||
const Input_argument& input,
|
||||
Task_token* this_blocker, Task_token* next_blocker)
|
||||
: options_(options), symtab_(symtab), dirpath_(dirpath), input_(input),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
: options_(options), input_objects_(input_objects), symtab_(symtab),
|
||||
dirpath_(dirpath), input_(input), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Read_symbols();
|
||||
|
@ -48,6 +49,7 @@ class Read_symbols : public Task
|
|||
|
||||
private:
|
||||
const General_options& options_;
|
||||
Object_list* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
const Dirsearch& dirpath_;
|
||||
const Input_argument& input_;
|
||||
|
@ -85,6 +87,8 @@ class Add_symbols : public Task
|
|||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
class Add_symbols_locker;
|
||||
|
||||
Symbol_table* symtab_;
|
||||
Object* object_;
|
||||
Read_symbols_data sd_;
|
||||
|
|
|
@ -101,7 +101,7 @@ Stringpool::add(const char* s)
|
|||
{
|
||||
// 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
|
||||
// don't think there is a way to handle this correct with
|
||||
// don't think there is a way to handle this correctly with
|
||||
// unordered_set, so this should be replaced with custom code to do
|
||||
// what we need, which is to return the empty slot.
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <utility>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "targetsize.h"
|
||||
#include "stringpool.h"
|
||||
|
||||
#ifndef GOLD_SYMTAB_H
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// targetsize.h -- representations which change size based on the target
|
||||
|
||||
#ifndef GOLD_TARGETSIZE_H
|
||||
#define GOLD_TARGETSIZE_H
|
||||
|
||||
// Tell GNU/Linux inttypes.h that we want the formatting macros.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// A template we use to get the right type sizes via specialization.
|
||||
// We never actually use the default version.
|
||||
|
||||
template<int size>
|
||||
struct Size_types
|
||||
{
|
||||
typedef signed char Signed_type;
|
||||
typedef unsigned char Unsigned_type;
|
||||
static const char* signed_printf_dec_format();
|
||||
static const char* unsigned_printf_dec_format();
|
||||
static const char* unsigned_printf_hex_format();
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Size_types<32>
|
||||
{
|
||||
typedef int32_t Signed_type;
|
||||
typedef uint32_t Unsigned_type;
|
||||
static const char* signed_printf_dec_format()
|
||||
{ return PRId32; }
|
||||
static const char* unsigned_printf_dec_format()
|
||||
{ return PRIu32; }
|
||||
static const char* unsigned_printf_hex_format()
|
||||
{ return PRIx32; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Size_types<64>
|
||||
{
|
||||
typedef int64_t Signed_type;
|
||||
typedef uint64_t Unsigned_type;
|
||||
static const char* signed_printf_dec_format()
|
||||
{ return PRId64; }
|
||||
static const char* unsigned_printf_dec_format()
|
||||
{ return PRIu64; }
|
||||
static const char* unsigned_printf_hex_format()
|
||||
{ return PRIx64; }
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_TARGETSIZE_H)
|
|
@ -146,6 +146,27 @@ class Task_block_token
|
|||
Workqueue* workqueue_;
|
||||
};
|
||||
|
||||
// An object which implements an RAII lock for any object which
|
||||
// supports lock and unlock methods.
|
||||
|
||||
template<typename Obj>
|
||||
class Task_lock_obj
|
||||
{
|
||||
public:
|
||||
Task_lock_obj(Obj& obj)
|
||||
: obj_(obj)
|
||||
{ this->obj_.lock(); }
|
||||
|
||||
~Task_lock_obj()
|
||||
{ this->obj_.unlock(); }
|
||||
|
||||
private:
|
||||
Task_lock_obj(const Task_lock_obj&);
|
||||
Task_lock_obj& operator=(const Task_lock_obj&);
|
||||
|
||||
Obj& obj_;
|
||||
};
|
||||
|
||||
// An abstract class used to lock Task_tokens using RAII. A typical
|
||||
// implementation would simply have a set of members of type
|
||||
// Task_read_token, Task_write_token, and Task_block_token.
|
||||
|
@ -209,21 +230,22 @@ class Task_locker_block : public Task_locker
|
|||
Task_block_token block_token_;
|
||||
};
|
||||
|
||||
// A version of Task_locker which may be used to hold a lock on a
|
||||
// File_read.
|
||||
// A version of Task_locker which may be used to hold a lock on any
|
||||
// object which supports lock() and unlock() methods.
|
||||
|
||||
class Task_locker_file : public Task_locker
|
||||
template<typename Obj>
|
||||
class Task_locker_obj : public Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker_file(File_read& file)
|
||||
: file_lock_(file)
|
||||
Task_locker_obj(Obj& obj)
|
||||
: obj_lock_(obj)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_file(const Task_locker_file&);
|
||||
Task_locker_file& operator=(const Task_locker_file&);
|
||||
Task_locker_obj(const Task_locker_obj&);
|
||||
Task_locker_obj& operator=(const Task_locker_obj&);
|
||||
|
||||
File_read_lock file_lock_;
|
||||
Task_lock_obj<Obj> obj_lock_;
|
||||
};
|
||||
|
||||
// The superclass for tasks to be placed on the workqueue. Each
|
||||
|
|
Loading…
Reference in a new issue