mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-19 14:34:07 +08:00
Finished layout code.
This commit is contained in:
parent
6b89cc2108
commit
75f65a3e30
@ -91,7 +91,8 @@ queue_initial_tasks(const General_options& options,
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
|
||||
workqueue->queue(new Layout_task(options, input_objects, this_blocker));
|
||||
workqueue->queue(new Layout_task(options, input_objects, symtab,
|
||||
this_blocker));
|
||||
}
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
16
gold/i386.cc
16
gold/i386.cc
@ -16,8 +16,22 @@ class Target_i386 : public Sized_target<32, false>
|
||||
{
|
||||
public:
|
||||
Target_i386()
|
||||
: Sized_target<32, false>(false, false)
|
||||
: Sized_target<32, false>(&i386_info)
|
||||
{ }
|
||||
|
||||
private:
|
||||
static const Target::Target_info i386_info;
|
||||
};
|
||||
|
||||
const Target::Target_info Target_i386::i386_info =
|
||||
{
|
||||
32, // size
|
||||
false, // is_big_endian
|
||||
false, // has_make_symbol
|
||||
false, // has_resolve,
|
||||
0x08048000, // text_segment_address,
|
||||
0x1000, // abi_pagesize
|
||||
0x1000 // common_pagesize
|
||||
};
|
||||
|
||||
// The selector for i386 object files.
|
||||
|
530
gold/layout.cc
530
gold/layout.cc
@ -52,15 +52,14 @@ Layout_task::run(Workqueue*)
|
||||
p != this->input_objects_->end();
|
||||
++p)
|
||||
(*p)->layout(&layout);
|
||||
layout.finalize(this->input_objects_);
|
||||
layout.finalize(this->input_objects_, this->symtab_);
|
||||
}
|
||||
|
||||
// Layout methods.
|
||||
|
||||
Layout::Layout(const General_options& options)
|
||||
: options_(options), namepool_(), signatures_(),
|
||||
section_name_map_(), segment_list_(), section_list_(),
|
||||
data_list_()
|
||||
: options_(options), namepool_(), sympool_(), signatures_(),
|
||||
section_name_map_(), segment_list_(), section_list_()
|
||||
{
|
||||
}
|
||||
|
||||
@ -169,6 +168,233 @@ Layout::layout(Object* object, const char* name,
|
||||
return os;
|
||||
}
|
||||
|
||||
// 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, 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, seg_flags);
|
||||
}
|
||||
|
||||
// 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, 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, seg_flags);
|
||||
}
|
||||
}
|
||||
|
||||
// If we see a loadable SHF_TLS section, we create a PT_TLS
|
||||
// segment.
|
||||
if ((flags & elfcpp::SHF_TLS) != 0)
|
||||
{
|
||||
// See if we already have an equivalent PT_TLS segment.
|
||||
for (p = this->segment_list_.begin();
|
||||
p != segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_TLS
|
||||
&& (((*p)->flags() & elfcpp::PF_W)
|
||||
== (seg_flags & elfcpp::PF_W)))
|
||||
{
|
||||
(*p)->add_output_section(os, seg_flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_TLS,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
oseg->add_output_section(os, seg_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Find the first read-only PT_LOAD segment, creating one if
|
||||
// necessary.
|
||||
|
||||
Output_segment*
|
||||
Layout::find_first_load_seg()
|
||||
{
|
||||
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_LOAD
|
||||
&& ((*p)->flags() & elfcpp::PF_R) != 0
|
||||
&& ((*p)->flags() & elfcpp::PF_W) == 0)
|
||||
return *p;
|
||||
}
|
||||
|
||||
Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
|
||||
this->segment_list_.push_back(load_seg);
|
||||
return load_seg;
|
||||
}
|
||||
|
||||
// Finalize the layout. When this is called, we have created all the
|
||||
// output sections and all the output segments which are based on
|
||||
// input sections. We have several things to do, and we have to do
|
||||
// them in the right order, so that we get the right results correctly
|
||||
// and efficiently.
|
||||
|
||||
// 1) Finalize the list of output segments and create the segment
|
||||
// table header.
|
||||
|
||||
// 2) Finalize the dynamic symbol table and associated sections.
|
||||
|
||||
// 3) Determine the final file offset of all the output segments.
|
||||
|
||||
// 4) Determine the final file offset of all the SHF_ALLOC output
|
||||
// sections.
|
||||
|
||||
// 5) Create the symbol table sections and the section name table
|
||||
// section.
|
||||
|
||||
// 6) Finalize the symbol table: set symbol values to their final
|
||||
// value and make a final determination of which symbols are going
|
||||
// into the output symbol table.
|
||||
|
||||
// 7) Create the section table header.
|
||||
|
||||
// 8) Determine the final file offset of all the output sections which
|
||||
// are not SHF_ALLOC, including the section table header.
|
||||
|
||||
// 9) Finalize the ELF file header.
|
||||
|
||||
// This function returns the size of the output file.
|
||||
|
||||
off_t
|
||||
Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
||||
{
|
||||
if (input_objects->any_dynamic())
|
||||
{
|
||||
// If there are any dynamic objects in the link, then we need
|
||||
// some additional segments: PT_PHDRS, PT_INTERP, and
|
||||
// PT_DYNAMIC. We also need to finalize the dynamic symbol
|
||||
// table and create the dynamic hash table.
|
||||
abort();
|
||||
}
|
||||
|
||||
// FIXME: Handle PT_GNU_STACK.
|
||||
|
||||
Output_segment* load_seg = this->find_first_load_seg();
|
||||
|
||||
// Lay out the segment headers.
|
||||
int size = input_objects->target()->get_size();
|
||||
Output_segment_headers* segment_headers;
|
||||
segment_headers = new Output_segment_headers(size, this->segment_list_);
|
||||
load_seg->add_initial_output_data(segment_headers);
|
||||
// FIXME: Attach them to PT_PHDRS if necessary.
|
||||
|
||||
// Lay out the file header.
|
||||
Output_file_header* file_header;
|
||||
file_header = new Output_file_header(size,
|
||||
this->options_,
|
||||
input_objects->target(),
|
||||
symtab,
|
||||
segment_headers);
|
||||
load_seg->add_initial_output_data(file_header);
|
||||
|
||||
// Set the file offsets of all the segments.
|
||||
off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
|
||||
|
||||
// Create the symbol table sections.
|
||||
// FIXME: We don't need to do this if we are stripping symbols.
|
||||
Output_section* osymtab;
|
||||
Output_section* ostrtab;
|
||||
this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
|
||||
|
||||
// Create the .shstrtab section.
|
||||
Output_section* shstrtab_section = this->create_shstrtab();
|
||||
|
||||
// Set the file offsets of all the sections not associated with
|
||||
// segments.
|
||||
off = this->set_section_offsets(off);
|
||||
|
||||
// Create the section table header.
|
||||
Output_section_headers* oshdrs = this->create_shdrs(size, off);
|
||||
off += oshdrs->data_size();
|
||||
|
||||
file_header->set_section_info(oshdrs, shstrtab_section);
|
||||
|
||||
// Now we know exactly where everything goes in the output file.
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -245,177 +471,177 @@ Layout::segment_precedes(const Output_segment* seg1,
|
||||
return paddr1 < paddr2;
|
||||
}
|
||||
|
||||
// Map section flags to segment flags.
|
||||
// Set the file offsets of all the segments. They have all been
|
||||
// created. LOAD_SEG must be be laid out first. Return the offset of
|
||||
// the data to follow.
|
||||
|
||||
elfcpp::Elf_Word
|
||||
Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
|
||||
off_t
|
||||
Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// Sort them into the final order.
|
||||
std::sort(this->segment_list_.begin(), this->segment_list_.end(),
|
||||
Layout::Compare_segments());
|
||||
|
||||
// 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
|
||||
// Find the PT_LOAD segments, and set their addresses and offsets
|
||||
// and their section's addresses and offsets.
|
||||
uint64_t addr = target->text_segment_address();
|
||||
off_t off = 0;
|
||||
bool was_readonly = false;
|
||||
for (Segment_list::iterator p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_LOAD
|
||||
&& ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
|
||||
if (load_seg != NULL && load_seg != *p)
|
||||
abort();
|
||||
load_seg = NULL;
|
||||
|
||||
// If the last segment was readonly, and this one is not,
|
||||
// then skip the address forward one page, maintaining the
|
||||
// same position within the page. This lets us store both
|
||||
// segments overlapping on a single page in the file, but
|
||||
// the loader will put them on different pages in memory.
|
||||
|
||||
uint64_t orig_addr = addr;
|
||||
uint64_t orig_off = off;
|
||||
|
||||
uint64_t aligned_addr = addr;
|
||||
uint64_t abi_pagesize = target->abi_pagesize();
|
||||
if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
|
||||
{
|
||||
(*p)->add_output_section(os);
|
||||
break;
|
||||
uint64_t align = (*p)->max_data_align();
|
||||
|
||||
addr = (addr + align - 1) & ~ (align - 1);
|
||||
aligned_addr = addr;
|
||||
if ((addr & (abi_pagesize - 1)) != 0)
|
||||
addr = addr + abi_pagesize;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
||||
uint64_t new_addr = (*p)->set_section_addresses(addr, &off);
|
||||
|
||||
// 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)
|
||||
// Now that we know the size of this segment, we may be able
|
||||
// to save a page in memory, at the cost of wasting some
|
||||
// file space, by instead aligning to the start of a new
|
||||
// page. Here we use the real machine page size rather than
|
||||
// the ABI mandated page size.
|
||||
|
||||
if (aligned_addr != addr)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_NOTE
|
||||
&& (((*p)->flags() & elfcpp::PF_W)
|
||||
== (seg_flags & elfcpp::PF_W)))
|
||||
uint64_t common_pagesize = target->common_pagesize();
|
||||
uint64_t first_off = (common_pagesize
|
||||
- (aligned_addr
|
||||
& (common_pagesize - 1)));
|
||||
uint64_t last_off = new_addr & (common_pagesize - 1);
|
||||
if (first_off > 0
|
||||
&& last_off > 0
|
||||
&& ((aligned_addr & ~ (common_pagesize - 1))
|
||||
!= (new_addr & ~ (common_pagesize - 1)))
|
||||
&& first_off + last_off <= common_pagesize)
|
||||
{
|
||||
(*p)->add_output_section(os);
|
||||
break;
|
||||
addr = ((aligned_addr + common_pagesize - 1)
|
||||
& ~ (common_pagesize - 1));
|
||||
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
||||
new_addr = (*p)->set_section_addresses(addr, &off);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
addr = new_addr;
|
||||
|
||||
// If we see a loadable SHF_TLS section, we create a PT_TLS
|
||||
// segment.
|
||||
if ((flags & elfcpp::SHF_TLS) != 0)
|
||||
{
|
||||
// See if we already have an equivalent PT_TLS segment.
|
||||
for (p = this->segment_list_.begin();
|
||||
p != segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::PT_TLS
|
||||
&& (((*p)->flags() & elfcpp::PF_W)
|
||||
== (seg_flags & elfcpp::PF_W)))
|
||||
{
|
||||
(*p)->add_output_section(os);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_TLS,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
oseg->add_output_section(os);
|
||||
}
|
||||
if (((*p)->flags() & elfcpp::PF_W) == 0)
|
||||
was_readonly = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the non-PT_LOAD segments, setting their offsets from their
|
||||
// section's offsets.
|
||||
for (Segment_list::iterator p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() != elfcpp::PT_LOAD)
|
||||
(*p)->set_offset();
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// Set the file offset of all the sections not associated with a
|
||||
// segment.
|
||||
|
||||
off_t
|
||||
Layout::set_section_offsets(off_t off)
|
||||
{
|
||||
for (Layout::Section_list::iterator p = this->section_list_.begin();
|
||||
p != this->section_list_.end();
|
||||
++p)
|
||||
{
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||
(*p)->set_address(0, off);
|
||||
off += (*p)->data_size();
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
// Create the symbol table sections.
|
||||
|
||||
void
|
||||
Layout::create_symtab_sections(const Input_objects* input_objects,
|
||||
Symbol_table* symtab,
|
||||
Output_section** posymtab,
|
||||
Output_section** postrtab)
|
||||
{
|
||||
off_t off = 0;
|
||||
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
|
||||
p != input_objects->end();
|
||||
++p)
|
||||
{
|
||||
Task_lock_obj<Object> tlo(**p);
|
||||
off = (*p)->finalize_local_symbols(off, &this->sympool_);
|
||||
}
|
||||
|
||||
off = symtab->finalize(off, &this->sympool_);
|
||||
|
||||
*posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
|
||||
*postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
|
||||
&this->sympool_);
|
||||
}
|
||||
|
||||
// Create the .shstrtab section, which holds the names of the
|
||||
// sections. At the time this is called, we have created all the
|
||||
// output sections except .shstrtab itself.
|
||||
|
||||
Output_section*
|
||||
Layout::create_shstrtab()
|
||||
{
|
||||
// FIXME: We don't need to create a .shstrtab section if we are
|
||||
// stripping everything.
|
||||
|
||||
const char* name = this->namepool_.add(".shstrtab");
|
||||
|
||||
Output_section* os = new Output_section_strtab(name,
|
||||
&this->namepool_);
|
||||
|
||||
this->section_list_.push_back(os);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Create the sections for the symbol table.
|
||||
// Create the section headers. SIZE is 32 or 64. OFF is the file
|
||||
// offset.
|
||||
|
||||
void
|
||||
Layout::create_symtab_sections()
|
||||
Output_section_headers*
|
||||
Layout::create_shdrs(int size, off_t off)
|
||||
{
|
||||
}
|
||||
|
||||
// Finalize the layout. When this is called, we have created all the
|
||||
// output sections and all the output segments which are based on
|
||||
// input sections. We have several things to do, and we have to do
|
||||
// them in the right order, so that we get the right results correctly
|
||||
// and efficiently.
|
||||
|
||||
// 1) Finalize the list of output segments and create the segment
|
||||
// table header.
|
||||
|
||||
// 2) Finalize the dynamic symbol table and associated sections.
|
||||
|
||||
// 3) Determine the final file offset of all the output segments.
|
||||
|
||||
// 4) Determine the final file offset of all the SHF_ALLOC output
|
||||
// sections.
|
||||
|
||||
// 5) Finalize the symbol table: set symbol values to their final
|
||||
// value and make a final determination of which symbols are going
|
||||
// into the output symbol table.
|
||||
|
||||
// 6) Create the symbol table sections and the section name table
|
||||
// section.
|
||||
|
||||
// 7) Create the section table header.
|
||||
|
||||
// 8) Determine the final file offset of all the output sections which
|
||||
// are not SHF_ALLOC, including the section table header.
|
||||
|
||||
// 9) Finalize the ELF file header.
|
||||
|
||||
void
|
||||
Layout::finalize(const Input_objects* input_objects)
|
||||
{
|
||||
if (input_objects->any_dynamic())
|
||||
{
|
||||
// If there are any dynamic objects in the link, then we need
|
||||
// some additional segments: PT_PHDRS, PT_INTERP, and
|
||||
// PT_DYNAMIC. We also need to finalize the dynamic symbol
|
||||
// table and create the dynamic hash table.
|
||||
abort();
|
||||
}
|
||||
|
||||
// FIXME: Handle PT_GNU_STACK.
|
||||
|
||||
std::sort(this->segment_list_.begin(), this->segment_list_.end(),
|
||||
Layout::Compare_segments());
|
||||
|
||||
Output_segment_headers* segment_headers;
|
||||
segment_headers = new Output_segment_headers(this->segment_list_);
|
||||
Output_section_headers* oshdrs;
|
||||
oshdrs = new Output_section_headers(size, this->segment_list_,
|
||||
this->section_list_);
|
||||
uint64_t addralign = oshdrs->addralign();
|
||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||
oshdrs->set_address(0, off);
|
||||
return oshdrs;
|
||||
}
|
||||
|
||||
// The mapping of .gnu.linkonce section names to real section names.
|
||||
|
@ -17,8 +17,10 @@ namespace gold
|
||||
{
|
||||
|
||||
class Input_objects;
|
||||
class Symbol_table;
|
||||
class Output_section;
|
||||
class Output_section_symtab;
|
||||
class Output_section_headers;
|
||||
class Output_segment;
|
||||
class Output_data;
|
||||
|
||||
@ -33,8 +35,9 @@ class Layout_task : public Task
|
||||
// from executing until all the input symbols have been read.
|
||||
Layout_task(const General_options& options,
|
||||
const Input_objects* input_objects,
|
||||
Symbol_table* symtab,
|
||||
Task_token* this_blocker)
|
||||
: options_(options), input_objects_(input_objects),
|
||||
: options_(options), input_objects_(input_objects), symtab_(symtab),
|
||||
this_blocker_(this_blocker)
|
||||
{ }
|
||||
|
||||
@ -57,6 +60,7 @@ class Layout_task : public Task
|
||||
|
||||
const General_options& options_;
|
||||
const Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Task_token* this_blocker_;
|
||||
};
|
||||
|
||||
@ -94,8 +98,8 @@ class Layout
|
||||
add_comdat(const char*, bool group);
|
||||
|
||||
// Finalize the layout after all the input sections have been added.
|
||||
void
|
||||
finalize(const Input_objects*);
|
||||
off_t
|
||||
finalize(const Input_objects*, Symbol_table*);
|
||||
|
||||
// The list of segments.
|
||||
|
||||
@ -123,18 +127,33 @@ class Layout
|
||||
static const Linkonce_mapping linkonce_mapping[];
|
||||
static const int linkonce_mapping_count;
|
||||
|
||||
// Lay out the local symbols from a SHT_SYMTAB section.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
add_symtab_locals(Object* object, const elfcpp::Shdr<size, big_endian>&);
|
||||
// Find the first read-only PT_LOAD segment, creating one if
|
||||
// necessary.
|
||||
Output_segment*
|
||||
find_first_load_seg();
|
||||
|
||||
// Set the final file offsets of all the segments.
|
||||
off_t
|
||||
set_segment_offsets(const Target*, Output_segment*);
|
||||
|
||||
// Set the final file offsets of all the sections not associated
|
||||
// with a segment.
|
||||
off_t
|
||||
set_section_offsets(off_t);
|
||||
|
||||
// Create the output sections for the symbol table.
|
||||
void
|
||||
create_symtab_sections();
|
||||
create_symtab_sections(const Input_objects*, Symbol_table*,
|
||||
Output_section** osymtab,
|
||||
Output_section** ostrtab);
|
||||
|
||||
// Finalize the symbol table.
|
||||
void
|
||||
finalize_symtab();
|
||||
// Create the .shstrtab section.
|
||||
Output_section*
|
||||
create_shstrtab();
|
||||
|
||||
// Create the section header table.
|
||||
Output_section_headers*
|
||||
create_shdrs(int size, off_t);
|
||||
|
||||
// Return whether to include this section in the link.
|
||||
template<int size, bool big_endian>
|
||||
@ -190,6 +209,8 @@ class Layout
|
||||
const General_options& options_;
|
||||
// The output section names.
|
||||
Stringpool namepool_;
|
||||
// The output symbol names.
|
||||
Stringpool sympool_;
|
||||
// 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.
|
||||
@ -199,9 +220,6 @@ class Layout
|
||||
// The list of output sections which are not attached to any output
|
||||
// segment.
|
||||
Section_list section_list_;
|
||||
// The list of output data objects which are not attached to any
|
||||
// output section or output segment.
|
||||
Data_list data_list_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
176
gold/object.cc
176
gold/object.cc
@ -47,7 +47,8 @@ Sized_object<size, big_endian>::Sized_object(
|
||||
shoff_(ehdr.get_e_shoff()),
|
||||
shstrndx_(0),
|
||||
symtab_shnum_(0),
|
||||
symbols_(NULL)
|
||||
symbols_(NULL),
|
||||
local_symbol_offset_(0)
|
||||
{
|
||||
if (ehdr.get_e_ehsize() != This::ehdr_size)
|
||||
{
|
||||
@ -70,6 +71,16 @@ Sized_object<size, big_endian>::~Sized_object()
|
||||
{
|
||||
}
|
||||
|
||||
// Read the section header for section SHNUM.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
const unsigned char*
|
||||
Sized_object<size, big_endian>::section_header(unsigned int shnum)
|
||||
{
|
||||
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
|
||||
return this->get_view(symtabshdroff, This::shdr_size);
|
||||
}
|
||||
|
||||
// Set up an object file bsaed on the file header. This sets up the
|
||||
// target and reads the section information.
|
||||
|
||||
@ -94,8 +105,7 @@ 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_, This::shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
typename This::Shdr shdr(this->section_header(0));
|
||||
if (shnum == 0)
|
||||
shnum = shdr.get_sh_size();
|
||||
if (shstrndx == elfcpp::SHN_XINDEX)
|
||||
@ -114,7 +124,7 @@ Sized_object<size, big_endian>::setup(
|
||||
p += This::shdr_size;
|
||||
for (unsigned int i = 1; i < shnum; ++i)
|
||||
{
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
typename This::Shdr shdr(p);
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
|
||||
{
|
||||
this->symtab_shnum_ = i;
|
||||
@ -136,23 +146,23 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
Read_symbols_data ret;
|
||||
ret.symbols = NULL;
|
||||
ret.symbols_size = 0;
|
||||
ret.first_global = 0;
|
||||
ret.symbol_names = NULL;
|
||||
ret.symbol_names_size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const int shdr_size = This::shdr_size;
|
||||
|
||||
// Read the symbol table section header.
|
||||
off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
|
||||
const unsigned char* psymtabshdr = this->get_view(symtabshdroff, shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
|
||||
typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
|
||||
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// We only need the external symbols.
|
||||
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;
|
||||
|
||||
// Read the symbol table.
|
||||
File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
|
||||
symtabshdr.get_sh_size());
|
||||
File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
|
||||
|
||||
// Read the section header for the symbol names.
|
||||
unsigned int strtab_shnum = symtabshdr.get_sh_link();
|
||||
@ -162,9 +172,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
program_name, this->name().c_str(), strtab_shnum);
|
||||
gold_exit(false);
|
||||
}
|
||||
off_t strtabshdroff = this->shoff_ + (strtab_shnum * shdr_size);
|
||||
const unsigned char *pstrtabshdr = this->get_view(strtabshdroff, shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> strtabshdr(pstrtabshdr);
|
||||
typename This::Shdr strtabshdr(this->section_header(strtab_shnum));
|
||||
if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
|
||||
{
|
||||
fprintf(stderr,
|
||||
@ -180,8 +188,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
|
||||
Read_symbols_data ret;
|
||||
ret.symbols = fvsymtab;
|
||||
ret.symbols_size = symtabshdr.get_sh_size();
|
||||
ret.first_global = symtabshdr.get_sh_info();
|
||||
ret.symbols_size = extsize;
|
||||
ret.symbol_names = fvstrtab;
|
||||
ret.symbol_names_size = strtabshdr.get_sh_size();
|
||||
|
||||
@ -211,29 +218,14 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
this->symbols_ = new Symbol*[symcount];
|
||||
|
||||
const elfcpp::Sym<size, big_endian>* syms =
|
||||
reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data());
|
||||
const char* sym_names =
|
||||
reinterpret_cast<const char*>(sd.symbol_names->data());
|
||||
|
||||
// We only add the global symbols to the symbol table.
|
||||
if (symcount > sd.first_global)
|
||||
{
|
||||
this->symbols_ = new Symbol*[symcount - sd.first_global];
|
||||
|
||||
const unsigned char* symdata = sd.symbols->data();
|
||||
symdata += sd.first_global * sym_size;
|
||||
const elfcpp::Sym<size, big_endian>* syms =
|
||||
reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(symdata);
|
||||
|
||||
symtab->add_from_object(this, syms, symcount - sd.first_global,
|
||||
sym_names, sd.symbol_names_size, this->symbols_);
|
||||
}
|
||||
|
||||
// Add the names of the local symbols. FIXME: We shouldn't do this
|
||||
// if we are stripping symbols.
|
||||
const elfcpp::Sym<size, big_endian>* local_syms =
|
||||
reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data());
|
||||
symtab->add_local_symbol_names(this, local_syms, sd.first_global,
|
||||
sym_names, sd.symbol_names_size);
|
||||
symtab->add_from_object(this, syms, symcount, sym_names,
|
||||
sd.symbol_names_size, this->symbols_);
|
||||
|
||||
delete sd.symbols;
|
||||
delete sd.symbol_names;
|
||||
@ -279,9 +271,8 @@ Sized_object<size, big_endian>::include_section_group(
|
||||
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);
|
||||
|
||||
typename This::Shdr symshdr(this->section_header(shdr.get_sh_link()));
|
||||
|
||||
// Read the symbol table entry.
|
||||
if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
|
||||
@ -302,10 +293,8 @@ Sized_object<size, big_endian>::include_section_group(
|
||||
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);
|
||||
|
||||
typename This::Shdr symnamehdr(this->section_header(symshdr.get_sh_link()));
|
||||
|
||||
// Read the symbol table names.
|
||||
const unsigned char *psymnamesu = this->get_view(symnamehdr.get_sh_offset(),
|
||||
@ -396,7 +385,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
|
||||
|
||||
// Get the section names.
|
||||
const unsigned char* pshdrnames = pshdrs + this->shstrndx_ * This::shdr_size;
|
||||
elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
|
||||
typename This::Shdr 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(),
|
||||
@ -411,7 +400,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
|
||||
|
||||
for (unsigned int i = 0; i < shnum; ++i)
|
||||
{
|
||||
elfcpp::Shdr<size, big_endian> shdr(pshdrs);
|
||||
typename This::Shdr shdr(pshdrs);
|
||||
|
||||
if (shdr.get_sh_name() >= names_size)
|
||||
{
|
||||
@ -456,12 +445,105 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the local symbols. Here we record the file offset at
|
||||
// which they should be output and we add their names to *POOL.
|
||||
// Return the new file offset. This function is always called from
|
||||
// the main thread. The actual output of the local symbols will occur
|
||||
// in a separate task.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||
Stringpool* pool)
|
||||
{
|
||||
this->local_symbol_offset_ = off;
|
||||
|
||||
// Read the symbol table section header.
|
||||
typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
|
||||
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// Read the local symbols.
|
||||
unsigned int loccount = symtabshdr.get_sh_info();
|
||||
const int sym_size = This::sym_size;
|
||||
off_t locsize = loccount * sym_size;
|
||||
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
|
||||
locsize);
|
||||
|
||||
// Read the section header for the symbol names.
|
||||
typename This::Shdr strtabshdr(
|
||||
this->section_header(symtabshdr.get_sh_link()));
|
||||
assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB);
|
||||
|
||||
// Read the symbol names.
|
||||
const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(),
|
||||
strtabshdr.get_sh_size());
|
||||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||
|
||||
// Loop over the local symbols.
|
||||
|
||||
std::vector<Map_to_output>& mo(this->map_to_output());
|
||||
unsigned int shnum = this->shnum();
|
||||
// Skip the first, dummy, symbol.
|
||||
psyms += sym_size;
|
||||
for (unsigned int i = 1; i < loccount; ++i)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(psyms);
|
||||
|
||||
unsigned int shndx = sym.get_st_shndx();
|
||||
|
||||
if (shndx >= elfcpp::SHN_LORESERVE)
|
||||
{
|
||||
if (shndx != elfcpp::SHN_ABS)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: unknown section index %u "
|
||||
"for local symbol %u\n"),
|
||||
program_name, this->name().c_str(), shndx, i);
|
||||
gold_exit(false);
|
||||
}
|
||||
// FIXME: Handle SHN_XINDEX.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shndx >= shnum)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: local symbol %u section index %u "
|
||||
"out of range\n"),
|
||||
program_name, this->name().c_str(), i, shndx);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (mo[shndx].output_section == NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
pool->add(pnames + sym.get_st_name());
|
||||
off += sym_size;
|
||||
|
||||
psyms += sym_size;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// Input_objects methods.
|
||||
|
||||
void
|
||||
Input_objects::add_object(Object* obj)
|
||||
{
|
||||
this->object_list_.push_back(obj);
|
||||
|
||||
Target* target = obj->target();
|
||||
if (this->target_ == NULL)
|
||||
this->target_ = target;
|
||||
else if (this->target_ != target)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: incompatible target\n",
|
||||
program_name, obj->name().c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (obj->is_dynamic())
|
||||
this->any_dynamic_ = true;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Stringpool;
|
||||
class Output_section;
|
||||
class Layout;
|
||||
|
||||
@ -25,8 +26,6 @@ struct Read_symbols_data
|
||||
File_view* symbols;
|
||||
// Size of symbol data in bytes.
|
||||
off_t symbols_size;
|
||||
// Index of first global symbol.
|
||||
unsigned int first_global;
|
||||
// Symbol names.
|
||||
File_view* symbol_names;
|
||||
// Size of symbol name data in bytes.
|
||||
@ -110,7 +109,13 @@ class Object
|
||||
layout(Layout* lay)
|
||||
{ this->do_layout(lay); }
|
||||
|
||||
protected:
|
||||
// Initial local symbol processing: set the offset where local
|
||||
// symbol information will be stored; add local symbol names to
|
||||
// *POOL; return the offset following the local symbols.
|
||||
off_t
|
||||
finalize_local_symbols(off_t off, Stringpool* pool)
|
||||
{ return this->do_finalize_local_symbols(off, pool); }
|
||||
|
||||
// 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.
|
||||
@ -123,6 +128,13 @@ class Object
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
// Given a section index, return the corresponding Map_to_output
|
||||
// information.
|
||||
const Map_to_output*
|
||||
section_output_info(unsigned int shnum) const
|
||||
{ return &this->map_to_output_[shnum]; }
|
||||
|
||||
protected:
|
||||
// Read the symbols--implemented by child class.
|
||||
virtual Read_symbols_data
|
||||
do_read_symbols() = 0;
|
||||
@ -136,6 +148,10 @@ class Object
|
||||
virtual void
|
||||
do_layout(Layout*) = 0;
|
||||
|
||||
// Finalize local symbols--implemented by child class.
|
||||
virtual off_t
|
||||
do_finalize_local_symbols(off_t, Stringpool*) = 0;
|
||||
|
||||
// Get the file.
|
||||
Input_file*
|
||||
input_file() const
|
||||
@ -152,7 +168,7 @@ class Object
|
||||
|
||||
// Get the number of sections.
|
||||
unsigned int
|
||||
shnum(void) const
|
||||
shnum() const
|
||||
{ return this->shnum_; }
|
||||
|
||||
// Set the number of sections.
|
||||
@ -243,6 +259,10 @@ class Sized_object : public Object
|
||||
void
|
||||
do_layout(Layout*);
|
||||
|
||||
// Finalize the local symbols.
|
||||
off_t
|
||||
do_finalize_local_symbols(off_t, Stringpool*);
|
||||
|
||||
// Return the appropriate Sized_target structure.
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target()
|
||||
@ -264,6 +284,11 @@ class Sized_object : public Object
|
||||
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;
|
||||
typedef elfcpp::Shdr<size, big_endian> Shdr;
|
||||
|
||||
// Read the section header for section SHNUM.
|
||||
const unsigned char*
|
||||
section_header(unsigned int shnum);
|
||||
|
||||
// Whether to include a section group in the link.
|
||||
bool
|
||||
@ -286,6 +311,8 @@ class Sized_object : public Object
|
||||
unsigned int symtab_shnum_;
|
||||
// The entries in the symbol table for the external symbols.
|
||||
Symbol** symbols_;
|
||||
// File offset for local symbols.
|
||||
off_t local_symbol_offset_;
|
||||
};
|
||||
|
||||
// A class to manage the list of all objects.
|
||||
@ -294,7 +321,7 @@ class Input_objects
|
||||
{
|
||||
public:
|
||||
Input_objects()
|
||||
: object_list_(), any_dynamic_(false)
|
||||
: object_list_(), target_(NULL), any_dynamic_(false)
|
||||
{ }
|
||||
|
||||
// The type of the list of input objects.
|
||||
@ -304,6 +331,11 @@ class Input_objects
|
||||
void
|
||||
add_object(Object*);
|
||||
|
||||
// Get the target we should use for the output file.
|
||||
Target*
|
||||
target() const
|
||||
{ return this->target_; }
|
||||
|
||||
// Iterate over all objects.
|
||||
Object_list::const_iterator
|
||||
begin() const
|
||||
@ -323,6 +355,7 @@ class Input_objects
|
||||
Input_objects& operator=(const Input_objects&);
|
||||
|
||||
Object_list object_list_;
|
||||
Target* target_;
|
||||
bool any_dynamic_;
|
||||
};
|
||||
|
||||
|
341
gold/output.cc
341
gold/output.cc
@ -3,6 +3,7 @@
|
||||
#include "gold.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
#include "object.h"
|
||||
#include "output.h"
|
||||
@ -16,18 +17,116 @@ Output_data::~Output_data()
|
||||
{
|
||||
}
|
||||
|
||||
// Set the address and offset.
|
||||
|
||||
void
|
||||
Output_data::set_address(uint64_t addr, off_t off)
|
||||
{
|
||||
this->address_ = addr;
|
||||
this->offset_ = off;
|
||||
|
||||
// Let the child class know.
|
||||
this->do_set_address(addr, off);
|
||||
}
|
||||
|
||||
// Return the default alignment for a size--32 or 64.
|
||||
|
||||
uint64_t
|
||||
Output_data::default_alignment(int size)
|
||||
{
|
||||
if (size == 32)
|
||||
return 4;
|
||||
else if (size == 64)
|
||||
return 8;
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Output_data_const methods.
|
||||
|
||||
void
|
||||
Output_data_const::write(Output_file* output, off_t off)
|
||||
Output_data_const::do_write(Output_file* output)
|
||||
{
|
||||
output->write(off, data_.data(), data_.size());
|
||||
output->write(this->offset(), data_.data(), data_.size());
|
||||
}
|
||||
|
||||
// Output_section_header methods. This currently assumes that the
|
||||
// segment and section lists are complete at construction time.
|
||||
|
||||
Output_section_headers::Output_section_headers(
|
||||
int size,
|
||||
const Layout::Segment_list& segment_list,
|
||||
const Layout::Section_list& section_list)
|
||||
: size_(size),
|
||||
segment_list_(segment_list),
|
||||
section_list_(section_list)
|
||||
{
|
||||
// Count all the sections.
|
||||
off_t count = 0;
|
||||
for (Layout::Segment_list::const_iterator p = segment_list.begin();
|
||||
p != segment_list.end();
|
||||
++p)
|
||||
count += (*p)->output_section_count();
|
||||
count += section_list.size();
|
||||
|
||||
int shdr_size;
|
||||
if (size == 32)
|
||||
shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
|
||||
else if (size == 64)
|
||||
shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
|
||||
else
|
||||
abort();
|
||||
|
||||
this->set_data_size(count * shdr_size);
|
||||
}
|
||||
|
||||
void
|
||||
Output_section_headers::do_write(Output_file*)
|
||||
{
|
||||
// FIXME: Unimplemented.
|
||||
abort();
|
||||
}
|
||||
|
||||
// Output_segment_header methods.
|
||||
|
||||
void
|
||||
Output_segment_headers::write(Output_file*, off_t)
|
||||
Output_segment_headers::do_write(Output_file*)
|
||||
{
|
||||
// FIXME: Unimplemented.
|
||||
abort();
|
||||
}
|
||||
|
||||
// Output_file_header methods.
|
||||
|
||||
Output_file_header::Output_file_header(int size,
|
||||
const General_options& options,
|
||||
const Target* target,
|
||||
const Symbol_table* symtab,
|
||||
const Output_segment_headers* osh)
|
||||
: size_(size),
|
||||
options_(options),
|
||||
target_(target),
|
||||
symtab_(symtab),
|
||||
program_header_(osh),
|
||||
section_header_(NULL),
|
||||
shstrtab_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// Set the section table information for a file header.
|
||||
|
||||
void
|
||||
Output_file_header::set_section_info(const Output_section_headers* shdrs,
|
||||
const Output_section* shstrtab)
|
||||
{
|
||||
this->section_header_ = shdrs;
|
||||
this->shstrtab_ = shstrtab;
|
||||
}
|
||||
|
||||
// Write out the file header.
|
||||
|
||||
void
|
||||
Output_file_header::do_write(Output_file*)
|
||||
{
|
||||
// FIXME: Unimplemented.
|
||||
abort();
|
||||
@ -40,10 +139,8 @@ Output_segment_headers::write(Output_file*, off_t)
|
||||
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),
|
||||
link_(0),
|
||||
info_(0),
|
||||
type_(type),
|
||||
@ -76,18 +173,49 @@ Output_section::add_input_section(Object* object, const char* secname,
|
||||
if (addralign > this->addralign_)
|
||||
this->addralign_ = addralign;
|
||||
|
||||
off_t ssize = this->get_size();
|
||||
off_t ssize = this->data_size();
|
||||
ssize = (ssize + addralign - 1) &~ (addralign - 1);
|
||||
|
||||
this->set_size(ssize + shdr.get_sh_size());
|
||||
// SHF_TLS/SHT_NOBITS sections are handled specially: they are
|
||||
// treated as having no size and taking up no space. We only use
|
||||
// the real size when setting the pt_memsz field of the PT_TLS
|
||||
// segment.
|
||||
if ((this->flags_ & elfcpp::SHF_TLS) == 0
|
||||
|| this->type_ != elfcpp::SHT_NOBITS)
|
||||
this->set_data_size(ssize + shdr.get_sh_size());
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Output_section_symtab methods.
|
||||
|
||||
Output_section_symtab::Output_section_symtab(const char* name, off_t size)
|
||||
: Output_section(name, elfcpp::SHT_SYMTAB, 0)
|
||||
{
|
||||
this->set_data_size(size);
|
||||
}
|
||||
|
||||
// Output_section_strtab methods.
|
||||
|
||||
Output_section_strtab::Output_section_strtab(const char* name,
|
||||
Stringpool* contents)
|
||||
: Output_section(name, elfcpp::SHT_STRTAB, 0),
|
||||
contents_(contents)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Output_section_strtab::do_write(Output_file*)
|
||||
{
|
||||
// FIXME: Unimplemented.
|
||||
abort();
|
||||
}
|
||||
|
||||
// Output segment methods.
|
||||
|
||||
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
||||
: output_data_(),
|
||||
output_bss_(),
|
||||
vaddr_(0),
|
||||
paddr_(0),
|
||||
memsz_(0),
|
||||
@ -102,10 +230,22 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
||||
// Add an Output_section to an Output_segment.
|
||||
|
||||
void
|
||||
Output_segment::add_output_section(Output_section* os)
|
||||
Output_segment::add_output_section(Output_section* os,
|
||||
elfcpp::Elf_Word seg_flags)
|
||||
{
|
||||
// Update the segment flags.
|
||||
this->flags_ |= os->flags() & (elfcpp::PF_R | elfcpp::PF_W | elfcpp::PF_X);
|
||||
assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
|
||||
|
||||
// Update the segment flags and alignment.
|
||||
this->flags_ |= seg_flags;
|
||||
uint64_t addralign = os->addralign();
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
Output_segment::Output_data_list* pdl;
|
||||
if (os->type() == elfcpp::SHT_NOBITS)
|
||||
pdl = &this->output_bss_;
|
||||
else
|
||||
pdl = &this->output_data_;
|
||||
|
||||
// So that PT_NOTE segments will work correctly, we need to ensure
|
||||
// that all SHT_NOTE sections are adjacent. This will normally
|
||||
@ -122,37 +262,196 @@ Output_segment::add_output_section(Output_section* os)
|
||||
|
||||
if (os->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
for (Layout::Data_list::iterator p = this->output_data_.begin();
|
||||
p != this->output_data_.end();
|
||||
++p)
|
||||
Layout::Data_list::iterator p = pdl->end();
|
||||
do
|
||||
{
|
||||
--p;
|
||||
if ((*p)->is_section_type(elfcpp::SHT_NOTE))
|
||||
{
|
||||
++p;
|
||||
this->output_data_.insert(p, os);
|
||||
pdl->insert(p, os);
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (p != pdl->begin());
|
||||
}
|
||||
|
||||
// Similarly, so that PT_TLS segments will work, we need to group
|
||||
// SHF_TLS sections.
|
||||
// SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special
|
||||
// case: we group the SHF_TLS/SHT_NOBITS sections right after the
|
||||
// SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
|
||||
// correctly.
|
||||
if ((os->flags() & elfcpp::SHF_TLS) != 0)
|
||||
{
|
||||
for (Layout::Data_list::iterator p = this->output_data_.begin();
|
||||
p != this->output_data_.end();
|
||||
++p)
|
||||
pdl = &this->output_data_;
|
||||
bool nobits = os->type() == elfcpp::SHT_NOBITS;
|
||||
Layout::Data_list::iterator p = pdl->end();
|
||||
do
|
||||
{
|
||||
if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
|
||||
--p;
|
||||
if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)
|
||||
&& (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS)))
|
||||
{
|
||||
++p;
|
||||
this->output_data_.insert(p, os);
|
||||
pdl->insert(p, os);
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (p != pdl->begin());
|
||||
}
|
||||
|
||||
this->output_data_.push_back(os);
|
||||
pdl->push_back(os);
|
||||
}
|
||||
|
||||
// Add an Output_data (which is not an Output_section) to the start of
|
||||
// a segment.
|
||||
|
||||
void
|
||||
Output_segment::add_initial_output_data(Output_data* od)
|
||||
{
|
||||
uint64_t addralign = od->addralign();
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
this->output_data_.push_front(od);
|
||||
}
|
||||
|
||||
// Return the maximum alignment of the Output_data in Output_segment.
|
||||
// We keep this up to date as we add Output_sections and Output_data.
|
||||
|
||||
uint64_t
|
||||
Output_segment::max_data_align() const
|
||||
{
|
||||
return this->align_;
|
||||
}
|
||||
|
||||
// Set the section addresses for an Output_segment. ADDR is the
|
||||
// address and *POFF is the file offset. Return the address of the
|
||||
// immediately following segment. Update *POFF.
|
||||
|
||||
uint64_t
|
||||
Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
|
||||
{
|
||||
assert(this->type_ == elfcpp::PT_LOAD);
|
||||
|
||||
this->vaddr_ = addr;
|
||||
this->paddr_ = addr;
|
||||
|
||||
off_t orig_off = *poff;
|
||||
this->offset_ = orig_off;
|
||||
|
||||
addr = this->set_section_list_addresses(&this->output_data_, addr, poff);
|
||||
this->filesz_ = *poff - orig_off;
|
||||
|
||||
off_t off = *poff;
|
||||
|
||||
return this->set_section_list_addresses(&this->output_bss_, addr, poff);
|
||||
this->memsz_ = *poff - orig_off;
|
||||
|
||||
// Ignore the file offset adjustments made by the BSS Output_data
|
||||
// objects.
|
||||
*poff = off;
|
||||
}
|
||||
|
||||
// Set the addresses in a list of Output_data structures.
|
||||
|
||||
uint64_t
|
||||
Output_segment::set_section_list_addresses(Output_data_list* pdl,
|
||||
uint64_t addr, off_t* poff)
|
||||
{
|
||||
off_t off = *poff;
|
||||
|
||||
for (Output_data_list::iterator p = pdl->begin();
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
addr = (addr + addralign - 1) & ~ (addralign - 1);
|
||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||
(*p)->set_address(addr, off);
|
||||
|
||||
uint64_t size = (*p)->data_size();
|
||||
addr += size;
|
||||
off += size;
|
||||
}
|
||||
|
||||
*poff = off;
|
||||
return addr;
|
||||
}
|
||||
|
||||
// For a non-PT_LOAD segment, set the offset from the sections, if
|
||||
// any.
|
||||
|
||||
void
|
||||
Output_segment::set_offset()
|
||||
{
|
||||
assert(this->type_ != elfcpp::PT_LOAD);
|
||||
|
||||
if (this->output_data_.empty() && this->output_bss_.empty())
|
||||
{
|
||||
this->vaddr_ = 0;
|
||||
this->paddr_ = 0;
|
||||
this->memsz_ = 0;
|
||||
this->align_ = 0;
|
||||
this->offset_ = 0;
|
||||
this->filesz_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const Output_data* first;
|
||||
if (this->output_data_.empty())
|
||||
first = this->output_bss_.front();
|
||||
else
|
||||
first = this->output_data_.front();
|
||||
this->vaddr_ = first->address();
|
||||
this->paddr_ = this->vaddr_;
|
||||
this->offset_ = first->offset();
|
||||
|
||||
if (this->output_data_.empty())
|
||||
this->filesz_ = 0;
|
||||
else
|
||||
{
|
||||
const Output_data* last_data = this->output_data_.back();
|
||||
this->filesz_ = (last_data->address()
|
||||
+ last_data->data_size()
|
||||
- this->vaddr_);
|
||||
}
|
||||
|
||||
const Output_data* last;
|
||||
if (this->output_bss_.empty())
|
||||
last = this->output_data_.back();
|
||||
else
|
||||
last = this->output_bss_.back();
|
||||
this->memsz_ = (last->address()
|
||||
+ last->data_size()
|
||||
- this->vaddr_);
|
||||
|
||||
// this->align_ was set as we added items.
|
||||
}
|
||||
|
||||
// Return the number of Output_sections in an Output_segment.
|
||||
|
||||
unsigned int
|
||||
Output_segment::output_section_count() const
|
||||
{
|
||||
return (this->output_section_count_list(&this->output_data_)
|
||||
+ this->output_section_count_list(&this->output_bss_));
|
||||
}
|
||||
|
||||
// Return the number of Output_sections in an Output_data_list.
|
||||
|
||||
unsigned int
|
||||
Output_segment::output_section_count_list(const Output_data_list* pdl) const
|
||||
{
|
||||
unsigned int count = 0;
|
||||
for (Output_data_list::const_iterator p = pdl->begin();
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->is_section())
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Output_file methods.
|
||||
|
258
gold/output.h
258
gold/output.h
@ -3,6 +3,7 @@
|
||||
#ifndef GOLD_OUTPUT_H
|
||||
#define GOLD_OUTPUT_H
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
#include "elfcpp.h"
|
||||
@ -22,47 +23,113 @@ class Sized_target;
|
||||
class Output_data
|
||||
{
|
||||
public:
|
||||
Output_data(off_t size = 0)
|
||||
: size_(size)
|
||||
explicit Output_data(off_t data_size = 0)
|
||||
: address_(0), data_size_(data_size), offset_(0)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
~Output_data();
|
||||
|
||||
// Return the size of the data. This can't be called "size" since
|
||||
// that interferes with the widely used template parameter name.
|
||||
off_t
|
||||
get_size()
|
||||
{ return this->size_; }
|
||||
// Return the address.
|
||||
uint64_t
|
||||
address() const
|
||||
{ return this->address_; }
|
||||
|
||||
// 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;
|
||||
// Return the size of the data.
|
||||
off_t
|
||||
data_size() const
|
||||
{ return this->data_size_; }
|
||||
|
||||
// Return the file offset.
|
||||
off_t
|
||||
offset() const
|
||||
{ return this->offset_; }
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
addralign() const
|
||||
{ return this->do_addralign(); }
|
||||
|
||||
// Return whether this is an Output_section.
|
||||
bool
|
||||
is_section() const
|
||||
{ return this->do_is_section(); }
|
||||
|
||||
// Return whether this is an Output_section of the specified type.
|
||||
virtual bool
|
||||
is_section_type(elfcpp::Elf_Word)
|
||||
{ return false; }
|
||||
bool
|
||||
is_section_type(elfcpp::Elf_Word stt) const
|
||||
{ return this->do_is_section_type(stt); }
|
||||
|
||||
// Return whether this is an Output_section with the specified flag
|
||||
// set.
|
||||
virtual bool
|
||||
is_section_flag_set(elfcpp::Elf_Xword)
|
||||
{ return false; }
|
||||
bool
|
||||
is_section_flag_set(elfcpp::Elf_Xword shf) const
|
||||
{ return this->do_is_section_flag_set(shf); }
|
||||
|
||||
// Set the address and file offset of this data.
|
||||
void
|
||||
set_address(uint64_t addr, off_t off);
|
||||
|
||||
// Write the data to the output file.
|
||||
void
|
||||
write(Output_file* file)
|
||||
{ this->do_write(file); }
|
||||
|
||||
protected:
|
||||
// Functions that child classes may or in some cases must implement.
|
||||
|
||||
// Write the data to the output file.
|
||||
virtual void
|
||||
do_write(Output_file*) = 0;
|
||||
|
||||
// Return the required alignment.
|
||||
virtual uint64_t
|
||||
do_addralign() const = 0;
|
||||
|
||||
// Return whether this is an Output_section.
|
||||
virtual bool
|
||||
do_is_section() const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is an Output_section of the specified type.
|
||||
// This only needs to be implement by Output_section.
|
||||
virtual bool
|
||||
do_is_section_type(elfcpp::Elf_Word) const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is an Output_section with the specific flag
|
||||
// set. This only needs to be implemented by Output_section.
|
||||
virtual bool
|
||||
do_is_section_flag_set(elfcpp::Elf_Xword) const
|
||||
{ return false; }
|
||||
|
||||
// Set the address and file offset of the data. This only needs to
|
||||
// be implemented if the child needs to know.
|
||||
virtual void
|
||||
do_set_address(uint64_t, off_t)
|
||||
{ }
|
||||
|
||||
// Functions that child classes may call.
|
||||
|
||||
// Set the size of the data.
|
||||
void
|
||||
set_size(off_t size)
|
||||
{ this->size_ = size; }
|
||||
set_data_size(off_t data_size)
|
||||
{ this->data_size_ = data_size; }
|
||||
|
||||
// Return default alignment for a size--32 or 64.
|
||||
static uint64_t
|
||||
default_alignment(int size);
|
||||
|
||||
private:
|
||||
Output_data(const Output_data&);
|
||||
Output_data& operator=(const Output_data&);
|
||||
|
||||
// Memory address in file (not always meaningful).
|
||||
uint64_t address_;
|
||||
// Size of data in file.
|
||||
off_t size_;
|
||||
off_t data_size_;
|
||||
// Offset within file.
|
||||
off_t offset_;
|
||||
};
|
||||
|
||||
// A simple case of Output_data in which we have constant data to
|
||||
@ -71,20 +138,26 @@ class Output_data
|
||||
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 std::string& data, uint64_t addralign)
|
||||
: Output_data(data.size()), data_(data), addralign_(addralign)
|
||||
{ }
|
||||
|
||||
Output_data_const(const char* p, off_t len)
|
||||
: Output_data(len), data_(p, len)
|
||||
Output_data_const(const char* p, off_t len, uint64_t addralign)
|
||||
: Output_data(len), data_(p, len), addralign_(addralign)
|
||||
{ }
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
write(Output_file* output, off_t off);
|
||||
do_write(Output_file* output);
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
uint64_t addralign_;
|
||||
};
|
||||
|
||||
// Output the section headers.
|
||||
@ -92,14 +165,21 @@ class Output_data_const : public Output_data
|
||||
class Output_section_headers : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_section_headers(const Layout::Segment_list&,
|
||||
Output_section_headers(int size,
|
||||
const Layout::Segment_list&,
|
||||
const Layout::Section_list&);
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
write(Output_file*, off_t);
|
||||
do_write(Output_file*);
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return Output_data::default_alignment(this->size_); }
|
||||
|
||||
private:
|
||||
int size_;
|
||||
const Layout::Segment_list& segment_list_;
|
||||
const Layout::Section_list& section_list_;
|
||||
};
|
||||
@ -109,15 +189,21 @@ class Output_section_headers : public Output_data
|
||||
class Output_segment_headers : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_segment_headers(const Layout::Segment_list& segment_list)
|
||||
: segment_list_(segment_list)
|
||||
Output_segment_headers(int size, const Layout::Segment_list& segment_list)
|
||||
: size_(size), segment_list_(segment_list)
|
||||
{ }
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
write(Output_file*, off_t);
|
||||
do_write(Output_file*);
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return Output_data::default_alignment(this->size_); }
|
||||
|
||||
private:
|
||||
int size_;
|
||||
const Layout::Segment_list& segment_list_;
|
||||
};
|
||||
|
||||
@ -126,18 +212,34 @@ class Output_segment_headers : public Output_data
|
||||
class Output_file_header : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_file_header(const General_options&,
|
||||
Output_file_header(int size,
|
||||
const General_options&,
|
||||
const Target*,
|
||||
const Symbol_table*,
|
||||
const Output_segment_headers*,
|
||||
const Output_section_headers*,
|
||||
const Output_section* shstrtab);
|
||||
const Output_segment_headers*);
|
||||
|
||||
// Add information about the section headers. We lay out the ELF
|
||||
// file header before we create the section headers.
|
||||
void set_section_info(const Output_section_headers*,
|
||||
const Output_section* shstrtab);
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
write(Output_file*, off_t);
|
||||
do_write(Output_file*);
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return Output_data::default_alignment(this->size_); }
|
||||
|
||||
// Set the address and offset--we only implement this for error
|
||||
// checking.
|
||||
void
|
||||
do_set_address(uint64_t, off_t off) const
|
||||
{ assert(off == 0); }
|
||||
|
||||
private:
|
||||
int size_;
|
||||
const General_options& options_;
|
||||
const Target* target_;
|
||||
const Symbol_table* symtab_;
|
||||
@ -178,21 +280,36 @@ class Output_section : public Output_data
|
||||
flags() const
|
||||
{ return this->flags_; }
|
||||
|
||||
// Return the address alignment.
|
||||
uint64_t
|
||||
addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Write the data to the file. For a typical Output_section, this
|
||||
// does nothing. We write out the data by looping over all the
|
||||
// input sections.
|
||||
virtual void
|
||||
write(Output_file*, off_t)
|
||||
do_write(Output_file*)
|
||||
{ }
|
||||
|
||||
// Return the address alignment--function required by parent class.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Return whether this is an Output_section.
|
||||
bool
|
||||
do_is_section() const
|
||||
{ return true; }
|
||||
|
||||
// Return whether this is a section of the specified type.
|
||||
bool
|
||||
is_section_type(elfcpp::Elf_Word type)
|
||||
do_is_section_type(elfcpp::Elf_Word type) const
|
||||
{ return this->type_ == type; }
|
||||
|
||||
// Return whether the specified section flag is set.
|
||||
bool
|
||||
is_section_flag_set(elfcpp::Elf_Xword flag)
|
||||
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
|
||||
{ return (this->flags_ & flag) != 0; }
|
||||
|
||||
private:
|
||||
@ -200,14 +317,12 @@ class Output_section : public Output_data
|
||||
|
||||
// The name of the section. This will point into a Stringpool.
|
||||
const char* name_;
|
||||
// The section address.
|
||||
uint64_t addr_;
|
||||
// The section address is in the parent class.
|
||||
// The section alignment.
|
||||
uint64_t addralign_;
|
||||
// The section entry size.
|
||||
uint64_t entsize_;
|
||||
// The file offset.
|
||||
off_t offset_;
|
||||
// The file offset is in the parent class.
|
||||
// The section link field.
|
||||
unsigned int link_;
|
||||
// The section info field.
|
||||
@ -224,8 +339,22 @@ class Output_section : public Output_data
|
||||
class Output_section_symtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_symtab();
|
||||
~Output_section_symtab();
|
||||
Output_section_symtab(const char* name, off_t size);
|
||||
};
|
||||
|
||||
// A special Output_section which holds a string table.
|
||||
|
||||
class Output_section_strtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_strtab(const char* name, Stringpool* contents);
|
||||
|
||||
// Write out the data.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
private:
|
||||
Stringpool* contents_;
|
||||
};
|
||||
|
||||
// An output segment. PT_LOAD segments are built from collections of
|
||||
@ -258,9 +387,35 @@ class Output_segment
|
||||
flags() const
|
||||
{ return this->flags_; }
|
||||
|
||||
// Return the maximum alignment of the Output_data.
|
||||
uint64_t
|
||||
max_data_align() const;
|
||||
|
||||
// Add an Output_section to this segment.
|
||||
void
|
||||
add_output_section(Output_section*);
|
||||
add_output_section(Output_section*, elfcpp::Elf_Word seg_flags);
|
||||
|
||||
// Add an Output_data (which is not an Output_section) to the start
|
||||
// of this segment.
|
||||
void
|
||||
add_initial_output_data(Output_data*);
|
||||
|
||||
// Set the address of the segment to ADDR and the offset to *POFF
|
||||
// (aligned if necessary), and set the addresses and offsets of all
|
||||
// contained output sections accordingly. Return the address of the
|
||||
// immediately following segment. Update *POFF. This should only
|
||||
// be called for a PT_LOAD segment.
|
||||
uint64_t
|
||||
set_section_addresses(uint64_t addr, off_t* poff);
|
||||
|
||||
// Set the offset of this segment based on the section. This should
|
||||
// only be called for a non-PT_LOAD segment.
|
||||
void
|
||||
set_offset();
|
||||
|
||||
// Return the number of output sections.
|
||||
unsigned int
|
||||
output_section_count() const;
|
||||
|
||||
private:
|
||||
Output_segment(const Output_segment&);
|
||||
@ -268,9 +423,18 @@ class Output_segment
|
||||
|
||||
typedef std::list<Output_data*> Output_data_list;
|
||||
|
||||
// The list of output sections attached to this segment. This is
|
||||
// cleared after layout.
|
||||
// Set the section addresses in an Output_data_list.
|
||||
uint64_t
|
||||
set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff);
|
||||
|
||||
// Return the number of Output_sections in an Output_data_list.
|
||||
unsigned int
|
||||
output_section_count_list(const Output_data_list*) const;
|
||||
|
||||
// The list of output data with contents attached to this segment.
|
||||
Output_data_list output_data_;
|
||||
// The list of output data without contents attached to this segment.
|
||||
Output_data_list output_bss_;
|
||||
// The segment virtual address.
|
||||
uint64_t vaddr_;
|
||||
// The segment physical address.
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-09-26 14:19-0700\n"
|
||||
"POT-Creation-Date: 2006-09-27 15:38-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"
|
||||
@ -99,103 +99,113 @@ msgstr ""
|
||||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:54
|
||||
#: object.cc:55
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:61
|
||||
#: object.cc:62
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:87
|
||||
#: object.cc:98
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:161
|
||||
#: object.cc:171
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:171
|
||||
#: object.cc:179
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:209
|
||||
#: object.cc:216
|
||||
#, c-format
|
||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:278
|
||||
#: object.cc:270
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:289
|
||||
#: object.cc:280
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:300
|
||||
#: object.cc:291
|
||||
#, c-format
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:318
|
||||
#: object.cc:307
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:340
|
||||
#: object.cc:329
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:419
|
||||
#: object.cc:408
|
||||
#, c-format
|
||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:499
|
||||
#, c-format
|
||||
msgid "%s: %s: unknown section index %u for local symbol %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:511
|
||||
#, c-format
|
||||
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:502
|
||||
#: object.cc:584
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:526 object.cc:579 object.cc:600
|
||||
#: object.cc:608 object.cc:661 object.cc:682
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:535
|
||||
#: object.cc:617
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:538
|
||||
#: object.cc:620
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:546
|
||||
#: object.cc:628
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:553
|
||||
#: object.cc:635
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:561
|
||||
#: object.cc:643
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:568
|
||||
#: object.cc:650
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
@ -250,32 +260,27 @@ msgstr ""
|
||||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:70
|
||||
#: output.cc:167
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:135
|
||||
#: resolve.cc:144
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:141
|
||||
#: resolve.cc:150
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:271
|
||||
#: symtab.cc:322
|
||||
#, c-format
|
||||
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:285
|
||||
#: symtab.cc:336
|
||||
#, c-format
|
||||
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:342
|
||||
#, c-format
|
||||
msgid "%s: %s: bad local symbol name offset %u at %lu\n"
|
||||
msgstr ""
|
||||
|
103
gold/symtab.cc
103
gold/symtab.cc
@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "object.h"
|
||||
#include "output.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
@ -52,7 +53,7 @@ Sized_symbol<size>::init(const char* name, const char* version, Object* object,
|
||||
// Class Symbol_table.
|
||||
|
||||
Symbol_table::Symbol_table()
|
||||
: size_(0), table_(), namepool_(), output_pool_(), forwarders_()
|
||||
: size_(0), offset_(0), table_(), namepool_(), forwarders_()
|
||||
{
|
||||
}
|
||||
|
||||
@ -371,32 +372,58 @@ Symbol_table::add_from_object(
|
||||
}
|
||||
}
|
||||
|
||||
// Record the names of the local symbols for an object.
|
||||
// Set the final values for all the symbols. Record the file offset
|
||||
// OFF. Add their names to POOL. Return the new file offset.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol_table::add_local_symbol_names(Sized_object<size, big_endian>* object,
|
||||
const elfcpp::Sym<size, big_endian>* syms,
|
||||
size_t count, const char* sym_names,
|
||||
size_t sym_name_size)
|
||||
off_t
|
||||
Symbol_table::finalize(off_t off, Stringpool* pool)
|
||||
{
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(syms);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (this->size_ == 32)
|
||||
return this->sized_finalize<32>(off, pool);
|
||||
else
|
||||
return this->sized_finalize<64>(off, pool);
|
||||
}
|
||||
|
||||
// Set the final value for all the symbols.
|
||||
|
||||
template<int size>
|
||||
off_t
|
||||
Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
||||
{
|
||||
off = (off + size - 1) & ~ (size - 1);
|
||||
this->offset_ = off;
|
||||
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
Symbol_table_type::iterator p = this->table_.begin();
|
||||
while (p != this->table_.end())
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(p);
|
||||
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
|
||||
|
||||
unsigned int st_name = sym.get_st_name();
|
||||
if (st_name >= sym_name_size)
|
||||
// FIXME: Here we need to decide which symbols should go into
|
||||
// the output file.
|
||||
|
||||
const Object::Map_to_output* mo =
|
||||
sym->object()->section_output_info(sym->shnum());
|
||||
|
||||
if (mo->output_section == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: bad local symbol name offset %u at %lu\n"),
|
||||
program_name, object->name().c_str(), st_name,
|
||||
static_cast<unsigned long>(i));
|
||||
gold_exit(false);
|
||||
// We should be able to erase this symbol from the symbol
|
||||
// table, but at least with gcc 4.0.2
|
||||
// std::unordered_map::erase doesn't appear to return the
|
||||
// new iterator.
|
||||
// p = this->table_.erase(p);
|
||||
++p;
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->set_value(mo->output_section->address() + mo->offset);
|
||||
pool->add(sym->name());
|
||||
++p;
|
||||
off += sym_size;
|
||||
}
|
||||
|
||||
this->output_pool_.add(sym_names + st_name);
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
@ -443,40 +470,4 @@ Symbol_table::add_from_object<64, false>(
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_local_symbol_names<32, true>(
|
||||
Sized_object<32, true>* object,
|
||||
const elfcpp::Sym<32, true>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_local_symbol_names<32, false>(
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Sym<32, false>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_local_symbol_names<64, true>(
|
||||
Sized_object<64, true>* object,
|
||||
const elfcpp::Sym<64, true>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_local_symbol_names<64, false>(
|
||||
Sized_object<64, false>* object,
|
||||
const elfcpp::Sym<64, false>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size);
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -182,6 +182,12 @@ class Sized_symbol : public Symbol
|
||||
symsize() const
|
||||
{ return this->size_; }
|
||||
|
||||
// Set the symbol value. This is called when we store the final
|
||||
// values of the symbols into the symbol table.
|
||||
void
|
||||
set_value(Value_type value)
|
||||
{ this->value_ = value; }
|
||||
|
||||
private:
|
||||
Sized_symbol(const Sized_symbol&);
|
||||
Sized_symbol& operator=(const Sized_symbol&);
|
||||
@ -230,13 +236,12 @@ class Symbol_table
|
||||
const Sized_symbol<size>*
|
||||
get_sized_symbol(const Symbol*) const;
|
||||
|
||||
// Record the names of the local symbols for an object.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
add_local_symbol_names(Sized_object<size, big_endian>* object,
|
||||
const elfcpp::Sym<size, big_endian>* syms,
|
||||
size_t count, const char* sym_names,
|
||||
size_t sym_name_size);
|
||||
// Finalize the symbol table after we have set the final addresses
|
||||
// of all the input sections. This sets the final symbol values and
|
||||
// adds the names to *POOL. It records the file offset OFF, and
|
||||
// returns the new file offset.
|
||||
off_t
|
||||
finalize(off_t, Stringpool*);
|
||||
|
||||
private:
|
||||
Symbol_table(const Symbol_table&);
|
||||
@ -276,6 +281,11 @@ class Symbol_table
|
||||
bool big_endian);
|
||||
#endif
|
||||
|
||||
// Finalize symbols specialized for size.
|
||||
template<int size>
|
||||
off_t
|
||||
sized_finalize(off_t, Stringpool*);
|
||||
|
||||
// The type of the symbol hash table.
|
||||
|
||||
typedef std::pair<const char*, const char*> Symbol_table_key;
|
||||
@ -298,6 +308,10 @@ class Symbol_table
|
||||
// The size of the symbols in the symbol table (32 or 64).
|
||||
int size_;
|
||||
|
||||
// The file offset within the output symtab section where we should
|
||||
// write the table.
|
||||
off_t offset_;
|
||||
|
||||
// The symbol hash table.
|
||||
Symbol_table_type table_;
|
||||
|
||||
@ -305,11 +319,6 @@ class Symbol_table
|
||||
// Entries in the hash table point into this pool.
|
||||
Stringpool namepool_;
|
||||
|
||||
// A pool of symbol names to go into the output file. This is used
|
||||
// for all symbols, global and local, but only the names of symbols
|
||||
// which will definitely be output are added to this pool.
|
||||
Stringpool output_pool_;
|
||||
|
||||
// Forwarding symbols.
|
||||
Unordered_map<Symbol*, Symbol*> forwarders_;
|
||||
};
|
||||
|
@ -13,6 +13,8 @@
|
||||
#ifndef GOLD_TARGET_H
|
||||
#define GOLD_TARGET_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "symtab.h"
|
||||
#include "elfcpp.h"
|
||||
|
||||
@ -33,43 +35,70 @@ class Target
|
||||
// return 32 or 64.
|
||||
int
|
||||
get_size() const
|
||||
{ return this->size_; }
|
||||
{ return this->pti_->size; }
|
||||
|
||||
// Return whether this target is big-endian.
|
||||
bool
|
||||
is_big_endian() const
|
||||
{ return this->is_big_endian_; }
|
||||
{ return this->pti_->is_big_endian; }
|
||||
|
||||
// Whether this target has a specific make_symbol function.
|
||||
bool
|
||||
has_make_symbol() const
|
||||
{ return this->has_make_symbol_; }
|
||||
{ return this->pti_->has_make_symbol; }
|
||||
|
||||
// Whether this target has a specific resolve function.
|
||||
bool
|
||||
has_resolve() const
|
||||
{ return this->has_resolve_; }
|
||||
{ return this->pti_->has_resolve; }
|
||||
|
||||
// Return the default address to use for the text segment.
|
||||
uint64_t
|
||||
text_segment_address() const
|
||||
{ return this->pti_->text_segment_address; }
|
||||
|
||||
// Return the ABI specified page size.
|
||||
uint64_t
|
||||
abi_pagesize() const
|
||||
{ return this->pti_->abi_pagesize; }
|
||||
|
||||
// Return the common page size used on actual systems.
|
||||
uint64_t
|
||||
common_pagesize() const
|
||||
{ return this->pti_->common_pagesize; }
|
||||
|
||||
protected:
|
||||
Target(int size, bool is_big_endian, bool has_make_symbol, bool has_resolve)
|
||||
: size_(size),
|
||||
is_big_endian_(is_big_endian),
|
||||
has_make_symbol_(has_make_symbol),
|
||||
has_resolve_(has_resolve)
|
||||
// This struct holds the constant information for a child class. We
|
||||
// use a struct to avoid the overhead of virtual function calls for
|
||||
// simple information.
|
||||
struct Target_info
|
||||
{
|
||||
// Address size (32 or 64).
|
||||
int size;
|
||||
// Whether the target is big endian.
|
||||
bool is_big_endian;
|
||||
// Whether this target has a specific make_symbol function.
|
||||
bool has_make_symbol;
|
||||
// Whether this target has a specific resolve function.
|
||||
bool has_resolve;
|
||||
// The default text segment address.
|
||||
uint64_t text_segment_address;
|
||||
// The ABI specified page size.
|
||||
uint64_t abi_pagesize;
|
||||
// The common page size used by actual implementations.
|
||||
uint64_t common_pagesize;
|
||||
};
|
||||
|
||||
Target(const Target_info* pti)
|
||||
: pti_(pti)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Target(const Target&);
|
||||
Target& operator=(const Target&);
|
||||
|
||||
// The target size.
|
||||
int size_;
|
||||
// Whether this target is big endian.
|
||||
bool is_big_endian_;
|
||||
// Whether this target has a special make_symbol function.
|
||||
bool has_make_symbol_;
|
||||
// Whether this target has a special resolve function.
|
||||
bool has_resolve_;
|
||||
// The target information.
|
||||
const Target_info* pti_;
|
||||
};
|
||||
|
||||
// The abstract class for a specific size and endianness of target.
|
||||
@ -96,9 +125,12 @@ class Sized_target : public Target
|
||||
{ abort(); }
|
||||
|
||||
protected:
|
||||
Sized_target(bool has_make_symbol, bool has_resolve)
|
||||
: Target(size, big_endian, has_make_symbol, has_resolve)
|
||||
{ }
|
||||
Sized_target(const Target::Target_info* pti)
|
||||
: Target(pti)
|
||||
{
|
||||
assert(pti->size == size);
|
||||
assert(pti->is_big_endian ? big_endian : !big_endian);
|
||||
}
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
Loading…
Reference in New Issue
Block a user