Line 1... |
Line 1... |
// layout.h -- lay out output file sections for gold -*- C++ -*-
|
// layout.h -- lay out output file sections for gold -*- C++ -*-
|
|
|
// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
// Written by Ian Lance Taylor <iant@google.com>.
|
// Written by Ian Lance Taylor <iant@google.com>.
|
|
|
// This file is part of gold.
|
// This file is part of gold.
|
|
|
// This program is free software; you can redistribute it and/or modify
|
// This program is free software; you can redistribute it and/or modify
|
Line 69... |
Line 69... |
// Used for incremental update links.
|
// Used for incremental update links.
|
|
|
class Free_list
|
class Free_list
|
{
|
{
|
public:
|
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()
|
Free_list()
|
: list_(), last_remove_(list_.begin()), extend_(false), length_(0)
|
: 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
|
void
|
init(off_t len, bool extend);
|
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
|
void
|
remove(off_t start, off_t end);
|
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
|
off_t
|
allocate(off_t len, uint64_t align, off_t minoff);
|
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
|
void
|
dump();
|
dump();
|
|
|
|
// Print usage statistics.
|
static void
|
static void
|
print_stats();
|
print_stats();
|
|
|
private:
|
private:
|
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>::iterator Iterator;
|
typedef std::list<Free_list_node>::iterator Iterator;
|
|
|
// The free list.
|
// The free list.
|
std::list<Free_list_node> list_;
|
std::list<Free_list_node> list_;
|
|
|
Line 111... |
Line 137... |
bool extend_;
|
bool extend_;
|
|
|
// The total length of the section, segment, or file.
|
// The total length of the section, segment, or file.
|
off_t length_;
|
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:
|
// Statistics:
|
// The total number of free lists used.
|
// The total number of free lists used.
|
static unsigned int num_lists;
|
static unsigned int num_lists;
|
// The total number of free list nodes used.
|
// The total number of free list nodes used.
|
static unsigned int num_nodes;
|
static unsigned int num_nodes;
|
Line 490... |
Line 520... |
Output_section*
|
Output_section*
|
layout(Sized_relobj_file<size, big_endian> *object, unsigned int shndx,
|
layout(Sized_relobj_file<size, big_endian> *object, unsigned int shndx,
|
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
|
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
|
unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
|
unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
|
|
|
|
bool
|
|
is_section_ordering_specified()
|
|
{ return this->section_ordering_specified_; }
|
|
|
|
void
|
|
set_section_ordering_specified()
|
|
{ this->section_ordering_specified_ = true; }
|
|
|
// For incremental updates, allocate a block of memory from the
|
// For incremental updates, allocate a block of memory from the
|
// free list. Find a block starting at or after MINOFF.
|
// free list. Find a block starting at or after MINOFF.
|
off_t
|
off_t
|
allocate(off_t len, uint64_t align, off_t minoff)
|
allocate(off_t len, uint64_t align, off_t minoff)
|
{ return this->free_list_.allocate(len, align, minoff); }
|
{ return this->free_list_.allocate(len, align, minoff); }
|
|
|
unsigned int
|
unsigned int
|
find_section_order_index(const std::string&);
|
find_section_order_index(const std::string&);
|
|
|
|
// Read the sequence of input sections from the file specified with
|
|
// linker option --section-ordering-file.
|
void
|
void
|
read_layout_from_file();
|
read_layout_from_file();
|
|
|
// Layout an input reloc section when doing a relocatable link. The
|
// Layout an input reloc section when doing a relocatable link. The
|
// section is RELOC_SHNDX in OBJECT, with data in SHDR.
|
// section is RELOC_SHNDX in OBJECT, with data in SHDR.
|
Line 547... |
Line 587... |
unsigned int shndx,
|
unsigned int shndx,
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
const elfcpp::Shdr<size, big_endian>& shdr,
|
unsigned int reloc_shndx, unsigned int reloc_type,
|
unsigned int reloc_shndx, unsigned int reloc_type,
|
off_t* offset);
|
off_t* offset);
|
|
|
|
// 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);
|
|
|
// Handle a GNU stack note. This is called once per input object
|
// Handle a GNU stack note. This is called once per input object
|
// file. SEEN_GNU_STACK is true if the object file has a
|
// file. SEEN_GNU_STACK is true if the object file has a
|
// .note.GNU-stack section. GNU_STACK_FLAGS is the section flags
|
// .note.GNU-stack section. GNU_STACK_FLAGS is the section flags
|
// from that section if there was one.
|
// from that section if there was one.
|
void
|
void
|
Line 607... |
Line 655... |
// tags.
|
// tags.
|
const Stringpool*
|
const Stringpool*
|
dynpool() const
|
dynpool() const
|
{ return &this->dynpool_; }
|
{ 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
|
// Return the symtab_xindex section used to hold large section
|
// indexes for the normal symbol table.
|
// indexes for the normal symbol table.
|
Output_symtab_xindex*
|
Output_symtab_xindex*
|
symtab_xindex() const
|
symtab_xindex() const
|
{ return this->symtab_xindex_; }
|
{ return this->symtab_xindex_; }
|
Line 643... |
Line 697... |
sizeof(".gnu.linkonce.wi.") - 1) == 0
|
sizeof(".gnu.linkonce.wi.") - 1) == 0
|
|| strncmp(name, ".line", sizeof(".line") - 1) == 0
|
|| strncmp(name, ".line", sizeof(".line") - 1) == 0
|
|| strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
|
|| strncmp(name, ".stab", sizeof(".stab") - 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
|
// Check if a comdat group or .gnu.linkonce section with the given
|
// NAME is selected for the link. If there is already a section,
|
// NAME is selected for the link. If there is already a section,
|
// *KEPT_SECTION is set to point to the signature and the function
|
// *KEPT_SECTION is set to point to the signature and the function
|
// returns false. Otherwise, OBJECT, SHNDX,IS_COMDAT, and
|
// returns false. Otherwise, OBJECT, SHNDX,IS_COMDAT, and
|
// IS_GROUP_NAME are recorded for this NAME in the layout object,
|
// IS_GROUP_NAME are recorded for this NAME in the layout object,
|
Line 687... |
Line 753... |
|
|
// Return the file offset of the normal symbol table.
|
// Return the file offset of the normal symbol table.
|
off_t
|
off_t
|
symtab_section_offset() const;
|
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.
|
// Return the dynamic symbol table.
|
Output_section*
|
Output_section*
|
dynsym_section() const
|
dynsym_section() const
|
{
|
{
|
gold_assert(this->dynsym_section_ != NULL);
|
gold_assert(this->dynsym_section_ != NULL);
|
Line 963... |
Line 1033... |
|
|
// Return the output section name to use given an input section
|
// Return the output section name to use given an input section
|
// name. Set *PLEN to the length of the name. *PLEN must be
|
// name. Set *PLEN to the length of the name. *PLEN must be
|
// initialized to the length of NAME.
|
// initialized to the length of NAME.
|
static const char*
|
static const char*
|
output_section_name(const char* name, size_t* plen);
|
output_section_name(const Relobj*, const char* name, size_t* plen);
|
|
|
// Return the number of allocated output sections.
|
// Return the number of allocated output sections.
|
size_t
|
size_t
|
allocated_output_section_count() const;
|
allocated_output_section_count() const;
|
|
|
Line 1000... |
Line 1070... |
|
|
// Attach an allocated section to a segment.
|
// Attach an allocated section to a segment.
|
void
|
void
|
attach_allocated_section_to_segment(Output_section*);
|
attach_allocated_section_to_segment(Output_section*);
|
|
|
|
// Make the .eh_frame section.
|
|
Output_section*
|
|
make_eh_frame_section(const Relobj*);
|
|
|
// Set the final file offsets of all the segments.
|
// Set the final file offsets of all the segments.
|
off_t
|
off_t
|
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
|
|
// Set the file offsets of the sections when doing a relocatable
|
// Set the file offsets of the sections when doing a relocatable
|
Line 1038... |
Line 1112... |
// Find appropriate places or orphan sections in a script.
|
// Find appropriate places or orphan sections in a script.
|
void
|
void
|
place_orphan_sections_in_script();
|
place_orphan_sections_in_script();
|
|
|
// Return whether SEG1 comes before SEG2 in the output file.
|
// Return whether SEG1 comes before SEG2 in the output file.
|
static bool
|
bool
|
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
|
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
|
|
|
// Use to save and restore segments during relaxation.
|
// Use to save and restore segments during relaxation.
|
typedef Unordered_map<const Output_segment*, const Output_segment*>
|
typedef Unordered_map<const Output_segment*, const Output_segment*>
|
Segment_states;
|
Segment_states;
|
Line 1088... |
Line 1162... |
|
|
typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
|
typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
|
|
|
// A comparison class for segments.
|
// A comparison class for segments.
|
|
|
struct Compare_segments
|
class Compare_segments
|
{
|
{
|
|
public:
|
|
Compare_segments(Layout* layout)
|
|
: layout_(layout)
|
|
{ }
|
|
|
bool
|
bool
|
operator()(const Output_segment* seg1, const Output_segment* seg2)
|
operator()(const Output_segment* seg1, const Output_segment* seg2)
|
{ return Layout::segment_precedes(seg1, seg2); }
|
{ return this->layout_->segment_precedes(seg1, seg2); }
|
|
|
|
private:
|
|
Layout* layout_;
|
};
|
};
|
|
|
typedef std::vector<Output_section_data*> Output_section_data_list;
|
typedef std::vector<Output_section_data*> Output_section_data_list;
|
|
|
// Debug checker class.
|
// Debug checker class.
|
Line 1166... |
Line 1248... |
Output_section_headers* section_headers_;
|
Output_section_headers* section_headers_;
|
// A pointer to the PT_TLS segment if there is one.
|
// A pointer to the PT_TLS segment if there is one.
|
Output_segment* tls_segment_;
|
Output_segment* tls_segment_;
|
// A pointer to the PT_GNU_RELRO segment if there is one.
|
// A pointer to the PT_GNU_RELRO segment if there is one.
|
Output_segment* relro_segment_;
|
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
|
// A backend may increase the size of the PT_GNU_RELRO segment if
|
// there is one. This is the amount to increase it by.
|
// there is one. This is the amount to increase it by.
|
unsigned int increase_relro_;
|
unsigned int increase_relro_;
|
// The SHT_SYMTAB output section.
|
// The SHT_SYMTAB output section.
|
Output_section* symtab_section_;
|
Output_section* symtab_section_;
|
Line 1222... |
Line 1306... |
bool any_postprocessing_sections_;
|
bool any_postprocessing_sections_;
|
// Whether we have resized the signatures_ hash table.
|
// Whether we have resized the signatures_ hash table.
|
bool resized_signatures_;
|
bool resized_signatures_;
|
// Whether we have created a .stab*str output section.
|
// Whether we have created a .stab*str output section.
|
bool have_stabstr_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_;
|
// In incremental build, holds information check the inputs and build the
|
// In incremental build, holds information check the inputs and build the
|
// .gnu_incremental_inputs section.
|
// .gnu_incremental_inputs section.
|
Incremental_inputs* incremental_inputs_;
|
Incremental_inputs* incremental_inputs_;
|
// Whether we record output section data created in script
|
// Whether we record output section data created in script
|
bool record_output_section_data_from_script_;
|
bool record_output_section_data_from_script_;
|