mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
bce5a025d2
During a -r (or --emit-relocs) link, if two sections had the same name but different section types, gold would put relocations for both sections into the same relocation section even though the data sections remained separate. For .eh_frame sections, when one section is PROGBITS and another is X86_64_UNWIND, we really should be using the UNWIND section type and combining the sections anyway. For other sections, we should be creating one relocation section for each output data section. gold/ PR gold/23016 * incremental.cc (can_incremental_update): Check for unwind section type. * layout.h (Layout::layout): Add sh_type parameter. * layout.cc (Layout::layout): Likewise. (Layout::layout_reloc): Create new output reloc section if data section does not already have one. (Layout::layout_eh_frame): Check for unwind section type. (Layout::make_eh_frame_section): Use unwind section type for .eh_frame and .eh_frame_hdr. * object.h (Sized_relobj_file::Shdr_write): New typedef. (Sized_relobj_file::layout_section): Add sh_type parameter. (Sized_relobj_file::Deferred_layout::Deferred_layout): Add sh_type parameter. * object.cc (Sized_relobj_file::check_eh_frame_flags): Check for unwind section type. (Sized_relobj_file::layout_section): Add sh_type parameter; pass it to Layout::layout. (Sized_relobj_file::do_layout): Make local copy of sh_type. Force .eh_frame sections to unwind section type. Pass sh_type to layout_section. (Sized_relobj_file<size, big_endian>::do_layout_deferred_sections): Pass sh_type to layout_section. * output.cc (Output_section::Output_section): Initialize reloc_section_. * output.h (Output_section::reloc_section): New method. (Output_section::set_reloc_section): New method. (Output_section::reloc_section_): New data member. * target.h (Target::unwind_section_type): New method. (Target::Target_info::unwind_section_type): New data member. * aarch64.cc (aarch64_info): Add unwind_section_type. * arm.cc (arm_info, arm_nacl_info): Likewise. * i386.cc (i386_info, i386_nacl_info, iamcu_info): Likewise. * mips.cc (mips_info, mips_nacl_info): Likewise. * powerpc.cc (powerpc_info): Likewise. * s390.cc (s390_info): Likewise. * sparc.cc (sparc_info): Likewise. * tilegx.cc (tilegx_info): Likewise. * x86_64.cc (x86_64_info, x86_64_nacl_info): Likewise. * testsuite/Makefile.am (pr23016_1, pr23016_2): New test cases. * testsuite/Makefile.in: Regenerate. * testsuite/testfile.cc: Add unwind_section_type. * testsuite/pr23016_1.sh: New test script. * testsuite/pr23016_1a.s: New source file. * testsuite/pr23016_1b.s: New source file. * testsuite/pr23016_2.sh: New test script. * testsuite/pr23016_2a.s: New source file. * testsuite/pr23016_2b.s: New source file.
1691 lines
51 KiB
C++
1691 lines
51 KiB
C++
// layout.h -- lay out output file sections for gold -*- C++ -*-
|
|
|
|
// Copyright (C) 2006-2018 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.
|
|
|
|
#ifndef GOLD_LAYOUT_H
|
|
#define GOLD_LAYOUT_H
|
|
|
|
#include <cstring>
|
|
#include <list>
|
|
#include <map>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "script.h"
|
|
#include "workqueue.h"
|
|
#include "object.h"
|
|
#include "dynobj.h"
|
|
#include "stringpool.h"
|
|
|
|
namespace gold
|
|
{
|
|
|
|
class General_options;
|
|
class Incremental_inputs;
|
|
class Incremental_binary;
|
|
class Input_objects;
|
|
class Mapfile;
|
|
class Symbol_table;
|
|
class Output_section_data;
|
|
class Output_section;
|
|
class Output_section_headers;
|
|
class Output_segment_headers;
|
|
class Output_file_header;
|
|
class Output_segment;
|
|
class Output_data;
|
|
class Output_data_reloc_generic;
|
|
class Output_data_dynamic;
|
|
class Output_symtab_xindex;
|
|
class Output_reduced_debug_abbrev_section;
|
|
class Output_reduced_debug_info_section;
|
|
class Eh_frame;
|
|
class Gdb_index;
|
|
class Target;
|
|
struct Timespec;
|
|
|
|
// Return TRUE if SECNAME is the name of a compressed debug section.
|
|
extern bool
|
|
is_compressed_debug_section(const char* secname);
|
|
|
|
// Return the name of the corresponding uncompressed debug section.
|
|
extern std::string
|
|
corresponding_uncompressed_section_name(std::string secname);
|
|
|
|
// Maintain a list of free space within a section, segment, or file.
|
|
// Used for incremental update links.
|
|
|
|
class Free_list
|
|
{
|
|
public:
|
|
struct Free_list_node
|
|
{
|
|
Free_list_node(off_t start, off_t end)
|
|
: start_(start), end_(end)
|
|
{ }
|
|
off_t start_;
|
|
off_t end_;
|
|
};
|
|
typedef std::list<Free_list_node>::const_iterator Const_iterator;
|
|
|
|
Free_list()
|
|
: list_(), last_remove_(list_.begin()), extend_(false), length_(0),
|
|
min_hole_(0)
|
|
{ }
|
|
|
|
// Initialize the free list for a section of length LEN.
|
|
// If EXTEND is true, free space may be allocated past the end.
|
|
void
|
|
init(off_t len, bool extend);
|
|
|
|
// Set the minimum hole size that is allowed when allocating
|
|
// from the free list.
|
|
void
|
|
set_min_hole_size(off_t min_hole)
|
|
{ this->min_hole_ = min_hole; }
|
|
|
|
// Remove a chunk from the free list.
|
|
void
|
|
remove(off_t start, off_t end);
|
|
|
|
// Allocate a chunk of space from the free list of length LEN,
|
|
// with alignment ALIGN, and minimum offset MINOFF.
|
|
off_t
|
|
allocate(off_t len, uint64_t align, off_t minoff);
|
|
|
|
// Return an iterator for the beginning of the free list.
|
|
Const_iterator
|
|
begin() const
|
|
{ return this->list_.begin(); }
|
|
|
|
// Return an iterator for the end of the free list.
|
|
Const_iterator
|
|
end() const
|
|
{ return this->list_.end(); }
|
|
|
|
// Dump the free list (for debugging).
|
|
void
|
|
dump();
|
|
|
|
// Print usage statistics.
|
|
static void
|
|
print_stats();
|
|
|
|
private:
|
|
typedef std::list<Free_list_node>::iterator Iterator;
|
|
|
|
// The free list.
|
|
std::list<Free_list_node> list_;
|
|
|
|
// The last node visited during a remove operation.
|
|
Iterator last_remove_;
|
|
|
|
// Whether we can extend past the original length.
|
|
bool extend_;
|
|
|
|
// The total length of the section, segment, or file.
|
|
off_t length_;
|
|
|
|
// The minimum hole size allowed. When allocating from the free list,
|
|
// we must not leave a hole smaller than this.
|
|
off_t min_hole_;
|
|
|
|
// Statistics:
|
|
// The total number of free lists used.
|
|
static unsigned int num_lists;
|
|
// The total number of free list nodes used.
|
|
static unsigned int num_nodes;
|
|
// The total number of calls to Free_list::remove.
|
|
static unsigned int num_removes;
|
|
// The total number of nodes visited during calls to Free_list::remove.
|
|
static unsigned int num_remove_visits;
|
|
// The total number of calls to Free_list::allocate.
|
|
static unsigned int num_allocates;
|
|
// The total number of nodes visited during calls to Free_list::allocate.
|
|
static unsigned int num_allocate_visits;
|
|
};
|
|
|
|
// This task function handles mapping the input sections to output
|
|
// sections and laying them out in memory.
|
|
|
|
class Layout_task_runner : public Task_function_runner
|
|
{
|
|
public:
|
|
// OPTIONS is the command line options, INPUT_OBJECTS is the list of
|
|
// input objects, SYMTAB is the symbol table, LAYOUT is the layout
|
|
// object.
|
|
Layout_task_runner(const General_options& options,
|
|
const Input_objects* input_objects,
|
|
Symbol_table* symtab,
|
|
Target* target,
|
|
Layout* layout,
|
|
Mapfile* mapfile)
|
|
: options_(options), input_objects_(input_objects), symtab_(symtab),
|
|
target_(target), layout_(layout), mapfile_(mapfile)
|
|
{ }
|
|
|
|
// Run the operation.
|
|
void
|
|
run(Workqueue*, const Task*);
|
|
|
|
private:
|
|
Layout_task_runner(const Layout_task_runner&);
|
|
Layout_task_runner& operator=(const Layout_task_runner&);
|
|
|
|
const General_options& options_;
|
|
const Input_objects* input_objects_;
|
|
Symbol_table* symtab_;
|
|
Target* target_;
|
|
Layout* layout_;
|
|
Mapfile* mapfile_;
|
|
};
|
|
|
|
// This class holds information about the comdat group or
|
|
// .gnu.linkonce section that will be kept for a given signature.
|
|
|
|
class Kept_section
|
|
{
|
|
private:
|
|
// For a comdat group, we build a mapping from the name of each
|
|
// section in the group to the section index and the size in object.
|
|
// When we discard a group in some other object file, we use this
|
|
// map to figure out which kept section the discarded section is
|
|
// associated with. We then use that mapping when processing relocs
|
|
// against discarded sections.
|
|
struct Comdat_section_info
|
|
{
|
|
// The section index.
|
|
unsigned int shndx;
|
|
// The section size.
|
|
uint64_t size;
|
|
|
|
Comdat_section_info(unsigned int a_shndx, uint64_t a_size)
|
|
: shndx(a_shndx), size(a_size)
|
|
{ }
|
|
};
|
|
|
|
// Most comdat groups have only one or two sections, so we use a
|
|
// std::map rather than an Unordered_map to optimize for that case
|
|
// without paying too heavily for groups with more sections.
|
|
typedef std::map<std::string, Comdat_section_info> Comdat_group;
|
|
|
|
public:
|
|
Kept_section()
|
|
: object_(NULL), shndx_(0), is_comdat_(false), is_group_name_(false)
|
|
{ this->u_.linkonce_size = 0; }
|
|
|
|
// We need to support copies for the signature map in the Layout
|
|
// object, but we should never copy an object after it has been
|
|
// marked as a comdat section.
|
|
Kept_section(const Kept_section& k)
|
|
: object_(k.object_), shndx_(k.shndx_), is_comdat_(false),
|
|
is_group_name_(k.is_group_name_)
|
|
{
|
|
gold_assert(!k.is_comdat_);
|
|
this->u_.linkonce_size = 0;
|
|
}
|
|
|
|
~Kept_section()
|
|
{
|
|
if (this->is_comdat_)
|
|
delete this->u_.group_sections;
|
|
}
|
|
|
|
// The object where this section lives.
|
|
Relobj*
|
|
object() const
|
|
{ return this->object_; }
|
|
|
|
// Set the object.
|
|
void
|
|
set_object(Relobj* object)
|
|
{
|
|
gold_assert(this->object_ == NULL);
|
|
this->object_ = object;
|
|
}
|
|
|
|
// The section index.
|
|
unsigned int
|
|
shndx() const
|
|
{ return this->shndx_; }
|
|
|
|
// Set the section index.
|
|
void
|
|
set_shndx(unsigned int shndx)
|
|
{
|
|
gold_assert(this->shndx_ == 0);
|
|
this->shndx_ = shndx;
|
|
}
|
|
|
|
// Whether this is a comdat group.
|
|
bool
|
|
is_comdat() const
|
|
{ return this->is_comdat_; }
|
|
|
|
// Set that this is a comdat group.
|
|
void
|
|
set_is_comdat()
|
|
{
|
|
gold_assert(!this->is_comdat_);
|
|
this->is_comdat_ = true;
|
|
this->u_.group_sections = new Comdat_group();
|
|
}
|
|
|
|
// Whether this is associated with the name of a group or section
|
|
// rather than the symbol name derived from a linkonce section.
|
|
bool
|
|
is_group_name() const
|
|
{ return this->is_group_name_; }
|
|
|
|
// Note that this represents a comdat group rather than a single
|
|
// linkonce section.
|
|
void
|
|
set_is_group_name()
|
|
{ this->is_group_name_ = true; }
|
|
|
|
// Add a section to the group list.
|
|
void
|
|
add_comdat_section(const std::string& name, unsigned int shndx,
|
|
uint64_t size)
|
|
{
|
|
gold_assert(this->is_comdat_);
|
|
Comdat_section_info sinfo(shndx, size);
|
|
this->u_.group_sections->insert(std::make_pair(name, sinfo));
|
|
}
|
|
|
|
// Look for a section name in the group list, and return whether it
|
|
// was found. If found, returns the section index and size.
|
|
bool
|
|
find_comdat_section(const std::string& name, unsigned int* pshndx,
|
|
uint64_t* psize) const
|
|
{
|
|
gold_assert(this->is_comdat_);
|
|
Comdat_group::const_iterator p = this->u_.group_sections->find(name);
|
|
if (p == this->u_.group_sections->end())
|
|
return false;
|
|
*pshndx = p->second.shndx;
|
|
*psize = p->second.size;
|
|
return true;
|
|
}
|
|
|
|
// If there is only one section in the group list, return true, and
|
|
// return the section index and size.
|
|
bool
|
|
find_single_comdat_section(unsigned int* pshndx, uint64_t* psize) const
|
|
{
|
|
gold_assert(this->is_comdat_);
|
|
if (this->u_.group_sections->size() != 1)
|
|
return false;
|
|
Comdat_group::const_iterator p = this->u_.group_sections->begin();
|
|
*pshndx = p->second.shndx;
|
|
*psize = p->second.size;
|
|
return true;
|
|
}
|
|
|
|
// Return the size of a linkonce section.
|
|
uint64_t
|
|
linkonce_size() const
|
|
{
|
|
gold_assert(!this->is_comdat_);
|
|
return this->u_.linkonce_size;
|
|
}
|
|
|
|
// Set the size of a linkonce section.
|
|
void
|
|
set_linkonce_size(uint64_t size)
|
|
{
|
|
gold_assert(!this->is_comdat_);
|
|
this->u_.linkonce_size = size;
|
|
}
|
|
|
|
private:
|
|
// No assignment.
|
|
Kept_section& operator=(const Kept_section&);
|
|
|
|
// The object containing the comdat group or .gnu.linkonce section.
|
|
Relobj* object_;
|
|
// Index of the group section for comdats and the section itself for
|
|
// .gnu.linkonce.
|
|
unsigned int shndx_;
|
|
// True if this is for a comdat group rather than a .gnu.linkonce
|
|
// section.
|
|
bool is_comdat_;
|
|
// The Kept_sections are values of a mapping, that maps names to
|
|
// them. This field is true if this struct is associated with the
|
|
// name of a comdat or .gnu.linkonce, false if it is associated with
|
|
// the name of a symbol obtained from the .gnu.linkonce.* name
|
|
// through some heuristics.
|
|
bool is_group_name_;
|
|
union
|
|
{
|
|
// If the is_comdat_ field is true, this holds a map from names of
|
|
// the sections in the group to section indexes in object_ and to
|
|
// section sizes.
|
|
Comdat_group* group_sections;
|
|
// If the is_comdat_ field is false, this holds the size of the
|
|
// single section.
|
|
uint64_t linkonce_size;
|
|
} u_;
|
|
};
|
|
|
|
// The ordering for output sections. This controls how output
|
|
// sections are ordered within a PT_LOAD output segment.
|
|
|
|
enum Output_section_order
|
|
{
|
|
// Unspecified. Used for non-load segments. Also used for the file
|
|
// and segment headers.
|
|
ORDER_INVALID,
|
|
|
|
// The PT_INTERP section should come first, so that the dynamic
|
|
// linker can pick it up quickly.
|
|
ORDER_INTERP,
|
|
|
|
// Loadable read-only note sections come next so that the PT_NOTE
|
|
// segment is on the first page of the executable.
|
|
ORDER_RO_NOTE,
|
|
|
|
// Put read-only sections used by the dynamic linker early in the
|
|
// executable to minimize paging.
|
|
ORDER_DYNAMIC_LINKER,
|
|
|
|
// Put reloc sections used by the dynamic linker after other
|
|
// sections used by the dynamic linker; otherwise, objcopy and strip
|
|
// get confused.
|
|
ORDER_DYNAMIC_RELOCS,
|
|
|
|
// Put the PLT reloc section after the other dynamic relocs;
|
|
// otherwise, prelink gets confused.
|
|
ORDER_DYNAMIC_PLT_RELOCS,
|
|
|
|
// The .init section.
|
|
ORDER_INIT,
|
|
|
|
// The PLT.
|
|
ORDER_PLT,
|
|
|
|
// The hot text sections, prefixed by .text.hot.
|
|
ORDER_TEXT_HOT,
|
|
|
|
// The regular text sections.
|
|
ORDER_TEXT,
|
|
|
|
// The startup text sections, prefixed by .text.startup.
|
|
ORDER_TEXT_STARTUP,
|
|
|
|
// The startup text sections, prefixed by .text.startup.
|
|
ORDER_TEXT_EXIT,
|
|
|
|
// The unlikely text sections, prefixed by .text.unlikely.
|
|
ORDER_TEXT_UNLIKELY,
|
|
|
|
// The .fini section.
|
|
ORDER_FINI,
|
|
|
|
// The read-only sections.
|
|
ORDER_READONLY,
|
|
|
|
// The exception frame sections.
|
|
ORDER_EHFRAME,
|
|
|
|
// The TLS sections come first in the data section.
|
|
ORDER_TLS_DATA,
|
|
ORDER_TLS_BSS,
|
|
|
|
// Local RELRO (read-only after relocation) sections come before
|
|
// non-local RELRO sections. This data will be fully resolved by
|
|
// the prelinker.
|
|
ORDER_RELRO_LOCAL,
|
|
|
|
// Non-local RELRO sections are grouped together after local RELRO
|
|
// sections. All RELRO sections must be adjacent so that they can
|
|
// all be put into a PT_GNU_RELRO segment.
|
|
ORDER_RELRO,
|
|
|
|
// We permit marking exactly one output section as the last RELRO
|
|
// section. We do this so that the read-only GOT can be adjacent to
|
|
// the writable GOT.
|
|
ORDER_RELRO_LAST,
|
|
|
|
// Similarly, we permit marking exactly one output section as the
|
|
// first non-RELRO section.
|
|
ORDER_NON_RELRO_FIRST,
|
|
|
|
// The regular data sections come after the RELRO sections.
|
|
ORDER_DATA,
|
|
|
|
// Large data sections normally go in large data segments.
|
|
ORDER_LARGE_DATA,
|
|
|
|
// Group writable notes so that we can have a single PT_NOTE
|
|
// segment.
|
|
ORDER_RW_NOTE,
|
|
|
|
// The small data sections must be at the end of the data sections,
|
|
// so that they can be adjacent to the small BSS sections.
|
|
ORDER_SMALL_DATA,
|
|
|
|
// The BSS sections start here.
|
|
|
|
// The small BSS sections must be at the start of the BSS sections,
|
|
// so that they can be adjacent to the small data sections.
|
|
ORDER_SMALL_BSS,
|
|
|
|
// The regular BSS sections.
|
|
ORDER_BSS,
|
|
|
|
// The large BSS sections come after the other BSS sections.
|
|
ORDER_LARGE_BSS,
|
|
|
|
// Maximum value.
|
|
ORDER_MAX
|
|
};
|
|
|
|
// This class handles the details of laying out input sections.
|
|
|
|
class Layout
|
|
{
|
|
public:
|
|
Layout(int number_of_input_files, Script_options*);
|
|
|
|
~Layout()
|
|
{
|
|
delete this->relaxation_debug_check_;
|
|
delete this->segment_states_;
|
|
}
|
|
|
|
// For incremental links, record the base file to be modified.
|
|
void
|
|
set_incremental_base(Incremental_binary* base);
|
|
|
|
Incremental_binary*
|
|
incremental_base()
|
|
{ return this->incremental_base_; }
|
|
|
|
// 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*
|
|
init_fixed_output_section(const char*, elfcpp::Shdr<size, big_endian>&);
|
|
|
|
// Given an input section SHNDX, named NAME, with data in SHDR, from
|
|
// the object file OBJECT, return the output section where this
|
|
// input section should go. 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 *OFFSET to the offset
|
|
// within the output section.
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
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 reloc_type, off_t* offset);
|
|
|
|
std::map<Section_id, unsigned int>*
|
|
get_section_order_map()
|
|
{ return &this->section_order_map_; }
|
|
|
|
// Struct to store segment info when mapping some input sections to
|
|
// unique segments using linker plugins. Mapping an input section to
|
|
// a unique segment is done by first placing such input sections in
|
|
// unique output sections and then mapping the output section to a
|
|
// unique segment. NAME is the name of the output section. FLAGS
|
|
// and ALIGN are the extra flags and alignment of the segment.
|
|
struct Unique_segment_info
|
|
{
|
|
// Identifier for the segment. ELF segments don't have names. This
|
|
// is used as the name of the output section mapped to the segment.
|
|
const char* name;
|
|
// Additional segment flags.
|
|
uint64_t flags;
|
|
// Segment alignment.
|
|
uint64_t align;
|
|
};
|
|
|
|
// Mapping from input section to segment.
|
|
typedef std::map<Const_section_id, Unique_segment_info*>
|
|
Section_segment_map;
|
|
|
|
// Maps section SECN to SEGMENT s.
|
|
void
|
|
insert_section_segment_map(Const_section_id secn, Unique_segment_info *s);
|
|
|
|
// Some input sections require special ordering, for compatibility
|
|
// with GNU ld. Given the name of an input section, return -1 if it
|
|
// does not require special ordering. Otherwise, return the index
|
|
// by which it should be ordered compared to other input sections
|
|
// that require special ordering.
|
|
static int
|
|
special_ordering_of_input_section(const char* name);
|
|
|
|
bool
|
|
is_section_ordering_specified()
|
|
{ return this->section_ordering_specified_; }
|
|
|
|
void
|
|
set_section_ordering_specified()
|
|
{ this->section_ordering_specified_ = true; }
|
|
|
|
bool
|
|
is_unique_segment_for_sections_specified() const
|
|
{ return this->unique_segment_for_sections_specified_; }
|
|
|
|
void
|
|
set_unique_segment_for_sections_specified()
|
|
{ this->unique_segment_for_sections_specified_ = true; }
|
|
|
|
// For incremental updates, allocate a block of memory from the
|
|
// free list. Find a block starting at or after MINOFF.
|
|
off_t
|
|
allocate(off_t len, uint64_t align, off_t minoff)
|
|
{ return this->free_list_.allocate(len, align, minoff); }
|
|
|
|
unsigned int
|
|
find_section_order_index(const std::string&);
|
|
|
|
// Read the sequence of input sections from the file specified with
|
|
// linker option --section-ordering-file.
|
|
void
|
|
read_layout_from_file();
|
|
|
|
// Layout an input reloc section when doing a relocatable link. The
|
|
// section is RELOC_SHNDX in OBJECT, with data in SHDR.
|
|
// DATA_SECTION is the reloc section to which it refers. RR is the
|
|
// relocatable information.
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
layout_reloc(Sized_relobj_file<size, big_endian>* object,
|
|
unsigned int reloc_shndx,
|
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
|
Output_section* data_section,
|
|
Relocatable_relocs* rr);
|
|
|
|
// Layout a group section when doing a relocatable link.
|
|
template<int size, bool big_endian>
|
|
void
|
|
layout_group(Symbol_table* symtab,
|
|
Sized_relobj_file<size, big_endian>* object,
|
|
unsigned int group_shndx,
|
|
const char* group_section_name,
|
|
const char* signature,
|
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
|
elfcpp::Elf_Word flags,
|
|
std::vector<unsigned int>* shndxes);
|
|
|
|
// Like layout, only for exception frame sections. OBJECT is an
|
|
// object file. SYMBOLS is the contents of the symbol table
|
|
// section, with size SYMBOLS_SIZE. SYMBOL_NAMES is the contents of
|
|
// the symbol name section, with size SYMBOL_NAMES_SIZE. SHNDX is a
|
|
// .eh_frame section in OBJECT. SHDR is the section header.
|
|
// 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. This
|
|
// returns the output section, and sets *OFFSET to the offset.
|
|
template<int size, bool big_endian>
|
|
Output_section*
|
|
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* offset);
|
|
|
|
// After processing all input files, we call this to make sure that
|
|
// the optimized .eh_frame sections have been added to the output
|
|
// section.
|
|
void
|
|
finalize_eh_frame_section();
|
|
|
|
// Add .eh_frame information for a PLT. The FDE must start with a
|
|
// 4-byte PC-relative reference to the start of the PLT, followed by
|
|
// a 4-byte size of PLT.
|
|
void
|
|
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);
|
|
|
|
// Remove .eh_frame information for a PLT. FDEs using the CIE must
|
|
// be removed in reverse order to the order they were added.
|
|
void
|
|
remove_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);
|
|
|
|
// Scan a .debug_info or .debug_types section, and add summary
|
|
// information to the .gdb_index section.
|
|
template<int size, bool big_endian>
|
|
void
|
|
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);
|
|
|
|
// Handle a GNU stack note. This is called once per input object
|
|
// file. SEEN_GNU_STACK is true if the object file has a
|
|
// .note.GNU-stack section. GNU_STACK_FLAGS is the section flags
|
|
// from that section if there was one.
|
|
void
|
|
layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags,
|
|
const Object*);
|
|
|
|
// Add an Output_section_data to the layout. This is used for
|
|
// special sections like the GOT section. ORDER is where the
|
|
// section should wind up in the output segment. IS_RELRO is true
|
|
// for relro sections.
|
|
Output_section*
|
|
add_output_section_data(const char* name, elfcpp::Elf_Word type,
|
|
elfcpp::Elf_Xword flags,
|
|
Output_section_data*, Output_section_order order,
|
|
bool is_relro);
|
|
|
|
// Increase the size of the relro segment by this much.
|
|
void
|
|
increase_relro(unsigned int s)
|
|
{ this->increase_relro_ += s; }
|
|
|
|
// Create dynamic sections if necessary.
|
|
void
|
|
create_initial_dynamic_sections(Symbol_table*);
|
|
|
|
// Define __start and __stop symbols for output sections.
|
|
void
|
|
define_section_symbols(Symbol_table*);
|
|
|
|
// Create automatic note sections.
|
|
void
|
|
create_notes();
|
|
|
|
// Create sections for linker scripts.
|
|
void
|
|
create_script_sections()
|
|
{ this->script_options_->create_script_sections(this); }
|
|
|
|
// Define symbols from any linker script.
|
|
void
|
|
define_script_symbols(Symbol_table* symtab)
|
|
{ this->script_options_->add_symbols_to_table(symtab); }
|
|
|
|
// Define symbols for group signatures.
|
|
void
|
|
define_group_signatures(Symbol_table*);
|
|
|
|
// Return the Stringpool used for symbol names.
|
|
const Stringpool*
|
|
sympool() const
|
|
{ return &this->sympool_; }
|
|
|
|
// Return the Stringpool used for dynamic symbol names and dynamic
|
|
// tags.
|
|
const Stringpool*
|
|
dynpool() const
|
|
{ return &this->dynpool_; }
|
|
|
|
// Return the .dynamic output section. This is only valid after the
|
|
// layout has been finalized.
|
|
Output_section*
|
|
dynamic_section() const
|
|
{ return this->dynamic_section_; }
|
|
|
|
// Return the symtab_xindex section used to hold large section
|
|
// indexes for the normal symbol table.
|
|
Output_symtab_xindex*
|
|
symtab_xindex() const
|
|
{ return this->symtab_xindex_; }
|
|
|
|
// Return the dynsym_xindex section used to hold large section
|
|
// indexes for the dynamic symbol table.
|
|
Output_symtab_xindex*
|
|
dynsym_xindex() const
|
|
{ return this->dynsym_xindex_; }
|
|
|
|
// Return whether a section is a .gnu.linkonce section, given the
|
|
// section name.
|
|
static inline bool
|
|
is_linkonce(const char* name)
|
|
{ return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
|
|
|
|
// Whether we have added an input section.
|
|
bool
|
|
have_added_input_section() const
|
|
{ return this->have_added_input_section_; }
|
|
|
|
// Return true if a section is a debugging section.
|
|
static inline bool
|
|
is_debug_info_section(const char* name)
|
|
{
|
|
// Debugging sections can only be recognized by name.
|
|
return (strncmp(name, ".debug", sizeof(".debug") - 1) == 0
|
|
|| strncmp(name, ".zdebug", sizeof(".zdebug") - 1) == 0
|
|
|| strncmp(name, ".gnu.linkonce.wi.",
|
|
sizeof(".gnu.linkonce.wi.") - 1) == 0
|
|
|| strncmp(name, ".line", sizeof(".line") - 1) == 0
|
|
|| strncmp(name, ".stab", sizeof(".stab") - 1) == 0
|
|
|| strncmp(name, ".pdr", sizeof(".pdr") - 1) == 0);
|
|
}
|
|
|
|
// 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".
|
|
static bool
|
|
match_file_name(const Relobj* relobj, const char* file_name);
|
|
|
|
// Return whether section SHNDX in RELOBJ is a .ctors/.dtors section
|
|
// with more than one word being mapped to a .init_array/.fini_array
|
|
// section.
|
|
bool
|
|
is_ctors_in_init_array(Relobj* relobj, unsigned int shndx) const;
|
|
|
|
// 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 signature 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 return
|
|
// false.
|
|
bool
|
|
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);
|
|
|
|
// Finalize the layout after all the input sections have been added.
|
|
off_t
|
|
finalize(const Input_objects*, Symbol_table*, Target*, const Task*);
|
|
|
|
// Return whether any sections require postprocessing.
|
|
bool
|
|
any_postprocessing_sections() const
|
|
{ return this->any_postprocessing_sections_; }
|
|
|
|
// Return the size of the output file.
|
|
off_t
|
|
output_file_size() const
|
|
{ return this->output_file_size_; }
|
|
|
|
// Return the TLS segment. This will return NULL if there isn't
|
|
// one.
|
|
Output_segment*
|
|
tls_segment() const
|
|
{ return this->tls_segment_; }
|
|
|
|
// Return the normal symbol table.
|
|
Output_section*
|
|
symtab_section() const
|
|
{
|
|
gold_assert(this->symtab_section_ != NULL);
|
|
return this->symtab_section_;
|
|
}
|
|
|
|
// Return the file offset of the normal symbol table.
|
|
off_t
|
|
symtab_section_offset() const;
|
|
|
|
// Return the section index of the normal symbol tabl.e
|
|
unsigned int
|
|
symtab_section_shndx() const;
|
|
|
|
// Return the dynamic symbol table.
|
|
Output_section*
|
|
dynsym_section() const
|
|
{
|
|
gold_assert(this->dynsym_section_ != NULL);
|
|
return this->dynsym_section_;
|
|
}
|
|
|
|
// Return the dynamic tags.
|
|
Output_data_dynamic*
|
|
dynamic_data() const
|
|
{ return this->dynamic_data_; }
|
|
|
|
// Write out the output sections.
|
|
void
|
|
write_output_sections(Output_file* of) const;
|
|
|
|
// Write out data not associated with an input file or the symbol
|
|
// table.
|
|
void
|
|
write_data(const Symbol_table*, Output_file*) const;
|
|
|
|
// Write out output sections which can not be written until all the
|
|
// input sections are complete.
|
|
void
|
|
write_sections_after_input_sections(Output_file* of);
|
|
|
|
// Return an output section named NAME, or NULL if there is none.
|
|
Output_section*
|
|
find_output_section(const char* name) const;
|
|
|
|
// 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*
|
|
find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
|
|
elfcpp::Elf_Word clear) const;
|
|
|
|
// Return the number of segments we expect to produce.
|
|
size_t
|
|
expected_segment_count() const;
|
|
|
|
// Set a flag to indicate that an object file uses the static TLS model.
|
|
void
|
|
set_has_static_tls()
|
|
{ this->has_static_tls_ = true; }
|
|
|
|
// Return true if any object file uses the static TLS model.
|
|
bool
|
|
has_static_tls() const
|
|
{ return this->has_static_tls_; }
|
|
|
|
// Return the options which may be set by a linker script.
|
|
Script_options*
|
|
script_options()
|
|
{ return this->script_options_; }
|
|
|
|
const Script_options*
|
|
script_options() const
|
|
{ return this->script_options_; }
|
|
|
|
// Return the object managing inputs in incremental build. NULL in
|
|
// non-incremental builds.
|
|
Incremental_inputs*
|
|
incremental_inputs() const
|
|
{ return this->incremental_inputs_; }
|
|
|
|
// For the target-specific code to add dynamic tags which are common
|
|
// to most targets.
|
|
void
|
|
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);
|
|
|
|
// Add a target-specific dynamic tag with constant value.
|
|
void
|
|
add_target_specific_dynamic_tag(elfcpp::DT tag, unsigned int val);
|
|
|
|
// Compute and write out the build ID if needed.
|
|
void
|
|
write_build_id(Output_file*, unsigned char*, size_t) const;
|
|
|
|
// Rewrite output file in binary format.
|
|
void
|
|
write_binary(Output_file* in) const;
|
|
|
|
// Print output sections to the map file.
|
|
void
|
|
print_to_mapfile(Mapfile*) const;
|
|
|
|
// Dump statistical information to stderr.
|
|
void
|
|
print_stats() const;
|
|
|
|
// A list of segments.
|
|
|
|
typedef std::vector<Output_segment*> Segment_list;
|
|
|
|
// A list of sections.
|
|
|
|
typedef std::vector<Output_section*> Section_list;
|
|
|
|
// The list of information to write out which is not attached to
|
|
// either a section or a segment.
|
|
typedef std::vector<Output_data*> Data_list;
|
|
|
|
// Store the allocated sections into the section list. This is used
|
|
// by the linker script code.
|
|
void
|
|
get_allocated_sections(Section_list*) const;
|
|
|
|
// Store the executable sections into the section list.
|
|
void
|
|
get_executable_sections(Section_list*) const;
|
|
|
|
// Make a section for a linker script to hold data.
|
|
Output_section*
|
|
make_output_section_for_script(const char* name,
|
|
Script_sections::Section_type section_type);
|
|
|
|
// Make a segment. This is used by the linker script code.
|
|
Output_segment*
|
|
make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags);
|
|
|
|
// Return the number of segments.
|
|
size_t
|
|
segment_count() const
|
|
{ return this->segment_list_.size(); }
|
|
|
|
// Map from section flags to segment flags.
|
|
static elfcpp::Elf_Word
|
|
section_flags_to_segment(elfcpp::Elf_Xword flags);
|
|
|
|
// Attach sections to segments.
|
|
void
|
|
attach_sections_to_segments(const Target*);
|
|
|
|
// For relaxation clean up, we need to know output section data created
|
|
// from a linker script.
|
|
void
|
|
new_output_section_data_from_script(Output_section_data* posd)
|
|
{
|
|
if (this->record_output_section_data_from_script_)
|
|
this->script_output_section_data_list_.push_back(posd);
|
|
}
|
|
|
|
// Return section list.
|
|
const Section_list&
|
|
section_list() const
|
|
{ return this->section_list_; }
|
|
|
|
// Returns TRUE iff NAME (an input section from RELOBJ) will
|
|
// be mapped to an output section that should be KEPT.
|
|
bool
|
|
keep_input_section(const Relobj*, const char*);
|
|
|
|
// Add a special output object that will be recreated afresh
|
|
// if there is another relaxation iteration.
|
|
void
|
|
add_relax_output(Output_data* data)
|
|
{ this->relax_output_list_.push_back(data); }
|
|
|
|
// Clear out (and free) everything added by add_relax_output.
|
|
void
|
|
reset_relax_output();
|
|
|
|
private:
|
|
Layout(const Layout&);
|
|
Layout& operator=(const Layout&);
|
|
|
|
// Mapping from input section names to output section names.
|
|
struct Section_name_mapping
|
|
{
|
|
const char* from;
|
|
int fromlen;
|
|
const char* to;
|
|
int tolen;
|
|
};
|
|
static const Section_name_mapping section_name_mapping[];
|
|
static const int section_name_mapping_count;
|
|
static const Section_name_mapping text_section_name_mapping[];
|
|
static const int text_section_name_mapping_count;
|
|
|
|
// Find section name NAME in map and return the mapped name if found
|
|
// with the length set in PLEN.
|
|
static const char* match_section_name(const Section_name_mapping* map,
|
|
const int count, const char* name,
|
|
size_t* plen);
|
|
|
|
// During a relocatable link, a list of group sections and
|
|
// signatures.
|
|
struct Group_signature
|
|
{
|
|
// The group section.
|
|
Output_section* section;
|
|
// The signature.
|
|
const char* signature;
|
|
|
|
Group_signature()
|
|
: section(NULL), signature(NULL)
|
|
{ }
|
|
|
|
Group_signature(Output_section* sectiona, const char* signaturea)
|
|
: section(sectiona), signature(signaturea)
|
|
{ }
|
|
};
|
|
typedef std::vector<Group_signature> Group_signatures;
|
|
|
|
// Create a note section, filling in the header.
|
|
Output_section*
|
|
create_note(const char* name, int note_type, const char* section_name,
|
|
size_t descsz, bool allocate, size_t* trailing_padding);
|
|
|
|
// Create a note section for gold version.
|
|
void
|
|
create_gold_note();
|
|
|
|
// Record whether the stack must be executable, and a user-supplied size.
|
|
void
|
|
create_stack_segment();
|
|
|
|
// Create a build ID note if needed.
|
|
void
|
|
create_build_id();
|
|
|
|
// Link .stab and .stabstr sections.
|
|
void
|
|
link_stabs_sections();
|
|
|
|
// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
|
|
// for the next run of incremental linking to check what has changed.
|
|
void
|
|
create_incremental_info_sections(Symbol_table*);
|
|
|
|
// Find the first read-only PT_LOAD segment, creating one if
|
|
// necessary.
|
|
Output_segment*
|
|
find_first_load_seg(const Target*);
|
|
|
|
// Count the local symbols in the regular symbol table and the dynamic
|
|
// symbol table, and build the respective string pools.
|
|
void
|
|
count_local_symbols(const Task*, const Input_objects*);
|
|
|
|
// Create the output sections for the symbol table.
|
|
void
|
|
create_symtab_sections(const Input_objects*, Symbol_table*,
|
|
unsigned int, off_t*, unsigned int);
|
|
|
|
// Create the .shstrtab section.
|
|
Output_section*
|
|
create_shstrtab();
|
|
|
|
// Create the section header table.
|
|
void
|
|
create_shdrs(const Output_section* shstrtab_section, off_t*);
|
|
|
|
// Create the dynamic symbol table.
|
|
void
|
|
create_dynamic_symtab(const Input_objects*, Symbol_table*,
|
|
Output_section** pdynstr,
|
|
unsigned int* plocal_dynamic_count,
|
|
unsigned int* pforced_local_dynamic_count,
|
|
std::vector<Symbol*>* pdynamic_symbols,
|
|
Versions* versions);
|
|
|
|
// Assign offsets to each local portion of the dynamic symbol table.
|
|
void
|
|
assign_local_dynsym_offsets(const Input_objects*);
|
|
|
|
// Finish the .dynamic section and PT_DYNAMIC segment.
|
|
void
|
|
finish_dynamic_section(const Input_objects*, const Symbol_table*);
|
|
|
|
// Set the size of the _DYNAMIC symbol.
|
|
void
|
|
set_dynamic_symbol_size(const Symbol_table*);
|
|
|
|
// Create the .interp section and PT_INTERP segment.
|
|
void
|
|
create_interp(const Target* target);
|
|
|
|
// Create the version sections.
|
|
void
|
|
create_version_sections(const Versions*,
|
|
const Symbol_table*,
|
|
unsigned int local_symcount,
|
|
const std::vector<Symbol*>& dynamic_symbols,
|
|
const Output_section* dynstr);
|
|
|
|
template<int size, bool big_endian>
|
|
void
|
|
sized_create_version_sections(const Versions* versions,
|
|
const Symbol_table*,
|
|
unsigned int local_symcount,
|
|
const std::vector<Symbol*>& dynamic_symbols,
|
|
const Output_section* dynstr);
|
|
|
|
// Return whether to include this section in the link.
|
|
template<int size, bool big_endian>
|
|
bool
|
|
include_section(Sized_relobj_file<size, big_endian>* object, const char* name,
|
|
const elfcpp::Shdr<size, big_endian>&);
|
|
|
|
// Return the output section name to use given an input section
|
|
// name. Set *PLEN to the length of the name. *PLEN must be
|
|
// initialized to the length of NAME.
|
|
static const char*
|
|
output_section_name(const Relobj*, const char* name, size_t* plen);
|
|
|
|
// Return the number of allocated output sections.
|
|
size_t
|
|
allocated_output_section_count() const;
|
|
|
|
// Return the output section for NAME, TYPE and FLAGS.
|
|
Output_section*
|
|
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);
|
|
|
|
// Clear the input section flags that should not be copied to the
|
|
// output section.
|
|
elfcpp::Elf_Xword
|
|
get_output_section_flags (elfcpp::Elf_Xword input_section_flags);
|
|
|
|
// Choose the output section for NAME in RELOBJ.
|
|
Output_section*
|
|
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);
|
|
|
|
// Create a new Output_section.
|
|
Output_section*
|
|
make_output_section(const char* name, elfcpp::Elf_Word type,
|
|
elfcpp::Elf_Xword flags, Output_section_order order,
|
|
bool is_relro);
|
|
|
|
// Attach a section to a segment.
|
|
void
|
|
attach_section_to_segment(const Target*, Output_section*);
|
|
|
|
// Get section order.
|
|
Output_section_order
|
|
default_section_order(Output_section*, bool is_relro_local);
|
|
|
|
// Attach an allocated section to a segment.
|
|
void
|
|
attach_allocated_section_to_segment(const Target*, Output_section*);
|
|
|
|
// Make the .eh_frame section.
|
|
Output_section*
|
|
make_eh_frame_section(const Relobj*);
|
|
|
|
// Set the final file offsets of all the segments.
|
|
off_t
|
|
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
|
|
|
// Set the file offsets of the sections when doing a relocatable
|
|
// link.
|
|
off_t
|
|
set_relocatable_section_offsets(Output_data*, unsigned int* pshndx);
|
|
|
|
// Set the final file offsets of all the sections not associated
|
|
// with a segment. We set section offsets in three passes: the
|
|
// first handles all allocated sections, the second sections that
|
|
// require postprocessing, and the last the late-bound STRTAB
|
|
// sections (probably only shstrtab, which is the one we care about
|
|
// because it holds section names).
|
|
enum Section_offset_pass
|
|
{
|
|
BEFORE_INPUT_SECTIONS_PASS,
|
|
POSTPROCESSING_SECTIONS_PASS,
|
|
STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS
|
|
};
|
|
off_t
|
|
set_section_offsets(off_t, Section_offset_pass pass);
|
|
|
|
// Set the final section indexes of all the sections not associated
|
|
// with a segment. Returns the next unused index.
|
|
unsigned int
|
|
set_section_indexes(unsigned int pshndx);
|
|
|
|
// Set the section addresses when using a script.
|
|
Output_segment*
|
|
set_section_addresses_from_script(Symbol_table*);
|
|
|
|
// Find appropriate places or orphan sections in a script.
|
|
void
|
|
place_orphan_sections_in_script();
|
|
|
|
// Return whether SEG1 comes before SEG2 in the output file.
|
|
bool
|
|
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
|
|
|
|
// Use to save and restore segments during relaxation.
|
|
typedef Unordered_map<const Output_segment*, const Output_segment*>
|
|
Segment_states;
|
|
|
|
// Save states of current output segments.
|
|
void
|
|
save_segments(Segment_states*);
|
|
|
|
// Restore output segment states.
|
|
void
|
|
restore_segments(const Segment_states*);
|
|
|
|
// Clean up after relaxation so that it is possible to lay out the
|
|
// sections and segments again.
|
|
void
|
|
clean_up_after_relaxation();
|
|
|
|
// Doing preparation work for relaxation. This is factored out to make
|
|
// Layout::finalized a bit smaller and easier to read.
|
|
void
|
|
prepare_for_relaxation();
|
|
|
|
// Main body of the relaxation loop, which lays out the section.
|
|
off_t
|
|
relaxation_loop_body(int, Target*, Symbol_table*, Output_segment**,
|
|
Output_segment*, Output_segment_headers*,
|
|
Output_file_header*, unsigned int*);
|
|
|
|
// A mapping used for kept comdats/.gnu.linkonce group signatures.
|
|
typedef Unordered_map<std::string, Kept_section> Signatures;
|
|
|
|
// Mapping from input section name/type/flags to output section. We
|
|
// use canonicalized strings here.
|
|
|
|
typedef std::pair<Stringpool::Key,
|
|
std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key;
|
|
|
|
struct Hash_key
|
|
{
|
|
size_t
|
|
operator()(const Key& k) const;
|
|
};
|
|
|
|
typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
|
|
|
|
// A comparison class for segments.
|
|
|
|
class Compare_segments
|
|
{
|
|
public:
|
|
Compare_segments(Layout* layout)
|
|
: layout_(layout)
|
|
{ }
|
|
|
|
bool
|
|
operator()(const Output_segment* seg1, const Output_segment* seg2)
|
|
{ return this->layout_->segment_precedes(seg1, seg2); }
|
|
|
|
private:
|
|
Layout* layout_;
|
|
};
|
|
|
|
typedef std::vector<Output_section_data*> Output_section_data_list;
|
|
|
|
// Debug checker class.
|
|
class Relaxation_debug_check
|
|
{
|
|
public:
|
|
Relaxation_debug_check()
|
|
: section_infos_()
|
|
{ }
|
|
|
|
// Check that sections and special data are in reset states.
|
|
void
|
|
check_output_data_for_reset_values(const Layout::Section_list&,
|
|
const Layout::Data_list& special_outputs,
|
|
const Layout::Data_list& relax_outputs);
|
|
|
|
// Record information of a section list.
|
|
void
|
|
read_sections(const Layout::Section_list&);
|
|
|
|
// Verify a section list with recorded information.
|
|
void
|
|
verify_sections(const Layout::Section_list&);
|
|
|
|
private:
|
|
// Information we care about a section.
|
|
struct Section_info
|
|
{
|
|
// Output section described by this.
|
|
Output_section* output_section;
|
|
// Load address.
|
|
uint64_t address;
|
|
// Data size.
|
|
off_t data_size;
|
|
// File offset.
|
|
off_t offset;
|
|
};
|
|
|
|
// Section information.
|
|
std::vector<Section_info> section_infos_;
|
|
};
|
|
|
|
// The number of input files, for sizing tables.
|
|
int number_of_input_files_;
|
|
// Information set by scripts or by command line options.
|
|
Script_options* script_options_;
|
|
// The output section names.
|
|
Stringpool namepool_;
|
|
// The output symbol names.
|
|
Stringpool sympool_;
|
|
// The dynamic strings, if needed.
|
|
Stringpool dynpool_;
|
|
// The list of group sections and linkonce sections which we have seen.
|
|
Signatures signatures_;
|
|
// The mapping from input section name/type/flags to output sections.
|
|
Section_name_map section_name_map_;
|
|
// The list of output segments.
|
|
Segment_list segment_list_;
|
|
// The list of output sections.
|
|
Section_list section_list_;
|
|
// The list of output sections which are not attached to any output
|
|
// segment.
|
|
Section_list unattached_section_list_;
|
|
// The list of unattached Output_data objects which require special
|
|
// handling because they are not Output_sections.
|
|
Data_list special_output_list_;
|
|
// Like special_output_list_, but cleared and recreated on each
|
|
// iteration of relaxation.
|
|
Data_list relax_output_list_;
|
|
// The section headers.
|
|
Output_section_headers* section_headers_;
|
|
// A pointer to the PT_TLS segment if there is one.
|
|
Output_segment* tls_segment_;
|
|
// A pointer to the PT_GNU_RELRO segment if there is one.
|
|
Output_segment* relro_segment_;
|
|
// A pointer to the PT_INTERP segment if there is one.
|
|
Output_segment* interp_segment_;
|
|
// A backend may increase the size of the PT_GNU_RELRO segment if
|
|
// there is one. This is the amount to increase it by.
|
|
unsigned int increase_relro_;
|
|
// The SHT_SYMTAB output section.
|
|
Output_section* symtab_section_;
|
|
// The SHT_SYMTAB_SHNDX for the regular symbol table if there is one.
|
|
Output_symtab_xindex* symtab_xindex_;
|
|
// The SHT_DYNSYM output section if there is one.
|
|
Output_section* dynsym_section_;
|
|
// The SHT_SYMTAB_SHNDX for the dynamic symbol table if there is one.
|
|
Output_symtab_xindex* dynsym_xindex_;
|
|
// The SHT_DYNAMIC output section if there is one.
|
|
Output_section* dynamic_section_;
|
|
// The _DYNAMIC symbol if there is one.
|
|
Symbol* dynamic_symbol_;
|
|
// The dynamic data which goes into dynamic_section_.
|
|
Output_data_dynamic* dynamic_data_;
|
|
// The exception frame output section if there is one.
|
|
Output_section* eh_frame_section_;
|
|
// The exception frame data for eh_frame_section_.
|
|
Eh_frame* eh_frame_data_;
|
|
// Whether we have added eh_frame_data_ to the .eh_frame section.
|
|
bool added_eh_frame_data_;
|
|
// The exception frame header output section if there is one.
|
|
Output_section* eh_frame_hdr_section_;
|
|
// The data for the .gdb_index section.
|
|
Gdb_index* gdb_index_data_;
|
|
// The space for the build ID checksum if there is one.
|
|
Output_section_data* build_id_note_;
|
|
// The output section containing dwarf abbreviations
|
|
Output_reduced_debug_abbrev_section* debug_abbrev_;
|
|
// The output section containing the dwarf debug info tree
|
|
Output_reduced_debug_info_section* debug_info_;
|
|
// A list of group sections and their signatures.
|
|
Group_signatures group_signatures_;
|
|
// The size of the output file.
|
|
off_t output_file_size_;
|
|
// Whether we have added an input section to an output section.
|
|
bool have_added_input_section_;
|
|
// Whether we have attached the sections to the segments.
|
|
bool sections_are_attached_;
|
|
// Whether we have seen an object file marked to require an
|
|
// executable stack.
|
|
bool input_requires_executable_stack_;
|
|
// Whether we have seen at least one object file with an executable
|
|
// stack marker.
|
|
bool input_with_gnu_stack_note_;
|
|
// Whether we have seen at least one object file without an
|
|
// executable stack marker.
|
|
bool input_without_gnu_stack_note_;
|
|
// Whether we have seen an object file that uses the static TLS model.
|
|
bool has_static_tls_;
|
|
// Whether any sections require postprocessing.
|
|
bool any_postprocessing_sections_;
|
|
// Whether we have resized the signatures_ hash table.
|
|
bool resized_signatures_;
|
|
// Whether we have created a .stab*str output section.
|
|
bool have_stabstr_section_;
|
|
// True if the input sections in the output sections should be sorted
|
|
// as specified in a section ordering file.
|
|
bool section_ordering_specified_;
|
|
// True if some input sections need to be mapped to a unique segment,
|
|
// after being mapped to a unique Output_section.
|
|
bool unique_segment_for_sections_specified_;
|
|
// In incremental build, holds information check the inputs and build the
|
|
// .gnu_incremental_inputs section.
|
|
Incremental_inputs* incremental_inputs_;
|
|
// Whether we record output section data created in script
|
|
bool record_output_section_data_from_script_;
|
|
// List of output data that needs to be removed at relaxation clean up.
|
|
Output_section_data_list script_output_section_data_list_;
|
|
// Structure to save segment states before entering the relaxation loop.
|
|
Segment_states* segment_states_;
|
|
// A relaxation debug checker. We only create one when in debugging mode.
|
|
Relaxation_debug_check* relaxation_debug_check_;
|
|
// Plugins specify section_ordering using this map. This is set in
|
|
// update_section_order in plugin.cc
|
|
std::map<Section_id, unsigned int> section_order_map_;
|
|
// This maps an input section to a unique segment. This is done by first
|
|
// placing such input sections in unique output sections and then mapping
|
|
// the output section to a unique segment. Unique_segment_info stores
|
|
// any additional flags and alignment of the new segment.
|
|
Section_segment_map section_segment_map_;
|
|
// Hash a pattern to its position in the section ordering file.
|
|
Unordered_map<std::string, unsigned int> input_section_position_;
|
|
// Vector of glob only patterns in the section_ordering file.
|
|
std::vector<std::string> input_section_glob_;
|
|
// For incremental links, the base file to be modified.
|
|
Incremental_binary* incremental_base_;
|
|
// For incremental links, a list of free space within the file.
|
|
Free_list free_list_;
|
|
};
|
|
|
|
// This task handles writing out data in output sections which is not
|
|
// part of an input section, or which requires special handling. When
|
|
// this is done, it unblocks both output_sections_blocker and
|
|
// final_blocker.
|
|
|
|
class Write_sections_task : public Task
|
|
{
|
|
public:
|
|
Write_sections_task(const Layout* layout, Output_file* of,
|
|
Task_token* output_sections_blocker,
|
|
Task_token* input_sections_blocker,
|
|
Task_token* final_blocker)
|
|
: layout_(layout), of_(of),
|
|
output_sections_blocker_(output_sections_blocker),
|
|
input_sections_blocker_(input_sections_blocker),
|
|
final_blocker_(final_blocker)
|
|
{ }
|
|
|
|
// The standard Task methods.
|
|
|
|
Task_token*
|
|
is_runnable();
|
|
|
|
void
|
|
locks(Task_locker*);
|
|
|
|
void
|
|
run(Workqueue*);
|
|
|
|
std::string
|
|
get_name() const
|
|
{ return "Write_sections_task"; }
|
|
|
|
private:
|
|
class Write_sections_locker;
|
|
|
|
const Layout* layout_;
|
|
Output_file* of_;
|
|
Task_token* output_sections_blocker_;
|
|
Task_token* input_sections_blocker_;
|
|
Task_token* final_blocker_;
|
|
};
|
|
|
|
// This task handles writing out data which is not part of a section
|
|
// or segment.
|
|
|
|
class Write_data_task : public Task
|
|
{
|
|
public:
|
|
Write_data_task(const Layout* layout, const Symbol_table* symtab,
|
|
Output_file* of, Task_token* final_blocker)
|
|
: layout_(layout), symtab_(symtab), of_(of), final_blocker_(final_blocker)
|
|
{ }
|
|
|
|
// The standard Task methods.
|
|
|
|
Task_token*
|
|
is_runnable();
|
|
|
|
void
|
|
locks(Task_locker*);
|
|
|
|
void
|
|
run(Workqueue*);
|
|
|
|
std::string
|
|
get_name() const
|
|
{ return "Write_data_task"; }
|
|
|
|
private:
|
|
const Layout* layout_;
|
|
const Symbol_table* symtab_;
|
|
Output_file* of_;
|
|
Task_token* final_blocker_;
|
|
};
|
|
|
|
// This task handles writing out the global symbols.
|
|
|
|
class Write_symbols_task : public Task
|
|
{
|
|
public:
|
|
Write_symbols_task(const Layout* layout, const Symbol_table* symtab,
|
|
const Input_objects* /*input_objects*/,
|
|
const Stringpool* sympool, const Stringpool* dynpool,
|
|
Output_file* of, Task_token* final_blocker)
|
|
: layout_(layout), symtab_(symtab),
|
|
sympool_(sympool), dynpool_(dynpool), of_(of),
|
|
final_blocker_(final_blocker)
|
|
{ }
|
|
|
|
// The standard Task methods.
|
|
|
|
Task_token*
|
|
is_runnable();
|
|
|
|
void
|
|
locks(Task_locker*);
|
|
|
|
void
|
|
run(Workqueue*);
|
|
|
|
std::string
|
|
get_name() const
|
|
{ return "Write_symbols_task"; }
|
|
|
|
private:
|
|
const Layout* layout_;
|
|
const Symbol_table* symtab_;
|
|
const Stringpool* sympool_;
|
|
const Stringpool* dynpool_;
|
|
Output_file* of_;
|
|
Task_token* final_blocker_;
|
|
};
|
|
|
|
// This task handles writing out data in output sections which can't
|
|
// be written out until all the input sections have been handled.
|
|
// This is for sections whose contents is based on the contents of
|
|
// other output sections.
|
|
|
|
class Write_after_input_sections_task : public Task
|
|
{
|
|
public:
|
|
Write_after_input_sections_task(Layout* layout, Output_file* of,
|
|
Task_token* input_sections_blocker,
|
|
Task_token* final_blocker)
|
|
: layout_(layout), of_(of),
|
|
input_sections_blocker_(input_sections_blocker),
|
|
final_blocker_(final_blocker)
|
|
{ }
|
|
|
|
// The standard Task methods.
|
|
|
|
Task_token*
|
|
is_runnable();
|
|
|
|
void
|
|
locks(Task_locker*);
|
|
|
|
void
|
|
run(Workqueue*);
|
|
|
|
std::string
|
|
get_name() const
|
|
{ return "Write_after_input_sections_task"; }
|
|
|
|
private:
|
|
Layout* layout_;
|
|
Output_file* of_;
|
|
Task_token* input_sections_blocker_;
|
|
Task_token* final_blocker_;
|
|
};
|
|
|
|
// This task function handles computation of the build id.
|
|
// When using --build-id=tree, it schedules the tasks that
|
|
// compute the hashes for each chunk of the file. This task
|
|
// cannot run until we have finalized the size of the output
|
|
// file, after the completion of Write_after_input_sections_task.
|
|
|
|
class Build_id_task_runner : public Task_function_runner
|
|
{
|
|
public:
|
|
Build_id_task_runner(const General_options* options, const Layout* layout,
|
|
Output_file* of)
|
|
: options_(options), layout_(layout), of_(of)
|
|
{ }
|
|
|
|
// Run the operation.
|
|
void
|
|
run(Workqueue*, const Task*);
|
|
|
|
private:
|
|
const General_options* options_;
|
|
const Layout* layout_;
|
|
Output_file* of_;
|
|
};
|
|
|
|
// This task function handles closing the file.
|
|
|
|
class Close_task_runner : public Task_function_runner
|
|
{
|
|
public:
|
|
Close_task_runner(const General_options* options, const Layout* layout,
|
|
Output_file* of, unsigned char* array_of_hashes,
|
|
size_t size_of_hashes)
|
|
: options_(options), layout_(layout), of_(of),
|
|
array_of_hashes_(array_of_hashes), size_of_hashes_(size_of_hashes)
|
|
{ }
|
|
|
|
// Run the operation.
|
|
void
|
|
run(Workqueue*, const Task*);
|
|
|
|
private:
|
|
const General_options* options_;
|
|
const Layout* layout_;
|
|
Output_file* of_;
|
|
unsigned char* const array_of_hashes_;
|
|
const size_t size_of_hashes_;
|
|
};
|
|
|
|
// A small helper function to align an address.
|
|
|
|
inline uint64_t
|
|
align_address(uint64_t address, uint64_t addralign)
|
|
{
|
|
if (addralign != 0)
|
|
address = (address + addralign - 1) &~ (addralign - 1);
|
|
return address;
|
|
}
|
|
|
|
} // End namespace gold.
|
|
|
|
#endif // !defined(GOLD_LAYOUT_H)
|