mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 19:14:52 +08:00
701821154b
Following the same format as the implementation in ld:
9e2bb0cb5e
Generate a .note.package FDO package metadata ELF note, following
the spec: https://systemd.io/ELF_PACKAGE_METADATA/
If the jansson library is available at build time (and it is explicitly
enabled), link ld to it, and use it to validate that the input is
correct JSON, to avoid writing garbage to the file. The
configure option --enable-jansson has to be used to explicitly enable
it (error out when not found). This allows bootstrappers (or others who
are not interested) to seamlessly skip it without issues.
elfcpp/
* elfcpp.h: Add FDO_PACKAGING_METADATA note type.
gold/
* Makefile.am: Add jansson flags and libraries.
* configure.ac: Check for jansson library.
* layout.cc (Layout::create_notes): Call create_package_metadata().
(Layout::create_package_metadata): New function.
* layout.h (Layout::create_package_metadata): New function.
(Layout::package_metadata_note_): New data member.
* options.h (class General_options): Add --package-metadata option.
* testsuite/Makefile.am (object_unittest): Add jansson libraries.
(binary_unittest): Likewise.
(leb128_unittest): Likewise.
(overflow_unittest): Likewise.
(package_metadata_test): New test.
* testsuite/package_metadata_main.c: New test source.
6514 lines
199 KiB
C++
6514 lines
199 KiB
C++
// layout.cc -- lay out output file sections for gold
|
|
|
|
// Copyright (C) 2006-2022 Free Software Foundation, Inc.
|
|
// Written by Ian Lance Taylor <iant@google.com>.
|
|
|
|
// This file is part of gold.
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
// MA 02110-1301, USA.
|
|
|
|
#include "gold.h"
|
|
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <utility>
|
|
#include <fcntl.h>
|
|
#include <fnmatch.h>
|
|
#include <unistd.h>
|
|
#include "libiberty.h"
|
|
#include "md5.h"
|
|
#include "sha1.h"
|
|
#ifdef __MINGW32__
|
|
#include <windows.h>
|
|
#include <rpcdce.h>
|
|
#endif
|
|
#ifdef HAVE_JANSSON
|
|
#include <jansson.h>
|
|
#endif
|
|
|
|
#include "parameters.h"
|
|
#include "options.h"
|
|
#include "mapfile.h"
|
|
#include "script.h"
|
|
#include "script-sections.h"
|
|
#include "output.h"
|
|
#include "symtab.h"
|
|
#include "dynobj.h"
|
|
#include "ehframe.h"
|
|
#include "gdb-index.h"
|
|
#include "compressed_output.h"
|
|
#include "reduced_debug_output.h"
|
|
#include "object.h"
|
|
#include "reloc.h"
|
|
#include "descriptors.h"
|
|
#include "plugin.h"
|
|
#include "incremental.h"
|
|
#include "layout.h"
|
|
|
|
namespace gold
|
|
{
|
|
|
|
// Class Free_list.
|
|
|
|
// The total number of free lists used.
|
|
unsigned int Free_list::num_lists = 0;
|
|
// The total number of free list nodes used.
|
|
unsigned int Free_list::num_nodes = 0;
|
|
// The total number of calls to Free_list::remove.
|
|
unsigned int Free_list::num_removes = 0;
|
|
// The total number of nodes visited during calls to Free_list::remove.
|
|
unsigned int Free_list::num_remove_visits = 0;
|
|
// The total number of calls to Free_list::allocate.
|
|
unsigned int Free_list::num_allocates = 0;
|
|
// The total number of nodes visited during calls to Free_list::allocate.
|
|
unsigned int Free_list::num_allocate_visits = 0;
|
|
|
|
// Initialize the free list. Creates a single free list node that
|
|
// describes the entire region of length LEN. If EXTEND is true,
|
|
// allocate() is allowed to extend the region beyond its initial
|
|
// length.
|
|
|
|
void
|
|
Free_list::init(off_t len, bool extend)
|
|
{
|
|
this->list_.push_front(Free_list_node(0, len));
|
|
this->last_remove_ = this->list_.begin();
|
|
this->extend_ = extend;
|
|
this->length_ = len;
|
|
++Free_list::num_lists;
|
|
++Free_list::num_nodes;
|
|
}
|
|
|
|
// Remove a chunk from the free list. Because we start with a single
|
|
// node that covers the entire section, and remove chunks from it one
|
|
// at a time, we do not need to coalesce chunks or handle cases that
|
|
// span more than one free node. We expect to remove chunks from the
|
|
// free list in order, and we expect to have only a few chunks of free
|
|
// space left (corresponding to files that have changed since the last
|
|
// incremental link), so a simple linear list should provide sufficient
|
|
// performance.
|
|
|
|
void
|
|
Free_list::remove(off_t start, off_t end)
|
|
{
|
|
if (start == end)
|
|
return;
|
|
gold_assert(start < end);
|
|
|
|
++Free_list::num_removes;
|
|
|
|
Iterator p = this->last_remove_;
|
|
if (p->start_ > start)
|
|
p = this->list_.begin();
|
|
|
|
for (; p != this->list_.end(); ++p)
|
|
{
|
|
++Free_list::num_remove_visits;
|
|
// Find a node that wholly contains the indicated region.
|
|
if (p->start_ <= start && p->end_ >= end)
|
|
{
|
|
// Case 1: the indicated region spans the whole node.
|
|
// Add some fuzz to avoid creating tiny free chunks.
|
|
if (p->start_ + 3 >= start && p->end_ <= end + 3)
|
|
p = this->list_.erase(p);
|
|
// Case 2: remove a chunk from the start of the node.
|
|
else if (p->start_ + 3 >= start)
|
|
p->start_ = end;
|
|
// Case 3: remove a chunk from the end of the node.
|
|
else if (p->end_ <= end + 3)
|
|
p->end_ = start;
|
|
// Case 4: remove a chunk from the middle, and split
|
|
// the node into two.
|
|
else
|
|
{
|
|
Free_list_node newnode(p->start_, start);
|
|
p->start_ = end;
|
|
this->list_.insert(p, newnode);
|
|
++Free_list::num_nodes;
|
|
}
|
|
this->last_remove_ = p;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Did not find a node containing the given chunk. This could happen
|
|
// because a small chunk was already removed due to the fuzz.
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"Free_list::remove(%d,%d) not found",
|
|
static_cast<int>(start), static_cast<int>(end));
|
|
}
|
|
|
|
// Allocate a chunk of size LEN from the free list. Returns -1ULL
|
|
// if a sufficiently large chunk of free space is not found.
|
|
// We use a simple first-fit algorithm.
|
|
|
|
off_t
|
|
Free_list::allocate(off_t len, uint64_t align, off_t minoff)
|
|
{
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"Free_list::allocate(%08lx, %d, %08lx)",
|
|
static_cast<long>(len), static_cast<int>(align),
|
|
static_cast<long>(minoff));
|
|
if (len == 0)
|
|
return align_address(minoff, align);
|
|
|
|
++Free_list::num_allocates;
|
|
|
|
// We usually want to drop free chunks smaller than 4 bytes.
|
|
// If we need to guarantee a minimum hole size, though, we need
|
|
// to keep track of all free chunks.
|
|
const int fuzz = this->min_hole_ > 0 ? 0 : 3;
|
|
|
|
for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
|
|
{
|
|
++Free_list::num_allocate_visits;
|
|
off_t start = p->start_ > minoff ? p->start_ : minoff;
|
|
start = align_address(start, align);
|
|
off_t end = start + len;
|
|
if (end > p->end_ && p->end_ == this->length_ && this->extend_)
|
|
{
|
|
this->length_ = end;
|
|
p->end_ = end;
|
|
}
|
|
if (end == p->end_ || (end <= p->end_ - this->min_hole_))
|
|
{
|
|
if (p->start_ + fuzz >= start && p->end_ <= end + fuzz)
|
|
this->list_.erase(p);
|
|
else if (p->start_ + fuzz >= start)
|
|
p->start_ = end;
|
|
else if (p->end_ <= end + fuzz)
|
|
p->end_ = start;
|
|
else
|
|
{
|
|
Free_list_node newnode(p->start_, start);
|
|
p->start_ = end;
|
|
this->list_.insert(p, newnode);
|
|
++Free_list::num_nodes;
|
|
}
|
|
return start;
|
|
}
|
|
}
|
|
if (this->extend_)
|
|
{
|
|
off_t start = align_address(this->length_, align);
|
|
this->length_ = start + len;
|
|
return start;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Dump the free list (for debugging).
|
|
void
|
|
Free_list::dump()
|
|
{
|
|
gold_info("Free list:\n start end length\n");
|
|
for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
|
|
gold_info(" %08lx %08lx %08lx", static_cast<long>(p->start_),
|
|
static_cast<long>(p->end_),
|
|
static_cast<long>(p->end_ - p->start_));
|
|
}
|
|
|
|
// Print the statistics for the free lists.
|
|
void
|
|
Free_list::print_stats()
|
|
{
|
|
fprintf(stderr, _("%s: total free lists: %u\n"),
|
|
program_name, Free_list::num_lists);
|
|
fprintf(stderr, _("%s: total free list nodes: %u\n"),
|
|
program_name, Free_list::num_nodes);
|
|
fprintf(stderr, _("%s: calls to Free_list::remove: %u\n"),
|
|
program_name, Free_list::num_removes);
|
|
fprintf(stderr, _("%s: nodes visited: %u\n"),
|
|
program_name, Free_list::num_remove_visits);
|
|
fprintf(stderr, _("%s: calls to Free_list::allocate: %u\n"),
|
|
program_name, Free_list::num_allocates);
|
|
fprintf(stderr, _("%s: nodes visited: %u\n"),
|
|
program_name, Free_list::num_allocate_visits);
|
|
}
|
|
|
|
// A Hash_task computes the MD5 checksum of an array of char.
|
|
|
|
class Hash_task : public Task
|
|
{
|
|
public:
|
|
Hash_task(Output_file* of,
|
|
size_t offset,
|
|
size_t size,
|
|
unsigned char* dst,
|
|
Task_token* final_blocker)
|
|
: of_(of), offset_(offset), size_(size), dst_(dst),
|
|
final_blocker_(final_blocker)
|
|
{ }
|
|
|
|
void
|
|
run(Workqueue*)
|
|
{
|
|
const unsigned char* iv =
|
|
this->of_->get_input_view(this->offset_, this->size_);
|
|
md5_buffer(reinterpret_cast<const char*>(iv), this->size_, this->dst_);
|
|
this->of_->free_input_view(this->offset_, this->size_, iv);
|
|
}
|
|
|
|
Task_token*
|
|
is_runnable()
|
|
{ return NULL; }
|
|
|
|
// Unblock FINAL_BLOCKER_ when done.
|
|
void
|
|
locks(Task_locker* tl)
|
|
{ tl->add(this, this->final_blocker_); }
|
|
|
|
std::string
|
|
get_name() const
|
|
{ return "Hash_task"; }
|
|
|
|
private:
|
|
Output_file* of_;
|
|
const size_t offset_;
|
|
const size_t size_;
|
|
unsigned char* const dst_;
|
|
Task_token* const final_blocker_;
|
|
};
|
|
|
|
// Layout::Relaxation_debug_check methods.
|
|
|
|
// Check that sections and special data are in reset states.
|
|
// We do not save states for Output_sections and special Output_data.
|
|
// So we check that they have not assigned any addresses or offsets.
|
|
// clean_up_after_relaxation simply resets their addresses and offsets.
|
|
void
|
|
Layout::Relaxation_debug_check::check_output_data_for_reset_values(
|
|
const Layout::Section_list& sections,
|
|
const Layout::Data_list& special_outputs,
|
|
const Layout::Data_list& relax_outputs)
|
|
{
|
|
for(Layout::Section_list::const_iterator p = sections.begin();
|
|
p != sections.end();
|
|
++p)
|
|
gold_assert((*p)->address_and_file_offset_have_reset_values());
|
|
|
|
for(Layout::Data_list::const_iterator p = special_outputs.begin();
|
|
p != special_outputs.end();
|
|
++p)
|
|
gold_assert((*p)->address_and_file_offset_have_reset_values());
|
|
|
|
gold_assert(relax_outputs.empty());
|
|
}
|
|
|
|
// Save information of SECTIONS for checking later.
|
|
|
|
void
|
|
Layout::Relaxation_debug_check::read_sections(
|
|
const Layout::Section_list& sections)
|
|
{
|
|
for(Layout::Section_list::const_iterator p = sections.begin();
|
|
p != sections.end();
|
|
++p)
|
|
{
|
|
Output_section* os = *p;
|
|
Section_info info;
|
|
info.output_section = os;
|
|
info.address = os->is_address_valid() ? os->address() : 0;
|
|
info.data_size = os->is_data_size_valid() ? os->data_size() : -1;
|
|
info.offset = os->is_offset_valid()? os->offset() : -1 ;
|
|
this->section_infos_.push_back(info);
|
|
}
|
|
}
|
|
|
|
// Verify SECTIONS using previously recorded information.
|
|
|
|
void
|
|
Layout::Relaxation_debug_check::verify_sections(
|
|
const Layout::Section_list& sections)
|
|
{
|
|
size_t i = 0;
|
|
for(Layout::Section_list::const_iterator p = sections.begin();
|
|
p != sections.end();
|
|
++p, ++i)
|
|
{
|
|
Output_section* os = *p;
|
|
uint64_t address = os->is_address_valid() ? os->address() : 0;
|
|
off_t data_size = os->is_data_size_valid() ? os->data_size() : -1;
|
|
off_t offset = os->is_offset_valid()? os->offset() : -1 ;
|
|
|
|
if (i >= this->section_infos_.size())
|
|
{
|
|
gold_fatal("Section_info of %s missing.\n", os->name());
|
|
}
|
|
const Section_info& info = this->section_infos_[i];
|
|
if (os != info.output_section)
|
|
gold_fatal("Section order changed. Expecting %s but see %s\n",
|
|
info.output_section->name(), os->name());
|
|
if (address != info.address
|
|
|| data_size != info.data_size
|
|
|| offset != info.offset)
|
|
gold_fatal("Section %s changed.\n", os->name());
|
|
}
|
|
}
|
|
|
|
// Layout_task_runner methods.
|
|
|
|
// Lay out the sections. This is called after all the input objects
|
|
// have been read.
|
|
|
|
void
|
|
Layout_task_runner::run(Workqueue* workqueue, const Task* task)
|
|
{
|
|
// See if any of the input definitions violate the One Definition Rule.
|
|
// TODO: if this is too slow, do this as a task, rather than inline.
|
|
this->symtab_->detect_odr_violations(task, this->options_.output_file_name());
|
|
|
|
Layout* layout = this->layout_;
|
|
off_t file_size = layout->finalize(this->input_objects_,
|
|
this->symtab_,
|
|
this->target_,
|
|
task);
|
|
|
|
// Now we know the final size of the output file and we know where
|
|
// each piece of information goes.
|
|
|
|
if (this->mapfile_ != NULL)
|
|
{
|
|
this->mapfile_->print_discarded_sections(this->input_objects_);
|
|
layout->print_to_mapfile(this->mapfile_);
|
|
}
|
|
|
|
Output_file* of;
|
|
if (layout->incremental_base() == NULL)
|
|
{
|
|
of = new Output_file(parameters->options().output_file_name());
|
|
if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
|
|
of->set_is_temporary();
|
|
of->open(file_size);
|
|
}
|
|
else
|
|
{
|
|
of = layout->incremental_base()->output_file();
|
|
|
|
// Apply the incremental relocations for symbols whose values
|
|
// have changed. We do this before we resize the file and start
|
|
// writing anything else to it, so that we can read the old
|
|
// incremental information from the file before (possibly)
|
|
// overwriting it.
|
|
if (parameters->incremental_update())
|
|
layout->incremental_base()->apply_incremental_relocs(this->symtab_,
|
|
this->layout_,
|
|
of);
|
|
|
|
of->resize(file_size);
|
|
}
|
|
|
|
// Queue up the final set of tasks.
|
|
gold::queue_final_tasks(this->options_, this->input_objects_,
|
|
this->symtab_, layout, workqueue, of);
|
|
}
|
|
|
|
// Layout methods.
|
|
|
|
Layout::Layout(int number_of_input_files, Script_options* script_options)
|
|
: number_of_input_files_(number_of_input_files),
|
|
script_options_(script_options),
|
|
namepool_(),
|
|
sympool_(),
|
|
dynpool_(),
|
|
signatures_(),
|
|
section_name_map_(),
|
|
segment_list_(),
|
|
section_list_(),
|
|
unattached_section_list_(),
|
|
special_output_list_(),
|
|
relax_output_list_(),
|
|
section_headers_(NULL),
|
|
tls_segment_(NULL),
|
|
relro_segment_(NULL),
|
|
interp_segment_(NULL),
|
|
increase_relro_(0),
|
|
symtab_section_(NULL),
|
|
symtab_xindex_(NULL),
|
|
dynsym_section_(NULL),
|
|
dynsym_xindex_(NULL),
|
|
dynamic_section_(NULL),
|
|
dynamic_symbol_(NULL),
|
|
dynamic_data_(NULL),
|
|
eh_frame_section_(NULL),
|
|
eh_frame_data_(NULL),
|
|
added_eh_frame_data_(false),
|
|
eh_frame_hdr_section_(NULL),
|
|
gdb_index_data_(NULL),
|
|
build_id_note_(NULL),
|
|
debug_abbrev_(NULL),
|
|
debug_info_(NULL),
|
|
group_signatures_(),
|
|
output_file_size_(-1),
|
|
have_added_input_section_(false),
|
|
sections_are_attached_(false),
|
|
input_requires_executable_stack_(false),
|
|
input_with_gnu_stack_note_(false),
|
|
input_without_gnu_stack_note_(false),
|
|
has_static_tls_(false),
|
|
any_postprocessing_sections_(false),
|
|
resized_signatures_(false),
|
|
have_stabstr_section_(false),
|
|
section_ordering_specified_(false),
|
|
unique_segment_for_sections_specified_(false),
|
|
incremental_inputs_(NULL),
|
|
record_output_section_data_from_script_(false),
|
|
lto_slim_object_(false),
|
|
script_output_section_data_list_(),
|
|
segment_states_(NULL),
|
|
relaxation_debug_check_(NULL),
|
|
section_order_map_(),
|
|
section_segment_map_(),
|
|
input_section_position_(),
|
|
input_section_glob_(),
|
|
incremental_base_(NULL),
|
|
free_list_(),
|
|
gnu_properties_()
|
|
{
|
|
// Make space for more than enough segments for a typical file.
|
|
// This is just for efficiency--it's OK if we wind up needing more.
|
|
this->segment_list_.reserve(12);
|
|
|
|
// We expect two unattached Output_data objects: the file header and
|
|
// the segment headers.
|
|
this->special_output_list_.reserve(2);
|
|
|
|
// Initialize structure needed for an incremental build.
|
|
if (parameters->incremental())
|
|
this->incremental_inputs_ = new Incremental_inputs;
|
|
|
|
// The section name pool is worth optimizing in all cases, because
|
|
// it is small, but there are often overlaps due to .rel sections.
|
|
this->namepool_.set_optimize();
|
|
}
|
|
|
|
// For incremental links, record the base file to be modified.
|
|
|
|
void
|
|
Layout::set_incremental_base(Incremental_binary* base)
|
|
{
|
|
this->incremental_base_ = base;
|
|
this->free_list_.init(base->output_file()->filesize(), true);
|
|
}
|
|
|
|
// Hash a key we use to look up an output section mapping.
|
|
|
|
size_t
|
|
Layout::Hash_key::operator()(const Layout::Key& k) const
|
|
{
|
|
return k.first + k.second.first + k.second.second;
|
|
}
|
|
|
|
// These are the debug sections that are actually used by gdb.
|
|
// Currently, we've checked versions of gdb up to and including 7.4.
|
|
// We only check the part of the name that follows ".debug_" or
|
|
// ".zdebug_".
|
|
|
|
static const char* gdb_sections[] =
|
|
{
|
|
"abbrev",
|
|
"addr", // Fission extension
|
|
// "aranges", // not used by gdb as of 7.4
|
|
"frame",
|
|
"gdb_scripts",
|
|
"info",
|
|
"types",
|
|
"line",
|
|
"loc",
|
|
"macinfo",
|
|
"macro",
|
|
// "pubnames", // not used by gdb as of 7.4
|
|
// "pubtypes", // not used by gdb as of 7.4
|
|
// "gnu_pubnames", // Fission extension
|
|
// "gnu_pubtypes", // Fission extension
|
|
"ranges",
|
|
"str",
|
|
"str_offsets",
|
|
};
|
|
|
|
// This is the minimum set of sections needed for line numbers.
|
|
|
|
static const char* lines_only_debug_sections[] =
|
|
{
|
|
"abbrev",
|
|
// "addr", // Fission extension
|
|
// "aranges", // not used by gdb as of 7.4
|
|
// "frame",
|
|
// "gdb_scripts",
|
|
"info",
|
|
// "types",
|
|
"line",
|
|
// "loc",
|
|
// "macinfo",
|
|
// "macro",
|
|
// "pubnames", // not used by gdb as of 7.4
|
|
// "pubtypes", // not used by gdb as of 7.4
|
|
// "gnu_pubnames", // Fission extension
|
|
// "gnu_pubtypes", // Fission extension
|
|
// "ranges",
|
|
"str",
|
|
"str_offsets", // Fission extension
|
|
};
|
|
|
|
// These sections are the DWARF fast-lookup tables, and are not needed
|
|
// when building a .gdb_index section.
|
|
|
|
static const char* gdb_fast_lookup_sections[] =
|
|
{
|
|
"aranges",
|
|
"pubnames",
|
|
"gnu_pubnames",
|
|
"pubtypes",
|
|
"gnu_pubtypes",
|
|
};
|
|
|
|
// Returns whether the given debug section is in the list of
|
|
// debug-sections-used-by-some-version-of-gdb. SUFFIX is the
|
|
// portion of the name following ".debug_" or ".zdebug_".
|
|
|
|
static inline bool
|
|
is_gdb_debug_section(const char* suffix)
|
|
{
|
|
// We can do this faster: binary search or a hashtable. But why bother?
|
|
for (size_t i = 0; i < sizeof(gdb_sections)/sizeof(*gdb_sections); ++i)
|
|
if (strcmp(suffix, gdb_sections[i]) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Returns whether the given section is needed for lines-only debugging.
|
|
|
|
static inline bool
|
|
is_lines_only_debug_section(const char* suffix)
|
|
{
|
|
// We can do this faster: binary search or a hashtable. But why bother?
|
|
for (size_t i = 0;
|
|
i < sizeof(lines_only_debug_sections)/sizeof(*lines_only_debug_sections);
|
|
++i)
|
|
if (strcmp(suffix, lines_only_debug_sections[i]) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Returns whether the given section is a fast-lookup section that
|
|
// will not be needed when building a .gdb_index section.
|
|
|
|
static inline bool
|
|
is_gdb_fast_lookup_section(const char* suffix)
|
|
{
|
|
// We can do this faster: binary search or a hashtable. But why bother?
|
|
for (size_t i = 0;
|
|
i < sizeof(gdb_fast_lookup_sections)/sizeof(*gdb_fast_lookup_sections);
|
|
++i)
|
|
if (strcmp(suffix, gdb_fast_lookup_sections[i]) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Sometimes we compress sections. This is typically done for
|
|
// sections that are not part of normal program execution (such as
|
|
// .debug_* sections), and where the readers of these sections know
|
|
// how to deal with compressed sections. This routine doesn't say for
|
|
// certain whether we'll compress -- it depends on commandline options
|
|
// as well -- just whether this section is a candidate for compression.
|
|
// (The Output_compressed_section class decides whether to compress
|
|
// a given section, and picks the name of the compressed section.)
|
|
|
|
static bool
|
|
is_compressible_debug_section(const char* secname)
|
|
{
|
|
return (is_prefix_of(".debug", secname));
|
|
}
|
|
|
|
// We may see compressed debug sections in input files. Return TRUE
|
|
// if this is the name of a compressed debug section.
|
|
|
|
bool
|
|
is_compressed_debug_section(const char* secname)
|
|
{
|
|
return (is_prefix_of(".zdebug", secname));
|
|
}
|
|
|
|
std::string
|
|
corresponding_uncompressed_section_name(std::string secname)
|
|
{
|
|
gold_assert(secname[0] == '.' && secname[1] == 'z');
|
|
std::string ret(".");
|
|
ret.append(secname, 2, std::string::npos);
|
|
return ret;
|
|
}
|
|
|
|
// Whether to include this section in the link.
|
|
|
|
template<int size, bool big_endian>
|
|
bool
|
|
Layout::include_section(Sized_relobj_file<size, big_endian>*, const char* name,
|
|
const elfcpp::Shdr<size, big_endian>& shdr)
|
|
{
|
|
if (!parameters->options().relocatable()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_EXCLUDE))
|
|
return false;
|
|
|
|
elfcpp::Elf_Word sh_type = shdr.get_sh_type();
|
|
|
|
if ((sh_type >= elfcpp::SHT_LOOS && sh_type <= elfcpp::SHT_HIOS)
|
|
|| (sh_type >= elfcpp::SHT_LOPROC && sh_type <= elfcpp::SHT_HIPROC))
|
|
return parameters->target().should_include_section(sh_type);
|
|
|
|
switch (sh_type)
|
|
{
|
|
case elfcpp::SHT_NULL:
|
|
case elfcpp::SHT_SYMTAB:
|
|
case elfcpp::SHT_DYNSYM:
|
|
case elfcpp::SHT_HASH:
|
|
case elfcpp::SHT_DYNAMIC:
|
|
case elfcpp::SHT_SYMTAB_SHNDX:
|
|
return false;
|
|
|
|
case elfcpp::SHT_STRTAB:
|
|
// Discard the sections which have special meanings in the ELF
|
|
// ABI. Keep others (e.g., .stabstr). We could also do this by
|
|
// checking the sh_link fields of the appropriate sections.
|
|
return (strcmp(name, ".dynstr") != 0
|
|
&& strcmp(name, ".strtab") != 0
|
|
&& strcmp(name, ".shstrtab") != 0);
|
|
|
|
case elfcpp::SHT_RELA:
|
|
case elfcpp::SHT_REL:
|
|
case elfcpp::SHT_GROUP:
|
|
// If we are emitting relocations these should be handled
|
|
// elsewhere.
|
|
gold_assert(!parameters->options().relocatable());
|
|
return false;
|
|
|
|
case elfcpp::SHT_PROGBITS:
|
|
if (parameters->options().strip_debug()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
|
{
|
|
if (is_debug_info_section(name))
|
|
return false;
|
|
}
|
|
if (parameters->options().strip_debug_non_line()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
|
{
|
|
// Debugging sections can only be recognized by name.
|
|
if (is_prefix_of(".debug_", name)
|
|
&& !is_lines_only_debug_section(name + 7))
|
|
return false;
|
|
if (is_prefix_of(".zdebug_", name)
|
|
&& !is_lines_only_debug_section(name + 8))
|
|
return false;
|
|
}
|
|
if (parameters->options().strip_debug_gdb()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
|
{
|
|
// Debugging sections can only be recognized by name.
|
|
if (is_prefix_of(".debug_", name)
|
|
&& !is_gdb_debug_section(name + 7))
|
|
return false;
|
|
if (is_prefix_of(".zdebug_", name)
|
|
&& !is_gdb_debug_section(name + 8))
|
|
return false;
|
|
}
|
|
if (parameters->options().gdb_index()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
|
{
|
|
// When building .gdb_index, we can strip .debug_pubnames,
|
|
// .debug_pubtypes, and .debug_aranges sections.
|
|
if (is_prefix_of(".debug_", name)
|
|
&& is_gdb_fast_lookup_section(name + 7))
|
|
return false;
|
|
if (is_prefix_of(".zdebug_", name)
|
|
&& is_gdb_fast_lookup_section(name + 8))
|
|
return false;
|
|
}
|
|
if (parameters->options().strip_lto_sections()
|
|
&& !parameters->options().relocatable()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
|
{
|
|
// Ignore LTO sections containing intermediate code.
|
|
if (is_prefix_of(".gnu.lto_", name))
|
|
return false;
|
|
}
|
|
// The GNU linker strips .gnu_debuglink sections, so we do too.
|
|
// This is a feature used to keep debugging information in
|
|
// separate files.
|
|
if (strcmp(name, ".gnu_debuglink") == 0)
|
|
return false;
|
|
return true;
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Return an output section named NAME, or NULL if there is none.
|
|
|
|
Output_section*
|
|
Layout::find_output_section(const char* name) const
|
|
{
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
if (strcmp((*p)->name(), name) == 0)
|
|
return *p;
|
|
return NULL;
|
|
}
|
|
|
|
// Return an output segment of type TYPE, with segment flags SET set
|
|
// and segment flags CLEAR clear. Return NULL if there is none.
|
|
|
|
Output_segment*
|
|
Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
|
|
elfcpp::Elf_Word clear) const
|
|
{
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
if (static_cast<elfcpp::PT>((*p)->type()) == type
|
|
&& ((*p)->flags() & set) == set
|
|
&& ((*p)->flags() & clear) == 0)
|
|
return *p;
|
|
return NULL;
|
|
}
|
|
|
|
// When we put a .ctors or .dtors section with more than one word into
|
|
// a .init_array or .fini_array section, we need to reverse the words
|
|
// in the .ctors/.dtors section. This is because .init_array executes
|
|
// constructors front to back, where .ctors executes them back to
|
|
// front, and vice-versa for .fini_array/.dtors. Although we do want
|
|
// to remap .ctors/.dtors into .init_array/.fini_array because it can
|
|
// be more efficient, we don't want to change the order in which
|
|
// constructors/destructors are run. This set just keeps track of
|
|
// these sections which need to be reversed. It is only changed by
|
|
// Layout::layout. It should be a private member of Layout, but that
|
|
// would require layout.h to #include object.h to get the definition
|
|
// of Section_id.
|
|
static Unordered_set<Section_id, Section_id_hash> ctors_sections_in_init_array;
|
|
|
|
// Return whether OBJECT/SHNDX is a .ctors/.dtors section mapped to a
|
|
// .init_array/.fini_array section.
|
|
|
|
bool
|
|
Layout::is_ctors_in_init_array(Relobj* relobj, unsigned int shndx) const
|
|
{
|
|
return (ctors_sections_in_init_array.find(Section_id(relobj, shndx))
|
|
!= ctors_sections_in_init_array.end());
|
|
}
|
|
|
|
// Return the output section to use for section NAME with type TYPE
|
|
// and section flags FLAGS. NAME must be canonicalized in the string
|
|
// pool, and NAME_KEY is the key. ORDER is where this should appear
|
|
// in the output sections. IS_RELRO is true for a relro section.
|
|
|
|
Output_section*
|
|
Layout::get_output_section(const char* name, Stringpool::Key name_key,
|
|
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
|
|
Output_section_order order, bool is_relro)
|
|
{
|
|
elfcpp::Elf_Word lookup_type = type;
|
|
|
|
// For lookup purposes, treat INIT_ARRAY, FINI_ARRAY, and
|
|
// PREINIT_ARRAY like PROGBITS. This ensures that we combine
|
|
// .init_array, .fini_array, and .preinit_array sections by name
|
|
// whatever their type in the input file. We do this because the
|
|
// types are not always right in the input files.
|
|
if (lookup_type == elfcpp::SHT_INIT_ARRAY
|
|
|| lookup_type == elfcpp::SHT_FINI_ARRAY
|
|
|| lookup_type == elfcpp::SHT_PREINIT_ARRAY)
|
|
lookup_type = elfcpp::SHT_PROGBITS;
|
|
|
|
elfcpp::Elf_Xword lookup_flags = flags;
|
|
|
|
// Ignoring SHF_WRITE and SHF_EXECINSTR here means that we combine
|
|
// read-write with read-only sections. Some other ELF linkers do
|
|
// not do this. FIXME: Perhaps there should be an option
|
|
// controlling this.
|
|
lookup_flags &= ~(elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR);
|
|
|
|
const Key key(name_key, std::make_pair(lookup_type, lookup_flags));
|
|
const std::pair<Key, Output_section*> v(key, NULL);
|
|
std::pair<Section_name_map::iterator, bool> ins(
|
|
this->section_name_map_.insert(v));
|
|
|
|
if (!ins.second)
|
|
return ins.first->second;
|
|
else
|
|
{
|
|
// This is the first time we've seen this name/type/flags
|
|
// combination. For compatibility with the GNU linker, we
|
|
// combine sections with contents and zero flags with sections
|
|
// with non-zero flags. This is a workaround for cases where
|
|
// assembler code forgets to set section flags. FIXME: Perhaps
|
|
// there should be an option to control this.
|
|
Output_section* os = NULL;
|
|
|
|
if (lookup_type == elfcpp::SHT_PROGBITS)
|
|
{
|
|
if (flags == 0)
|
|
{
|
|
Output_section* same_name = this->find_output_section(name);
|
|
if (same_name != NULL
|
|
&& (same_name->type() == elfcpp::SHT_PROGBITS
|
|
|| same_name->type() == elfcpp::SHT_INIT_ARRAY
|
|
|| same_name->type() == elfcpp::SHT_FINI_ARRAY
|
|
|| same_name->type() == elfcpp::SHT_PREINIT_ARRAY)
|
|
&& (same_name->flags() & elfcpp::SHF_TLS) == 0)
|
|
os = same_name;
|
|
}
|
|
else if ((flags & elfcpp::SHF_TLS) == 0)
|
|
{
|
|
elfcpp::Elf_Xword zero_flags = 0;
|
|
const Key zero_key(name_key, std::make_pair(lookup_type,
|
|
zero_flags));
|
|
Section_name_map::iterator p =
|
|
this->section_name_map_.find(zero_key);
|
|
if (p != this->section_name_map_.end())
|
|
os = p->second;
|
|
}
|
|
}
|
|
|
|
if (os == NULL)
|
|
os = this->make_output_section(name, type, flags, order, is_relro);
|
|
|
|
ins.first->second = os;
|
|
return os;
|
|
}
|
|
}
|
|
|
|
// Returns TRUE iff NAME (an input section from RELOBJ) will
|
|
// be mapped to an output section that should be KEPT.
|
|
|
|
bool
|
|
Layout::keep_input_section(const Relobj* relobj, const char* name)
|
|
{
|
|
if (! this->script_options_->saw_sections_clause())
|
|
return false;
|
|
|
|
Script_sections* ss = this->script_options_->script_sections();
|
|
const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
|
|
Output_section** output_section_slot;
|
|
Script_sections::Section_type script_section_type;
|
|
bool keep;
|
|
|
|
name = ss->output_section_name(file_name, name, &output_section_slot,
|
|
&script_section_type, &keep, true);
|
|
return name != NULL && keep;
|
|
}
|
|
|
|
// Clear the input section flags that should not be copied to the
|
|
// output section.
|
|
|
|
elfcpp::Elf_Xword
|
|
Layout::get_output_section_flags(elfcpp::Elf_Xword input_section_flags)
|
|
{
|
|
// Some flags in the input section should not be automatically
|
|
// copied to the output section.
|
|
input_section_flags &= ~ (elfcpp::SHF_INFO_LINK
|
|
| elfcpp::SHF_GROUP
|
|
| elfcpp::SHF_COMPRESSED
|
|
| elfcpp::SHF_MERGE
|
|
| elfcpp::SHF_STRINGS);
|
|
|
|
// We only clear the SHF_LINK_ORDER flag in for
|
|
// a non-relocatable link.
|
|
if (!parameters->options().relocatable())
|
|
input_section_flags &= ~elfcpp::SHF_LINK_ORDER;
|
|
|
|
return input_section_flags;
|
|
}
|
|
|
|
// Pick the output section to use for section NAME, in input file
|
|
// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a
|
|
// linker created section. IS_INPUT_SECTION is true if we are
|
|
// choosing an output section for an input section found in a input
|
|
// file. ORDER is where this section should appear in the output
|
|
// sections. IS_RELRO is true for a relro section. This will return
|
|
// NULL if the input section should be discarded. MATCH_INPUT_SPEC
|
|
// is true if the section name should be matched against input specs
|
|
// in a linker script.
|
|
|
|
Output_section*
|
|
Layout::choose_output_section(const Relobj* relobj, const char* name,
|
|
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
|
|
bool is_input_section, Output_section_order order,
|
|
bool is_relro, bool is_reloc,
|
|
bool match_input_spec)
|
|
{
|
|
// We should not see any input sections after we have attached
|
|
// sections to segments.
|
|
gold_assert(!is_input_section || !this->sections_are_attached_);
|
|
|
|
flags = this->get_output_section_flags(flags);
|
|
|
|
if (this->script_options_->saw_sections_clause() && !is_reloc)
|
|
{
|
|
// We are using a SECTIONS clause, so the output section is
|
|
// chosen based only on the name.
|
|
|
|
Script_sections* ss = this->script_options_->script_sections();
|
|
const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
|
|
Output_section** output_section_slot;
|
|
Script_sections::Section_type script_section_type;
|
|
const char* orig_name = name;
|
|
bool keep;
|
|
name = ss->output_section_name(file_name, name, &output_section_slot,
|
|
&script_section_type, &keep,
|
|
match_input_spec);
|
|
|
|
if (name == NULL)
|
|
{
|
|
gold_debug(DEBUG_SCRIPT, _("Unable to create output section '%s' "
|
|
"because it is not allowed by the "
|
|
"SECTIONS clause of the linker script"),
|
|
orig_name);
|
|
// The SECTIONS clause says to discard this input section.
|
|
return NULL;
|
|
}
|
|
|
|
// We can only handle script section types ST_NONE and ST_NOLOAD.
|
|
switch (script_section_type)
|
|
{
|
|
case Script_sections::ST_NONE:
|
|
break;
|
|
case Script_sections::ST_NOLOAD:
|
|
flags &= elfcpp::SHF_ALLOC;
|
|
break;
|
|
default:
|
|
gold_unreachable();
|
|
}
|
|
|
|
// If this is an orphan section--one not mentioned in the linker
|
|
// script--then OUTPUT_SECTION_SLOT will be NULL, and we do the
|
|
// default processing below.
|
|
|
|
if (output_section_slot != NULL)
|
|
{
|
|
if (*output_section_slot != NULL)
|
|
{
|
|
(*output_section_slot)->update_flags_for_input_section(flags);
|
|
return *output_section_slot;
|
|
}
|
|
|
|
// We don't put sections found in the linker script into
|
|
// SECTION_NAME_MAP_. That keeps us from getting confused
|
|
// if an orphan section is mapped to a section with the same
|
|
// name as one in the linker script.
|
|
|
|
name = this->namepool_.add(name, false, NULL);
|
|
|
|
Output_section* os = this->make_output_section(name, type, flags,
|
|
order, is_relro);
|
|
|
|
os->set_found_in_sections_clause();
|
|
|
|
// Special handling for NOLOAD sections.
|
|
if (script_section_type == Script_sections::ST_NOLOAD)
|
|
{
|
|
os->set_is_noload();
|
|
|
|
// The constructor of Output_section sets addresses of non-ALLOC
|
|
// sections to 0 by default. We don't want that for NOLOAD
|
|
// sections even if they have no SHF_ALLOC flag.
|
|
if ((os->flags() & elfcpp::SHF_ALLOC) == 0
|
|
&& os->is_address_valid())
|
|
{
|
|
gold_assert(os->address() == 0
|
|
&& !os->is_offset_valid()
|
|
&& !os->is_data_size_valid());
|
|
os->reset_address_and_file_offset();
|
|
}
|
|
}
|
|
|
|
*output_section_slot = os;
|
|
return os;
|
|
}
|
|
}
|
|
|
|
// FIXME: Handle SHF_OS_NONCONFORMING somewhere.
|
|
|
|
size_t len = strlen(name);
|
|
std::string uncompressed_name;
|
|
|
|
// Compressed debug sections should be mapped to the corresponding
|
|
// uncompressed section.
|
|
if (is_compressed_debug_section(name))
|
|
{
|
|
uncompressed_name =
|
|
corresponding_uncompressed_section_name(std::string(name, len));
|
|
name = uncompressed_name.c_str();
|
|
len = uncompressed_name.length();
|
|
}
|
|
|
|
// Turn NAME from the name of the input section into the name of the
|
|
// output section.
|
|
if (is_input_section
|
|
&& !this->script_options_->saw_sections_clause()
|
|
&& !parameters->options().relocatable())
|
|
{
|
|
const char *orig_name = name;
|
|
name = parameters->target().output_section_name(relobj, name, &len);
|
|
if (name == NULL)
|
|
name = Layout::output_section_name(relobj, orig_name, &len);
|
|
}
|
|
|
|
Stringpool::Key name_key;
|
|
name = this->namepool_.add_with_length(name, len, true, &name_key);
|
|
|
|
// Find or make the output section. The output section is selected
|
|
// based on the section name, type, and flags.
|
|
return this->get_output_section(name, name_key, type, flags, order, is_relro);
|
|
}
|
|
|
|
// For incremental links, record the initial fixed layout of a section
|
|
// from the base file, and return a pointer to the Output_section.
|
|
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
Layout::init_fixed_output_section(const char* name,
|
|
elfcpp::Shdr<size, big_endian>& shdr)
|
|
{
|
|
unsigned int sh_type = shdr.get_sh_type();
|
|
|
|
// We preserve the layout of PROGBITS, NOBITS, INIT_ARRAY, FINI_ARRAY,
|
|
// PRE_INIT_ARRAY, and NOTE sections.
|
|
// All others will be created from scratch and reallocated.
|
|
if (!can_incremental_update(sh_type))
|
|
return NULL;
|
|
|
|
// If we're generating a .gdb_index section, we need to regenerate
|
|
// it from scratch.
|
|
if (parameters->options().gdb_index()
|
|
&& sh_type == elfcpp::SHT_PROGBITS
|
|
&& strcmp(name, ".gdb_index") == 0)
|
|
return NULL;
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr sh_addr = shdr.get_sh_addr();
|
|
typename elfcpp::Elf_types<size>::Elf_Off sh_offset = shdr.get_sh_offset();
|
|
typename elfcpp::Elf_types<size>::Elf_WXword sh_size = shdr.get_sh_size();
|
|
typename elfcpp::Elf_types<size>::Elf_WXword sh_flags =
|
|
this->get_output_section_flags(shdr.get_sh_flags());
|
|
typename elfcpp::Elf_types<size>::Elf_WXword sh_addralign =
|
|
shdr.get_sh_addralign();
|
|
|
|
// Make the output section.
|
|
Stringpool::Key name_key;
|
|
name = this->namepool_.add(name, true, &name_key);
|
|
Output_section* os = this->get_output_section(name, name_key, sh_type,
|
|
sh_flags, ORDER_INVALID, false);
|
|
os->set_fixed_layout(sh_addr, sh_offset, sh_size, sh_addralign);
|
|
if (sh_type != elfcpp::SHT_NOBITS)
|
|
this->free_list_.remove(sh_offset, sh_offset + sh_size);
|
|
return os;
|
|
}
|
|
|
|
// Return the index by which an input section should be ordered. This
|
|
// is used to sort some .text sections, for compatibility with GNU ld.
|
|
|
|
int
|
|
Layout::special_ordering_of_input_section(const char* name)
|
|
{
|
|
// The GNU linker has some special handling for some sections that
|
|
// wind up in the .text section. Sections that start with these
|
|
// prefixes must appear first, and must appear in the order listed
|
|
// here.
|
|
static const char* const text_section_sort[] =
|
|
{
|
|
".text.unlikely",
|
|
".text.exit",
|
|
".text.startup",
|
|
".text.hot",
|
|
".text.sorted"
|
|
};
|
|
|
|
for (size_t i = 0;
|
|
i < sizeof(text_section_sort) / sizeof(text_section_sort[0]);
|
|
i++)
|
|
if (is_prefix_of(text_section_sort[i], name))
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Return the output section to use for input section SHNDX, with name
|
|
// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the
|
|
// index of a relocation section which applies to this section, or 0
|
|
// if none, or -1U if more than one. RELOC_TYPE is the type of the
|
|
// relocation section if there is one. Set *OFF to the offset of this
|
|
// input section without the output section. Return NULL if the
|
|
// section should be discarded. Set *OFF to -1 if the section
|
|
// contents should not be written directly to the output file, but
|
|
// will instead receive special handling.
|
|
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
|
|
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
|
|
unsigned int sh_type, unsigned int reloc_shndx,
|
|
unsigned int, off_t* off)
|
|
{
|
|
*off = 0;
|
|
|
|
if (!this->include_section(object, name, shdr))
|
|
return NULL;
|
|
|
|
// In a relocatable link a grouped section must not be combined with
|
|
// any other sections.
|
|
Output_section* os;
|
|
if (parameters->options().relocatable()
|
|
&& (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0)
|
|
{
|
|
// Some flags in the input section should not be automatically
|
|
// copied to the output section.
|
|
elfcpp::Elf_Xword sh_flags = (shdr.get_sh_flags()
|
|
& ~ elfcpp::SHF_COMPRESSED);
|
|
name = this->namepool_.add(name, true, NULL);
|
|
os = this->make_output_section(name, sh_type, sh_flags, ORDER_INVALID,
|
|
false);
|
|
}
|
|
else
|
|
{
|
|
// Get the section flags and mask out any flags that do not
|
|
// take part in section matching.
|
|
elfcpp::Elf_Xword sh_flags
|
|
= (this->get_output_section_flags(shdr.get_sh_flags())
|
|
& ~object->osabi().ignored_sh_flags());
|
|
|
|
// All ".text.unlikely.*" sections can be moved to a unique
|
|
// segment with --text-unlikely-segment option.
|
|
bool text_unlikely_segment
|
|
= (parameters->options().text_unlikely_segment()
|
|
&& is_prefix_of(".text.unlikely",
|
|
object->section_name(shndx).c_str()));
|
|
if (text_unlikely_segment)
|
|
{
|
|
Stringpool::Key name_key;
|
|
const char* os_name = this->namepool_.add(".text.unlikely", true,
|
|
&name_key);
|
|
os = this->get_output_section(os_name, name_key, sh_type, sh_flags,
|
|
ORDER_INVALID, false);
|
|
// Map this output section to a unique segment. This is done to
|
|
// separate "text" that is not likely to be executed from "text"
|
|
// that is likely executed.
|
|
os->set_is_unique_segment();
|
|
}
|
|
else
|
|
{
|
|
// Plugins can choose to place one or more subsets of sections in
|
|
// unique segments and this is done by mapping these section subsets
|
|
// to unique output sections. Check if this section needs to be
|
|
// remapped to a unique output section.
|
|
Section_segment_map::iterator it
|
|
= this->section_segment_map_.find(Const_section_id(object, shndx));
|
|
if (it == this->section_segment_map_.end())
|
|
{
|
|
os = this->choose_output_section(object, name, sh_type,
|
|
sh_flags, true, ORDER_INVALID,
|
|
false, false, true);
|
|
}
|
|
else
|
|
{
|
|
// We know the name of the output section, directly call
|
|
// get_output_section here by-passing choose_output_section.
|
|
const char* os_name = it->second->name;
|
|
Stringpool::Key name_key;
|
|
os_name = this->namepool_.add(os_name, true, &name_key);
|
|
os = this->get_output_section(os_name, name_key, sh_type,
|
|
sh_flags, ORDER_INVALID, false);
|
|
if (!os->is_unique_segment())
|
|
{
|
|
os->set_is_unique_segment();
|
|
os->set_extra_segment_flags(it->second->flags);
|
|
os->set_segment_alignment(it->second->align);
|
|
}
|
|
}
|
|
}
|
|
if (os == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
// By default the GNU linker sorts input sections whose names match
|
|
// .ctors.*, .dtors.*, .init_array.*, or .fini_array.*. The
|
|
// sections are sorted by name. This is used to implement
|
|
// constructor priority ordering. We are compatible. When we put
|
|
// .ctor sections in .init_array and .dtor sections in .fini_array,
|
|
// we must also sort plain .ctor and .dtor sections.
|
|
if (!this->script_options_->saw_sections_clause()
|
|
&& !parameters->options().relocatable()
|
|
&& (is_prefix_of(".ctors.", name)
|
|
|| is_prefix_of(".dtors.", name)
|
|
|| is_prefix_of(".init_array.", name)
|
|
|| is_prefix_of(".fini_array.", name)
|
|
|| (parameters->options().ctors_in_init_array()
|
|
&& (strcmp(name, ".ctors") == 0
|
|
|| strcmp(name, ".dtors") == 0))))
|
|
os->set_must_sort_attached_input_sections();
|
|
|
|
// By default the GNU linker sorts some special text sections ahead
|
|
// of others. We are compatible.
|
|
if (parameters->options().text_reorder()
|
|
&& !this->script_options_->saw_sections_clause()
|
|
&& !this->is_section_ordering_specified()
|
|
&& !parameters->options().relocatable()
|
|
&& Layout::special_ordering_of_input_section(name) >= 0)
|
|
os->set_must_sort_attached_input_sections();
|
|
|
|
// If this is a .ctors or .ctors.* section being mapped to a
|
|
// .init_array section, or a .dtors or .dtors.* section being mapped
|
|
// to a .fini_array section, we will need to reverse the words if
|
|
// there is more than one. Record this section for later. See
|
|
// ctors_sections_in_init_array above.
|
|
if (!this->script_options_->saw_sections_clause()
|
|
&& !parameters->options().relocatable()
|
|
&& shdr.get_sh_size() > size / 8
|
|
&& (((strcmp(name, ".ctors") == 0
|
|
|| is_prefix_of(".ctors.", name))
|
|
&& strcmp(os->name(), ".init_array") == 0)
|
|
|| ((strcmp(name, ".dtors") == 0
|
|
|| is_prefix_of(".dtors.", name))
|
|
&& strcmp(os->name(), ".fini_array") == 0)))
|
|
ctors_sections_in_init_array.insert(Section_id(object, shndx));
|
|
|
|
// FIXME: Handle SHF_LINK_ORDER somewhere.
|
|
|
|
elfcpp::Elf_Xword orig_flags = os->flags();
|
|
|
|
*off = os->add_input_section(this, object, shndx, name, shdr, reloc_shndx,
|
|
this->script_options_->saw_sections_clause());
|
|
|
|
// If the flags changed, we may have to change the order.
|
|
if ((orig_flags & elfcpp::SHF_ALLOC) != 0)
|
|
{
|
|
orig_flags &= (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR);
|
|
elfcpp::Elf_Xword new_flags =
|
|
os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR);
|
|
if (orig_flags != new_flags)
|
|
os->set_order(this->default_section_order(os, false));
|
|
}
|
|
|
|
this->have_added_input_section_ = true;
|
|
|
|
return os;
|
|
}
|
|
|
|
// Maps section SECN to SEGMENT s.
|
|
void
|
|
Layout::insert_section_segment_map(Const_section_id secn,
|
|
Unique_segment_info *s)
|
|
{
|
|
gold_assert(this->unique_segment_for_sections_specified_);
|
|
this->section_segment_map_[secn] = s;
|
|
}
|
|
|
|
// Handle a relocation section when doing a relocatable link.
|
|
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
Layout::layout_reloc(Sized_relobj_file<size, big_endian>*,
|
|
unsigned int,
|
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr)
|
|
{
|
|
gold_assert(parameters->options().relocatable()
|
|
|| parameters->options().emit_relocs());
|
|
|
|
int sh_type = shdr.get_sh_type();
|
|
|
|
std::string name;
|
|
if (sh_type == elfcpp::SHT_REL)
|
|
name = ".rel";
|
|
else if (sh_type == elfcpp::SHT_RELA)
|
|
name = ".rela";
|
|
else
|
|
gold_unreachable();
|
|
name += data_section->name();
|
|
|
|
// If the output data section already has a reloc section, use that;
|
|
// otherwise, make a new one.
|
|
Output_section* os = data_section->reloc_section();
|
|
if (os == NULL)
|
|
{
|
|
const char* n = this->namepool_.add(name.c_str(), true, NULL);
|
|
os = this->make_output_section(n, sh_type, shdr.get_sh_flags(),
|
|
ORDER_INVALID, false);
|
|
os->set_should_link_to_symtab();
|
|
os->set_info_section(data_section);
|
|
data_section->set_reloc_section(os);
|
|
}
|
|
|
|
Output_section_data* posd;
|
|
if (sh_type == elfcpp::SHT_REL)
|
|
{
|
|
os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
|
|
posd = new Output_relocatable_relocs<elfcpp::SHT_REL,
|
|
size,
|
|
big_endian>(rr);
|
|
}
|
|
else if (sh_type == elfcpp::SHT_RELA)
|
|
{
|
|
os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
|
|
posd = new Output_relocatable_relocs<elfcpp::SHT_RELA,
|
|
size,
|
|
big_endian>(rr);
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
|
|
os->add_output_section_data(posd);
|
|
rr->set_output_data(posd);
|
|
|
|
return os;
|
|
}
|
|
|
|
// Handle a group section when doing a relocatable link.
|
|
|
|
template<int size, bool big_endian>
|
|
void
|
|
Layout::layout_group(Symbol_table* symtab,
|
|
Sized_relobj_file<size, big_endian>* object,
|
|
unsigned int,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes)
|
|
{
|
|
gold_assert(parameters->options().relocatable());
|
|
gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP);
|
|
group_section_name = this->namepool_.add(group_section_name, true, NULL);
|
|
Output_section* os = this->make_output_section(group_section_name,
|
|
elfcpp::SHT_GROUP,
|
|
shdr.get_sh_flags(),
|
|
ORDER_INVALID, false);
|
|
|
|
// We need to find a symbol with the signature in the symbol table.
|
|
// If we don't find one now, we need to look again later.
|
|
Symbol* sym = symtab->lookup(signature, NULL);
|
|
if (sym != NULL)
|
|
os->set_info_symndx(sym);
|
|
else
|
|
{
|
|
// Reserve some space to minimize reallocations.
|
|
if (this->group_signatures_.empty())
|
|
this->group_signatures_.reserve(this->number_of_input_files_ * 16);
|
|
|
|
// We will wind up using a symbol whose name is the signature.
|
|
// So just put the signature in the symbol name pool to save it.
|
|
signature = symtab->canonicalize_name(signature);
|
|
this->group_signatures_.push_back(Group_signature(os, signature));
|
|
}
|
|
|
|
os->set_should_link_to_symtab();
|
|
os->set_entsize(4);
|
|
|
|
section_size_type entry_count =
|
|
convert_to_section_size_type(shdr.get_sh_size() / 4);
|
|
Output_section_data* posd =
|
|
new Output_data_group<size, big_endian>(object, entry_count, flags,
|
|
shndxes);
|
|
os->add_output_section_data(posd);
|
|
}
|
|
|
|
// Special GNU handling of sections name .eh_frame. They will
|
|
// normally hold exception frame data as defined by the C++ ABI
|
|
// (http://codesourcery.com/cxx-abi/).
|
|
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
Layout::layout_eh_frame(Sized_relobj_file<size, big_endian>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
const unsigned char* symbol_names,
|
|
off_t symbol_names_size,
|
|
unsigned int shndx,
|
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
|
unsigned int reloc_shndx, unsigned int reloc_type,
|
|
off_t* off)
|
|
{
|
|
const unsigned int unwind_section_type =
|
|
parameters->target().unwind_section_type();
|
|
|
|
gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS
|
|
|| shdr.get_sh_type() == unwind_section_type);
|
|
gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0);
|
|
|
|
Output_section* os = this->make_eh_frame_section(object);
|
|
if (os == NULL)
|
|
return NULL;
|
|
|
|
gold_assert(this->eh_frame_section_ == os);
|
|
|
|
elfcpp::Elf_Xword orig_flags = os->flags();
|
|
|
|
Eh_frame::Eh_frame_section_disposition disp =
|
|
Eh_frame::EH_UNRECOGNIZED_SECTION;
|
|
if (!parameters->incremental())
|
|
{
|
|
disp = this->eh_frame_data_->add_ehframe_input_section(object,
|
|
symbols,
|
|
symbols_size,
|
|
symbol_names,
|
|
symbol_names_size,
|
|
shndx,
|
|
reloc_shndx,
|
|
reloc_type);
|
|
}
|
|
|
|
if (disp == Eh_frame::EH_OPTIMIZABLE_SECTION)
|
|
{
|
|
os->update_flags_for_input_section(shdr.get_sh_flags());
|
|
|
|
// A writable .eh_frame section is a RELRO section.
|
|
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
|
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
|
{
|
|
os->set_is_relro();
|
|
os->set_order(ORDER_RELRO);
|
|
}
|
|
|
|
*off = -1;
|
|
return os;
|
|
}
|
|
|
|
if (disp == Eh_frame::EH_END_MARKER_SECTION && !this->added_eh_frame_data_)
|
|
{
|
|
// We found the end marker section, so now we can add the set of
|
|
// optimized sections to the output section. We need to postpone
|
|
// adding this until we've found a section we can optimize so that
|
|
// the .eh_frame section in crtbeginT.o winds up at the start of
|
|
// the output section.
|
|
os->add_output_section_data(this->eh_frame_data_);
|
|
this->added_eh_frame_data_ = true;
|
|
}
|
|
|
|
// We couldn't handle this .eh_frame section for some reason.
|
|
// Add it as a normal section.
|
|
bool saw_sections_clause = this->script_options_->saw_sections_clause();
|
|
*off = os->add_input_section(this, object, shndx, ".eh_frame", shdr,
|
|
reloc_shndx, saw_sections_clause);
|
|
this->have_added_input_section_ = true;
|
|
|
|
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
|
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
|
os->set_order(this->default_section_order(os, false));
|
|
|
|
return os;
|
|
}
|
|
|
|
void
|
|
Layout::finalize_eh_frame_section()
|
|
{
|
|
// If we never found an end marker section, we need to add the
|
|
// optimized eh sections to the output section now.
|
|
if (!parameters->incremental()
|
|
&& this->eh_frame_section_ != NULL
|
|
&& !this->added_eh_frame_data_)
|
|
{
|
|
this->eh_frame_section_->add_output_section_data(this->eh_frame_data_);
|
|
this->added_eh_frame_data_ = true;
|
|
}
|
|
}
|
|
|
|
// Create and return the magic .eh_frame section. Create
|
|
// .eh_frame_hdr also if appropriate. OBJECT is the object with the
|
|
// input .eh_frame section; it may be NULL.
|
|
|
|
Output_section*
|
|
Layout::make_eh_frame_section(const Relobj* object)
|
|
{
|
|
const unsigned int unwind_section_type =
|
|
parameters->target().unwind_section_type();
|
|
|
|
Output_section* os = this->choose_output_section(object, ".eh_frame",
|
|
unwind_section_type,
|
|
elfcpp::SHF_ALLOC, false,
|
|
ORDER_EHFRAME, false, false,
|
|
false);
|
|
if (os == NULL)
|
|
return NULL;
|
|
|
|
if (this->eh_frame_section_ == NULL)
|
|
{
|
|
this->eh_frame_section_ = os;
|
|
this->eh_frame_data_ = new Eh_frame();
|
|
|
|
// For incremental linking, we do not optimize .eh_frame sections
|
|
// or create a .eh_frame_hdr section.
|
|
if (parameters->options().eh_frame_hdr() && !parameters->incremental())
|
|
{
|
|
Output_section* hdr_os =
|
|
this->choose_output_section(NULL, ".eh_frame_hdr",
|
|
unwind_section_type,
|
|
elfcpp::SHF_ALLOC, false,
|
|
ORDER_EHFRAME, false, false,
|
|
false);
|
|
|
|
if (hdr_os != NULL)
|
|
{
|
|
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os,
|
|
this->eh_frame_data_);
|
|
hdr_os->add_output_section_data(hdr_posd);
|
|
|
|
hdr_os->set_after_input_sections();
|
|
|
|
if (!this->script_options_->saw_phdrs_clause())
|
|
{
|
|
Output_segment* hdr_oseg;
|
|
hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
|
|
elfcpp::PF_R);
|
|
hdr_oseg->add_output_section_to_nonload(hdr_os,
|
|
elfcpp::PF_R);
|
|
}
|
|
|
|
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
|
|
}
|
|
}
|
|
}
|
|
|
|
return os;
|
|
}
|
|
|
|
// Add an exception frame for a PLT. This is called from target code.
|
|
|
|
void
|
|
Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
|
size_t cie_length, const unsigned char* fde_data,
|
|
size_t fde_length)
|
|
{
|
|
if (parameters->incremental())
|
|
{
|
|
// FIXME: Maybe this could work some day....
|
|
return;
|
|
}
|
|
Output_section* os = this->make_eh_frame_section(NULL);
|
|
if (os == NULL)
|
|
return;
|
|
this->eh_frame_data_->add_ehframe_for_plt(plt, cie_data, cie_length,
|
|
fde_data, fde_length);
|
|
if (!this->added_eh_frame_data_)
|
|
{
|
|
os->add_output_section_data(this->eh_frame_data_);
|
|
this->added_eh_frame_data_ = true;
|
|
}
|
|
}
|
|
|
|
// Remove all post-map .eh_frame information for a PLT.
|
|
|
|
void
|
|
Layout::remove_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
|
size_t cie_length)
|
|
{
|
|
if (parameters->incremental())
|
|
{
|
|
// FIXME: Maybe this could work some day....
|
|
return;
|
|
}
|
|
this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length);
|
|
}
|
|
|
|
// Scan a .debug_info or .debug_types section, and add summary
|
|
// information to the .gdb_index section.
|
|
|
|
template<int size, bool big_endian>
|
|
void
|
|
Layout::add_to_gdb_index(bool is_type_unit,
|
|
Sized_relobj<size, big_endian>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
unsigned int shndx,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type)
|
|
{
|
|
if (this->gdb_index_data_ == NULL)
|
|
{
|
|
Output_section* os = this->choose_output_section(NULL, ".gdb_index",
|
|
elfcpp::SHT_PROGBITS, 0,
|
|
false, ORDER_INVALID,
|
|
false, false, false);
|
|
if (os == NULL)
|
|
return;
|
|
|
|
this->gdb_index_data_ = new Gdb_index(os);
|
|
os->add_output_section_data(this->gdb_index_data_);
|
|
os->set_after_input_sections();
|
|
}
|
|
|
|
this->gdb_index_data_->scan_debug_info(is_type_unit, object, symbols,
|
|
symbols_size, shndx, reloc_shndx,
|
|
reloc_type);
|
|
}
|
|
|
|
// Add POSD to an output section using NAME, TYPE, and FLAGS. Return
|
|
// the output section.
|
|
|
|
Output_section*
|
|
Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
|
|
elfcpp::Elf_Xword flags,
|
|
Output_section_data* posd,
|
|
Output_section_order order, bool is_relro)
|
|
{
|
|
Output_section* os = this->choose_output_section(NULL, name, type, flags,
|
|
false, order, is_relro,
|
|
false, false);
|
|
if (os != NULL)
|
|
os->add_output_section_data(posd);
|
|
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. ORDER is the order in which this section should
|
|
// appear in the output segment. IS_RELRO is true if this is a relro
|
|
// (read-only after relocations) section.
|
|
|
|
Output_section*
|
|
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
|
elfcpp::Elf_Xword flags,
|
|
Output_section_order order, bool is_relro)
|
|
{
|
|
Output_section* os;
|
|
if ((flags & elfcpp::SHF_ALLOC) == 0
|
|
&& strcmp(parameters->options().compress_debug_sections(), "none") != 0
|
|
&& is_compressible_debug_section(name))
|
|
os = new Output_compressed_section(¶meters->options(), name, type,
|
|
flags);
|
|
else if ((flags & elfcpp::SHF_ALLOC) == 0
|
|
&& parameters->options().strip_debug_non_line()
|
|
&& strcmp(".debug_abbrev", name) == 0)
|
|
{
|
|
os = this->debug_abbrev_ = new Output_reduced_debug_abbrev_section(
|
|
name, type, flags);
|
|
if (this->debug_info_)
|
|
this->debug_info_->set_abbreviations(this->debug_abbrev_);
|
|
}
|
|
else if ((flags & elfcpp::SHF_ALLOC) == 0
|
|
&& parameters->options().strip_debug_non_line()
|
|
&& strcmp(".debug_info", name) == 0)
|
|
{
|
|
os = this->debug_info_ = new Output_reduced_debug_info_section(
|
|
name, type, flags);
|
|
if (this->debug_abbrev_)
|
|
this->debug_info_->set_abbreviations(this->debug_abbrev_);
|
|
}
|
|
else
|
|
{
|
|
// Sometimes .init_array*, .preinit_array* and .fini_array* do
|
|
// not have correct section types. Force them here.
|
|
if (type == elfcpp::SHT_PROGBITS)
|
|
{
|
|
if (is_prefix_of(".init_array", name))
|
|
type = elfcpp::SHT_INIT_ARRAY;
|
|
else if (is_prefix_of(".preinit_array", name))
|
|
type = elfcpp::SHT_PREINIT_ARRAY;
|
|
else if (is_prefix_of(".fini_array", name))
|
|
type = elfcpp::SHT_FINI_ARRAY;
|
|
}
|
|
|
|
// FIXME: const_cast is ugly.
|
|
Target* target = const_cast<Target*>(¶meters->target());
|
|
os = target->make_output_section(name, type, flags);
|
|
}
|
|
|
|
// With -z relro, we have to recognize the special sections by name.
|
|
// There is no other way.
|
|
bool is_relro_local = false;
|
|
if (!this->script_options_->saw_sections_clause()
|
|
&& parameters->options().relro()
|
|
&& (flags & elfcpp::SHF_ALLOC) != 0
|
|
&& (flags & elfcpp::SHF_WRITE) != 0)
|
|
{
|
|
if (type == elfcpp::SHT_PROGBITS)
|
|
{
|
|
if ((flags & elfcpp::SHF_TLS) != 0)
|
|
is_relro = true;
|
|
else if (strcmp(name, ".data.rel.ro") == 0)
|
|
is_relro = true;
|
|
else if (strcmp(name, ".data.rel.ro.local") == 0)
|
|
{
|
|
is_relro = true;
|
|
is_relro_local = true;
|
|
}
|
|
else if (strcmp(name, ".ctors") == 0
|
|
|| strcmp(name, ".dtors") == 0
|
|
|| strcmp(name, ".jcr") == 0)
|
|
is_relro = true;
|
|
}
|
|
else if (type == elfcpp::SHT_INIT_ARRAY
|
|
|| type == elfcpp::SHT_FINI_ARRAY
|
|
|| type == elfcpp::SHT_PREINIT_ARRAY)
|
|
is_relro = true;
|
|
}
|
|
|
|
if (is_relro)
|
|
os->set_is_relro();
|
|
|
|
if (order == ORDER_INVALID && (flags & elfcpp::SHF_ALLOC) != 0)
|
|
order = this->default_section_order(os, is_relro_local);
|
|
|
|
os->set_order(order);
|
|
|
|
parameters->target().new_output_section(os);
|
|
|
|
this->section_list_.push_back(os);
|
|
|
|
// The GNU linker by default sorts some sections by priority, so we
|
|
// do the same. We need to know that this might happen before we
|
|
// attach any input sections.
|
|
if (!this->script_options_->saw_sections_clause()
|
|
&& !parameters->options().relocatable()
|
|
&& (strcmp(name, ".init_array") == 0
|
|
|| strcmp(name, ".fini_array") == 0
|
|
|| (!parameters->options().ctors_in_init_array()
|
|
&& (strcmp(name, ".ctors") == 0
|
|
|| strcmp(name, ".dtors") == 0))))
|
|
os->set_may_sort_attached_input_sections();
|
|
|
|
// The GNU linker by default sorts .text.{unlikely,exit,startup,hot}
|
|
// sections before other .text sections. We are compatible. We
|
|
// need to know that this might happen before we attach any input
|
|
// sections.
|
|
if (parameters->options().text_reorder()
|
|
&& !this->script_options_->saw_sections_clause()
|
|
&& !this->is_section_ordering_specified()
|
|
&& !parameters->options().relocatable()
|
|
&& strcmp(name, ".text") == 0)
|
|
os->set_may_sort_attached_input_sections();
|
|
|
|
// GNU linker sorts section by name with --sort-section=name.
|
|
if (strcmp(parameters->options().sort_section(), "name") == 0)
|
|
os->set_must_sort_attached_input_sections();
|
|
|
|
// Check for .stab*str sections, as .stab* sections need to link to
|
|
// them.
|
|
if (type == elfcpp::SHT_STRTAB
|
|
&& !this->have_stabstr_section_
|
|
&& strncmp(name, ".stab", 5) == 0
|
|
&& strcmp(name + strlen(name) - 3, "str") == 0)
|
|
this->have_stabstr_section_ = true;
|
|
|
|
// During a full incremental link, we add patch space to most
|
|
// PROGBITS and NOBITS sections. Flag those that may be
|
|
// arbitrarily padded.
|
|
if ((type == elfcpp::SHT_PROGBITS || type == elfcpp::SHT_NOBITS)
|
|
&& order != ORDER_INTERP
|
|
&& order != ORDER_INIT
|
|
&& order != ORDER_PLT
|
|
&& order != ORDER_FINI
|
|
&& order != ORDER_RELRO_LAST
|
|
&& order != ORDER_NON_RELRO_FIRST
|
|
&& strcmp(name, ".eh_frame") != 0
|
|
&& strcmp(name, ".ctors") != 0
|
|
&& strcmp(name, ".dtors") != 0
|
|
&& strcmp(name, ".jcr") != 0)
|
|
{
|
|
os->set_is_patch_space_allowed();
|
|
|
|
// Certain sections require "holes" to be filled with
|
|
// specific fill patterns. These fill patterns may have
|
|
// a minimum size, so we must prevent allocations from the
|
|
// free list that leave a hole smaller than the minimum.
|
|
if (strcmp(name, ".debug_info") == 0)
|
|
os->set_free_space_fill(new Output_fill_debug_info(false));
|
|
else if (strcmp(name, ".debug_types") == 0)
|
|
os->set_free_space_fill(new Output_fill_debug_info(true));
|
|
else if (strcmp(name, ".debug_line") == 0)
|
|
os->set_free_space_fill(new Output_fill_debug_line());
|
|
}
|
|
|
|
// If we have already attached the sections to segments, then we
|
|
// need to attach this one now. This happens for sections created
|
|
// directly by the linker.
|
|
if (this->sections_are_attached_)
|
|
this->attach_section_to_segment(¶meters->target(), os);
|
|
|
|
return os;
|
|
}
|
|
|
|
// Return the default order in which a section should be placed in an
|
|
// output segment. This function captures a lot of the ideas in
|
|
// ld/scripttempl/elf.sc in the GNU linker. Note that the order of a
|
|
// linker created section is normally set when the section is created;
|
|
// this function is used for input sections.
|
|
|
|
Output_section_order
|
|
Layout::default_section_order(Output_section* os, bool is_relro_local)
|
|
{
|
|
gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
|
|
bool is_write = (os->flags() & elfcpp::SHF_WRITE) != 0;
|
|
bool is_execinstr = (os->flags() & elfcpp::SHF_EXECINSTR) != 0;
|
|
bool is_bss = false;
|
|
|
|
switch (os->type())
|
|
{
|
|
default:
|
|
case elfcpp::SHT_PROGBITS:
|
|
break;
|
|
case elfcpp::SHT_NOBITS:
|
|
is_bss = true;
|
|
break;
|
|
case elfcpp::SHT_RELA:
|
|
case elfcpp::SHT_REL:
|
|
if (!is_write)
|
|
return ORDER_DYNAMIC_RELOCS;
|
|
break;
|
|
case elfcpp::SHT_HASH:
|
|
case elfcpp::SHT_DYNAMIC:
|
|
case elfcpp::SHT_SHLIB:
|
|
case elfcpp::SHT_DYNSYM:
|
|
case elfcpp::SHT_GNU_HASH:
|
|
case elfcpp::SHT_GNU_verdef:
|
|
case elfcpp::SHT_GNU_verneed:
|
|
case elfcpp::SHT_GNU_versym:
|
|
if (!is_write)
|
|
return ORDER_DYNAMIC_LINKER;
|
|
break;
|
|
case elfcpp::SHT_NOTE:
|
|
return is_write ? ORDER_RW_NOTE : ORDER_RO_NOTE;
|
|
}
|
|
|
|
if ((os->flags() & elfcpp::SHF_TLS) != 0)
|
|
return is_bss ? ORDER_TLS_BSS : ORDER_TLS_DATA;
|
|
|
|
if (!is_bss && !is_write)
|
|
{
|
|
if (is_execinstr)
|
|
{
|
|
if (strcmp(os->name(), ".init") == 0)
|
|
return ORDER_INIT;
|
|
else if (strcmp(os->name(), ".fini") == 0)
|
|
return ORDER_FINI;
|
|
else if (parameters->options().keep_text_section_prefix())
|
|
{
|
|
// -z,keep-text-section-prefix introduces additional
|
|
// output sections.
|
|
if (strcmp(os->name(), ".text.hot") == 0)
|
|
return ORDER_TEXT_HOT;
|
|
else if (strcmp(os->name(), ".text.startup") == 0)
|
|
return ORDER_TEXT_STARTUP;
|
|
else if (strcmp(os->name(), ".text.exit") == 0)
|
|
return ORDER_TEXT_EXIT;
|
|
else if (strcmp(os->name(), ".text.unlikely") == 0)
|
|
return ORDER_TEXT_UNLIKELY;
|
|
}
|
|
}
|
|
return is_execinstr ? ORDER_TEXT : ORDER_READONLY;
|
|
}
|
|
|
|
if (os->is_relro())
|
|
return is_relro_local ? ORDER_RELRO_LOCAL : ORDER_RELRO;
|
|
|
|
if (os->is_small_section())
|
|
return is_bss ? ORDER_SMALL_BSS : ORDER_SMALL_DATA;
|
|
if (os->is_large_section())
|
|
return is_bss ? ORDER_LARGE_BSS : ORDER_LARGE_DATA;
|
|
|
|
return is_bss ? ORDER_BSS : ORDER_DATA;
|
|
}
|
|
|
|
// Attach output sections to segments. This is called after we have
|
|
// seen all the input sections.
|
|
|
|
void
|
|
Layout::attach_sections_to_segments(const Target* target)
|
|
{
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
this->attach_section_to_segment(target, *p);
|
|
|
|
this->sections_are_attached_ = true;
|
|
}
|
|
|
|
// Attach an output section to a segment.
|
|
|
|
void
|
|
Layout::attach_section_to_segment(const Target* target, Output_section* os)
|
|
{
|
|
if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
|
|
this->unattached_section_list_.push_back(os);
|
|
else
|
|
this->attach_allocated_section_to_segment(target, os);
|
|
}
|
|
|
|
// Attach an allocated output section to a segment.
|
|
|
|
void
|
|
Layout::attach_allocated_section_to_segment(const Target* target,
|
|
Output_section* os)
|
|
{
|
|
elfcpp::Elf_Xword flags = os->flags();
|
|
gold_assert((flags & elfcpp::SHF_ALLOC) != 0);
|
|
|
|
if (parameters->options().relocatable())
|
|
return;
|
|
|
|
// If we have a SECTIONS clause, we can't handle the attachment to
|
|
// segments until after we've seen all the sections.
|
|
if (this->script_options_->saw_sections_clause())
|
|
return;
|
|
|
|
gold_assert(!this->script_options_->saw_phdrs_clause());
|
|
|
|
// This output section goes into a PT_LOAD segment.
|
|
|
|
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
|
|
|
|
// If this output section's segment has extra flags that need to be set,
|
|
// coming from a linker plugin, do that.
|
|
seg_flags |= os->extra_segment_flags();
|
|
|
|
// Check for --section-start.
|
|
uint64_t addr;
|
|
bool is_address_set = parameters->options().section_start(os->name(), &addr);
|
|
|
|
// In general the only thing we really care about for PT_LOAD
|
|
// segments is whether or not they are writable or executable,
|
|
// so that is how we search for them.
|
|
// Large data sections also go into their own PT_LOAD segment.
|
|
// People who need segments sorted on some other basis will
|
|
// have to use a linker script.
|
|
|
|
Segment_list::const_iterator p;
|
|
if (!os->is_unique_segment())
|
|
{
|
|
for (p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->type() != elfcpp::PT_LOAD)
|
|
continue;
|
|
if ((*p)->is_unique_segment())
|
|
continue;
|
|
if (!parameters->options().omagic()
|
|
&& ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
|
|
continue;
|
|
if ((target->isolate_execinstr() || parameters->options().rosegment())
|
|
&& ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
|
|
continue;
|
|
// If -Tbss was specified, we need to separate the data and BSS
|
|
// segments.
|
|
if (parameters->options().user_set_Tbss())
|
|
{
|
|
if ((os->type() == elfcpp::SHT_NOBITS)
|
|
== (*p)->has_any_data_sections())
|
|
continue;
|
|
}
|
|
if (os->is_large_data_section() && !(*p)->is_large_data_segment())
|
|
continue;
|
|
|
|
if (is_address_set)
|
|
{
|
|
if ((*p)->are_addresses_set())
|
|
continue;
|
|
|
|
(*p)->add_initial_output_data(os);
|
|
(*p)->update_flags_for_output_section(seg_flags);
|
|
(*p)->set_addresses(addr, addr);
|
|
break;
|
|
}
|
|
|
|
(*p)->add_output_section_to_load(this, os, seg_flags);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p == this->segment_list_.end()
|
|
|| os->is_unique_segment())
|
|
{
|
|
Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
|
|
seg_flags);
|
|
if (os->is_large_data_section())
|
|
oseg->set_is_large_data_segment();
|
|
oseg->add_output_section_to_load(this, os, seg_flags);
|
|
if (is_address_set)
|
|
oseg->set_addresses(addr, addr);
|
|
// Check if segment should be marked unique. For segments marked
|
|
// unique by linker plugins, set the new alignment if specified.
|
|
if (os->is_unique_segment())
|
|
{
|
|
oseg->set_is_unique_segment();
|
|
if (os->segment_alignment() != 0)
|
|
oseg->set_minimum_p_align(os->segment_alignment());
|
|
}
|
|
}
|
|
|
|
// If we see a loadable SHT_NOTE section, we create a PT_NOTE
|
|
// segment.
|
|
if (os->type() == elfcpp::SHT_NOTE)
|
|
{
|
|
uint64_t os_align = os->addralign();
|
|
|
|
// 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)->align() == os_align
|
|
&& (((*p)->flags() & elfcpp::PF_W)
|
|
== (seg_flags & elfcpp::PF_W)))
|
|
{
|
|
(*p)->add_output_section_to_nonload(os, seg_flags);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p == this->segment_list_.end())
|
|
{
|
|
Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
|
|
seg_flags);
|
|
oseg->add_output_section_to_nonload(os, seg_flags);
|
|
oseg->set_align(os_align);
|
|
}
|
|
}
|
|
|
|
// If we see a loadable SHF_TLS section, we create a PT_TLS
|
|
// segment. There can only be one such segment.
|
|
if ((flags & elfcpp::SHF_TLS) != 0)
|
|
{
|
|
if (this->tls_segment_ == NULL)
|
|
this->make_output_segment(elfcpp::PT_TLS, seg_flags);
|
|
this->tls_segment_->add_output_section_to_nonload(os, seg_flags);
|
|
}
|
|
|
|
// If -z relro is in effect, and we see a relro section, we create a
|
|
// PT_GNU_RELRO segment. There can only be one such segment.
|
|
if (os->is_relro() && parameters->options().relro())
|
|
{
|
|
gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
|
|
if (this->relro_segment_ == NULL)
|
|
this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags);
|
|
this->relro_segment_->add_output_section_to_nonload(os, seg_flags);
|
|
}
|
|
|
|
// If we see a section named .interp, put it into a PT_INTERP
|
|
// segment. This seems broken to me, but this is what GNU ld does,
|
|
// and glibc expects it.
|
|
if (strcmp(os->name(), ".interp") == 0
|
|
&& !this->script_options_->saw_phdrs_clause())
|
|
{
|
|
if (this->interp_segment_ == NULL)
|
|
this->make_output_segment(elfcpp::PT_INTERP, seg_flags);
|
|
else
|
|
gold_warning(_("multiple '.interp' sections in input files "
|
|
"may cause confusing PT_INTERP segment"));
|
|
this->interp_segment_->add_output_section_to_nonload(os, seg_flags);
|
|
}
|
|
}
|
|
|
|
// Make an output section for a script.
|
|
|
|
Output_section*
|
|
Layout::make_output_section_for_script(
|
|
const char* name,
|
|
Script_sections::Section_type section_type)
|
|
{
|
|
name = this->namepool_.add(name, false, NULL);
|
|
elfcpp::Elf_Xword sh_flags = elfcpp::SHF_ALLOC;
|
|
if (section_type == Script_sections::ST_NOLOAD)
|
|
sh_flags = 0;
|
|
Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS,
|
|
sh_flags, ORDER_INVALID,
|
|
false);
|
|
os->set_found_in_sections_clause();
|
|
if (section_type == Script_sections::ST_NOLOAD)
|
|
os->set_is_noload();
|
|
return os;
|
|
}
|
|
|
|
// Return the number of segments we expect to see.
|
|
|
|
size_t
|
|
Layout::expected_segment_count() const
|
|
{
|
|
size_t ret = this->segment_list_.size();
|
|
|
|
// If we didn't see a SECTIONS clause in a linker script, we should
|
|
// already have the complete list of segments. Otherwise we ask the
|
|
// SECTIONS clause how many segments it expects, and add in the ones
|
|
// we already have (PT_GNU_STACK, PT_GNU_EH_FRAME, etc.)
|
|
|
|
if (!this->script_options_->saw_sections_clause())
|
|
return ret;
|
|
else
|
|
{
|
|
const Script_sections* ss = this->script_options_->script_sections();
|
|
return ret + ss->expected_segment_count(this);
|
|
}
|
|
}
|
|
|
|
// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK
|
|
// is whether we saw a .note.GNU-stack section in the object file.
|
|
// GNU_STACK_FLAGS is the section flags. The flags give the
|
|
// protection required for stack memory. We record this in an
|
|
// executable as a PT_GNU_STACK segment. If an object file does not
|
|
// have a .note.GNU-stack segment, we must assume that it is an old
|
|
// object. On some targets that will force an executable stack.
|
|
|
|
void
|
|
Layout::layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags,
|
|
const Object* obj)
|
|
{
|
|
if (!seen_gnu_stack)
|
|
{
|
|
this->input_without_gnu_stack_note_ = true;
|
|
if (parameters->options().warn_execstack()
|
|
&& parameters->target().is_default_stack_executable())
|
|
gold_warning(_("%s: missing .note.GNU-stack section"
|
|
" implies executable stack"),
|
|
obj->name().c_str());
|
|
}
|
|
else
|
|
{
|
|
this->input_with_gnu_stack_note_ = true;
|
|
if ((gnu_stack_flags & elfcpp::SHF_EXECINSTR) != 0)
|
|
{
|
|
this->input_requires_executable_stack_ = true;
|
|
if (parameters->options().warn_execstack())
|
|
gold_warning(_("%s: requires executable stack"),
|
|
obj->name().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read a value with given size and endianness.
|
|
|
|
static inline uint64_t
|
|
read_sized_value(size_t size, const unsigned char* buf, bool is_big_endian,
|
|
const Object* object)
|
|
{
|
|
uint64_t val = 0;
|
|
if (size == 4)
|
|
{
|
|
if (is_big_endian)
|
|
val = elfcpp::Swap<32, true>::readval(buf);
|
|
else
|
|
val = elfcpp::Swap<32, false>::readval(buf);
|
|
}
|
|
else if (size == 8)
|
|
{
|
|
if (is_big_endian)
|
|
val = elfcpp::Swap<64, true>::readval(buf);
|
|
else
|
|
val = elfcpp::Swap<64, false>::readval(buf);
|
|
}
|
|
else
|
|
{
|
|
gold_warning(_("%s: in .note.gnu.property section, "
|
|
"pr_datasz must be 4 or 8"),
|
|
object->name().c_str());
|
|
}
|
|
return val;
|
|
}
|
|
|
|
// Write a value with given size and endianness.
|
|
|
|
static inline void
|
|
write_sized_value(uint64_t value, size_t size, unsigned char* buf,
|
|
bool is_big_endian)
|
|
{
|
|
if (size == 4)
|
|
{
|
|
if (is_big_endian)
|
|
elfcpp::Swap<32, true>::writeval(buf, static_cast<uint32_t>(value));
|
|
else
|
|
elfcpp::Swap<32, false>::writeval(buf, static_cast<uint32_t>(value));
|
|
}
|
|
else if (size == 8)
|
|
{
|
|
if (is_big_endian)
|
|
elfcpp::Swap<64, true>::writeval(buf, value);
|
|
else
|
|
elfcpp::Swap<64, false>::writeval(buf, value);
|
|
}
|
|
else
|
|
{
|
|
// We will have already complained about this.
|
|
}
|
|
}
|
|
|
|
// Handle the .note.gnu.property section at layout time.
|
|
|
|
void
|
|
Layout::layout_gnu_property(unsigned int note_type,
|
|
unsigned int pr_type,
|
|
size_t pr_datasz,
|
|
const unsigned char* pr_data,
|
|
const Object* object)
|
|
{
|
|
// We currently support only the one note type.
|
|
gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0);
|
|
|
|
if (pr_type >= elfcpp::GNU_PROPERTY_LOPROC
|
|
&& pr_type < elfcpp::GNU_PROPERTY_HIPROC)
|
|
{
|
|
// Target-dependent property value; call the target to record.
|
|
const int size = parameters->target().get_size();
|
|
const bool is_big_endian = parameters->target().is_big_endian();
|
|
if (size == 32)
|
|
{
|
|
if (is_big_endian)
|
|
{
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
parameters->sized_target<32, true>()->
|
|
record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
|
|
object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
parameters->sized_target<32, false>()->
|
|
record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
|
|
object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
}
|
|
else if (size == 64)
|
|
{
|
|
if (is_big_endian)
|
|
{
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
parameters->sized_target<64, true>()->
|
|
record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
|
|
object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
parameters->sized_target<64, false>()->
|
|
record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
|
|
object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
return;
|
|
}
|
|
|
|
Gnu_properties::iterator pprop = this->gnu_properties_.find(pr_type);
|
|
if (pprop == this->gnu_properties_.end())
|
|
{
|
|
Gnu_property prop;
|
|
prop.pr_datasz = pr_datasz;
|
|
prop.pr_data = new unsigned char[pr_datasz];
|
|
memcpy(prop.pr_data, pr_data, pr_datasz);
|
|
this->gnu_properties_[pr_type] = prop;
|
|
}
|
|
else
|
|
{
|
|
const bool is_big_endian = parameters->target().is_big_endian();
|
|
switch (pr_type)
|
|
{
|
|
case elfcpp::GNU_PROPERTY_STACK_SIZE:
|
|
// Record the maximum value seen.
|
|
{
|
|
uint64_t val1 = read_sized_value(pprop->second.pr_datasz,
|
|
pprop->second.pr_data,
|
|
is_big_endian, object);
|
|
uint64_t val2 = read_sized_value(pr_datasz, pr_data,
|
|
is_big_endian, object);
|
|
if (val2 > val1)
|
|
write_sized_value(val2, pprop->second.pr_datasz,
|
|
pprop->second.pr_data, is_big_endian);
|
|
}
|
|
break;
|
|
case elfcpp::GNU_PROPERTY_NO_COPY_ON_PROTECTED:
|
|
// No data to merge.
|
|
break;
|
|
default:
|
|
gold_warning(_("%s: unknown program property type %d "
|
|
"in .note.gnu.property section"),
|
|
object->name().c_str(), pr_type);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Merge per-object properties with program properties.
|
|
// This lets the target identify objects that are missing certain
|
|
// properties, in cases where properties must be ANDed together.
|
|
|
|
void
|
|
Layout::merge_gnu_properties(const Object* object)
|
|
{
|
|
const int size = parameters->target().get_size();
|
|
const bool is_big_endian = parameters->target().is_big_endian();
|
|
if (size == 32)
|
|
{
|
|
if (is_big_endian)
|
|
{
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
parameters->sized_target<32, true>()->merge_gnu_properties(object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
parameters->sized_target<32, false>()->merge_gnu_properties(object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
}
|
|
else if (size == 64)
|
|
{
|
|
if (is_big_endian)
|
|
{
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
parameters->sized_target<64, true>()->merge_gnu_properties(object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
parameters->sized_target<64, false>()->merge_gnu_properties(object);
|
|
#else
|
|
gold_unreachable();
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
}
|
|
|
|
// Add a target-specific property for the output .note.gnu.property section.
|
|
|
|
void
|
|
Layout::add_gnu_property(unsigned int note_type,
|
|
unsigned int pr_type,
|
|
size_t pr_datasz,
|
|
const unsigned char* pr_data)
|
|
{
|
|
gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0);
|
|
|
|
Gnu_property prop;
|
|
prop.pr_datasz = pr_datasz;
|
|
prop.pr_data = new unsigned char[pr_datasz];
|
|
memcpy(prop.pr_data, pr_data, pr_datasz);
|
|
this->gnu_properties_[pr_type] = prop;
|
|
}
|
|
|
|
// Create automatic note sections.
|
|
|
|
void
|
|
Layout::create_notes()
|
|
{
|
|
this->create_gnu_properties_note();
|
|
this->create_gold_note();
|
|
this->create_stack_segment();
|
|
this->create_build_id();
|
|
this->create_package_metadata();
|
|
}
|
|
|
|
// Create the dynamic sections which are needed before we read the
|
|
// relocs.
|
|
|
|
void
|
|
Layout::create_initial_dynamic_sections(Symbol_table* symtab)
|
|
{
|
|
if (parameters->doing_static_link())
|
|
return;
|
|
|
|
this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic",
|
|
elfcpp::SHT_DYNAMIC,
|
|
(elfcpp::SHF_ALLOC
|
|
| elfcpp::SHF_WRITE),
|
|
false, ORDER_RELRO,
|
|
true, false, false);
|
|
|
|
// A linker script may discard .dynamic, so check for NULL.
|
|
if (this->dynamic_section_ != NULL)
|
|
{
|
|
this->dynamic_symbol_ =
|
|
symtab->define_in_output_data("_DYNAMIC", NULL,
|
|
Symbol_table::PREDEFINED,
|
|
this->dynamic_section_, 0, 0,
|
|
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
|
|
elfcpp::STV_HIDDEN, 0, false, false);
|
|
|
|
this->dynamic_data_ = new Output_data_dynamic(&this->dynpool_);
|
|
|
|
this->dynamic_section_->add_output_section_data(this->dynamic_data_);
|
|
}
|
|
}
|
|
|
|
// For each output section whose name can be represented as C symbol,
|
|
// define __start and __stop symbols for the section. This is a GNU
|
|
// extension.
|
|
|
|
void
|
|
Layout::define_section_symbols(Symbol_table* symtab)
|
|
{
|
|
const elfcpp::STV visibility = parameters->options().start_stop_visibility_enum();
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
const char* const name = (*p)->name();
|
|
if (is_cident(name))
|
|
{
|
|
const std::string name_string(name);
|
|
const std::string start_name(cident_section_start_prefix
|
|
+ name_string);
|
|
const std::string stop_name(cident_section_stop_prefix
|
|
+ name_string);
|
|
|
|
symtab->define_in_output_data(start_name.c_str(),
|
|
NULL, // version
|
|
Symbol_table::PREDEFINED,
|
|
*p,
|
|
0, // value
|
|
0, // symsize
|
|
elfcpp::STT_NOTYPE,
|
|
elfcpp::STB_GLOBAL,
|
|
visibility,
|
|
0, // nonvis
|
|
false, // offset_is_from_end
|
|
true); // only_if_ref
|
|
|
|
symtab->define_in_output_data(stop_name.c_str(),
|
|
NULL, // version
|
|
Symbol_table::PREDEFINED,
|
|
*p,
|
|
0, // value
|
|
0, // symsize
|
|
elfcpp::STT_NOTYPE,
|
|
elfcpp::STB_GLOBAL,
|
|
visibility,
|
|
0, // nonvis
|
|
true, // offset_is_from_end
|
|
true); // only_if_ref
|
|
}
|
|
}
|
|
}
|
|
|
|
// Define symbols for group signatures.
|
|
|
|
void
|
|
Layout::define_group_signatures(Symbol_table* symtab)
|
|
{
|
|
for (Group_signatures::iterator p = this->group_signatures_.begin();
|
|
p != this->group_signatures_.end();
|
|
++p)
|
|
{
|
|
Symbol* sym = symtab->lookup(p->signature, NULL);
|
|
if (sym != NULL)
|
|
p->section->set_info_symndx(sym);
|
|
else
|
|
{
|
|
// Force the name of the group section to the group
|
|
// signature, and use the group's section symbol as the
|
|
// signature symbol.
|
|
if (strcmp(p->section->name(), p->signature) != 0)
|
|
{
|
|
const char* name = this->namepool_.add(p->signature,
|
|
true, NULL);
|
|
p->section->set_name(name);
|
|
}
|
|
p->section->set_needs_symtab_index();
|
|
p->section->set_info_section_symndx(p->section);
|
|
}
|
|
}
|
|
|
|
this->group_signatures_.clear();
|
|
}
|
|
|
|
// Find the first read-only PT_LOAD segment, creating one if
|
|
// necessary.
|
|
|
|
Output_segment*
|
|
Layout::find_first_load_seg(const Target* target)
|
|
{
|
|
Output_segment* best = NULL;
|
|
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
|
|
&& (parameters->options().omagic()
|
|
|| ((*p)->flags() & elfcpp::PF_W) == 0)
|
|
&& (!target->isolate_execinstr()
|
|
|| ((*p)->flags() & elfcpp::PF_X) == 0))
|
|
{
|
|
if (best == NULL || this->segment_precedes(*p, best))
|
|
best = *p;
|
|
}
|
|
}
|
|
if (best != NULL)
|
|
return best;
|
|
|
|
gold_assert(!this->script_options_->saw_phdrs_clause());
|
|
|
|
Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD,
|
|
elfcpp::PF_R);
|
|
return load_seg;
|
|
}
|
|
|
|
// Save states of all current output segments. Store saved states
|
|
// in SEGMENT_STATES.
|
|
|
|
void
|
|
Layout::save_segments(Segment_states* segment_states)
|
|
{
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
{
|
|
Output_segment* segment = *p;
|
|
// Shallow copy.
|
|
Output_segment* copy = new Output_segment(*segment);
|
|
(*segment_states)[segment] = copy;
|
|
}
|
|
}
|
|
|
|
// Restore states of output segments and delete any segment not found in
|
|
// SEGMENT_STATES.
|
|
|
|
void
|
|
Layout::restore_segments(const Segment_states* segment_states)
|
|
{
|
|
// Go through the segment list and remove any segment added in the
|
|
// relaxation loop.
|
|
this->tls_segment_ = NULL;
|
|
this->relro_segment_ = NULL;
|
|
Segment_list::iterator list_iter = this->segment_list_.begin();
|
|
while (list_iter != this->segment_list_.end())
|
|
{
|
|
Output_segment* segment = *list_iter;
|
|
Segment_states::const_iterator states_iter =
|
|
segment_states->find(segment);
|
|
if (states_iter != segment_states->end())
|
|
{
|
|
const Output_segment* copy = states_iter->second;
|
|
// Shallow copy to restore states.
|
|
*segment = *copy;
|
|
|
|
// Also fix up TLS and RELRO segment pointers as appropriate.
|
|
if (segment->type() == elfcpp::PT_TLS)
|
|
this->tls_segment_ = segment;
|
|
else if (segment->type() == elfcpp::PT_GNU_RELRO)
|
|
this->relro_segment_ = segment;
|
|
|
|
++list_iter;
|
|
}
|
|
else
|
|
{
|
|
list_iter = this->segment_list_.erase(list_iter);
|
|
// This is a segment created during section layout. It should be
|
|
// safe to remove it since we should have removed all pointers to it.
|
|
delete segment;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up after relaxation so that sections can be laid out again.
|
|
|
|
void
|
|
Layout::clean_up_after_relaxation()
|
|
{
|
|
// Restore the segments to point state just prior to the relaxation loop.
|
|
Script_sections* script_section = this->script_options_->script_sections();
|
|
script_section->release_segments();
|
|
this->restore_segments(this->segment_states_);
|
|
|
|
// Reset section addresses and file offsets
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
(*p)->restore_states();
|
|
|
|
// If an input section changes size because of relaxation,
|
|
// we need to adjust the section offsets of all input sections.
|
|
// after such a section.
|
|
if ((*p)->section_offsets_need_adjustment())
|
|
(*p)->adjust_section_offsets();
|
|
|
|
(*p)->reset_address_and_file_offset();
|
|
}
|
|
|
|
// Reset special output object address and file offsets.
|
|
for (Data_list::iterator p = this->special_output_list_.begin();
|
|
p != this->special_output_list_.end();
|
|
++p)
|
|
(*p)->reset_address_and_file_offset();
|
|
|
|
// A linker script may have created some output section data objects.
|
|
// They are useless now.
|
|
for (Output_section_data_list::const_iterator p =
|
|
this->script_output_section_data_list_.begin();
|
|
p != this->script_output_section_data_list_.end();
|
|
++p)
|
|
delete *p;
|
|
this->script_output_section_data_list_.clear();
|
|
|
|
// Special-case fill output objects are recreated each time through
|
|
// the relaxation loop.
|
|
this->reset_relax_output();
|
|
}
|
|
|
|
void
|
|
Layout::reset_relax_output()
|
|
{
|
|
for (Data_list::const_iterator p = this->relax_output_list_.begin();
|
|
p != this->relax_output_list_.end();
|
|
++p)
|
|
delete *p;
|
|
this->relax_output_list_.clear();
|
|
}
|
|
|
|
// Prepare for relaxation.
|
|
|
|
void
|
|
Layout::prepare_for_relaxation()
|
|
{
|
|
// Create an relaxation debug check if in debugging mode.
|
|
if (is_debugging_enabled(DEBUG_RELAXATION))
|
|
this->relaxation_debug_check_ = new Relaxation_debug_check();
|
|
|
|
// Save segment states.
|
|
this->segment_states_ = new Segment_states();
|
|
this->save_segments(this->segment_states_);
|
|
|
|
for(Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
(*p)->save_states();
|
|
|
|
if (is_debugging_enabled(DEBUG_RELAXATION))
|
|
this->relaxation_debug_check_->check_output_data_for_reset_values(
|
|
this->section_list_, this->special_output_list_,
|
|
this->relax_output_list_);
|
|
|
|
// Also enable recording of output section data from scripts.
|
|
this->record_output_section_data_from_script_ = true;
|
|
}
|
|
|
|
// If the user set the address of the text segment, that may not be
|
|
// compatible with putting the segment headers and file headers into
|
|
// that segment. For isolate_execinstr() targets, it's the rodata
|
|
// segment rather than text where we might put the headers.
|
|
static inline bool
|
|
load_seg_unusable_for_headers(const Target* target)
|
|
{
|
|
const General_options& options = parameters->options();
|
|
if (target->isolate_execinstr())
|
|
return (options.user_set_Trodata_segment()
|
|
&& options.Trodata_segment() % target->abi_pagesize() != 0);
|
|
else
|
|
return (options.user_set_Ttext()
|
|
&& options.Ttext() % target->abi_pagesize() != 0);
|
|
}
|
|
|
|
// Relaxation loop body: If target has no relaxation, this runs only once
|
|
// Otherwise, the target relaxation hook is called at the end of
|
|
// each iteration. If the hook returns true, it means re-layout of
|
|
// section is required.
|
|
//
|
|
// The number of segments created by a linking script without a PHDRS
|
|
// clause may be affected by section sizes and alignments. There is
|
|
// a remote chance that relaxation causes different number of PT_LOAD
|
|
// segments are created and sections are attached to different segments.
|
|
// Therefore, we always throw away all segments created during section
|
|
// layout. In order to be able to restart the section layout, we keep
|
|
// a copy of the segment list right before the relaxation loop and use
|
|
// that to restore the segments.
|
|
//
|
|
// PASS is the current relaxation pass number.
|
|
// SYMTAB is a symbol table.
|
|
// PLOAD_SEG is the address of a pointer for the load segment.
|
|
// PHDR_SEG is a pointer to the PHDR segment.
|
|
// SEGMENT_HEADERS points to the output segment header.
|
|
// FILE_HEADER points to the output file header.
|
|
// PSHNDX is the address to store the output section index.
|
|
|
|
off_t inline
|
|
Layout::relaxation_loop_body(
|
|
int pass,
|
|
Target* target,
|
|
Symbol_table* symtab,
|
|
Output_segment** pload_seg,
|
|
Output_segment* phdr_seg,
|
|
Output_segment_headers* segment_headers,
|
|
Output_file_header* file_header,
|
|
unsigned int* pshndx)
|
|
{
|
|
// If this is not the first iteration, we need to clean up after
|
|
// relaxation so that we can lay out the sections again.
|
|
if (pass != 0)
|
|
this->clean_up_after_relaxation();
|
|
|
|
// If there is a SECTIONS clause, put all the input sections into
|
|
// the required order.
|
|
Output_segment* load_seg;
|
|
if (this->script_options_->saw_sections_clause())
|
|
load_seg = this->set_section_addresses_from_script(symtab);
|
|
else if (parameters->options().relocatable())
|
|
load_seg = NULL;
|
|
else
|
|
load_seg = this->find_first_load_seg(target);
|
|
|
|
if (parameters->options().oformat_enum()
|
|
!= General_options::OBJECT_FORMAT_ELF)
|
|
load_seg = NULL;
|
|
|
|
if (load_seg_unusable_for_headers(target))
|
|
{
|
|
load_seg = NULL;
|
|
phdr_seg = NULL;
|
|
}
|
|
|
|
gold_assert(phdr_seg == NULL
|
|
|| load_seg != NULL
|
|
|| this->script_options_->saw_sections_clause());
|
|
|
|
// If the address of the load segment we found has been set by
|
|
// --section-start rather than by a script, then adjust the VMA and
|
|
// LMA downward if possible to include the file and section headers.
|
|
uint64_t header_gap = 0;
|
|
if (load_seg != NULL
|
|
&& load_seg->are_addresses_set()
|
|
&& !this->script_options_->saw_sections_clause()
|
|
&& !parameters->options().relocatable())
|
|
{
|
|
file_header->finalize_data_size();
|
|
segment_headers->finalize_data_size();
|
|
size_t sizeof_headers = (file_header->data_size()
|
|
+ segment_headers->data_size());
|
|
const uint64_t abi_pagesize = target->abi_pagesize();
|
|
uint64_t hdr_paddr = load_seg->paddr() - sizeof_headers;
|
|
hdr_paddr &= ~(abi_pagesize - 1);
|
|
uint64_t subtract = load_seg->paddr() - hdr_paddr;
|
|
if (load_seg->paddr() < subtract || load_seg->vaddr() < subtract)
|
|
load_seg = NULL;
|
|
else
|
|
{
|
|
load_seg->set_addresses(load_seg->vaddr() - subtract,
|
|
load_seg->paddr() - subtract);
|
|
header_gap = subtract - sizeof_headers;
|
|
}
|
|
}
|
|
|
|
// Lay out the segment headers.
|
|
if (!parameters->options().relocatable())
|
|
{
|
|
gold_assert(segment_headers != NULL);
|
|
if (header_gap != 0 && load_seg != NULL)
|
|
{
|
|
Output_data_zero_fill* z = new Output_data_zero_fill(header_gap, 1);
|
|
load_seg->add_initial_output_data(z);
|
|
}
|
|
if (load_seg != NULL)
|
|
load_seg->add_initial_output_data(segment_headers);
|
|
if (phdr_seg != NULL)
|
|
phdr_seg->add_initial_output_data(segment_headers);
|
|
}
|
|
|
|
// Lay out the file header.
|
|
if (load_seg != NULL)
|
|
load_seg->add_initial_output_data(file_header);
|
|
|
|
if (this->script_options_->saw_phdrs_clause()
|
|
&& !parameters->options().relocatable())
|
|
{
|
|
// Support use of FILEHDRS and PHDRS attachments in a PHDRS
|
|
// clause in a linker script.
|
|
Script_sections* ss = this->script_options_->script_sections();
|
|
ss->put_headers_in_phdrs(file_header, segment_headers);
|
|
}
|
|
|
|
// We set the output section indexes in set_segment_offsets and
|
|
// set_section_indexes.
|
|
*pshndx = 1;
|
|
|
|
// Set the file offsets of all the segments, and all the sections
|
|
// they contain.
|
|
off_t off;
|
|
if (!parameters->options().relocatable())
|
|
off = this->set_segment_offsets(target, load_seg, pshndx);
|
|
else
|
|
off = this->set_relocatable_section_offsets(file_header, pshndx);
|
|
|
|
// Verify that the dummy relaxation does not change anything.
|
|
if (is_debugging_enabled(DEBUG_RELAXATION))
|
|
{
|
|
if (pass == 0)
|
|
this->relaxation_debug_check_->read_sections(this->section_list_);
|
|
else
|
|
this->relaxation_debug_check_->verify_sections(this->section_list_);
|
|
}
|
|
|
|
*pload_seg = load_seg;
|
|
return off;
|
|
}
|
|
|
|
// Search the list of patterns and find the position of the given section
|
|
// name in the output section. If the section name matches a glob
|
|
// pattern and a non-glob name, then the non-glob position takes
|
|
// precedence. Return 0 if no match is found.
|
|
|
|
unsigned int
|
|
Layout::find_section_order_index(const std::string& section_name)
|
|
{
|
|
Unordered_map<std::string, unsigned int>::iterator map_it;
|
|
map_it = this->input_section_position_.find(section_name);
|
|
if (map_it != this->input_section_position_.end())
|
|
return map_it->second;
|
|
|
|
// Absolute match failed. Linear search the glob patterns.
|
|
std::vector<std::string>::iterator it;
|
|
for (it = this->input_section_glob_.begin();
|
|
it != this->input_section_glob_.end();
|
|
++it)
|
|
{
|
|
if (fnmatch((*it).c_str(), section_name.c_str(), FNM_NOESCAPE) == 0)
|
|
{
|
|
map_it = this->input_section_position_.find(*it);
|
|
gold_assert(map_it != this->input_section_position_.end());
|
|
return map_it->second;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Read the sequence of input sections from the file specified with
|
|
// option --section-ordering-file.
|
|
|
|
void
|
|
Layout::read_layout_from_file()
|
|
{
|
|
const char* filename = parameters->options().section_ordering_file();
|
|
std::ifstream in;
|
|
std::string line;
|
|
|
|
in.open(filename);
|
|
if (!in)
|
|
gold_fatal(_("unable to open --section-ordering-file file %s: %s"),
|
|
filename, strerror(errno));
|
|
|
|
File_read::record_file_read(filename);
|
|
|
|
std::getline(in, line); // this chops off the trailing \n, if any
|
|
unsigned int position = 1;
|
|
this->set_section_ordering_specified();
|
|
|
|
while (in)
|
|
{
|
|
if (!line.empty() && line[line.length() - 1] == '\r') // Windows
|
|
line.resize(line.length() - 1);
|
|
// Ignore comments, beginning with '#'
|
|
if (line[0] == '#')
|
|
{
|
|
std::getline(in, line);
|
|
continue;
|
|
}
|
|
this->input_section_position_[line] = position;
|
|
// Store all glob patterns in a vector.
|
|
if (is_wildcard_string(line.c_str()))
|
|
this->input_section_glob_.push_back(line);
|
|
position++;
|
|
std::getline(in, line);
|
|
}
|
|
}
|
|
|
|
// 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,
|
|
Target* target, const Task* task)
|
|
{
|
|
unsigned int local_dynamic_count = 0;
|
|
unsigned int forced_local_dynamic_count = 0;
|
|
|
|
target->finalize_sections(this, input_objects, symtab);
|
|
|
|
this->count_local_symbols(task, input_objects);
|
|
|
|
this->link_stabs_sections();
|
|
|
|
Output_segment* phdr_seg = NULL;
|
|
if (!parameters->options().relocatable() && !parameters->doing_static_link())
|
|
{
|
|
// There was a dynamic object in the link. We need to create
|
|
// some information for the dynamic linker.
|
|
|
|
// Create the PT_PHDR segment which will hold the program
|
|
// headers.
|
|
if (!this->script_options_->saw_phdrs_clause())
|
|
phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
|
|
|
|
// Create the dynamic symbol table, including the hash table.
|
|
Output_section* dynstr;
|
|
std::vector<Symbol*> dynamic_symbols;
|
|
Versions versions(*this->script_options()->version_script_info(),
|
|
&this->dynpool_);
|
|
this->create_dynamic_symtab(input_objects, symtab, &dynstr,
|
|
&local_dynamic_count,
|
|
&forced_local_dynamic_count,
|
|
&dynamic_symbols,
|
|
&versions);
|
|
|
|
// Create the .interp section to hold the name of the
|
|
// interpreter, and put it in a PT_INTERP segment. Don't do it
|
|
// if we saw a .interp section in an input file.
|
|
if ((!parameters->options().shared()
|
|
|| parameters->options().dynamic_linker() != NULL)
|
|
&& this->interp_segment_ == NULL)
|
|
this->create_interp(target);
|
|
|
|
// Finish the .dynamic section to hold the dynamic data, and put
|
|
// it in a PT_DYNAMIC segment.
|
|
this->finish_dynamic_section(input_objects, symtab);
|
|
|
|
// We should have added everything we need to the dynamic string
|
|
// table.
|
|
this->dynpool_.set_string_offsets();
|
|
|
|
// Create the version sections. We can't do this until the
|
|
// dynamic string table is complete.
|
|
this->create_version_sections(&versions, symtab,
|
|
(local_dynamic_count
|
|
+ forced_local_dynamic_count),
|
|
dynamic_symbols, dynstr);
|
|
|
|
// Set the size of the _DYNAMIC symbol. We can't do this until
|
|
// after we call create_version_sections.
|
|
this->set_dynamic_symbol_size(symtab);
|
|
}
|
|
|
|
// Create segment headers.
|
|
Output_segment_headers* segment_headers =
|
|
(parameters->options().relocatable()
|
|
? NULL
|
|
: new Output_segment_headers(this->segment_list_));
|
|
|
|
// Lay out the file header.
|
|
Output_file_header* file_header = new Output_file_header(target, symtab,
|
|
segment_headers);
|
|
|
|
this->special_output_list_.push_back(file_header);
|
|
if (segment_headers != NULL)
|
|
this->special_output_list_.push_back(segment_headers);
|
|
|
|
// Find approriate places for orphan output sections if we are using
|
|
// a linker script.
|
|
if (this->script_options_->saw_sections_clause())
|
|
this->place_orphan_sections_in_script();
|
|
|
|
Output_segment* load_seg;
|
|
off_t off;
|
|
unsigned int shndx;
|
|
int pass = 0;
|
|
|
|
// Take a snapshot of the section layout as needed.
|
|
if (target->may_relax())
|
|
this->prepare_for_relaxation();
|
|
|
|
// Run the relaxation loop to lay out sections.
|
|
do
|
|
{
|
|
off = this->relaxation_loop_body(pass, target, symtab, &load_seg,
|
|
phdr_seg, segment_headers, file_header,
|
|
&shndx);
|
|
pass++;
|
|
}
|
|
while (target->may_relax()
|
|
&& target->relax(pass, input_objects, symtab, this, task));
|
|
|
|
// If there is a load segment that contains the file and program headers,
|
|
// provide a symbol __ehdr_start pointing there.
|
|
// A program can use this to examine itself robustly.
|
|
Symbol *ehdr_start = symtab->lookup("__ehdr_start");
|
|
if (ehdr_start != NULL && ehdr_start->is_predefined())
|
|
{
|
|
if (load_seg != NULL)
|
|
ehdr_start->set_output_segment(load_seg, Symbol::SEGMENT_START);
|
|
else
|
|
ehdr_start->set_undefined();
|
|
}
|
|
|
|
// Set the file offsets of all the non-data sections we've seen so
|
|
// far which don't have to wait for the input sections. We need
|
|
// this in order to finalize local symbols in non-allocated
|
|
// sections.
|
|
off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
|
|
|
|
// Set the section indexes of all unallocated sections seen so far,
|
|
// in case any of them are somehow referenced by a symbol.
|
|
shndx = this->set_section_indexes(shndx);
|
|
|
|
// Create the symbol table sections.
|
|
this->create_symtab_sections(input_objects, symtab, shndx, &off,
|
|
local_dynamic_count);
|
|
if (!parameters->doing_static_link())
|
|
this->assign_local_dynsym_offsets(input_objects);
|
|
|
|
// Process any symbol assignments from a linker script. This must
|
|
// be called after the symbol table has been finalized.
|
|
this->script_options_->finalize_symbols(symtab, this);
|
|
|
|
// Create the incremental inputs sections.
|
|
if (this->incremental_inputs_)
|
|
{
|
|
this->incremental_inputs_->finalize();
|
|
this->create_incremental_info_sections(symtab);
|
|
}
|
|
|
|
// Create the .shstrtab section.
|
|
Output_section* shstrtab_section = this->create_shstrtab();
|
|
|
|
// Set the file offsets of the rest of the non-data sections which
|
|
// don't have to wait for the input sections.
|
|
off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
|
|
|
|
// Now that all sections have been created, set the section indexes
|
|
// for any sections which haven't been done yet.
|
|
shndx = this->set_section_indexes(shndx);
|
|
|
|
// Create the section table header.
|
|
this->create_shdrs(shstrtab_section, &off);
|
|
|
|
// If there are no sections which require postprocessing, we can
|
|
// handle the section names now, and avoid a resize later.
|
|
if (!this->any_postprocessing_sections_)
|
|
{
|
|
off = this->set_section_offsets(off,
|
|
POSTPROCESSING_SECTIONS_PASS);
|
|
off =
|
|
this->set_section_offsets(off,
|
|
STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS);
|
|
}
|
|
|
|
file_header->set_section_info(this->section_headers_, shstrtab_section);
|
|
|
|
// Now we know exactly where everything goes in the output file
|
|
// (except for non-allocated sections which require postprocessing).
|
|
Output_data::layout_complete();
|
|
|
|
this->output_file_size_ = off;
|
|
|
|
return off;
|
|
}
|
|
|
|
// Create a note header following the format defined in the ELF ABI.
|
|
// NAME is the name, NOTE_TYPE is the type, SECTION_NAME is the name
|
|
// of the section to create, DESCSZ is the size of the descriptor.
|
|
// ALLOCATE is true if the section should be allocated in memory.
|
|
// This returns the new note section. It sets *TRAILING_PADDING to
|
|
// the number of trailing zero bytes required.
|
|
|
|
Output_section*
|
|
Layout::create_note(const char* name, int note_type,
|
|
const char* section_name, size_t descsz,
|
|
bool allocate, size_t* trailing_padding)
|
|
{
|
|
// Authorities all agree that the values in a .note field should
|
|
// be aligned on 4-byte boundaries for 32-bit binaries. However,
|
|
// they differ on what the alignment is for 64-bit binaries.
|
|
// The GABI says unambiguously they take 8-byte alignment:
|
|
// http://sco.com/developers/gabi/latest/ch5.pheader.html#note_section
|
|
// Other documentation says alignment should always be 4 bytes:
|
|
// http://www.netbsd.org/docs/kernel/elf-notes.html#note-format
|
|
// GNU ld and GNU readelf both support the latter (at least as of
|
|
// version 2.16.91), and glibc always generates the latter for
|
|
// .note.ABI-tag (as of version 1.6), so that's the one we go with
|
|
// here.
|
|
#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION // This is not defined by default.
|
|
const int size = parameters->target().get_size();
|
|
#else
|
|
const int size = 32;
|
|
#endif
|
|
// The NT_GNU_PROPERTY_TYPE_0 note is aligned to the pointer size.
|
|
const int addralign = ((note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0
|
|
? parameters->target().get_size()
|
|
: size) / 8);
|
|
|
|
// The contents of the .note section.
|
|
size_t namesz = strlen(name) + 1;
|
|
size_t aligned_namesz = align_address(namesz, size / 8);
|
|
size_t aligned_descsz = align_address(descsz, size / 8);
|
|
|
|
size_t notehdrsz = 3 * (size / 8) + aligned_namesz;
|
|
|
|
unsigned char* buffer = new unsigned char[notehdrsz];
|
|
memset(buffer, 0, notehdrsz);
|
|
|
|
bool is_big_endian = parameters->target().is_big_endian();
|
|
|
|
if (size == 32)
|
|
{
|
|
if (!is_big_endian)
|
|
{
|
|
elfcpp::Swap<32, false>::writeval(buffer, namesz);
|
|
elfcpp::Swap<32, false>::writeval(buffer + 4, descsz);
|
|
elfcpp::Swap<32, false>::writeval(buffer + 8, note_type);
|
|
}
|
|
else
|
|
{
|
|
elfcpp::Swap<32, true>::writeval(buffer, namesz);
|
|
elfcpp::Swap<32, true>::writeval(buffer + 4, descsz);
|
|
elfcpp::Swap<32, true>::writeval(buffer + 8, note_type);
|
|
}
|
|
}
|
|
else if (size == 64)
|
|
{
|
|
if (!is_big_endian)
|
|
{
|
|
elfcpp::Swap<64, false>::writeval(buffer, namesz);
|
|
elfcpp::Swap<64, false>::writeval(buffer + 8, descsz);
|
|
elfcpp::Swap<64, false>::writeval(buffer + 16, note_type);
|
|
}
|
|
else
|
|
{
|
|
elfcpp::Swap<64, true>::writeval(buffer, namesz);
|
|
elfcpp::Swap<64, true>::writeval(buffer + 8, descsz);
|
|
elfcpp::Swap<64, true>::writeval(buffer + 16, note_type);
|
|
}
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
|
|
memcpy(buffer + 3 * (size / 8), name, namesz);
|
|
|
|
elfcpp::Elf_Xword flags = 0;
|
|
Output_section_order order = ORDER_INVALID;
|
|
if (allocate)
|
|
{
|
|
flags = elfcpp::SHF_ALLOC;
|
|
order = (note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0
|
|
? ORDER_PROPERTY_NOTE : ORDER_RO_NOTE);
|
|
}
|
|
Output_section* os = this->choose_output_section(NULL, section_name,
|
|
elfcpp::SHT_NOTE,
|
|
flags, false, order, false,
|
|
false, true);
|
|
if (os == NULL)
|
|
return NULL;
|
|
|
|
Output_section_data* posd = new Output_data_const_buffer(buffer, notehdrsz,
|
|
addralign,
|
|
"** note header");
|
|
os->add_output_section_data(posd);
|
|
|
|
*trailing_padding = aligned_descsz - descsz;
|
|
|
|
return os;
|
|
}
|
|
|
|
// Create a .note.gnu.property section to record program properties
|
|
// accumulated from the input files.
|
|
|
|
void
|
|
Layout::create_gnu_properties_note()
|
|
{
|
|
parameters->target().finalize_gnu_properties(this);
|
|
|
|
if (this->gnu_properties_.empty())
|
|
return;
|
|
|
|
const unsigned int size = parameters->target().get_size();
|
|
const bool is_big_endian = parameters->target().is_big_endian();
|
|
|
|
// Compute the total size of the properties array.
|
|
size_t descsz = 0;
|
|
for (Gnu_properties::const_iterator prop = this->gnu_properties_.begin();
|
|
prop != this->gnu_properties_.end();
|
|
++prop)
|
|
{
|
|
descsz = align_address(descsz + 8 + prop->second.pr_datasz, size / 8);
|
|
}
|
|
|
|
// Create the note section.
|
|
size_t trailing_padding;
|
|
Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_PROPERTY_TYPE_0,
|
|
".note.gnu.property", descsz,
|
|
true, &trailing_padding);
|
|
if (os == NULL)
|
|
return;
|
|
gold_assert(trailing_padding == 0);
|
|
|
|
// Allocate and fill the properties array.
|
|
unsigned char* desc = new unsigned char[descsz];
|
|
unsigned char* p = desc;
|
|
for (Gnu_properties::const_iterator prop = this->gnu_properties_.begin();
|
|
prop != this->gnu_properties_.end();
|
|
++prop)
|
|
{
|
|
size_t datasz = prop->second.pr_datasz;
|
|
size_t aligned_datasz = align_address(prop->second.pr_datasz, size / 8);
|
|
write_sized_value(prop->first, 4, p, is_big_endian);
|
|
write_sized_value(datasz, 4, p + 4, is_big_endian);
|
|
memcpy(p + 8, prop->second.pr_data, datasz);
|
|
if (aligned_datasz > datasz)
|
|
memset(p + 8 + datasz, 0, aligned_datasz - datasz);
|
|
p += 8 + aligned_datasz;
|
|
}
|
|
Output_section_data* posd = new Output_data_const(desc, descsz, 4);
|
|
os->add_output_section_data(posd);
|
|
}
|
|
|
|
// For an executable or shared library, create a note to record the
|
|
// version of gold used to create the binary.
|
|
|
|
void
|
|
Layout::create_gold_note()
|
|
{
|
|
if (parameters->options().relocatable()
|
|
|| parameters->incremental_update())
|
|
return;
|
|
|
|
std::string desc = std::string("gold ") + gold::get_version_string();
|
|
|
|
size_t trailing_padding;
|
|
Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_GOLD_VERSION,
|
|
".note.gnu.gold-version", desc.size(),
|
|
false, &trailing_padding);
|
|
if (os == NULL)
|
|
return;
|
|
|
|
Output_section_data* posd = new Output_data_const(desc, 4);
|
|
os->add_output_section_data(posd);
|
|
|
|
if (trailing_padding > 0)
|
|
{
|
|
posd = new Output_data_zero_fill(trailing_padding, 0);
|
|
os->add_output_section_data(posd);
|
|
}
|
|
}
|
|
|
|
// Record whether the stack should be executable. This can be set
|
|
// from the command line using the -z execstack or -z noexecstack
|
|
// options. Otherwise, if any input file has a .note.GNU-stack
|
|
// section with the SHF_EXECINSTR flag set, the stack should be
|
|
// executable. Otherwise, if at least one input file a
|
|
// .note.GNU-stack section, and some input file has no .note.GNU-stack
|
|
// section, we use the target default for whether the stack should be
|
|
// executable. If -z stack-size was used to set a p_memsz value for
|
|
// PT_GNU_STACK, we generate the segment regardless. Otherwise, we
|
|
// don't generate a stack note. When generating a object file, we
|
|
// create a .note.GNU-stack section with the appropriate marking.
|
|
// When generating an executable or shared library, we create a
|
|
// PT_GNU_STACK segment.
|
|
|
|
void
|
|
Layout::create_stack_segment()
|
|
{
|
|
bool is_stack_executable;
|
|
if (parameters->options().is_execstack_set())
|
|
{
|
|
is_stack_executable = parameters->options().is_stack_executable();
|
|
if (!is_stack_executable
|
|
&& this->input_requires_executable_stack_
|
|
&& parameters->options().warn_execstack())
|
|
gold_warning(_("one or more inputs require executable stack, "
|
|
"but -z noexecstack was given"));
|
|
}
|
|
else if (!this->input_with_gnu_stack_note_
|
|
&& (!parameters->options().user_set_stack_size()
|
|
|| parameters->options().relocatable()))
|
|
return;
|
|
else
|
|
{
|
|
if (this->input_requires_executable_stack_)
|
|
is_stack_executable = true;
|
|
else if (this->input_without_gnu_stack_note_)
|
|
is_stack_executable =
|
|
parameters->target().is_default_stack_executable();
|
|
else
|
|
is_stack_executable = false;
|
|
}
|
|
|
|
if (parameters->options().relocatable())
|
|
{
|
|
const char* name = this->namepool_.add(".note.GNU-stack", false, NULL);
|
|
elfcpp::Elf_Xword flags = 0;
|
|
if (is_stack_executable)
|
|
flags |= elfcpp::SHF_EXECINSTR;
|
|
this->make_output_section(name, elfcpp::SHT_PROGBITS, flags,
|
|
ORDER_INVALID, false);
|
|
}
|
|
else
|
|
{
|
|
if (this->script_options_->saw_phdrs_clause())
|
|
return;
|
|
int flags = elfcpp::PF_R | elfcpp::PF_W;
|
|
if (is_stack_executable)
|
|
flags |= elfcpp::PF_X;
|
|
Output_segment* seg =
|
|
this->make_output_segment(elfcpp::PT_GNU_STACK, flags);
|
|
seg->set_size(parameters->options().stack_size());
|
|
// BFD lets targets override this default alignment, but the only
|
|
// targets that do so are ones that Gold does not support so far.
|
|
seg->set_minimum_p_align(16);
|
|
}
|
|
}
|
|
|
|
// If --build-id was used, set up the build ID note.
|
|
|
|
void
|
|
Layout::create_build_id()
|
|
{
|
|
if (!parameters->options().user_set_build_id())
|
|
return;
|
|
|
|
const char* style = parameters->options().build_id();
|
|
if (strcmp(style, "none") == 0)
|
|
return;
|
|
|
|
// Set DESCSZ to the size of the note descriptor. When possible,
|
|
// set DESC to the note descriptor contents.
|
|
size_t descsz;
|
|
std::string desc;
|
|
if (strcmp(style, "md5") == 0)
|
|
descsz = 128 / 8;
|
|
else if ((strcmp(style, "sha1") == 0) || (strcmp(style, "tree") == 0))
|
|
descsz = 160 / 8;
|
|
else if (strcmp(style, "uuid") == 0)
|
|
{
|
|
#ifndef __MINGW32__
|
|
const size_t uuidsz = 128 / 8;
|
|
|
|
char buffer[uuidsz];
|
|
memset(buffer, 0, uuidsz);
|
|
|
|
int descriptor = open_descriptor(-1, "/dev/urandom", O_RDONLY);
|
|
if (descriptor < 0)
|
|
gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"),
|
|
strerror(errno));
|
|
else
|
|
{
|
|
ssize_t got = ::read(descriptor, buffer, uuidsz);
|
|
release_descriptor(descriptor, true);
|
|
if (got < 0)
|
|
gold_error(_("/dev/urandom: read failed: %s"), strerror(errno));
|
|
else if (static_cast<size_t>(got) != uuidsz)
|
|
gold_error(_("/dev/urandom: expected %zu bytes, got %zd bytes"),
|
|
uuidsz, got);
|
|
}
|
|
|
|
desc.assign(buffer, uuidsz);
|
|
descsz = uuidsz;
|
|
#else // __MINGW32__
|
|
UUID uuid;
|
|
typedef RPC_STATUS (RPC_ENTRY *UuidCreateFn)(UUID *Uuid);
|
|
|
|
HMODULE rpc_library = LoadLibrary("rpcrt4.dll");
|
|
if (!rpc_library)
|
|
gold_error(_("--build-id=uuid failed: could not load rpcrt4.dll"));
|
|
else
|
|
{
|
|
UuidCreateFn uuid_create = reinterpret_cast<UuidCreateFn>(
|
|
GetProcAddress(rpc_library, "UuidCreate"));
|
|
if (!uuid_create)
|
|
gold_error(_("--build-id=uuid failed: could not find UuidCreate"));
|
|
else if (uuid_create(&uuid) != RPC_S_OK)
|
|
gold_error(_("__build_id=uuid failed: call UuidCreate() failed"));
|
|
FreeLibrary(rpc_library);
|
|
}
|
|
desc.assign(reinterpret_cast<const char *>(&uuid), sizeof(UUID));
|
|
descsz = sizeof(UUID);
|
|
#endif // __MINGW32__
|
|
}
|
|
else if (strncmp(style, "0x", 2) == 0)
|
|
{
|
|
hex_init();
|
|
const char* p = style + 2;
|
|
while (*p != '\0')
|
|
{
|
|
if (hex_p(p[0]) && hex_p(p[1]))
|
|
{
|
|
char c = (hex_value(p[0]) << 4) | hex_value(p[1]);
|
|
desc += c;
|
|
p += 2;
|
|
}
|
|
else if (*p == '-' || *p == ':')
|
|
++p;
|
|
else
|
|
gold_fatal(_("--build-id argument '%s' not a valid hex number"),
|
|
style);
|
|
}
|
|
descsz = desc.size();
|
|
}
|
|
else
|
|
gold_fatal(_("unrecognized --build-id argument '%s'"), style);
|
|
|
|
// Create the note.
|
|
size_t trailing_padding;
|
|
Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_BUILD_ID,
|
|
".note.gnu.build-id", descsz, true,
|
|
&trailing_padding);
|
|
if (os == NULL)
|
|
return;
|
|
|
|
if (!desc.empty())
|
|
{
|
|
// We know the value already, so we fill it in now.
|
|
gold_assert(desc.size() == descsz);
|
|
|
|
Output_section_data* posd = new Output_data_const(desc, 4);
|
|
os->add_output_section_data(posd);
|
|
|
|
if (trailing_padding != 0)
|
|
{
|
|
posd = new Output_data_zero_fill(trailing_padding, 0);
|
|
os->add_output_section_data(posd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We need to compute a checksum after we have completed the
|
|
// link.
|
|
gold_assert(trailing_padding == 0);
|
|
this->build_id_note_ = new Output_data_zero_fill(descsz, 4);
|
|
os->add_output_section_data(this->build_id_note_);
|
|
}
|
|
}
|
|
|
|
// If --package-metadata was used, set up the package metadata note.
|
|
// https://systemd.io/ELF_PACKAGE_METADATA/
|
|
|
|
void
|
|
Layout::create_package_metadata()
|
|
{
|
|
if (!parameters->options().user_set_package_metadata())
|
|
return;
|
|
|
|
const char* desc = parameters->options().package_metadata();
|
|
if (strcmp(desc, "") == 0)
|
|
return;
|
|
|
|
#ifdef HAVE_JANSSON
|
|
json_error_t json_error;
|
|
json_t *json = json_loads(desc, 0, &json_error);
|
|
if (json)
|
|
json_decref(json);
|
|
else
|
|
{
|
|
gold_fatal(_("error: --package-metadata=%s does not contain valid "
|
|
"JSON: %s\n"),
|
|
desc, json_error.text);
|
|
}
|
|
#endif
|
|
|
|
// Create the note.
|
|
size_t trailing_padding;
|
|
// Ensure the trailing NULL byte is always included, as per specification.
|
|
size_t descsz = strlen(desc) + 1;
|
|
Output_section* os = this->create_note("FDO", elfcpp::FDO_PACKAGING_METADATA,
|
|
".note.package", descsz, true,
|
|
&trailing_padding);
|
|
if (os == NULL)
|
|
return;
|
|
|
|
Output_section_data* posd = new Output_data_const(desc, descsz, 4);
|
|
os->add_output_section_data(posd);
|
|
|
|
if (trailing_padding != 0)
|
|
{
|
|
posd = new Output_data_zero_fill(trailing_padding, 0);
|
|
os->add_output_section_data(posd);
|
|
}
|
|
}
|
|
|
|
// If we have both .stabXX and .stabXXstr sections, then the sh_link
|
|
// field of the former should point to the latter. I'm not sure who
|
|
// started this, but the GNU linker does it, and some tools depend
|
|
// upon it.
|
|
|
|
void
|
|
Layout::link_stabs_sections()
|
|
{
|
|
if (!this->have_stabstr_section_)
|
|
return;
|
|
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->type() != elfcpp::SHT_STRTAB)
|
|
continue;
|
|
|
|
const char* name = (*p)->name();
|
|
if (strncmp(name, ".stab", 5) != 0)
|
|
continue;
|
|
|
|
size_t len = strlen(name);
|
|
if (strcmp(name + len - 3, "str") != 0)
|
|
continue;
|
|
|
|
std::string stab_name(name, len - 3);
|
|
Output_section* stab_sec;
|
|
stab_sec = this->find_output_section(stab_name.c_str());
|
|
if (stab_sec != NULL)
|
|
stab_sec->set_link_section(*p);
|
|
}
|
|
}
|
|
|
|
// Create .gnu_incremental_inputs and related sections needed
|
|
// for the next run of incremental linking to check what has changed.
|
|
|
|
void
|
|
Layout::create_incremental_info_sections(Symbol_table* symtab)
|
|
{
|
|
Incremental_inputs* incr = this->incremental_inputs_;
|
|
|
|
gold_assert(incr != NULL);
|
|
|
|
// Create the .gnu_incremental_inputs, _symtab, and _relocs input sections.
|
|
incr->create_data_sections(symtab);
|
|
|
|
// Add the .gnu_incremental_inputs section.
|
|
const char* incremental_inputs_name =
|
|
this->namepool_.add(".gnu_incremental_inputs", false, NULL);
|
|
Output_section* incremental_inputs_os =
|
|
this->make_output_section(incremental_inputs_name,
|
|
elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0,
|
|
ORDER_INVALID, false);
|
|
incremental_inputs_os->add_output_section_data(incr->inputs_section());
|
|
|
|
// Add the .gnu_incremental_symtab section.
|
|
const char* incremental_symtab_name =
|
|
this->namepool_.add(".gnu_incremental_symtab", false, NULL);
|
|
Output_section* incremental_symtab_os =
|
|
this->make_output_section(incremental_symtab_name,
|
|
elfcpp::SHT_GNU_INCREMENTAL_SYMTAB, 0,
|
|
ORDER_INVALID, false);
|
|
incremental_symtab_os->add_output_section_data(incr->symtab_section());
|
|
incremental_symtab_os->set_entsize(4);
|
|
|
|
// Add the .gnu_incremental_relocs section.
|
|
const char* incremental_relocs_name =
|
|
this->namepool_.add(".gnu_incremental_relocs", false, NULL);
|
|
Output_section* incremental_relocs_os =
|
|
this->make_output_section(incremental_relocs_name,
|
|
elfcpp::SHT_GNU_INCREMENTAL_RELOCS, 0,
|
|
ORDER_INVALID, false);
|
|
incremental_relocs_os->add_output_section_data(incr->relocs_section());
|
|
incremental_relocs_os->set_entsize(incr->relocs_entsize());
|
|
|
|
// Add the .gnu_incremental_got_plt section.
|
|
const char* incremental_got_plt_name =
|
|
this->namepool_.add(".gnu_incremental_got_plt", false, NULL);
|
|
Output_section* incremental_got_plt_os =
|
|
this->make_output_section(incremental_got_plt_name,
|
|
elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT, 0,
|
|
ORDER_INVALID, false);
|
|
incremental_got_plt_os->add_output_section_data(incr->got_plt_section());
|
|
|
|
// Add the .gnu_incremental_strtab section.
|
|
const char* incremental_strtab_name =
|
|
this->namepool_.add(".gnu_incremental_strtab", false, NULL);
|
|
Output_section* incremental_strtab_os = this->make_output_section(incremental_strtab_name,
|
|
elfcpp::SHT_STRTAB, 0,
|
|
ORDER_INVALID, false);
|
|
Output_data_strtab* strtab_data =
|
|
new Output_data_strtab(incr->get_stringpool());
|
|
incremental_strtab_os->add_output_section_data(strtab_data);
|
|
|
|
incremental_inputs_os->set_after_input_sections();
|
|
incremental_symtab_os->set_after_input_sections();
|
|
incremental_relocs_os->set_after_input_sections();
|
|
incremental_got_plt_os->set_after_input_sections();
|
|
|
|
incremental_inputs_os->set_link_section(incremental_strtab_os);
|
|
incremental_symtab_os->set_link_section(incremental_inputs_os);
|
|
incremental_relocs_os->set_link_section(incremental_inputs_os);
|
|
incremental_got_plt_os->set_link_section(incremental_inputs_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 have normally not yet been set.
|
|
|
|
bool
|
|
Layout::segment_precedes(const Output_segment* seg1,
|
|
const Output_segment* seg2)
|
|
{
|
|
// In order to produce a stable ordering if we're called with the same pointer
|
|
// return false.
|
|
if (seg1 == seg2)
|
|
return false;
|
|
|
|
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)
|
|
{
|
|
gold_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)
|
|
{
|
|
gold_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;
|
|
|
|
// We put the PT_TLS segment last except for the PT_GNU_RELRO
|
|
// segment, because that is where the dynamic linker expects to find
|
|
// it (this is just for efficiency; other positions would also work
|
|
// correctly).
|
|
if (type1 == elfcpp::PT_TLS
|
|
&& type2 != elfcpp::PT_TLS
|
|
&& type2 != elfcpp::PT_GNU_RELRO)
|
|
return false;
|
|
if (type2 == elfcpp::PT_TLS
|
|
&& type1 != elfcpp::PT_TLS
|
|
&& type1 != elfcpp::PT_GNU_RELRO)
|
|
return true;
|
|
|
|
// We put the PT_GNU_RELRO segment last, because that is where the
|
|
// dynamic linker expects to find it (as with PT_TLS, this is just
|
|
// for efficiency).
|
|
if (type1 == elfcpp::PT_GNU_RELRO && type2 != elfcpp::PT_GNU_RELRO)
|
|
return false;
|
|
if (type2 == elfcpp::PT_GNU_RELRO && type1 != elfcpp::PT_GNU_RELRO)
|
|
return true;
|
|
|
|
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, except
|
|
// when a linker script specifies such.
|
|
if (type1 != elfcpp::PT_LOAD)
|
|
{
|
|
if (type1 != type2)
|
|
return type1 < type2;
|
|
uint64_t align1 = seg1->align();
|
|
uint64_t align2 = seg2->align();
|
|
// Place segments with larger alignments first.
|
|
if (align1 != align2)
|
|
return align1 > align2;
|
|
gold_assert(flags1 != flags2
|
|
|| this->script_options_->saw_phdrs_clause());
|
|
return flags1 < flags2;
|
|
}
|
|
|
|
// If the addresses are set already, sort by load address.
|
|
if (seg1->are_addresses_set())
|
|
{
|
|
if (!seg2->are_addresses_set())
|
|
return true;
|
|
|
|
unsigned int section_count1 = seg1->output_section_count();
|
|
unsigned int section_count2 = seg2->output_section_count();
|
|
if (section_count1 == 0 && section_count2 > 0)
|
|
return true;
|
|
if (section_count1 > 0 && section_count2 == 0)
|
|
return false;
|
|
|
|
uint64_t paddr1 = (seg1->are_addresses_set()
|
|
? seg1->paddr()
|
|
: seg1->first_section_load_address());
|
|
uint64_t paddr2 = (seg2->are_addresses_set()
|
|
? seg2->paddr()
|
|
: seg2->first_section_load_address());
|
|
|
|
if (paddr1 != paddr2)
|
|
return paddr1 < paddr2;
|
|
}
|
|
else if (seg2->are_addresses_set())
|
|
return false;
|
|
|
|
// A segment which holds large data comes after a segment which does
|
|
// not hold large data.
|
|
if (seg1->is_large_data_segment())
|
|
{
|
|
if (!seg2->is_large_data_segment())
|
|
return false;
|
|
}
|
|
else if (seg2->is_large_data_segment())
|
|
return true;
|
|
|
|
// Otherwise, we sort PT_LOAD segments based on the flags. Readonly
|
|
// segments come before writable segments. Then writable segments
|
|
// with data come before writable segments without data. 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_W) != 0
|
|
&& seg1->has_any_data_sections() != seg2->has_any_data_sections())
|
|
return seg1->has_any_data_sections();
|
|
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;
|
|
|
|
// We shouldn't get here--we shouldn't create segments which we
|
|
// can't distinguish. Unless of course we are using a weird linker
|
|
// script or overlapping --section-start options. We could also get
|
|
// here if plugins want unique segments for subsets of sections.
|
|
gold_assert(this->script_options_->saw_phdrs_clause()
|
|
|| parameters->options().any_section_start()
|
|
|| this->is_unique_segment_for_sections_specified()
|
|
|| parameters->options().text_unlikely_segment());
|
|
return false;
|
|
}
|
|
|
|
// Increase OFF so that it is congruent to ADDR modulo ABI_PAGESIZE.
|
|
|
|
static off_t
|
|
align_file_offset(off_t off, uint64_t addr, uint64_t abi_pagesize)
|
|
{
|
|
uint64_t unsigned_off = off;
|
|
uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1))
|
|
| (addr & (abi_pagesize - 1)));
|
|
if (aligned_off < unsigned_off)
|
|
aligned_off += abi_pagesize;
|
|
return aligned_off;
|
|
}
|
|
|
|
// On targets where the text segment contains only executable code,
|
|
// a non-executable segment is never the text segment.
|
|
|
|
static inline bool
|
|
is_text_segment(const Target* target, const Output_segment* seg)
|
|
{
|
|
elfcpp::Elf_Xword flags = seg->flags();
|
|
if ((flags & elfcpp::PF_W) != 0)
|
|
return false;
|
|
if ((flags & elfcpp::PF_X) == 0)
|
|
return !target->isolate_execinstr();
|
|
return true;
|
|
}
|
|
|
|
// Set the file offsets of all the segments, and all the sections they
|
|
// contain. They have all been created. LOAD_SEG must be laid out
|
|
// first. Return the offset of the data to follow.
|
|
|
|
off_t
|
|
Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
|
|
unsigned int* pshndx)
|
|
{
|
|
// Sort them into the final order. We use a stable sort so that we
|
|
// don't randomize the order of indistinguishable segments created
|
|
// by linker scripts.
|
|
std::stable_sort(this->segment_list_.begin(), this->segment_list_.end(),
|
|
Layout::Compare_segments(this));
|
|
|
|
// Find the PT_LOAD segments, and set their addresses and offsets
|
|
// and their section's addresses and offsets.
|
|
uint64_t start_addr;
|
|
if (parameters->options().user_set_Ttext())
|
|
start_addr = parameters->options().Ttext();
|
|
else if (parameters->options().output_is_position_independent())
|
|
start_addr = 0;
|
|
else
|
|
start_addr = target->default_text_segment_address();
|
|
|
|
uint64_t addr = start_addr;
|
|
off_t off = 0;
|
|
|
|
// If LOAD_SEG is NULL, then the file header and segment headers
|
|
// will not be loadable. But they still need to be at offset 0 in
|
|
// the file. Set their offsets now.
|
|
if (load_seg == NULL)
|
|
{
|
|
for (Data_list::iterator p = this->special_output_list_.begin();
|
|
p != this->special_output_list_.end();
|
|
++p)
|
|
{
|
|
off = align_address(off, (*p)->addralign());
|
|
(*p)->set_address_and_file_offset(0, off);
|
|
off += (*p)->data_size();
|
|
}
|
|
}
|
|
|
|
unsigned int increase_relro = this->increase_relro_;
|
|
if (this->script_options_->saw_sections_clause())
|
|
increase_relro = 0;
|
|
|
|
const bool check_sections = parameters->options().check_sections();
|
|
Output_segment* last_load_segment = NULL;
|
|
|
|
unsigned int shndx_begin = *pshndx;
|
|
unsigned int shndx_load_seg = *pshndx;
|
|
|
|
for (Segment_list::iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->type() == elfcpp::PT_LOAD)
|
|
{
|
|
if (target->isolate_execinstr())
|
|
{
|
|
// When we hit the segment that should contain the
|
|
// file headers, reset the file offset so we place
|
|
// it and subsequent segments appropriately.
|
|
// We'll fix up the preceding segments below.
|
|
if (load_seg == *p)
|
|
{
|
|
if (off == 0)
|
|
load_seg = NULL;
|
|
else
|
|
{
|
|
off = 0;
|
|
shndx_load_seg = *pshndx;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Verify that the file headers fall into the first segment.
|
|
if (load_seg != NULL && load_seg != *p)
|
|
gold_unreachable();
|
|
load_seg = NULL;
|
|
}
|
|
|
|
bool are_addresses_set = (*p)->are_addresses_set();
|
|
if (are_addresses_set)
|
|
{
|
|
// When it comes to setting file offsets, we care about
|
|
// the physical address.
|
|
addr = (*p)->paddr();
|
|
}
|
|
else if (parameters->options().user_set_Ttext()
|
|
&& (parameters->options().omagic()
|
|
|| is_text_segment(target, *p)))
|
|
{
|
|
are_addresses_set = true;
|
|
}
|
|
else if (parameters->options().user_set_Trodata_segment()
|
|
&& ((*p)->flags() & (elfcpp::PF_W | elfcpp::PF_X)) == 0)
|
|
{
|
|
addr = parameters->options().Trodata_segment();
|
|
are_addresses_set = true;
|
|
}
|
|
else if (parameters->options().user_set_Tdata()
|
|
&& ((*p)->flags() & elfcpp::PF_W) != 0
|
|
&& (!parameters->options().user_set_Tbss()
|
|
|| (*p)->has_any_data_sections()))
|
|
{
|
|
addr = parameters->options().Tdata();
|
|
are_addresses_set = true;
|
|
}
|
|
else if (parameters->options().user_set_Tbss()
|
|
&& ((*p)->flags() & elfcpp::PF_W) != 0
|
|
&& !(*p)->has_any_data_sections())
|
|
{
|
|
addr = parameters->options().Tbss();
|
|
are_addresses_set = true;
|
|
}
|
|
|
|
uint64_t orig_addr = addr;
|
|
uint64_t orig_off = off;
|
|
|
|
uint64_t aligned_addr = 0;
|
|
uint64_t abi_pagesize = target->abi_pagesize();
|
|
uint64_t common_pagesize = target->common_pagesize();
|
|
|
|
if (!parameters->options().nmagic()
|
|
&& !parameters->options().omagic())
|
|
(*p)->set_minimum_p_align(abi_pagesize);
|
|
|
|
if (!are_addresses_set)
|
|
{
|
|
// 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. We will revisit this
|
|
// decision once we know the size of the segment.
|
|
|
|
uint64_t max_align = (*p)->maximum_alignment();
|
|
if (max_align > abi_pagesize)
|
|
addr = align_address(addr, max_align);
|
|
aligned_addr = addr;
|
|
|
|
if (load_seg == *p)
|
|
{
|
|
// This is the segment that will contain the file
|
|
// headers, so its offset will have to be exactly zero.
|
|
gold_assert(orig_off == 0);
|
|
|
|
// If the target wants a fixed minimum distance from the
|
|
// text segment to the read-only segment, move up now.
|
|
uint64_t min_addr =
|
|
start_addr + (parameters->options().user_set_rosegment_gap()
|
|
? parameters->options().rosegment_gap()
|
|
: target->rosegment_gap());
|
|
if (addr < min_addr)
|
|
addr = min_addr;
|
|
|
|
// But this is not the first segment! To make its
|
|
// address congruent with its offset, that address better
|
|
// be aligned to the ABI-mandated page size.
|
|
addr = align_address(addr, abi_pagesize);
|
|
aligned_addr = addr;
|
|
}
|
|
else
|
|
{
|
|
if ((addr & (abi_pagesize - 1)) != 0)
|
|
addr = addr + abi_pagesize;
|
|
|
|
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
|
}
|
|
}
|
|
|
|
if (!parameters->options().nmagic()
|
|
&& !parameters->options().omagic())
|
|
{
|
|
// Here we are also taking care of the case when
|
|
// the maximum segment alignment is larger than the page size.
|
|
off = align_file_offset(off, addr,
|
|
std::max(abi_pagesize,
|
|
(*p)->maximum_alignment()));
|
|
}
|
|
else
|
|
{
|
|
// This is -N or -n with a section script which prevents
|
|
// us from using a load segment. We need to ensure that
|
|
// the file offset is aligned to the alignment of the
|
|
// segment. This is because the linker script
|
|
// implicitly assumed a zero offset. If we don't align
|
|
// here, then the alignment of the sections in the
|
|
// linker script may not match the alignment of the
|
|
// sections in the set_section_addresses call below,
|
|
// causing an error about dot moving backward.
|
|
off = align_address(off, (*p)->maximum_alignment());
|
|
}
|
|
|
|
unsigned int shndx_hold = *pshndx;
|
|
bool has_relro = false;
|
|
uint64_t new_addr = (*p)->set_section_addresses(target, this,
|
|
false, addr,
|
|
&increase_relro,
|
|
&has_relro,
|
|
&off, pshndx);
|
|
|
|
// 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 the segment has been
|
|
// aligned so that the relro data ends at a page boundary,
|
|
// we do not try to realign it.
|
|
|
|
if (!are_addresses_set
|
|
&& !has_relro
|
|
&& aligned_addr != addr
|
|
&& !parameters->incremental())
|
|
{
|
|
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)
|
|
{
|
|
*pshndx = shndx_hold;
|
|
addr = align_address(aligned_addr, common_pagesize);
|
|
addr = align_address(addr, (*p)->maximum_alignment());
|
|
if ((addr & (abi_pagesize - 1)) != 0)
|
|
addr = addr + abi_pagesize;
|
|
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
|
off = align_file_offset(off, addr, abi_pagesize);
|
|
|
|
increase_relro = this->increase_relro_;
|
|
if (this->script_options_->saw_sections_clause())
|
|
increase_relro = 0;
|
|
has_relro = false;
|
|
|
|
new_addr = (*p)->set_section_addresses(target, this,
|
|
true, addr,
|
|
&increase_relro,
|
|
&has_relro,
|
|
&off, pshndx);
|
|
}
|
|
}
|
|
|
|
addr = new_addr;
|
|
|
|
// Implement --check-sections. We know that the segments
|
|
// are sorted by LMA.
|
|
if (check_sections && last_load_segment != NULL)
|
|
{
|
|
gold_assert(last_load_segment->paddr() <= (*p)->paddr());
|
|
if (last_load_segment->paddr() + last_load_segment->memsz()
|
|
> (*p)->paddr())
|
|
{
|
|
unsigned long long lb1 = last_load_segment->paddr();
|
|
unsigned long long le1 = lb1 + last_load_segment->memsz();
|
|
unsigned long long lb2 = (*p)->paddr();
|
|
unsigned long long le2 = lb2 + (*p)->memsz();
|
|
gold_error(_("load segment overlap [0x%llx -> 0x%llx] and "
|
|
"[0x%llx -> 0x%llx]"),
|
|
lb1, le1, lb2, le2);
|
|
}
|
|
}
|
|
last_load_segment = *p;
|
|
}
|
|
}
|
|
|
|
if (load_seg != NULL && target->isolate_execinstr())
|
|
{
|
|
// Process the early segments again, setting their file offsets
|
|
// so they land after the segments starting at LOAD_SEG.
|
|
off = align_file_offset(off, 0, target->abi_pagesize());
|
|
|
|
this->reset_relax_output();
|
|
|
|
for (Segment_list::iterator p = this->segment_list_.begin();
|
|
*p != load_seg;
|
|
++p)
|
|
{
|
|
if ((*p)->type() == elfcpp::PT_LOAD)
|
|
{
|
|
// We repeat the whole job of assigning addresses and
|
|
// offsets, but we really only want to change the offsets and
|
|
// must ensure that the addresses all come out the same as
|
|
// they did the first time through.
|
|
bool has_relro = false;
|
|
const uint64_t old_addr = (*p)->vaddr();
|
|
const uint64_t old_end = old_addr + (*p)->memsz();
|
|
uint64_t new_addr = (*p)->set_section_addresses(target, this,
|
|
true, old_addr,
|
|
&increase_relro,
|
|
&has_relro,
|
|
&off,
|
|
&shndx_begin);
|
|
gold_assert(new_addr == old_end);
|
|
}
|
|
}
|
|
|
|
gold_assert(shndx_begin == shndx_load_seg);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
// PT_GNU_STACK was set up correctly when it was created.
|
|
if ((*p)->type() != elfcpp::PT_LOAD
|
|
&& (*p)->type() != elfcpp::PT_GNU_STACK)
|
|
(*p)->set_offset((*p)->type() == elfcpp::PT_GNU_RELRO
|
|
? increase_relro
|
|
: 0);
|
|
}
|
|
|
|
// Set the TLS offsets for each section in the PT_TLS segment.
|
|
if (this->tls_segment_ != NULL)
|
|
this->tls_segment_->set_tls_offsets();
|
|
|
|
return off;
|
|
}
|
|
|
|
// Set the offsets of all the allocated sections when doing a
|
|
// relocatable link. This does the same jobs as set_segment_offsets,
|
|
// only for a relocatable link.
|
|
|
|
off_t
|
|
Layout::set_relocatable_section_offsets(Output_data* file_header,
|
|
unsigned int* pshndx)
|
|
{
|
|
off_t off = 0;
|
|
|
|
file_header->set_address_and_file_offset(0, 0);
|
|
off += file_header->data_size();
|
|
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
// We skip unallocated sections here, except that group sections
|
|
// have to come first.
|
|
if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
|
|
&& (*p)->type() != elfcpp::SHT_GROUP)
|
|
continue;
|
|
|
|
off = align_address(off, (*p)->addralign());
|
|
|
|
// The linker script might have set the address.
|
|
if (!(*p)->is_address_valid())
|
|
(*p)->set_address(0);
|
|
(*p)->set_file_offset(off);
|
|
(*p)->finalize_data_size();
|
|
if ((*p)->type() != elfcpp::SHT_NOBITS)
|
|
off += (*p)->data_size();
|
|
|
|
(*p)->set_out_shndx(*pshndx);
|
|
++*pshndx;
|
|
}
|
|
|
|
return off;
|
|
}
|
|
|
|
// Set the file offset of all the sections not associated with a
|
|
// segment.
|
|
|
|
off_t
|
|
Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
|
|
{
|
|
off_t startoff = off;
|
|
off_t maxoff = off;
|
|
|
|
for (Section_list::iterator p = this->unattached_section_list_.begin();
|
|
p != this->unattached_section_list_.end();
|
|
++p)
|
|
{
|
|
// The symtab section is handled in create_symtab_sections.
|
|
if (*p == this->symtab_section_)
|
|
continue;
|
|
|
|
// If we've already set the data size, don't set it again.
|
|
if ((*p)->is_offset_valid() && (*p)->is_data_size_valid())
|
|
continue;
|
|
|
|
if (pass == BEFORE_INPUT_SECTIONS_PASS
|
|
&& (*p)->requires_postprocessing())
|
|
{
|
|
(*p)->create_postprocessing_buffer();
|
|
this->any_postprocessing_sections_ = true;
|
|
}
|
|
|
|
if (pass == BEFORE_INPUT_SECTIONS_PASS
|
|
&& (*p)->after_input_sections())
|
|
continue;
|
|
else if (pass == POSTPROCESSING_SECTIONS_PASS
|
|
&& (!(*p)->after_input_sections()
|
|
|| (*p)->type() == elfcpp::SHT_STRTAB))
|
|
continue;
|
|
else if (pass == STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS
|
|
&& (!(*p)->after_input_sections()
|
|
|| (*p)->type() != elfcpp::SHT_STRTAB))
|
|
continue;
|
|
|
|
if (!parameters->incremental_update())
|
|
{
|
|
off = align_address(off, (*p)->addralign());
|
|
(*p)->set_file_offset(off);
|
|
(*p)->finalize_data_size();
|
|
}
|
|
else
|
|
{
|
|
// Incremental update: allocate file space from free list.
|
|
(*p)->pre_finalize_data_size();
|
|
off_t current_size = (*p)->current_data_size();
|
|
off = this->allocate(current_size, (*p)->addralign(), startoff);
|
|
if (off == -1)
|
|
{
|
|
if (is_debugging_enabled(DEBUG_INCREMENTAL))
|
|
this->free_list_.dump();
|
|
gold_assert((*p)->output_section() != NULL);
|
|
gold_fallback(_("out of patch space for section %s; "
|
|
"relink with --incremental-full"),
|
|
(*p)->output_section()->name());
|
|
}
|
|
(*p)->set_file_offset(off);
|
|
(*p)->finalize_data_size();
|
|
if ((*p)->data_size() > current_size)
|
|
{
|
|
gold_assert((*p)->output_section() != NULL);
|
|
gold_fallback(_("%s: section changed size; "
|
|
"relink with --incremental-full"),
|
|
(*p)->output_section()->name());
|
|
}
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"set_section_offsets: %08lx %08lx %s",
|
|
static_cast<long>(off),
|
|
static_cast<long>((*p)->data_size()),
|
|
((*p)->output_section() != NULL
|
|
? (*p)->output_section()->name() : "(special)"));
|
|
}
|
|
|
|
off += (*p)->data_size();
|
|
if (off > maxoff)
|
|
maxoff = off;
|
|
|
|
// At this point the name must be set.
|
|
if (pass != STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS)
|
|
this->namepool_.add((*p)->name(), false, NULL);
|
|
}
|
|
return maxoff;
|
|
}
|
|
|
|
// Set the section indexes of all the sections not associated with a
|
|
// segment.
|
|
|
|
unsigned int
|
|
Layout::set_section_indexes(unsigned int shndx)
|
|
{
|
|
for (Section_list::iterator p = this->unattached_section_list_.begin();
|
|
p != this->unattached_section_list_.end();
|
|
++p)
|
|
{
|
|
if (!(*p)->has_out_shndx())
|
|
{
|
|
(*p)->set_out_shndx(shndx);
|
|
++shndx;
|
|
}
|
|
}
|
|
return shndx;
|
|
}
|
|
|
|
// Set the section addresses according to the linker script. This is
|
|
// only called when we see a SECTIONS clause. This returns the
|
|
// program segment which should hold the file header and segment
|
|
// headers, if any. It will return NULL if they should not be in a
|
|
// segment.
|
|
|
|
Output_segment*
|
|
Layout::set_section_addresses_from_script(Symbol_table* symtab)
|
|
{
|
|
Script_sections* ss = this->script_options_->script_sections();
|
|
gold_assert(ss->saw_sections_clause());
|
|
return this->script_options_->set_section_addresses(symtab, this);
|
|
}
|
|
|
|
// Place the orphan sections in the linker script.
|
|
|
|
void
|
|
Layout::place_orphan_sections_in_script()
|
|
{
|
|
Script_sections* ss = this->script_options_->script_sections();
|
|
gold_assert(ss->saw_sections_clause());
|
|
|
|
// Place each orphaned output section in the script.
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if (!(*p)->found_in_sections_clause())
|
|
ss->place_orphan(*p);
|
|
}
|
|
}
|
|
|
|
// Count the local symbols in the regular symbol table and the dynamic
|
|
// symbol table, and build the respective string pools.
|
|
|
|
void
|
|
Layout::count_local_symbols(const Task* task,
|
|
const Input_objects* input_objects)
|
|
{
|
|
// First, figure out an upper bound on the number of symbols we'll
|
|
// be inserting into each pool. This helps us create the pools with
|
|
// the right size, to avoid unnecessary hashtable resizing.
|
|
unsigned int symbol_count = 0;
|
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
|
p != input_objects->relobj_end();
|
|
++p)
|
|
symbol_count += (*p)->local_symbol_count();
|
|
|
|
// Go from "upper bound" to "estimate." We overcount for two
|
|
// reasons: we double-count symbols that occur in more than one
|
|
// object file, and we count symbols that are dropped from the
|
|
// output. Add it all together and assume we overcount by 100%.
|
|
symbol_count /= 2;
|
|
|
|
// We assume all symbols will go into both the sympool and dynpool.
|
|
this->sympool_.reserve(symbol_count);
|
|
this->dynpool_.reserve(symbol_count);
|
|
|
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
|
p != input_objects->relobj_end();
|
|
++p)
|
|
{
|
|
Task_lock_obj<Object> tlo(task, *p);
|
|
(*p)->count_local_symbols(&this->sympool_, &this->dynpool_);
|
|
}
|
|
}
|
|
|
|
// Create the symbol table sections. Here we also set the final
|
|
// values of the symbols. At this point all the loadable sections are
|
|
// fully laid out. SHNUM is the number of sections so far.
|
|
|
|
void
|
|
Layout::create_symtab_sections(const Input_objects* input_objects,
|
|
Symbol_table* symtab,
|
|
unsigned int shnum,
|
|
off_t* poff,
|
|
unsigned int local_dynamic_count)
|
|
{
|
|
int symsize;
|
|
unsigned int align;
|
|
if (parameters->target().get_size() == 32)
|
|
{
|
|
symsize = elfcpp::Elf_sizes<32>::sym_size;
|
|
align = 4;
|
|
}
|
|
else if (parameters->target().get_size() == 64)
|
|
{
|
|
symsize = elfcpp::Elf_sizes<64>::sym_size;
|
|
align = 8;
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
|
|
// Compute file offsets relative to the start of the symtab section.
|
|
off_t off = 0;
|
|
|
|
// Save space for the dummy symbol at the start of the section. We
|
|
// never bother to write this out--it will just be left as zero.
|
|
off += symsize;
|
|
unsigned int local_symbol_index = 1;
|
|
|
|
// Add STT_SECTION symbols for each Output section which needs one.
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if (!(*p)->needs_symtab_index())
|
|
(*p)->set_symtab_index(-1U);
|
|
else
|
|
{
|
|
(*p)->set_symtab_index(local_symbol_index);
|
|
++local_symbol_index;
|
|
off += symsize;
|
|
}
|
|
}
|
|
|
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
|
p != input_objects->relobj_end();
|
|
++p)
|
|
{
|
|
unsigned int index = (*p)->finalize_local_symbols(local_symbol_index,
|
|
off, symtab);
|
|
off += (index - local_symbol_index) * symsize;
|
|
local_symbol_index = index;
|
|
}
|
|
|
|
unsigned int local_symcount = local_symbol_index;
|
|
gold_assert(static_cast<off_t>(local_symcount * symsize) == off);
|
|
|
|
off_t dynoff;
|
|
size_t dyncount;
|
|
if (this->dynsym_section_ == NULL)
|
|
{
|
|
dynoff = 0;
|
|
dyncount = 0;
|
|
}
|
|
else
|
|
{
|
|
off_t locsize = local_dynamic_count * this->dynsym_section_->entsize();
|
|
dynoff = this->dynsym_section_->offset() + locsize;
|
|
dyncount = (this->dynsym_section_->data_size() - locsize) / symsize;
|
|
gold_assert(static_cast<off_t>(dyncount * symsize)
|
|
== this->dynsym_section_->data_size() - locsize);
|
|
}
|
|
|
|
off_t global_off = off;
|
|
off = symtab->finalize(off, dynoff, local_dynamic_count, dyncount,
|
|
&this->sympool_, &local_symcount);
|
|
|
|
if (!parameters->options().strip_all())
|
|
{
|
|
this->sympool_.set_string_offsets();
|
|
|
|
const char* symtab_name = this->namepool_.add(".symtab", false, NULL);
|
|
Output_section* osymtab = this->make_output_section(symtab_name,
|
|
elfcpp::SHT_SYMTAB,
|
|
0, ORDER_INVALID,
|
|
false);
|
|
this->symtab_section_ = osymtab;
|
|
|
|
Output_section_data* pos = new Output_data_fixed_space(off, align,
|
|
"** symtab");
|
|
osymtab->add_output_section_data(pos);
|
|
|
|
// We generate a .symtab_shndx section if we have more than
|
|
// SHN_LORESERVE sections. Technically it is possible that we
|
|
// don't need one, because it is possible that there are no
|
|
// symbols in any of sections with indexes larger than
|
|
// SHN_LORESERVE. That is probably unusual, though, and it is
|
|
// easier to always create one than to compute section indexes
|
|
// twice (once here, once when writing out the symbols).
|
|
if (shnum >= elfcpp::SHN_LORESERVE)
|
|
{
|
|
const char* symtab_xindex_name = this->namepool_.add(".symtab_shndx",
|
|
false, NULL);
|
|
Output_section* osymtab_xindex =
|
|
this->make_output_section(symtab_xindex_name,
|
|
elfcpp::SHT_SYMTAB_SHNDX, 0,
|
|
ORDER_INVALID, false);
|
|
|
|
size_t symcount = off / symsize;
|
|
this->symtab_xindex_ = new Output_symtab_xindex(symcount);
|
|
|
|
osymtab_xindex->add_output_section_data(this->symtab_xindex_);
|
|
|
|
osymtab_xindex->set_link_section(osymtab);
|
|
osymtab_xindex->set_addralign(4);
|
|
osymtab_xindex->set_entsize(4);
|
|
|
|
osymtab_xindex->set_after_input_sections();
|
|
|
|
// This tells the driver code to wait until the symbol table
|
|
// has written out before writing out the postprocessing
|
|
// sections, including the .symtab_shndx section.
|
|
this->any_postprocessing_sections_ = true;
|
|
}
|
|
|
|
const char* strtab_name = this->namepool_.add(".strtab", false, NULL);
|
|
Output_section* ostrtab = this->make_output_section(strtab_name,
|
|
elfcpp::SHT_STRTAB,
|
|
0, ORDER_INVALID,
|
|
false);
|
|
|
|
Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
|
|
ostrtab->add_output_section_data(pstr);
|
|
|
|
off_t symtab_off;
|
|
if (!parameters->incremental_update())
|
|
symtab_off = align_address(*poff, align);
|
|
else
|
|
{
|
|
symtab_off = this->allocate(off, align, *poff);
|
|
if (off == -1)
|
|
gold_fallback(_("out of patch space for symbol table; "
|
|
"relink with --incremental-full"));
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"create_symtab_sections: %08lx %08lx .symtab",
|
|
static_cast<long>(symtab_off),
|
|
static_cast<long>(off));
|
|
}
|
|
|
|
symtab->set_file_offset(symtab_off + global_off);
|
|
osymtab->set_file_offset(symtab_off);
|
|
osymtab->finalize_data_size();
|
|
osymtab->set_link_section(ostrtab);
|
|
osymtab->set_info(local_symcount);
|
|
osymtab->set_entsize(symsize);
|
|
|
|
if (symtab_off + off > *poff)
|
|
*poff = symtab_off + off;
|
|
}
|
|
}
|
|
|
|
// 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", false, NULL);
|
|
|
|
Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0,
|
|
ORDER_INVALID, false);
|
|
|
|
if (strcmp(parameters->options().compress_debug_sections(), "none") != 0)
|
|
{
|
|
// We can't write out this section until we've set all the
|
|
// section names, and we don't set the names of compressed
|
|
// output sections until relocations are complete. FIXME: With
|
|
// the current names we use, this is unnecessary.
|
|
os->set_after_input_sections();
|
|
}
|
|
|
|
Output_section_data* posd = new Output_data_strtab(&this->namepool_);
|
|
os->add_output_section_data(posd);
|
|
|
|
return os;
|
|
}
|
|
|
|
// Create the section headers. SIZE is 32 or 64. OFF is the file
|
|
// offset.
|
|
|
|
void
|
|
Layout::create_shdrs(const Output_section* shstrtab_section, off_t* poff)
|
|
{
|
|
Output_section_headers* oshdrs;
|
|
oshdrs = new Output_section_headers(this,
|
|
&this->segment_list_,
|
|
&this->section_list_,
|
|
&this->unattached_section_list_,
|
|
&this->namepool_,
|
|
shstrtab_section);
|
|
off_t off;
|
|
if (!parameters->incremental_update())
|
|
off = align_address(*poff, oshdrs->addralign());
|
|
else
|
|
{
|
|
oshdrs->pre_finalize_data_size();
|
|
off = this->allocate(oshdrs->data_size(), oshdrs->addralign(), *poff);
|
|
if (off == -1)
|
|
gold_fallback(_("out of patch space for section header table; "
|
|
"relink with --incremental-full"));
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"create_shdrs: %08lx %08lx (section header table)",
|
|
static_cast<long>(off),
|
|
static_cast<long>(off + oshdrs->data_size()));
|
|
}
|
|
oshdrs->set_address_and_file_offset(0, off);
|
|
off += oshdrs->data_size();
|
|
if (off > *poff)
|
|
*poff = off;
|
|
this->section_headers_ = oshdrs;
|
|
}
|
|
|
|
// Count the allocated sections.
|
|
|
|
size_t
|
|
Layout::allocated_output_section_count() const
|
|
{
|
|
size_t section_count = 0;
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
section_count += (*p)->output_section_count();
|
|
return section_count;
|
|
}
|
|
|
|
// Create the dynamic symbol table.
|
|
// *PLOCAL_DYNAMIC_COUNT will be set to the number of local symbols
|
|
// from input objects, and *PFORCED_LOCAL_DYNAMIC_COUNT will be set
|
|
// to the number of global symbols that have been forced local.
|
|
// We need to remember the former because the forced-local symbols are
|
|
// written along with the global symbols in Symtab::write_globals().
|
|
|
|
void
|
|
Layout::create_dynamic_symtab(const Input_objects* input_objects,
|
|
Symbol_table* symtab,
|
|
Output_section** pdynstr,
|
|
unsigned int* plocal_dynamic_count,
|
|
unsigned int* pforced_local_dynamic_count,
|
|
std::vector<Symbol*>* pdynamic_symbols,
|
|
Versions* pversions)
|
|
{
|
|
// Count all the symbols in the dynamic symbol table, and set the
|
|
// dynamic symbol indexes.
|
|
|
|
// Skip symbol 0, which is always all zeroes.
|
|
unsigned int index = 1;
|
|
|
|
// Add STT_SECTION symbols for each Output section which needs one.
|
|
for (Section_list::iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if (!(*p)->needs_dynsym_index())
|
|
(*p)->set_dynsym_index(-1U);
|
|
else
|
|
{
|
|
(*p)->set_dynsym_index(index);
|
|
++index;
|
|
}
|
|
}
|
|
|
|
// Count the local symbols that need to go in the dynamic symbol table,
|
|
// and set the dynamic symbol indexes.
|
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
|
p != input_objects->relobj_end();
|
|
++p)
|
|
{
|
|
unsigned int new_index = (*p)->set_local_dynsym_indexes(index);
|
|
index = new_index;
|
|
}
|
|
|
|
unsigned int local_symcount = index;
|
|
unsigned int forced_local_count = 0;
|
|
|
|
index = symtab->set_dynsym_indexes(index, &forced_local_count,
|
|
pdynamic_symbols, &this->dynpool_,
|
|
pversions);
|
|
|
|
*plocal_dynamic_count = local_symcount;
|
|
*pforced_local_dynamic_count = forced_local_count;
|
|
|
|
int symsize;
|
|
unsigned int align;
|
|
const int size = parameters->target().get_size();
|
|
if (size == 32)
|
|
{
|
|
symsize = elfcpp::Elf_sizes<32>::sym_size;
|
|
align = 4;
|
|
}
|
|
else if (size == 64)
|
|
{
|
|
symsize = elfcpp::Elf_sizes<64>::sym_size;
|
|
align = 8;
|
|
}
|
|
else
|
|
gold_unreachable();
|
|
|
|
// Create the dynamic symbol table section.
|
|
|
|
Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
|
|
elfcpp::SHT_DYNSYM,
|
|
elfcpp::SHF_ALLOC,
|
|
false,
|
|
ORDER_DYNAMIC_LINKER,
|
|
false, false, false);
|
|
|
|
// Check for NULL as a linker script may discard .dynsym.
|
|
if (dynsym != NULL)
|
|
{
|
|
Output_section_data* odata = new Output_data_fixed_space(index * symsize,
|
|
align,
|
|
"** dynsym");
|
|
dynsym->add_output_section_data(odata);
|
|
|
|
dynsym->set_info(local_symcount + forced_local_count);
|
|
dynsym->set_entsize(symsize);
|
|
dynsym->set_addralign(align);
|
|
|
|
this->dynsym_section_ = dynsym;
|
|
}
|
|
|
|
Output_data_dynamic* const odyn = this->dynamic_data_;
|
|
if (odyn != NULL)
|
|
{
|
|
odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
|
|
odyn->add_constant(elfcpp::DT_SYMENT, symsize);
|
|
}
|
|
|
|
// If there are more than SHN_LORESERVE allocated sections, we
|
|
// create a .dynsym_shndx section. It is possible that we don't
|
|
// need one, because it is possible that there are no dynamic
|
|
// symbols in any of the sections with indexes larger than
|
|
// SHN_LORESERVE. This is probably unusual, though, and at this
|
|
// time we don't know the actual section indexes so it is
|
|
// inconvenient to check.
|
|
if (this->allocated_output_section_count() >= elfcpp::SHN_LORESERVE)
|
|
{
|
|
Output_section* dynsym_xindex =
|
|
this->choose_output_section(NULL, ".dynsym_shndx",
|
|
elfcpp::SHT_SYMTAB_SHNDX,
|
|
elfcpp::SHF_ALLOC,
|
|
false, ORDER_DYNAMIC_LINKER, false, false,
|
|
false);
|
|
|
|
if (dynsym_xindex != NULL)
|
|
{
|
|
this->dynsym_xindex_ = new Output_symtab_xindex(index);
|
|
|
|
dynsym_xindex->add_output_section_data(this->dynsym_xindex_);
|
|
|
|
dynsym_xindex->set_link_section(dynsym);
|
|
dynsym_xindex->set_addralign(4);
|
|
dynsym_xindex->set_entsize(4);
|
|
|
|
dynsym_xindex->set_after_input_sections();
|
|
|
|
// This tells the driver code to wait until the symbol table
|
|
// has written out before writing out the postprocessing
|
|
// sections, including the .dynsym_shndx section.
|
|
this->any_postprocessing_sections_ = true;
|
|
}
|
|
}
|
|
|
|
// Create the dynamic string table section.
|
|
|
|
Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
|
|
elfcpp::SHT_STRTAB,
|
|
elfcpp::SHF_ALLOC,
|
|
false,
|
|
ORDER_DYNAMIC_LINKER,
|
|
false, false, false);
|
|
*pdynstr = dynstr;
|
|
if (dynstr != NULL)
|
|
{
|
|
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
|
|
dynstr->add_output_section_data(strdata);
|
|
|
|
if (dynsym != NULL)
|
|
dynsym->set_link_section(dynstr);
|
|
if (this->dynamic_section_ != NULL)
|
|
this->dynamic_section_->set_link_section(dynstr);
|
|
|
|
if (odyn != NULL)
|
|
{
|
|
odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
|
|
odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
|
|
}
|
|
}
|
|
|
|
// Create the hash tables. The Gnu-style hash table must be
|
|
// built first, because it changes the order of the symbols
|
|
// in the dynamic symbol table.
|
|
|
|
if (strcmp(parameters->options().hash_style(), "gnu") == 0
|
|
|| strcmp(parameters->options().hash_style(), "both") == 0)
|
|
{
|
|
unsigned char* phash;
|
|
unsigned int hashlen;
|
|
Dynobj::create_gnu_hash_table(*pdynamic_symbols,
|
|
local_symcount + forced_local_count,
|
|
&phash, &hashlen);
|
|
|
|
Output_section* hashsec =
|
|
this->choose_output_section(NULL, ".gnu.hash", elfcpp::SHT_GNU_HASH,
|
|
elfcpp::SHF_ALLOC, false,
|
|
ORDER_DYNAMIC_LINKER, false, false,
|
|
false);
|
|
|
|
Output_section_data* hashdata = new Output_data_const_buffer(phash,
|
|
hashlen,
|
|
align,
|
|
"** hash");
|
|
if (hashsec != NULL && hashdata != NULL)
|
|
hashsec->add_output_section_data(hashdata);
|
|
|
|
if (hashsec != NULL)
|
|
{
|
|
if (dynsym != NULL)
|
|
hashsec->set_link_section(dynsym);
|
|
|
|
// For a 64-bit target, the entries in .gnu.hash do not have
|
|
// a uniform size, so we only set the entry size for a
|
|
// 32-bit target.
|
|
if (parameters->target().get_size() == 32)
|
|
hashsec->set_entsize(4);
|
|
|
|
if (odyn != NULL)
|
|
odyn->add_section_address(elfcpp::DT_GNU_HASH, hashsec);
|
|
}
|
|
}
|
|
|
|
if (strcmp(parameters->options().hash_style(), "sysv") == 0
|
|
|| strcmp(parameters->options().hash_style(), "both") == 0)
|
|
{
|
|
unsigned char* phash;
|
|
unsigned int hashlen;
|
|
Dynobj::create_elf_hash_table(*pdynamic_symbols,
|
|
local_symcount + forced_local_count,
|
|
&phash, &hashlen);
|
|
|
|
Output_section* hashsec =
|
|
this->choose_output_section(NULL, ".hash", elfcpp::SHT_HASH,
|
|
elfcpp::SHF_ALLOC, false,
|
|
ORDER_DYNAMIC_LINKER, false, false,
|
|
false);
|
|
|
|
Output_section_data* hashdata = new Output_data_const_buffer(phash,
|
|
hashlen,
|
|
align,
|
|
"** hash");
|
|
if (hashsec != NULL && hashdata != NULL)
|
|
hashsec->add_output_section_data(hashdata);
|
|
|
|
if (hashsec != NULL)
|
|
{
|
|
if (dynsym != NULL)
|
|
hashsec->set_link_section(dynsym);
|
|
hashsec->set_entsize(parameters->target().hash_entry_size() / 8);
|
|
}
|
|
|
|
if (odyn != NULL)
|
|
odyn->add_section_address(elfcpp::DT_HASH, hashsec);
|
|
}
|
|
}
|
|
|
|
// Assign offsets to each local portion of the dynamic symbol table.
|
|
|
|
void
|
|
Layout::assign_local_dynsym_offsets(const Input_objects* input_objects)
|
|
{
|
|
Output_section* dynsym = this->dynsym_section_;
|
|
if (dynsym == NULL)
|
|
return;
|
|
|
|
off_t off = dynsym->offset();
|
|
|
|
// Skip the dummy symbol at the start of the section.
|
|
off += dynsym->entsize();
|
|
|
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
|
p != input_objects->relobj_end();
|
|
++p)
|
|
{
|
|
unsigned int count = (*p)->set_local_dynsym_offset(off);
|
|
off += count * dynsym->entsize();
|
|
}
|
|
}
|
|
|
|
// Create the version sections.
|
|
|
|
void
|
|
Layout::create_version_sections(const Versions* versions,
|
|
const Symbol_table* symtab,
|
|
unsigned int local_symcount,
|
|
const std::vector<Symbol*>& dynamic_symbols,
|
|
const Output_section* dynstr)
|
|
{
|
|
if (!versions->any_defs() && !versions->any_needs())
|
|
return;
|
|
|
|
switch (parameters->size_and_endianness())
|
|
{
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
case Parameters::TARGET_32_LITTLE:
|
|
this->sized_create_version_sections<32, false>(versions, symtab,
|
|
local_symcount,
|
|
dynamic_symbols, dynstr);
|
|
break;
|
|
#endif
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
case Parameters::TARGET_32_BIG:
|
|
this->sized_create_version_sections<32, true>(versions, symtab,
|
|
local_symcount,
|
|
dynamic_symbols, dynstr);
|
|
break;
|
|
#endif
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
case Parameters::TARGET_64_LITTLE:
|
|
this->sized_create_version_sections<64, false>(versions, symtab,
|
|
local_symcount,
|
|
dynamic_symbols, dynstr);
|
|
break;
|
|
#endif
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
case Parameters::TARGET_64_BIG:
|
|
this->sized_create_version_sections<64, true>(versions, symtab,
|
|
local_symcount,
|
|
dynamic_symbols, dynstr);
|
|
break;
|
|
#endif
|
|
default:
|
|
gold_unreachable();
|
|
}
|
|
}
|
|
|
|
// Create the version sections, sized version.
|
|
|
|
template<int size, bool big_endian>
|
|
void
|
|
Layout::sized_create_version_sections(
|
|
const Versions* versions,
|
|
const Symbol_table* symtab,
|
|
unsigned int local_symcount,
|
|
const std::vector<Symbol*>& dynamic_symbols,
|
|
const Output_section* dynstr)
|
|
{
|
|
Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
|
|
elfcpp::SHT_GNU_versym,
|
|
elfcpp::SHF_ALLOC,
|
|
false,
|
|
ORDER_DYNAMIC_LINKER,
|
|
false, false, false);
|
|
|
|
// Check for NULL since a linker script may discard this section.
|
|
if (vsec != NULL)
|
|
{
|
|
unsigned char* vbuf;
|
|
unsigned int vsize;
|
|
versions->symbol_section_contents<size, big_endian>(symtab,
|
|
&this->dynpool_,
|
|
local_symcount,
|
|
dynamic_symbols,
|
|
&vbuf, &vsize);
|
|
|
|
Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2,
|
|
"** versions");
|
|
|
|
vsec->add_output_section_data(vdata);
|
|
vsec->set_entsize(2);
|
|
vsec->set_link_section(this->dynsym_section_);
|
|
}
|
|
|
|
Output_data_dynamic* const odyn = this->dynamic_data_;
|
|
if (odyn != NULL && vsec != NULL)
|
|
odyn->add_section_address(elfcpp::DT_VERSYM, vsec);
|
|
|
|
if (versions->any_defs())
|
|
{
|
|
Output_section* vdsec;
|
|
vdsec = this->choose_output_section(NULL, ".gnu.version_d",
|
|
elfcpp::SHT_GNU_verdef,
|
|
elfcpp::SHF_ALLOC,
|
|
false, ORDER_DYNAMIC_LINKER, false,
|
|
false, false);
|
|
|
|
if (vdsec != NULL)
|
|
{
|
|
unsigned char* vdbuf;
|
|
unsigned int vdsize;
|
|
unsigned int vdentries;
|
|
versions->def_section_contents<size, big_endian>(&this->dynpool_,
|
|
&vdbuf, &vdsize,
|
|
&vdentries);
|
|
|
|
Output_section_data* vddata =
|
|
new Output_data_const_buffer(vdbuf, vdsize, 4, "** version defs");
|
|
|
|
vdsec->add_output_section_data(vddata);
|
|
vdsec->set_link_section(dynstr);
|
|
vdsec->set_info(vdentries);
|
|
|
|
if (odyn != NULL)
|
|
{
|
|
odyn->add_section_address(elfcpp::DT_VERDEF, vdsec);
|
|
odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (versions->any_needs())
|
|
{
|
|
Output_section* vnsec;
|
|
vnsec = this->choose_output_section(NULL, ".gnu.version_r",
|
|
elfcpp::SHT_GNU_verneed,
|
|
elfcpp::SHF_ALLOC,
|
|
false, ORDER_DYNAMIC_LINKER, false,
|
|
false, false);
|
|
|
|
if (vnsec != NULL)
|
|
{
|
|
unsigned char* vnbuf;
|
|
unsigned int vnsize;
|
|
unsigned int vnentries;
|
|
versions->need_section_contents<size, big_endian>(&this->dynpool_,
|
|
&vnbuf, &vnsize,
|
|
&vnentries);
|
|
|
|
Output_section_data* vndata =
|
|
new Output_data_const_buffer(vnbuf, vnsize, 4, "** version refs");
|
|
|
|
vnsec->add_output_section_data(vndata);
|
|
vnsec->set_link_section(dynstr);
|
|
vnsec->set_info(vnentries);
|
|
|
|
if (odyn != NULL)
|
|
{
|
|
odyn->add_section_address(elfcpp::DT_VERNEED, vnsec);
|
|
odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create the .interp section and PT_INTERP segment.
|
|
|
|
void
|
|
Layout::create_interp(const Target* target)
|
|
{
|
|
gold_assert(this->interp_segment_ == NULL);
|
|
|
|
const char* interp = parameters->options().dynamic_linker();
|
|
if (interp == NULL)
|
|
{
|
|
interp = target->dynamic_linker();
|
|
gold_assert(interp != NULL);
|
|
}
|
|
|
|
size_t len = strlen(interp) + 1;
|
|
|
|
Output_section_data* odata = new Output_data_const(interp, len, 1);
|
|
|
|
Output_section* osec = this->choose_output_section(NULL, ".interp",
|
|
elfcpp::SHT_PROGBITS,
|
|
elfcpp::SHF_ALLOC,
|
|
false, ORDER_INTERP,
|
|
false, false, false);
|
|
if (osec != NULL)
|
|
osec->add_output_section_data(odata);
|
|
}
|
|
|
|
// Add dynamic tags for the PLT and the dynamic relocs. This is
|
|
// called by the target-specific code. This does nothing if not doing
|
|
// a dynamic link.
|
|
|
|
// USE_REL is true for REL relocs rather than RELA relocs.
|
|
|
|
// If PLT_GOT is not NULL, then DT_PLTGOT points to it.
|
|
|
|
// If PLT_REL is not NULL, it is used for DT_PLTRELSZ, and DT_JMPREL,
|
|
// and we also set DT_PLTREL. We use PLT_REL's output section, since
|
|
// some targets have multiple reloc sections in PLT_REL.
|
|
|
|
// If DYN_REL is not NULL, it is used for DT_REL/DT_RELA,
|
|
// DT_RELSZ/DT_RELASZ, DT_RELENT/DT_RELAENT. Again we use the output
|
|
// section.
|
|
|
|
// If ADD_DEBUG is true, we add a DT_DEBUG entry when generating an
|
|
// executable.
|
|
|
|
void
|
|
Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
|
|
const Output_data* plt_rel,
|
|
const Output_data_reloc_generic* dyn_rel,
|
|
bool add_debug, bool dynrel_includes_plt)
|
|
{
|
|
Output_data_dynamic* odyn = this->dynamic_data_;
|
|
if (odyn == NULL)
|
|
return;
|
|
|
|
if (plt_got != NULL && plt_got->output_section() != NULL)
|
|
odyn->add_section_address(elfcpp::DT_PLTGOT, plt_got);
|
|
|
|
if (plt_rel != NULL && plt_rel->output_section() != NULL)
|
|
{
|
|
odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel->output_section());
|
|
odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel->output_section());
|
|
odyn->add_constant(elfcpp::DT_PLTREL,
|
|
use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA);
|
|
}
|
|
|
|
if ((dyn_rel != NULL && dyn_rel->output_section() != NULL)
|
|
|| (dynrel_includes_plt
|
|
&& plt_rel != NULL
|
|
&& plt_rel->output_section() != NULL))
|
|
{
|
|
bool have_dyn_rel = dyn_rel != NULL && dyn_rel->output_section() != NULL;
|
|
bool have_plt_rel = plt_rel != NULL && plt_rel->output_section() != NULL;
|
|
odyn->add_section_address(use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA,
|
|
(have_dyn_rel
|
|
? dyn_rel->output_section()
|
|
: plt_rel->output_section()));
|
|
elfcpp::DT size_tag = use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ;
|
|
if (have_dyn_rel && have_plt_rel && dynrel_includes_plt)
|
|
odyn->add_section_size(size_tag,
|
|
dyn_rel->output_section(),
|
|
plt_rel->output_section());
|
|
else if (have_dyn_rel)
|
|
odyn->add_section_size(size_tag, dyn_rel->output_section());
|
|
else
|
|
odyn->add_section_size(size_tag, plt_rel->output_section());
|
|
const int size = parameters->target().get_size();
|
|
elfcpp::DT rel_tag;
|
|
int rel_size;
|
|
if (use_rel)
|
|
{
|
|
rel_tag = elfcpp::DT_RELENT;
|
|
if (size == 32)
|
|
rel_size = Reloc_types<elfcpp::SHT_REL, 32, false>::reloc_size;
|
|
else if (size == 64)
|
|
rel_size = Reloc_types<elfcpp::SHT_REL, 64, false>::reloc_size;
|
|
else
|
|
gold_unreachable();
|
|
}
|
|
else
|
|
{
|
|
rel_tag = elfcpp::DT_RELAENT;
|
|
if (size == 32)
|
|
rel_size = Reloc_types<elfcpp::SHT_RELA, 32, false>::reloc_size;
|
|
else if (size == 64)
|
|
rel_size = Reloc_types<elfcpp::SHT_RELA, 64, false>::reloc_size;
|
|
else
|
|
gold_unreachable();
|
|
}
|
|
odyn->add_constant(rel_tag, rel_size);
|
|
|
|
if (parameters->options().combreloc() && have_dyn_rel)
|
|
{
|
|
size_t c = dyn_rel->relative_reloc_count();
|
|
if (c > 0)
|
|
odyn->add_constant((use_rel
|
|
? elfcpp::DT_RELCOUNT
|
|
: elfcpp::DT_RELACOUNT),
|
|
c);
|
|
}
|
|
}
|
|
|
|
if (add_debug && !parameters->options().shared())
|
|
{
|
|
// The value of the DT_DEBUG tag is filled in by the dynamic
|
|
// linker at run time, and used by the debugger.
|
|
odyn->add_constant(elfcpp::DT_DEBUG, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
Layout::add_target_specific_dynamic_tag(elfcpp::DT tag, unsigned int val)
|
|
{
|
|
Output_data_dynamic* odyn = this->dynamic_data_;
|
|
if (odyn == NULL)
|
|
return;
|
|
odyn->add_constant(tag, val);
|
|
}
|
|
|
|
// Finish the .dynamic section and PT_DYNAMIC segment.
|
|
|
|
void
|
|
Layout::finish_dynamic_section(const Input_objects* input_objects,
|
|
const Symbol_table* symtab)
|
|
{
|
|
if (!this->script_options_->saw_phdrs_clause()
|
|
&& this->dynamic_section_ != NULL)
|
|
{
|
|
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
|
|
(elfcpp::PF_R
|
|
| elfcpp::PF_W));
|
|
oseg->add_output_section_to_nonload(this->dynamic_section_,
|
|
elfcpp::PF_R | elfcpp::PF_W);
|
|
}
|
|
|
|
Output_data_dynamic* const odyn = this->dynamic_data_;
|
|
if (odyn == NULL)
|
|
return;
|
|
|
|
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
|
|
p != input_objects->dynobj_end();
|
|
++p)
|
|
{
|
|
if (!(*p)->is_needed() && (*p)->as_needed())
|
|
{
|
|
// This dynamic object was linked with --as-needed, but it
|
|
// is not needed.
|
|
continue;
|
|
}
|
|
|
|
odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname());
|
|
}
|
|
|
|
if (parameters->options().shared())
|
|
{
|
|
const char* soname = parameters->options().soname();
|
|
if (soname != NULL)
|
|
odyn->add_string(elfcpp::DT_SONAME, soname);
|
|
}
|
|
|
|
Symbol* sym = symtab->lookup(parameters->options().init());
|
|
if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
|
|
odyn->add_symbol(elfcpp::DT_INIT, sym);
|
|
|
|
sym = symtab->lookup(parameters->options().fini());
|
|
if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
|
|
odyn->add_symbol(elfcpp::DT_FINI, sym);
|
|
|
|
// Look for .init_array, .preinit_array and .fini_array by checking
|
|
// section types.
|
|
for(Layout::Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
switch((*p)->type())
|
|
{
|
|
case elfcpp::SHT_FINI_ARRAY:
|
|
odyn->add_section_address(elfcpp::DT_FINI_ARRAY, *p);
|
|
odyn->add_section_size(elfcpp::DT_FINI_ARRAYSZ, *p);
|
|
break;
|
|
case elfcpp::SHT_INIT_ARRAY:
|
|
odyn->add_section_address(elfcpp::DT_INIT_ARRAY, *p);
|
|
odyn->add_section_size(elfcpp::DT_INIT_ARRAYSZ, *p);
|
|
break;
|
|
case elfcpp::SHT_PREINIT_ARRAY:
|
|
odyn->add_section_address(elfcpp::DT_PREINIT_ARRAY, *p);
|
|
odyn->add_section_size(elfcpp::DT_PREINIT_ARRAYSZ, *p);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Add a DT_RPATH entry if needed.
|
|
const General_options::Dir_list& rpath(parameters->options().rpath());
|
|
if (!rpath.empty())
|
|
{
|
|
std::string rpath_val;
|
|
for (General_options::Dir_list::const_iterator p = rpath.begin();
|
|
p != rpath.end();
|
|
++p)
|
|
{
|
|
if (rpath_val.empty())
|
|
rpath_val = p->name();
|
|
else
|
|
{
|
|
// Eliminate duplicates.
|
|
General_options::Dir_list::const_iterator q;
|
|
for (q = rpath.begin(); q != p; ++q)
|
|
if (q->name() == p->name())
|
|
break;
|
|
if (q == p)
|
|
{
|
|
rpath_val += ':';
|
|
rpath_val += p->name();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!parameters->options().enable_new_dtags())
|
|
odyn->add_string(elfcpp::DT_RPATH, rpath_val);
|
|
else
|
|
odyn->add_string(elfcpp::DT_RUNPATH, rpath_val);
|
|
}
|
|
|
|
// Look for text segments that have dynamic relocations.
|
|
bool have_textrel = false;
|
|
if (!this->script_options_->saw_sections_clause())
|
|
{
|
|
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_W) == 0
|
|
&& (*p)->has_dynamic_reloc())
|
|
{
|
|
have_textrel = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We don't know the section -> segment mapping, so we are
|
|
// conservative and just look for readonly sections with
|
|
// relocations. If those sections wind up in writable segments,
|
|
// then we have created an unnecessary DT_TEXTREL entry.
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0
|
|
&& ((*p)->flags() & elfcpp::SHF_WRITE) == 0
|
|
&& (*p)->has_dynamic_reloc())
|
|
{
|
|
have_textrel = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parameters->options().filter() != NULL)
|
|
odyn->add_string(elfcpp::DT_FILTER, parameters->options().filter());
|
|
if (parameters->options().any_auxiliary())
|
|
{
|
|
for (options::String_set::const_iterator p =
|
|
parameters->options().auxiliary_begin();
|
|
p != parameters->options().auxiliary_end();
|
|
++p)
|
|
odyn->add_string(elfcpp::DT_AUXILIARY, *p);
|
|
}
|
|
|
|
// Add a DT_FLAGS entry if necessary.
|
|
unsigned int flags = 0;
|
|
if (have_textrel)
|
|
{
|
|
// Add a DT_TEXTREL for compatibility with older loaders.
|
|
odyn->add_constant(elfcpp::DT_TEXTREL, 0);
|
|
flags |= elfcpp::DF_TEXTREL;
|
|
|
|
if (parameters->options().text())
|
|
gold_error(_("read-only segment has dynamic relocations"));
|
|
else if (parameters->options().warn_shared_textrel()
|
|
&& parameters->options().shared())
|
|
gold_warning(_("shared library text segment is not shareable"));
|
|
}
|
|
if (parameters->options().shared() && this->has_static_tls())
|
|
flags |= elfcpp::DF_STATIC_TLS;
|
|
if (parameters->options().origin())
|
|
flags |= elfcpp::DF_ORIGIN;
|
|
if (parameters->options().Bsymbolic()
|
|
&& !parameters->options().have_dynamic_list())
|
|
{
|
|
flags |= elfcpp::DF_SYMBOLIC;
|
|
// Add DT_SYMBOLIC for compatibility with older loaders.
|
|
odyn->add_constant(elfcpp::DT_SYMBOLIC, 0);
|
|
}
|
|
if (parameters->options().now())
|
|
flags |= elfcpp::DF_BIND_NOW;
|
|
if (flags != 0)
|
|
odyn->add_constant(elfcpp::DT_FLAGS, flags);
|
|
|
|
flags = 0;
|
|
if (parameters->options().global())
|
|
flags |= elfcpp::DF_1_GLOBAL;
|
|
if (parameters->options().initfirst())
|
|
flags |= elfcpp::DF_1_INITFIRST;
|
|
if (parameters->options().interpose())
|
|
flags |= elfcpp::DF_1_INTERPOSE;
|
|
if (parameters->options().loadfltr())
|
|
flags |= elfcpp::DF_1_LOADFLTR;
|
|
if (parameters->options().nodefaultlib())
|
|
flags |= elfcpp::DF_1_NODEFLIB;
|
|
if (parameters->options().nodelete())
|
|
flags |= elfcpp::DF_1_NODELETE;
|
|
if (parameters->options().nodlopen())
|
|
flags |= elfcpp::DF_1_NOOPEN;
|
|
if (parameters->options().nodump())
|
|
flags |= elfcpp::DF_1_NODUMP;
|
|
if (!parameters->options().shared())
|
|
flags &= ~(elfcpp::DF_1_INITFIRST
|
|
| elfcpp::DF_1_NODELETE
|
|
| elfcpp::DF_1_NOOPEN);
|
|
if (parameters->options().origin())
|
|
flags |= elfcpp::DF_1_ORIGIN;
|
|
if (parameters->options().now())
|
|
flags |= elfcpp::DF_1_NOW;
|
|
if (parameters->options().Bgroup())
|
|
flags |= elfcpp::DF_1_GROUP;
|
|
if (parameters->options().pie())
|
|
flags |= elfcpp::DF_1_PIE;
|
|
if (flags != 0)
|
|
odyn->add_constant(elfcpp::DT_FLAGS_1, flags);
|
|
|
|
flags = 0;
|
|
if (parameters->options().unique())
|
|
flags |= elfcpp::DF_GNU_1_UNIQUE;
|
|
if (flags != 0)
|
|
odyn->add_constant(elfcpp::DT_GNU_FLAGS_1, flags);
|
|
}
|
|
|
|
// Set the size of the _DYNAMIC symbol table to be the size of the
|
|
// dynamic data.
|
|
|
|
void
|
|
Layout::set_dynamic_symbol_size(const Symbol_table* symtab)
|
|
{
|
|
Output_data_dynamic* const odyn = this->dynamic_data_;
|
|
if (odyn == NULL)
|
|
return;
|
|
odyn->finalize_data_size();
|
|
if (this->dynamic_symbol_ == NULL)
|
|
return;
|
|
off_t data_size = odyn->data_size();
|
|
const int size = parameters->target().get_size();
|
|
if (size == 32)
|
|
symtab->get_sized_symbol<32>(this->dynamic_symbol_)->set_symsize(data_size);
|
|
else if (size == 64)
|
|
symtab->get_sized_symbol<64>(this->dynamic_symbol_)->set_symsize(data_size);
|
|
else
|
|
gold_unreachable();
|
|
}
|
|
|
|
// The mapping of input section name prefixes to output section names.
|
|
// In some cases one prefix is itself a prefix of another prefix; in
|
|
// such a case the longer prefix must come first. These prefixes are
|
|
// based on the GNU linker default ELF linker script.
|
|
|
|
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
|
|
#define MAPPING_INIT_EXACT(f, t) { f, 0, t, sizeof(t) - 1 }
|
|
const Layout::Section_name_mapping Layout::section_name_mapping[] =
|
|
{
|
|
MAPPING_INIT(".text.", ".text"),
|
|
MAPPING_INIT(".rodata.", ".rodata"),
|
|
MAPPING_INIT(".data.rel.ro.local.", ".data.rel.ro.local"),
|
|
MAPPING_INIT_EXACT(".data.rel.ro.local", ".data.rel.ro.local"),
|
|
MAPPING_INIT(".data.rel.ro.", ".data.rel.ro"),
|
|
MAPPING_INIT_EXACT(".data.rel.ro", ".data.rel.ro"),
|
|
MAPPING_INIT(".data.", ".data"),
|
|
MAPPING_INIT(".bss.", ".bss"),
|
|
MAPPING_INIT(".tdata.", ".tdata"),
|
|
MAPPING_INIT(".tbss.", ".tbss"),
|
|
MAPPING_INIT(".init_array.", ".init_array"),
|
|
MAPPING_INIT(".fini_array.", ".fini_array"),
|
|
MAPPING_INIT(".sdata.", ".sdata"),
|
|
MAPPING_INIT(".sbss.", ".sbss"),
|
|
// FIXME: In the GNU linker, .sbss2 and .sdata2 are handled
|
|
// differently depending on whether it is creating a shared library.
|
|
MAPPING_INIT(".sdata2.", ".sdata"),
|
|
MAPPING_INIT(".sbss2.", ".sbss"),
|
|
MAPPING_INIT(".lrodata.", ".lrodata"),
|
|
MAPPING_INIT(".ldata.", ".ldata"),
|
|
MAPPING_INIT(".lbss.", ".lbss"),
|
|
MAPPING_INIT(".gcc_except_table.", ".gcc_except_table"),
|
|
MAPPING_INIT(".gnu.linkonce.d.rel.ro.local.", ".data.rel.ro.local"),
|
|
MAPPING_INIT(".gnu.linkonce.d.rel.ro.", ".data.rel.ro"),
|
|
MAPPING_INIT(".gnu.linkonce.t.", ".text"),
|
|
MAPPING_INIT(".gnu.linkonce.r.", ".rodata"),
|
|
MAPPING_INIT(".gnu.linkonce.d.", ".data"),
|
|
MAPPING_INIT(".gnu.linkonce.b.", ".bss"),
|
|
MAPPING_INIT(".gnu.linkonce.s.", ".sdata"),
|
|
MAPPING_INIT(".gnu.linkonce.sb.", ".sbss"),
|
|
MAPPING_INIT(".gnu.linkonce.s2.", ".sdata"),
|
|
MAPPING_INIT(".gnu.linkonce.sb2.", ".sbss"),
|
|
MAPPING_INIT(".gnu.linkonce.wi.", ".debug_info"),
|
|
MAPPING_INIT(".gnu.linkonce.td.", ".tdata"),
|
|
MAPPING_INIT(".gnu.linkonce.tb.", ".tbss"),
|
|
MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
|
|
MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
|
|
MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
|
|
MAPPING_INIT(".ARM.extab", ".ARM.extab"),
|
|
MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
|
|
MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
|
|
MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
|
|
MAPPING_INIT(".gnu.build.attributes.", ".gnu.build.attributes"),
|
|
};
|
|
|
|
// Mapping for ".text" section prefixes with -z,keep-text-section-prefix.
|
|
const Layout::Section_name_mapping Layout::text_section_name_mapping[] =
|
|
{
|
|
MAPPING_INIT(".text.hot.", ".text.hot"),
|
|
MAPPING_INIT_EXACT(".text.hot", ".text.hot"),
|
|
MAPPING_INIT(".text.unlikely.", ".text.unlikely"),
|
|
MAPPING_INIT_EXACT(".text.unlikely", ".text.unlikely"),
|
|
MAPPING_INIT(".text.startup.", ".text.startup"),
|
|
MAPPING_INIT_EXACT(".text.startup", ".text.startup"),
|
|
MAPPING_INIT(".text.exit.", ".text.exit"),
|
|
MAPPING_INIT_EXACT(".text.exit", ".text.exit"),
|
|
MAPPING_INIT(".text.", ".text"),
|
|
};
|
|
#undef MAPPING_INIT
|
|
#undef MAPPING_INIT_EXACT
|
|
|
|
const int Layout::section_name_mapping_count =
|
|
(sizeof(Layout::section_name_mapping)
|
|
/ sizeof(Layout::section_name_mapping[0]));
|
|
|
|
const int Layout::text_section_name_mapping_count =
|
|
(sizeof(Layout::text_section_name_mapping)
|
|
/ sizeof(Layout::text_section_name_mapping[0]));
|
|
|
|
// Find section name NAME in PSNM and return the mapped name if found
|
|
// with the length set in PLEN.
|
|
const char *
|
|
Layout::match_section_name(const Layout::Section_name_mapping* psnm,
|
|
const int count,
|
|
const char* name, size_t* plen)
|
|
{
|
|
for (int i = 0; i < count; ++i, ++psnm)
|
|
{
|
|
if (psnm->fromlen > 0)
|
|
{
|
|
if (strncmp(name, psnm->from, psnm->fromlen) == 0)
|
|
{
|
|
*plen = psnm->tolen;
|
|
return psnm->to;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(name, psnm->from) == 0)
|
|
{
|
|
*plen = psnm->tolen;
|
|
return psnm->to;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Choose the output section name to use given an input section name.
|
|
// Set *PLEN to the length of the name. *PLEN is initialized to the
|
|
// length of NAME.
|
|
|
|
const char*
|
|
Layout::output_section_name(const Relobj* relobj, const char* name,
|
|
size_t* plen)
|
|
{
|
|
// gcc 4.3 generates the following sorts of section names when it
|
|
// needs a section name specific to a function:
|
|
// .text.FN
|
|
// .rodata.FN
|
|
// .sdata2.FN
|
|
// .data.FN
|
|
// .data.rel.FN
|
|
// .data.rel.local.FN
|
|
// .data.rel.ro.FN
|
|
// .data.rel.ro.local.FN
|
|
// .sdata.FN
|
|
// .bss.FN
|
|
// .sbss.FN
|
|
// .tdata.FN
|
|
// .tbss.FN
|
|
|
|
// The GNU linker maps all of those to the part before the .FN,
|
|
// except that .data.rel.local.FN is mapped to .data, and
|
|
// .data.rel.ro.local.FN is mapped to .data.rel.ro. The sections
|
|
// beginning with .data.rel.ro.local are grouped together.
|
|
|
|
// For an anonymous namespace, the string FN can contain a '.'.
|
|
|
|
// Also of interest: .rodata.strN.N, .rodata.cstN, both of which the
|
|
// GNU linker maps to .rodata.
|
|
|
|
// The .data.rel.ro sections are used with -z relro. The sections
|
|
// are recognized by name. We use the same names that the GNU
|
|
// linker does for these sections.
|
|
|
|
// It is hard to handle this in a principled way, so we don't even
|
|
// try. We use a table of mappings. If the input section name is
|
|
// not found in the table, we simply use it as the output section
|
|
// name.
|
|
|
|
if (parameters->options().keep_text_section_prefix()
|
|
&& is_prefix_of(".text", name))
|
|
{
|
|
const char* match = match_section_name(text_section_name_mapping,
|
|
text_section_name_mapping_count,
|
|
name, plen);
|
|
if (match != NULL)
|
|
return match;
|
|
}
|
|
|
|
const char* match = match_section_name(section_name_mapping,
|
|
section_name_mapping_count, name, plen);
|
|
if (match != NULL)
|
|
return match;
|
|
|
|
// As an additional complication, .ctors sections are output in
|
|
// either .ctors or .init_array sections, and .dtors sections are
|
|
// output in either .dtors or .fini_array sections.
|
|
if (is_prefix_of(".ctors.", name) || is_prefix_of(".dtors.", name))
|
|
{
|
|
if (parameters->options().ctors_in_init_array())
|
|
{
|
|
*plen = 11;
|
|
return name[1] == 'c' ? ".init_array" : ".fini_array";
|
|
}
|
|
else
|
|
{
|
|
*plen = 6;
|
|
return name[1] == 'c' ? ".ctors" : ".dtors";
|
|
}
|
|
}
|
|
if (parameters->options().ctors_in_init_array()
|
|
&& (strcmp(name, ".ctors") == 0 || strcmp(name, ".dtors") == 0))
|
|
{
|
|
// To make .init_array/.fini_array work with gcc we must exclude
|
|
// .ctors and .dtors sections from the crtbegin and crtend
|
|
// files.
|
|
if (relobj == NULL
|
|
|| (!Layout::match_file_name(relobj, "crtbegin")
|
|
&& !Layout::match_file_name(relobj, "crtend")))
|
|
{
|
|
*plen = 11;
|
|
return name[1] == 'c' ? ".init_array" : ".fini_array";
|
|
}
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
// Return true if RELOBJ is an input file whose base name matches
|
|
// FILE_NAME. The base name must have an extension of ".o", and must
|
|
// be exactly FILE_NAME.o or FILE_NAME, one character, ".o". This is
|
|
// to match crtbegin.o as well as crtbeginS.o without getting confused
|
|
// by other possibilities. Overall matching the file name this way is
|
|
// a dreadful hack, but the GNU linker does it in order to better
|
|
// support gcc, and we need to be compatible.
|
|
|
|
bool
|
|
Layout::match_file_name(const Relobj* relobj, const char* match)
|
|
{
|
|
const std::string& file_name(relobj->name());
|
|
const char* base_name = lbasename(file_name.c_str());
|
|
size_t match_len = strlen(match);
|
|
if (strncmp(base_name, match, match_len) != 0)
|
|
return false;
|
|
size_t base_len = strlen(base_name);
|
|
if (base_len != match_len + 2 && base_len != match_len + 3)
|
|
return false;
|
|
return memcmp(base_name + base_len - 2, ".o", 2) == 0;
|
|
}
|
|
|
|
// Check if a comdat group or .gnu.linkonce section with the given
|
|
// NAME is selected for the link. If there is already a section,
|
|
// *KEPT_SECTION is set to point to the existing section and the
|
|
// function returns false. Otherwise, OBJECT, SHNDX, IS_COMDAT, and
|
|
// IS_GROUP_NAME are recorded for this NAME in the layout object,
|
|
// *KEPT_SECTION is set to the internal copy and the function returns
|
|
// true.
|
|
|
|
bool
|
|
Layout::find_or_add_kept_section(const std::string& name,
|
|
Relobj* object,
|
|
unsigned int shndx,
|
|
bool is_comdat,
|
|
bool is_group_name,
|
|
Kept_section** kept_section)
|
|
{
|
|
// It's normal to see a couple of entries here, for the x86 thunk
|
|
// sections. If we see more than a few, we're linking a C++
|
|
// program, and we resize to get more space to minimize rehashing.
|
|
if (this->signatures_.size() > 4
|
|
&& !this->resized_signatures_)
|
|
{
|
|
reserve_unordered_map(&this->signatures_,
|
|
this->number_of_input_files_ * 64);
|
|
this->resized_signatures_ = true;
|
|
}
|
|
|
|
Kept_section candidate;
|
|
std::pair<Signatures::iterator, bool> ins =
|
|
this->signatures_.insert(std::make_pair(name, candidate));
|
|
|
|
if (kept_section != NULL)
|
|
*kept_section = &ins.first->second;
|
|
if (ins.second)
|
|
{
|
|
// This is the first time we've seen this signature.
|
|
ins.first->second.set_object(object);
|
|
ins.first->second.set_shndx(shndx);
|
|
if (is_comdat)
|
|
ins.first->second.set_is_comdat();
|
|
if (is_group_name)
|
|
ins.first->second.set_is_group_name();
|
|
return true;
|
|
}
|
|
|
|
// We have already seen this signature.
|
|
|
|
if (ins.first->second.is_group_name())
|
|
{
|
|
// We've already seen a real section group with this signature.
|
|
// If the kept group is from a plugin object, and we're in the
|
|
// replacement phase, accept the new one as a replacement.
|
|
if (ins.first->second.object() == NULL
|
|
&& parameters->options().plugins()->in_replacement_phase())
|
|
{
|
|
ins.first->second.set_object(object);
|
|
ins.first->second.set_shndx(shndx);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if (is_group_name)
|
|
{
|
|
// This is a real section group, and we've already seen a
|
|
// linkonce section with this signature. Record that we've seen
|
|
// a section group, and don't include this section group.
|
|
ins.first->second.set_is_group_name();
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Store the allocated sections into the section list.
|
|
|
|
void
|
|
Layout::get_allocated_sections(Section_list* section_list) const
|
|
{
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
|
|
section_list->push_back(*p);
|
|
}
|
|
|
|
// Store the executable sections into the section list.
|
|
|
|
void
|
|
Layout::get_executable_sections(Section_list* section_list) const
|
|
{
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
if (((*p)->flags() & (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
|
|
== (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
|
|
section_list->push_back(*p);
|
|
}
|
|
|
|
// Create an output segment.
|
|
|
|
Output_segment*
|
|
Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
|
{
|
|
gold_assert(!parameters->options().relocatable());
|
|
Output_segment* oseg = new Output_segment(type, flags);
|
|
this->segment_list_.push_back(oseg);
|
|
|
|
if (type == elfcpp::PT_TLS)
|
|
this->tls_segment_ = oseg;
|
|
else if (type == elfcpp::PT_GNU_RELRO)
|
|
this->relro_segment_ = oseg;
|
|
else if (type == elfcpp::PT_INTERP)
|
|
this->interp_segment_ = oseg;
|
|
|
|
return oseg;
|
|
}
|
|
|
|
// Return the file offset of the normal symbol table.
|
|
|
|
off_t
|
|
Layout::symtab_section_offset() const
|
|
{
|
|
if (this->symtab_section_ != NULL)
|
|
return this->symtab_section_->offset();
|
|
return 0;
|
|
}
|
|
|
|
// Return the section index of the normal symbol table. It may have
|
|
// been stripped by the -s/--strip-all option.
|
|
|
|
unsigned int
|
|
Layout::symtab_section_shndx() const
|
|
{
|
|
if (this->symtab_section_ != NULL)
|
|
return this->symtab_section_->out_shndx();
|
|
return 0;
|
|
}
|
|
|
|
// Write out the Output_sections. Most won't have anything to write,
|
|
// since most of the data will come from input sections which are
|
|
// handled elsewhere. But some Output_sections do have Output_data.
|
|
|
|
void
|
|
Layout::write_output_sections(Output_file* of) const
|
|
{
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if (!(*p)->after_input_sections())
|
|
(*p)->write(of);
|
|
}
|
|
}
|
|
|
|
// Write out data not associated with a section or the symbol table.
|
|
|
|
void
|
|
Layout::write_data(const Symbol_table* symtab, Output_file* of) const
|
|
{
|
|
if (!parameters->options().strip_all())
|
|
{
|
|
const Output_section* symtab_section = this->symtab_section_;
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->needs_symtab_index())
|
|
{
|
|
gold_assert(symtab_section != NULL);
|
|
unsigned int index = (*p)->symtab_index();
|
|
gold_assert(index > 0 && index != -1U);
|
|
off_t off = (symtab_section->offset()
|
|
+ index * symtab_section->entsize());
|
|
symtab->write_section_symbol(*p, this->symtab_xindex_, of, off);
|
|
}
|
|
}
|
|
}
|
|
|
|
const Output_section* dynsym_section = this->dynsym_section_;
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->needs_dynsym_index())
|
|
{
|
|
gold_assert(dynsym_section != NULL);
|
|
unsigned int index = (*p)->dynsym_index();
|
|
gold_assert(index > 0 && index != -1U);
|
|
off_t off = (dynsym_section->offset()
|
|
+ index * dynsym_section->entsize());
|
|
symtab->write_section_symbol(*p, this->dynsym_xindex_, of, off);
|
|
}
|
|
}
|
|
|
|
// Write out the Output_data which are not in an Output_section.
|
|
for (Data_list::const_iterator p = this->special_output_list_.begin();
|
|
p != this->special_output_list_.end();
|
|
++p)
|
|
(*p)->write(of);
|
|
|
|
// Write out the Output_data which are not in an Output_section
|
|
// and are regenerated in each iteration of relaxation.
|
|
for (Data_list::const_iterator p = this->relax_output_list_.begin();
|
|
p != this->relax_output_list_.end();
|
|
++p)
|
|
(*p)->write(of);
|
|
}
|
|
|
|
// Write out the Output_sections which can only be written after the
|
|
// input sections are complete.
|
|
|
|
void
|
|
Layout::write_sections_after_input_sections(Output_file* of)
|
|
{
|
|
// Determine the final section offsets, and thus the final output
|
|
// file size. Note we finalize the .shstrab last, to allow the
|
|
// after_input_section sections to modify their section-names before
|
|
// writing.
|
|
if (this->any_postprocessing_sections_)
|
|
{
|
|
off_t off = this->output_file_size_;
|
|
off = this->set_section_offsets(off, POSTPROCESSING_SECTIONS_PASS);
|
|
|
|
// Now that we've finalized the names, we can finalize the shstrab.
|
|
off =
|
|
this->set_section_offsets(off,
|
|
STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS);
|
|
|
|
if (off > this->output_file_size_)
|
|
{
|
|
of->resize(off);
|
|
this->output_file_size_ = off;
|
|
}
|
|
}
|
|
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->after_input_sections())
|
|
(*p)->write(of);
|
|
}
|
|
|
|
this->section_headers_->write(of);
|
|
}
|
|
|
|
// If a tree-style build ID was requested, the parallel part of that computation
|
|
// is already done, and the final hash-of-hashes is computed here. For other
|
|
// types of build IDs, all the work is done here.
|
|
|
|
void
|
|
Layout::write_build_id(Output_file* of, unsigned char* array_of_hashes,
|
|
size_t size_of_hashes) const
|
|
{
|
|
if (this->build_id_note_ == NULL)
|
|
return;
|
|
|
|
unsigned char* ov = of->get_output_view(this->build_id_note_->offset(),
|
|
this->build_id_note_->data_size());
|
|
|
|
if (array_of_hashes == NULL)
|
|
{
|
|
const size_t output_file_size = this->output_file_size();
|
|
const unsigned char* iv = of->get_input_view(0, output_file_size);
|
|
const char* style = parameters->options().build_id();
|
|
|
|
// If we get here with style == "tree" then the output must be
|
|
// too small for chunking, and we use SHA-1 in that case.
|
|
if ((strcmp(style, "sha1") == 0) || (strcmp(style, "tree") == 0))
|
|
sha1_buffer(reinterpret_cast<const char*>(iv), output_file_size, ov);
|
|
else if (strcmp(style, "md5") == 0)
|
|
md5_buffer(reinterpret_cast<const char*>(iv), output_file_size, ov);
|
|
else
|
|
gold_unreachable();
|
|
|
|
of->free_input_view(0, output_file_size, iv);
|
|
}
|
|
else
|
|
{
|
|
// Non-overlapping substrings of the output file have been hashed.
|
|
// Compute SHA-1 hash of the hashes.
|
|
sha1_buffer(reinterpret_cast<const char*>(array_of_hashes),
|
|
size_of_hashes, ov);
|
|
delete[] array_of_hashes;
|
|
}
|
|
|
|
of->write_output_view(this->build_id_note_->offset(),
|
|
this->build_id_note_->data_size(),
|
|
ov);
|
|
}
|
|
|
|
// Write out a binary file. This is called after the link is
|
|
// complete. IN is the temporary output file we used to generate the
|
|
// ELF code. We simply walk through the segments, read them from
|
|
// their file offset in IN, and write them to their load address in
|
|
// the output file. FIXME: with a bit more work, we could support
|
|
// S-records and/or Intel hex format here.
|
|
|
|
void
|
|
Layout::write_binary(Output_file* in) const
|
|
{
|
|
gold_assert(parameters->options().oformat_enum()
|
|
== General_options::OBJECT_FORMAT_BINARY);
|
|
|
|
// Get the size of the binary file.
|
|
uint64_t max_load_address = 0;
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->type() == elfcpp::PT_LOAD && (*p)->filesz() > 0)
|
|
{
|
|
uint64_t max_paddr = (*p)->paddr() + (*p)->filesz();
|
|
if (max_paddr > max_load_address)
|
|
max_load_address = max_paddr;
|
|
}
|
|
}
|
|
|
|
Output_file out(parameters->options().output_file_name());
|
|
out.open(max_load_address);
|
|
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
{
|
|
if ((*p)->type() == elfcpp::PT_LOAD && (*p)->filesz() > 0)
|
|
{
|
|
const unsigned char* vin = in->get_input_view((*p)->offset(),
|
|
(*p)->filesz());
|
|
unsigned char* vout = out.get_output_view((*p)->paddr(),
|
|
(*p)->filesz());
|
|
memcpy(vout, vin, (*p)->filesz());
|
|
out.write_output_view((*p)->paddr(), (*p)->filesz(), vout);
|
|
in->free_input_view((*p)->offset(), (*p)->filesz(), vin);
|
|
}
|
|
}
|
|
|
|
out.close();
|
|
}
|
|
|
|
// Print the output sections to the map file.
|
|
|
|
void
|
|
Layout::print_to_mapfile(Mapfile* mapfile) const
|
|
{
|
|
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
|
p != this->segment_list_.end();
|
|
++p)
|
|
(*p)->print_sections_to_mapfile(mapfile);
|
|
for (Section_list::const_iterator p = this->unattached_section_list_.begin();
|
|
p != this->unattached_section_list_.end();
|
|
++p)
|
|
(*p)->print_to_mapfile(mapfile);
|
|
}
|
|
|
|
// Print statistical information to stderr. This is used for --stats.
|
|
|
|
void
|
|
Layout::print_stats() const
|
|
{
|
|
this->namepool_.print_stats("section name pool");
|
|
this->sympool_.print_stats("output symbol name pool");
|
|
this->dynpool_.print_stats("dynamic name pool");
|
|
|
|
for (Section_list::const_iterator p = this->section_list_.begin();
|
|
p != this->section_list_.end();
|
|
++p)
|
|
(*p)->print_merge_stats();
|
|
}
|
|
|
|
// Write_sections_task methods.
|
|
|
|
// We can always run this task.
|
|
|
|
Task_token*
|
|
Write_sections_task::is_runnable()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// We need to unlock both OUTPUT_SECTIONS_BLOCKER and FINAL_BLOCKER
|
|
// when finished.
|
|
|
|
void
|
|
Write_sections_task::locks(Task_locker* tl)
|
|
{
|
|
tl->add(this, this->output_sections_blocker_);
|
|
if (this->input_sections_blocker_ != NULL)
|
|
tl->add(this, this->input_sections_blocker_);
|
|
tl->add(this, this->final_blocker_);
|
|
}
|
|
|
|
// Run the task--write out the data.
|
|
|
|
void
|
|
Write_sections_task::run(Workqueue*)
|
|
{
|
|
this->layout_->write_output_sections(this->of_);
|
|
}
|
|
|
|
// Write_data_task methods.
|
|
|
|
// We can always run this task.
|
|
|
|
Task_token*
|
|
Write_data_task::is_runnable()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// We need to unlock FINAL_BLOCKER when finished.
|
|
|
|
void
|
|
Write_data_task::locks(Task_locker* tl)
|
|
{
|
|
tl->add(this, this->final_blocker_);
|
|
}
|
|
|
|
// Run the task--write out the data.
|
|
|
|
void
|
|
Write_data_task::run(Workqueue*)
|
|
{
|
|
this->layout_->write_data(this->symtab_, this->of_);
|
|
}
|
|
|
|
// Write_symbols_task methods.
|
|
|
|
// We can always run this task.
|
|
|
|
Task_token*
|
|
Write_symbols_task::is_runnable()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// We need to unlock FINAL_BLOCKER when finished.
|
|
|
|
void
|
|
Write_symbols_task::locks(Task_locker* tl)
|
|
{
|
|
tl->add(this, this->final_blocker_);
|
|
}
|
|
|
|
// Run the task--write out the symbols.
|
|
|
|
void
|
|
Write_symbols_task::run(Workqueue*)
|
|
{
|
|
this->symtab_->write_globals(this->sympool_, this->dynpool_,
|
|
this->layout_->symtab_xindex(),
|
|
this->layout_->dynsym_xindex(), this->of_);
|
|
}
|
|
|
|
// Write_after_input_sections_task methods.
|
|
|
|
// We can only run this task after the input sections have completed.
|
|
|
|
Task_token*
|
|
Write_after_input_sections_task::is_runnable()
|
|
{
|
|
if (this->input_sections_blocker_->is_blocked())
|
|
return this->input_sections_blocker_;
|
|
return NULL;
|
|
}
|
|
|
|
// We need to unlock FINAL_BLOCKER when finished.
|
|
|
|
void
|
|
Write_after_input_sections_task::locks(Task_locker* tl)
|
|
{
|
|
tl->add(this, this->final_blocker_);
|
|
}
|
|
|
|
// Run the task.
|
|
|
|
void
|
|
Write_after_input_sections_task::run(Workqueue*)
|
|
{
|
|
this->layout_->write_sections_after_input_sections(this->of_);
|
|
}
|
|
|
|
// Build IDs can be computed as a "flat" sha1 or md5 of a string of bytes,
|
|
// or as a "tree" where each chunk of the string is hashed and then those
|
|
// hashes are put into a (much smaller) string which is hashed with sha1.
|
|
// We compute a checksum over the entire file because that is simplest.
|
|
|
|
void
|
|
Build_id_task_runner::run(Workqueue* workqueue, const Task*)
|
|
{
|
|
Task_token* post_hash_tasks_blocker = new Task_token(true);
|
|
const Layout* layout = this->layout_;
|
|
Output_file* of = this->of_;
|
|
const size_t filesize = (layout->output_file_size() <= 0 ? 0
|
|
: static_cast<size_t>(layout->output_file_size()));
|
|
unsigned char* array_of_hashes = NULL;
|
|
size_t size_of_hashes = 0;
|
|
|
|
if (strcmp(this->options_->build_id(), "tree") == 0
|
|
&& this->options_->build_id_chunk_size_for_treehash() > 0
|
|
&& filesize > 0
|
|
&& (filesize >= this->options_->build_id_min_file_size_for_treehash()))
|
|
{
|
|
static const size_t MD5_OUTPUT_SIZE_IN_BYTES = 16;
|
|
const size_t chunk_size =
|
|
this->options_->build_id_chunk_size_for_treehash();
|
|
const size_t num_hashes = ((filesize - 1) / chunk_size) + 1;
|
|
post_hash_tasks_blocker->add_blockers(num_hashes);
|
|
size_of_hashes = num_hashes * MD5_OUTPUT_SIZE_IN_BYTES;
|
|
array_of_hashes = new unsigned char[size_of_hashes];
|
|
unsigned char *dst = array_of_hashes;
|
|
for (size_t i = 0, src_offset = 0; i < num_hashes;
|
|
i++, dst += MD5_OUTPUT_SIZE_IN_BYTES, src_offset += chunk_size)
|
|
{
|
|
size_t size = std::min(chunk_size, filesize - src_offset);
|
|
workqueue->queue(new Hash_task(of,
|
|
src_offset,
|
|
size,
|
|
dst,
|
|
post_hash_tasks_blocker));
|
|
}
|
|
}
|
|
|
|
// Queue the final task to write the build id and close the output file.
|
|
workqueue->queue(new Task_function(new Close_task_runner(this->options_,
|
|
layout,
|
|
of,
|
|
array_of_hashes,
|
|
size_of_hashes),
|
|
post_hash_tasks_blocker,
|
|
"Task_function Close_task_runner"));
|
|
}
|
|
|
|
// Close_task_runner methods.
|
|
|
|
// Finish up the build ID computation, if necessary, and write a binary file,
|
|
// if necessary. Then close the output file.
|
|
|
|
void
|
|
Close_task_runner::run(Workqueue*, const Task*)
|
|
{
|
|
// At this point the multi-threaded part of the build ID computation,
|
|
// if any, is done. See Build_id_task_runner.
|
|
this->layout_->write_build_id(this->of_, this->array_of_hashes_,
|
|
this->size_of_hashes_);
|
|
|
|
// If we've been asked to create a binary file, we do so here.
|
|
if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF)
|
|
this->layout_->write_binary(this->of_);
|
|
|
|
if (this->options_->dependency_file())
|
|
File_read::write_dependency_file(this->options_->dependency_file(),
|
|
this->options_->output_file_name());
|
|
|
|
this->of_->close();
|
|
}
|
|
|
|
// Instantiate the templates we need. We could use the configure
|
|
// script to restrict this to only the ones for implemented targets.
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::init_fixed_output_section<32, false>(
|
|
const char* name,
|
|
elfcpp::Shdr<32, false>& shdr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
Output_section*
|
|
Layout::init_fixed_output_section<32, true>(
|
|
const char* name,
|
|
elfcpp::Shdr<32, true>& shdr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::init_fixed_output_section<64, false>(
|
|
const char* name,
|
|
elfcpp::Shdr<64, false>& shdr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
Output_section*
|
|
Layout::init_fixed_output_section<64, true>(
|
|
const char* name,
|
|
elfcpp::Shdr<64, true>& shdr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout<32, false>(Sized_relobj_file<32, false>* object,
|
|
unsigned int shndx,
|
|
const char* name,
|
|
const elfcpp::Shdr<32, false>& shdr,
|
|
unsigned int, unsigned int, unsigned int, off_t*);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout<32, true>(Sized_relobj_file<32, true>* object,
|
|
unsigned int shndx,
|
|
const char* name,
|
|
const elfcpp::Shdr<32, true>& shdr,
|
|
unsigned int, unsigned int, unsigned int, off_t*);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout<64, false>(Sized_relobj_file<64, false>* object,
|
|
unsigned int shndx,
|
|
const char* name,
|
|
const elfcpp::Shdr<64, false>& shdr,
|
|
unsigned int, unsigned int, unsigned int, off_t*);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout<64, true>(Sized_relobj_file<64, true>* object,
|
|
unsigned int shndx,
|
|
const char* name,
|
|
const elfcpp::Shdr<64, true>& shdr,
|
|
unsigned int, unsigned int, unsigned int, off_t*);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout_reloc<32, false>(Sized_relobj_file<32, false>* object,
|
|
unsigned int reloc_shndx,
|
|
const elfcpp::Shdr<32, false>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout_reloc<32, true>(Sized_relobj_file<32, true>* object,
|
|
unsigned int reloc_shndx,
|
|
const elfcpp::Shdr<32, true>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout_reloc<64, false>(Sized_relobj_file<64, false>* object,
|
|
unsigned int reloc_shndx,
|
|
const elfcpp::Shdr<64, false>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout_reloc<64, true>(Sized_relobj_file<64, true>* object,
|
|
unsigned int reloc_shndx,
|
|
const elfcpp::Shdr<64, true>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
void
|
|
Layout::layout_group<32, false>(Symbol_table* symtab,
|
|
Sized_relobj_file<32, false>* object,
|
|
unsigned int,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<32, false>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
void
|
|
Layout::layout_group<32, true>(Symbol_table* symtab,
|
|
Sized_relobj_file<32, true>* object,
|
|
unsigned int,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<32, true>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
void
|
|
Layout::layout_group<64, false>(Symbol_table* symtab,
|
|
Sized_relobj_file<64, false>* object,
|
|
unsigned int,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<64, false>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
void
|
|
Layout::layout_group<64, true>(Symbol_table* symtab,
|
|
Sized_relobj_file<64, true>* object,
|
|
unsigned int,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<64, true>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout_eh_frame<32, false>(Sized_relobj_file<32, false>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
const unsigned char* symbol_names,
|
|
off_t symbol_names_size,
|
|
unsigned int shndx,
|
|
const elfcpp::Shdr<32, false>& shdr,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type,
|
|
off_t* off);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout_eh_frame<32, true>(Sized_relobj_file<32, true>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
const unsigned char* symbol_names,
|
|
off_t symbol_names_size,
|
|
unsigned int shndx,
|
|
const elfcpp::Shdr<32, true>& shdr,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type,
|
|
off_t* off);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
Output_section*
|
|
Layout::layout_eh_frame<64, false>(Sized_relobj_file<64, false>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
const unsigned char* symbol_names,
|
|
off_t symbol_names_size,
|
|
unsigned int shndx,
|
|
const elfcpp::Shdr<64, false>& shdr,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type,
|
|
off_t* off);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
Output_section*
|
|
Layout::layout_eh_frame<64, true>(Sized_relobj_file<64, true>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
const unsigned char* symbol_names,
|
|
off_t symbol_names_size,
|
|
unsigned int shndx,
|
|
const elfcpp::Shdr<64, true>& shdr,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type,
|
|
off_t* off);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
template
|
|
void
|
|
Layout::add_to_gdb_index(bool is_type_unit,
|
|
Sized_relobj<32, false>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
unsigned int shndx,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
template
|
|
void
|
|
Layout::add_to_gdb_index(bool is_type_unit,
|
|
Sized_relobj<32, true>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
unsigned int shndx,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
template
|
|
void
|
|
Layout::add_to_gdb_index(bool is_type_unit,
|
|
Sized_relobj<64, false>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
unsigned int shndx,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type);
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
template
|
|
void
|
|
Layout::add_to_gdb_index(bool is_type_unit,
|
|
Sized_relobj<64, true>* object,
|
|
const unsigned char* symbols,
|
|
off_t symbols_size,
|
|
unsigned int shndx,
|
|
unsigned int reloc_shndx,
|
|
unsigned int reloc_type);
|
|
#endif
|
|
|
|
} // End namespace gold.
|