19 changed files with 1472 additions and 164 deletions
@ -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.
|
|||
@ -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)
|
|||
@ -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.
|
|||
@ -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)
|
|||
@ -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)
|
|||
Loading…
Reference in new issue