New drop, with first cut of section layout code.

This commit is contained in:
Ian Lance Taylor 2006-09-21 22:13:18 +00:00
parent 5ffff7c1d1
commit a2fb1b05e4
19 changed files with 1479 additions and 171 deletions

View File

@ -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

View File

@ -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@

View File

@ -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.

View File

@ -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
View 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
View 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)

View File

@ -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.

View File

@ -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.

View File

@ -14,8 +14,6 @@
#include <list>
#include "gold.h"
namespace gold
{

159
gold/output.cc Normal file
View 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
View 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)

View File

@ -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

View File

@ -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"

View File

@ -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_);
@ -71,7 +70,9 @@ Read_symbols::run(Workqueue* workqueue)
// This is an ELF object.
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

View File

@ -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_;

View File

@ -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.

View File

@ -7,7 +7,6 @@
#include <utility>
#include "elfcpp.h"
#include "targetsize.h"
#include "stringpool.h"
#ifndef GOLD_SYMTAB_H

View File

@ -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)

View File

@ -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