Line 34... |
Line 34... |
#include <sys/mman.h>
|
#include <sys/mman.h>
|
#endif
|
#endif
|
|
|
#include "libiberty.h"
|
#include "libiberty.h"
|
|
|
|
#include "dwarf.h"
|
#include "parameters.h"
|
#include "parameters.h"
|
#include "object.h"
|
#include "object.h"
|
#include "symtab.h"
|
#include "symtab.h"
|
#include "reloc.h"
|
#include "reloc.h"
|
#include "merge.h"
|
#include "merge.h"
|
#include "descriptors.h"
|
#include "descriptors.h"
|
|
#include "layout.h"
|
#include "output.h"
|
#include "output.h"
|
|
|
// For systems without mmap support.
|
// For systems without mmap support.
|
#ifndef HAVE_MMAP
|
#ifndef HAVE_MMAP
|
# define mmap gold_mmap
|
# define mmap gold_mmap
|
Line 1344... |
Line 1346... |
// If the symbol is resolved locally, we need to write out the
|
// If the symbol is resolved locally, we need to write out the
|
// link-time value, which will be relocated dynamically by a
|
// link-time value, which will be relocated dynamically by a
|
// RELATIVE relocation.
|
// RELATIVE relocation.
|
Symbol* gsym = this->u_.gsym;
|
Symbol* gsym = this->u_.gsym;
|
if (this->use_plt_offset_ && gsym->has_plt_offset())
|
if (this->use_plt_offset_ && gsym->has_plt_offset())
|
val = (parameters->target().plt_section_for_global(gsym)->address()
|
val = (parameters->target().plt_address_for_global(gsym)
|
+ gsym->plt_offset());
|
+ gsym->plt_offset());
|
else
|
else
|
{
|
{
|
Sized_symbol<size>* sgsym;
|
Sized_symbol<size>* sgsym;
|
// This cast is a bit ugly. We don't want to put a
|
// This cast is a bit ugly. We don't want to put a
|
Line 1378... |
Line 1380... |
const Symbol_value<size>* symval = object->local_symbol(lsi);
|
const Symbol_value<size>* symval = object->local_symbol(lsi);
|
if (!this->use_plt_offset_)
|
if (!this->use_plt_offset_)
|
val = symval->value(this->u_.object, 0);
|
val = symval->value(this->u_.object, 0);
|
else
|
else
|
{
|
{
|
const Output_data* plt =
|
uint64_t plt_address =
|
parameters->target().plt_section_for_local(object, lsi);
|
parameters->target().plt_address_for_local(object, lsi);
|
val = plt->address() + object->local_plt_offset(lsi);
|
val = plt_address + object->local_plt_offset(lsi);
|
}
|
}
|
}
|
}
|
break;
|
break;
|
}
|
}
|
|
|
Line 1923... |
Line 1925... |
gold_assert(symndx * 4 < this->data_size());
|
gold_assert(symndx * 4 < this->data_size());
|
elfcpp::Swap<32, big_endian>::writeval(oview + symndx * 4, p->second);
|
elfcpp::Swap<32, big_endian>::writeval(oview + symndx * 4, p->second);
|
}
|
}
|
}
|
}
|
|
|
|
// Output_fill_debug_info methods.
|
|
|
|
// Return the minimum size needed for a dummy compilation unit header.
|
|
|
|
size_t
|
|
Output_fill_debug_info::do_minimum_hole_size() const
|
|
{
|
|
// Compile unit header fields: unit_length, version, debug_abbrev_offset,
|
|
// address_size.
|
|
const size_t len = 4 + 2 + 4 + 1;
|
|
// For type units, add type_signature, type_offset.
|
|
if (this->is_debug_types_)
|
|
return len + 8 + 4;
|
|
return len;
|
|
}
|
|
|
|
// Write a dummy compilation unit header to fill a hole in the
|
|
// .debug_info or .debug_types section.
|
|
|
|
void
|
|
Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
|
|
{
|
|
gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)", off, len);
|
|
|
|
gold_assert(len >= this->do_minimum_hole_size());
|
|
|
|
unsigned char* const oview = of->get_output_view(off, len);
|
|
unsigned char* pov = oview;
|
|
|
|
// Write header fields: unit_length, version, debug_abbrev_offset,
|
|
// address_size.
|
|
if (this->is_big_endian())
|
|
{
|
|
elfcpp::Swap<32, true>::writeval(pov, len - 4);
|
|
elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
|
|
elfcpp::Swap<32, true>::writeval(pov + 6, 0);
|
|
}
|
|
else
|
|
{
|
|
elfcpp::Swap<32, false>::writeval(pov, len - 4);
|
|
elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
|
|
elfcpp::Swap<32, false>::writeval(pov + 6, 0);
|
|
}
|
|
pov += 4 + 2 + 4;
|
|
*pov++ = 4;
|
|
|
|
// For type units, the additional header fields -- type_signature,
|
|
// type_offset -- can be filled with zeroes.
|
|
|
|
// Fill the remainder of the free space with zeroes. The first
|
|
// zero should tell the consumer there are no DIEs to read in this
|
|
// compilation unit.
|
|
if (pov < oview + len)
|
|
memset(pov, 0, oview + len - pov);
|
|
|
|
of->write_output_view(off, len, oview);
|
|
}
|
|
|
|
// Output_fill_debug_line methods.
|
|
|
|
// Return the minimum size needed for a dummy line number program header.
|
|
|
|
size_t
|
|
Output_fill_debug_line::do_minimum_hole_size() const
|
|
{
|
|
// Line number program header fields: unit_length, version, header_length,
|
|
// minimum_instruction_length, default_is_stmt, line_base, line_range,
|
|
// opcode_base, standard_opcode_lengths[], include_directories, filenames.
|
|
const size_t len = 4 + 2 + 4 + this->header_length;
|
|
return len;
|
|
}
|
|
|
|
// Write a dummy line number program header to fill a hole in the
|
|
// .debug_line section.
|
|
|
|
void
|
|
Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
|
|
{
|
|
gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)", off, len);
|
|
|
|
gold_assert(len >= this->do_minimum_hole_size());
|
|
|
|
unsigned char* const oview = of->get_output_view(off, len);
|
|
unsigned char* pov = oview;
|
|
|
|
// Write header fields: unit_length, version, header_length,
|
|
// minimum_instruction_length, default_is_stmt, line_base, line_range,
|
|
// opcode_base, standard_opcode_lengths[], include_directories, filenames.
|
|
// We set the header_length field to cover the entire hole, so the
|
|
// line number program is empty.
|
|
if (this->is_big_endian())
|
|
{
|
|
elfcpp::Swap<32, true>::writeval(pov, len - 4);
|
|
elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
|
|
elfcpp::Swap<32, true>::writeval(pov + 6, len - (4 + 2 + 4));
|
|
}
|
|
else
|
|
{
|
|
elfcpp::Swap<32, false>::writeval(pov, len - 4);
|
|
elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
|
|
elfcpp::Swap<32, false>::writeval(pov + 6, len - (4 + 2 + 4));
|
|
}
|
|
pov += 4 + 2 + 4;
|
|
*pov++ = 1; // minimum_instruction_length
|
|
*pov++ = 0; // default_is_stmt
|
|
*pov++ = 0; // line_base
|
|
*pov++ = 5; // line_range
|
|
*pov++ = 13; // opcode_base
|
|
*pov++ = 0; // standard_opcode_lengths[1]
|
|
*pov++ = 1; // standard_opcode_lengths[2]
|
|
*pov++ = 1; // standard_opcode_lengths[3]
|
|
*pov++ = 1; // standard_opcode_lengths[4]
|
|
*pov++ = 1; // standard_opcode_lengths[5]
|
|
*pov++ = 0; // standard_opcode_lengths[6]
|
|
*pov++ = 0; // standard_opcode_lengths[7]
|
|
*pov++ = 0; // standard_opcode_lengths[8]
|
|
*pov++ = 1; // standard_opcode_lengths[9]
|
|
*pov++ = 0; // standard_opcode_lengths[10]
|
|
*pov++ = 0; // standard_opcode_lengths[11]
|
|
*pov++ = 1; // standard_opcode_lengths[12]
|
|
*pov++ = 0; // include_directories (empty)
|
|
*pov++ = 0; // filenames (empty)
|
|
|
|
// Some consumers don't check the header_length field, and simply
|
|
// start reading the line number program immediately following the
|
|
// header. For those consumers, we fill the remainder of the free
|
|
// space with DW_LNS_set_basic_block opcodes. These are effectively
|
|
// no-ops: the resulting line table program will not create any rows.
|
|
if (pov < oview + len)
|
|
memset(pov, elfcpp::DW_LNS_set_basic_block, oview + len - pov);
|
|
|
|
of->write_output_view(off, len, oview);
|
|
}
|
|
|
// Output_section::Input_section methods.
|
// Output_section::Input_section methods.
|
|
|
// Return the current data size. For an input section we store the size here.
|
// Return the current data size. For an input section we store the size here.
|
// For an Output_section_data, we have to ask it for the size.
|
// For an Output_section_data, we have to ask it for the size.
|
|
|
Line 2150... |
Line 2286... |
is_entsize_zero_(false),
|
is_entsize_zero_(false),
|
section_offsets_need_adjustment_(false),
|
section_offsets_need_adjustment_(false),
|
is_noload_(false),
|
is_noload_(false),
|
always_keeps_input_sections_(false),
|
always_keeps_input_sections_(false),
|
has_fixed_layout_(false),
|
has_fixed_layout_(false),
|
|
is_patch_space_allowed_(false),
|
tls_offset_(0),
|
tls_offset_(0),
|
checkpoint_(NULL),
|
checkpoint_(NULL),
|
lookup_maps_(new Output_section_lookup_maps),
|
lookup_maps_(new Output_section_lookup_maps),
|
free_list_()
|
free_list_(),
|
|
free_space_fill_(NULL),
|
|
patch_space_(0)
|
{
|
{
|
// An unallocated section has no address. Forcing this means that
|
// An unallocated section has no address. Forcing this means that
|
// we don't need special treatment for symbols defined in debug
|
// we don't need special treatment for symbols defined in debug
|
// sections.
|
// sections.
|
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
Line 2268... |
Line 2407... |
{
|
{
|
// For incremental updates, find a chunk of unused space in the section.
|
// For incremental updates, find a chunk of unused space in the section.
|
offset_in_section = this->free_list_.allocate(input_section_size,
|
offset_in_section = this->free_list_.allocate(input_section_size,
|
addralign, 0);
|
addralign, 0);
|
if (offset_in_section == -1)
|
if (offset_in_section == -1)
|
gold_fallback(_("out of patch space; relink with --incremental-full"));
|
gold_fallback(_("out of patch space in section %s; "
|
|
"relink with --incremental-full"),
|
|
this->name());
|
aligned_offset_in_section = offset_in_section;
|
aligned_offset_in_section = offset_in_section;
|
}
|
}
|
else
|
else
|
{
|
{
|
offset_in_section = this->current_data_size_for_child();
|
offset_in_section = this->current_data_size_for_child();
|
Line 2289... |
Line 2430... |
if (!this->generate_code_fills_at_write_
|
if (!this->generate_code_fills_at_write_
|
&& !have_sections_script
|
&& !have_sections_script
|
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
|
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
|
&& parameters->target().has_code_fill()
|
&& parameters->target().has_code_fill()
|
&& (parameters->target().may_relax()
|
&& (parameters->target().may_relax()
|
|| parameters->options().section_ordering_file()))
|
|| layout->is_section_ordering_specified()))
|
{
|
{
|
gold_assert(this->fills_.empty());
|
gold_assert(this->fills_.empty());
|
this->generate_code_fills_at_write_ = true;
|
this->generate_code_fills_at_write_ = true;
|
}
|
}
|
|
|
Line 2328... |
Line 2469... |
|| !this->input_sections_.empty()
|
|| !this->input_sections_.empty()
|
|| this->may_sort_attached_input_sections()
|
|| this->may_sort_attached_input_sections()
|
|| this->must_sort_attached_input_sections()
|
|| this->must_sort_attached_input_sections()
|
|| parameters->options().user_set_Map()
|
|| parameters->options().user_set_Map()
|
|| parameters->target().may_relax()
|
|| parameters->target().may_relax()
|
|| parameters->options().section_ordering_file())
|
|| layout->is_section_ordering_specified())
|
{
|
{
|
Input_section isecn(object, shndx, input_section_size, addralign);
|
Input_section isecn(object, shndx, input_section_size, addralign);
|
if (parameters->options().section_ordering_file())
|
if (layout->is_section_ordering_specified())
|
{
|
{
|
unsigned int section_order_index =
|
unsigned int section_order_index =
|
layout->find_section_order_index(std::string(secname));
|
layout->find_section_order_index(std::string(secname));
|
if (section_order_index != 0)
|
if (section_order_index != 0)
|
{
|
{
|
Line 2372... |
Line 2513... |
{
|
{
|
// For incremental updates, find a chunk of unused space.
|
// For incremental updates, find a chunk of unused space.
|
offset_in_section = this->free_list_.allocate(posd->data_size(),
|
offset_in_section = this->free_list_.allocate(posd->data_size(),
|
posd->addralign(), 0);
|
posd->addralign(), 0);
|
if (offset_in_section == -1)
|
if (offset_in_section == -1)
|
gold_fallback(_("out of patch space; "
|
gold_fallback(_("out of patch space in section %s; "
|
"relink with --incremental-full"));
|
"relink with --incremental-full"),
|
|
this->name());
|
// Finalize the address and offset now.
|
// Finalize the address and offset now.
|
uint64_t addr = this->address();
|
uint64_t addr = this->address();
|
off_t offset = this->offset();
|
off_t offset = this->offset();
|
posd->set_address_and_file_offset(addr + offset_in_section,
|
posd->set_address_and_file_offset(addr + offset_in_section,
|
offset + offset_in_section);
|
offset + offset_in_section);
|
Line 2413... |
Line 2555... |
{
|
{
|
Input_section inp(poris);
|
Input_section inp(poris);
|
|
|
// If the --section-ordering-file option is used to specify the order of
|
// If the --section-ordering-file option is used to specify the order of
|
// sections, we need to keep track of sections.
|
// sections, we need to keep track of sections.
|
if (parameters->options().section_ordering_file())
|
if (layout->is_section_ordering_specified())
|
{
|
{
|
unsigned int section_order_index =
|
unsigned int section_order_index =
|
layout->find_section_order_index(name);
|
layout->find_section_order_index(name);
|
if (section_order_index != 0)
|
if (section_order_index != 0)
|
{
|
{
|
Line 2943... |
Line 3085... |
// setting the addresses of any Output_section_data objects.
|
// setting the addresses of any Output_section_data objects.
|
|
|
void
|
void
|
Output_section::set_final_data_size()
|
Output_section::set_final_data_size()
|
{
|
{
|
|
off_t data_size;
|
|
|
if (this->input_sections_.empty())
|
if (this->input_sections_.empty())
|
|
data_size = this->current_data_size_for_child();
|
|
else
|
{
|
{
|
this->set_data_size(this->current_data_size_for_child());
|
|
return;
|
|
}
|
|
|
|
if (this->must_sort_attached_input_sections()
|
if (this->must_sort_attached_input_sections()
|
|| this->input_section_order_specified())
|
|| this->input_section_order_specified())
|
this->sort_attached_input_sections();
|
this->sort_attached_input_sections();
|
|
|
uint64_t address = this->address();
|
uint64_t address = this->address();
|
Line 2965... |
Line 3107... |
off = align_address(off, p->addralign());
|
off = align_address(off, p->addralign());
|
p->set_address_and_file_offset(address + (off - startoff), off,
|
p->set_address_and_file_offset(address + (off - startoff), off,
|
startoff);
|
startoff);
|
off += p->data_size();
|
off += p->data_size();
|
}
|
}
|
|
data_size = off - startoff;
|
|
}
|
|
|
|
// For full incremental links, we want to allocate some patch space
|
|
// in most sections for subsequent incremental updates.
|
|
if (this->is_patch_space_allowed_ && parameters->incremental_full())
|
|
{
|
|
double pct = parameters->options().incremental_patch();
|
|
size_t extra = static_cast<size_t>(data_size * pct);
|
|
if (this->free_space_fill_ != NULL
|
|
&& this->free_space_fill_->minimum_hole_size() > extra)
|
|
extra = this->free_space_fill_->minimum_hole_size();
|
|
off_t new_size = align_address(data_size + extra, this->addralign());
|
|
this->patch_space_ = new_size - data_size;
|
|
gold_debug(DEBUG_INCREMENTAL,
|
|
"set_final_data_size: %08lx + %08lx: section %s",
|
|
static_cast<long>(data_size),
|
|
static_cast<long>(this->patch_space_),
|
|
this->name());
|
|
data_size = new_size;
|
|
}
|
|
|
this->set_data_size(off - startoff);
|
this->set_data_size(data_size);
|
}
|
}
|
|
|
// Reset the address and file offset.
|
// Reset the address and file offset.
|
|
|
void
|
void
|
Line 2985... |
Line 3148... |
|
|
for (Input_section_list::iterator p = this->input_sections_.begin();
|
for (Input_section_list::iterator p = this->input_sections_.begin();
|
p != this->input_sections_.end();
|
p != this->input_sections_.end();
|
++p)
|
++p)
|
p->reset_address_and_file_offset();
|
p->reset_address_and_file_offset();
|
|
|
|
// Remove any patch space that was added in set_final_data_size.
|
|
if (this->patch_space_ > 0)
|
|
{
|
|
this->set_current_data_size_for_child(this->current_data_size_for_child()
|
|
- this->patch_space_);
|
|
this->patch_space_ = 0;
|
|
}
|
}
|
}
|
|
|
// Return true if address and file offset have the values after reset.
|
// Return true if address and file offset have the values after reset.
|
|
|
bool
|
bool
|
Line 3015... |
Line 3186... |
// In a few cases we need to sort the input sections attached to an
|
// In a few cases we need to sort the input sections attached to an
|
// output section. This is used to implement the type of constructor
|
// output section. This is used to implement the type of constructor
|
// priority ordering implemented by the GNU linker, in which the
|
// priority ordering implemented by the GNU linker, in which the
|
// priority becomes part of the section name and the sections are
|
// priority becomes part of the section name and the sections are
|
// sorted by name. We only do this for an output section if we see an
|
// sorted by name. We only do this for an output section if we see an
|
// attached input section matching ".ctor.*", ".dtor.*",
|
// attached input section matching ".ctors.*", ".dtors.*",
|
// ".init_array.*" or ".fini_array.*".
|
// ".init_array.*" or ".fini_array.*".
|
|
|
class Output_section::Input_section_sort_entry
|
class Output_section::Input_section_sort_entry
|
{
|
{
|
public:
|
public:
|
Line 3090... |
Line 3261... |
{
|
{
|
gold_assert(this->section_has_name_);
|
gold_assert(this->section_has_name_);
|
return this->section_name_.find('.', 1) != std::string::npos;
|
return this->section_name_.find('.', 1) != std::string::npos;
|
}
|
}
|
|
|
|
// Return the priority. Believe it or not, gcc encodes the priority
|
|
// differently for .ctors/.dtors and .init_array/.fini_array
|
|
// sections.
|
|
unsigned int
|
|
get_priority() const
|
|
{
|
|
gold_assert(this->section_has_name_);
|
|
bool is_ctors;
|
|
if (is_prefix_of(".ctors.", this->section_name_.c_str())
|
|
|| is_prefix_of(".dtors.", this->section_name_.c_str()))
|
|
is_ctors = true;
|
|
else if (is_prefix_of(".init_array.", this->section_name_.c_str())
|
|
|| is_prefix_of(".fini_array.", this->section_name_.c_str()))
|
|
is_ctors = false;
|
|
else
|
|
return 0;
|
|
char* end;
|
|
unsigned long prio = strtoul((this->section_name_.c_str()
|
|
+ (is_ctors ? 7 : 12)),
|
|
&end, 10);
|
|
if (*end != '\0')
|
|
return 0;
|
|
else if (is_ctors)
|
|
return 65535 - prio;
|
|
else
|
|
return prio;
|
|
}
|
|
|
// Return true if this an input file whose base name matches
|
// Return true if this an input file whose base name matches
|
// FILE_NAME. The base name must have an extension of ".o", and
|
// FILE_NAME. The base name must have an extension of ".o", and
|
// must be exactly FILE_NAME.o or FILE_NAME, one character, ".o".
|
// must be exactly FILE_NAME.o or FILE_NAME, one character, ".o".
|
// This is to match crtbegin.o as well as crtbeginS.o without
|
// This is to match crtbegin.o as well as crtbeginS.o without
|
// getting confused by other possibilities. Overall matching the
|
// getting confused by other possibilities. Overall matching the
|
// file name this way is a dreadful hack, but the GNU linker does it
|
// 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.
|
// in order to better support gcc, and we need to be compatible.
|
bool
|
bool
|
match_file_name(const char* match_file_name) const
|
match_file_name(const char* file_name) const
|
{
|
{ return Layout::match_file_name(this->input_section_.relobj(), file_name); }
|
const std::string& file_name(this->input_section_.relobj()->name());
|
|
const char* base_name = lbasename(file_name.c_str());
|
|
size_t match_len = strlen(match_file_name);
|
|
if (strncmp(base_name, match_file_name, 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;
|
|
}
|
|
|
|
// Returns 1 if THIS should appear before S in section order, -1 if S
|
// Returns 1 if THIS should appear before S in section order, -1 if S
|
// appears before THIS and 0 if they are not comparable.
|
// appears before THIS and 0 if they are not comparable.
|
int
|
int
|
compare_section_ordering(const Input_section_sort_entry& s) const
|
compare_section_ordering(const Input_section_sort_entry& s) const
|
Line 3231... |
Line 3420... |
if (s1_has_priority && !s2_has_priority)
|
if (s1_has_priority && !s2_has_priority)
|
return true;
|
return true;
|
if (!s1_has_priority && s2_has_priority)
|
if (!s1_has_priority && s2_has_priority)
|
return false;
|
return false;
|
|
|
|
// .ctors and .dtors sections without priority come after
|
|
// .init_array and .fini_array sections without priority.
|
|
if (!s1_has_priority
|
|
&& (s1.section_name() == ".ctors" || s1.section_name() == ".dtors")
|
|
&& s1.section_name() != s2.section_name())
|
|
return false;
|
|
if (!s2_has_priority
|
|
&& (s2.section_name() == ".ctors" || s2.section_name() == ".dtors")
|
|
&& s2.section_name() != s1.section_name())
|
|
return true;
|
|
|
|
// Sort by priority if we can.
|
|
if (s1_has_priority)
|
|
{
|
|
unsigned int s1_prio = s1.get_priority();
|
|
unsigned int s2_prio = s2.get_priority();
|
|
if (s1_prio < s2_prio)
|
|
return true;
|
|
else if (s1_prio > s2_prio)
|
|
return false;
|
|
}
|
|
|
// Check if a section order exists for these sections through a section
|
// Check if a section order exists for these sections through a section
|
// ordering file. If sequence_num is 0, an order does not exist.
|
// ordering file. If sequence_num is 0, an order does not exist.
|
int sequence_num = s1.compare_section_ordering(s2);
|
int sequence_num = s1.compare_section_ordering(s2);
|
if (sequence_num != 0)
|
if (sequence_num != 0)
|
return sequence_num == 1;
|
return sequence_num == 1;
|
Line 3265... |
Line 3476... |
return s1.index() < s2.index();
|
return s1.index() < s2.index();
|
|
|
return s1_secn_index < s2_secn_index;
|
return s1_secn_index < s2_secn_index;
|
}
|
}
|
|
|
|
// This updates the section order index of input sections according to the
|
|
// the order specified in the mapping from Section id to order index.
|
|
|
|
void
|
|
Output_section::update_section_layout(
|
|
const Section_layout_order& order_map)
|
|
{
|
|
for (Input_section_list::iterator p = this->input_sections_.begin();
|
|
p != this->input_sections_.end();
|
|
++p)
|
|
{
|
|
if (p->is_input_section()
|
|
|| p->is_relaxed_input_section())
|
|
{
|
|
Object* obj = (p->is_input_section()
|
|
? p->relobj()
|
|
: p->relaxed_input_section()->relobj());
|
|
unsigned int shndx = p->shndx();
|
|
Section_layout_order::const_iterator it
|
|
= order_map.find(Section_id(obj, shndx));
|
|
if (it == order_map.end())
|
|
continue;
|
|
unsigned int section_order_index = it->second;
|
|
if (section_order_index != 0)
|
|
{
|
|
p->set_section_order_index(section_order_index);
|
|
this->set_input_section_order_specified();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
// Sort the input sections attached to an output section.
|
// Sort the input sections attached to an output section.
|
|
|
void
|
void
|
Output_section::sort_attached_input_sections()
|
Output_section::sort_attached_input_sections()
|
{
|
{
|
Line 3307... |
Line 3550... |
std::sort(sort_list.begin(), sort_list.end(),
|
std::sort(sort_list.begin(), sort_list.end(),
|
Input_section_sort_compare());
|
Input_section_sort_compare());
|
}
|
}
|
else
|
else
|
{
|
{
|
gold_assert(parameters->options().section_ordering_file());
|
gold_assert(this->input_section_order_specified());
|
std::sort(sort_list.begin(), sort_list.end(),
|
std::sort(sort_list.begin(), sort_list.end(),
|
Input_section_sort_section_order_index_compare());
|
Input_section_sort_section_order_index_compare());
|
}
|
}
|
|
|
// Copy the sorted input sections back to our list.
|
// Copy the sorted input sections back to our list.
|
Line 3347... |
Line 3590... |
oshdr->put_sh_offset(this->offset());
|
oshdr->put_sh_offset(this->offset());
|
oshdr->put_sh_size(this->data_size());
|
oshdr->put_sh_size(this->data_size());
|
if (this->link_section_ != NULL)
|
if (this->link_section_ != NULL)
|
oshdr->put_sh_link(this->link_section_->out_shndx());
|
oshdr->put_sh_link(this->link_section_->out_shndx());
|
else if (this->should_link_to_symtab_)
|
else if (this->should_link_to_symtab_)
|
oshdr->put_sh_link(layout->symtab_section()->out_shndx());
|
oshdr->put_sh_link(layout->symtab_section_shndx());
|
else if (this->should_link_to_dynsym_)
|
else if (this->should_link_to_dynsym_)
|
oshdr->put_sh_link(layout->dynsym_section()->out_shndx());
|
oshdr->put_sh_link(layout->dynsym_section()->out_shndx());
|
else
|
else
|
oshdr->put_sh_link(this->link_);
|
oshdr->put_sh_link(this->link_);
|
|
|
Line 3409... |
Line 3652... |
}
|
}
|
|
|
p->write(of);
|
p->write(of);
|
off = aligned_off + p->data_size();
|
off = aligned_off + p->data_size();
|
}
|
}
|
|
|
|
// For incremental links, fill in unused chunks in debug sections
|
|
// with dummy compilation unit headers.
|
|
if (this->free_space_fill_ != NULL)
|
|
{
|
|
for (Free_list::Const_iterator p = this->free_list_.begin();
|
|
p != this->free_list_.end();
|
|
++p)
|
|
{
|
|
off_t off = p->start_;
|
|
size_t len = p->end_ - off;
|
|
this->free_space_fill_->write(of, this->offset() + off, len);
|
|
}
|
|
if (this->patch_space_ > 0)
|
|
{
|
|
off_t off = this->current_data_size_for_child() - this->patch_space_;
|
|
this->free_space_fill_->write(of, this->offset() + off,
|
|
this->patch_space_);
|
|
}
|
|
}
|
}
|
}
|
|
|
// If a section requires postprocessing, create the buffer to use.
|
// If a section requires postprocessing, create the buffer to use.
|
|
|
void
|
void
|
Line 4222... |
Line 4485... |
}
|
}
|
(*p)->set_file_offset(off);
|
(*p)->set_file_offset(off);
|
(*p)->finalize_data_size();
|
(*p)->finalize_data_size();
|
}
|
}
|
|
|
|
if (parameters->incremental_update())
|
gold_debug(DEBUG_INCREMENTAL,
|
gold_debug(DEBUG_INCREMENTAL,
|
"set_section_list_addresses: %08lx %08lx %s",
|
"set_section_list_addresses: %08lx %08lx %s",
|
static_cast<long>(off),
|
static_cast<long>(off),
|
static_cast<long>((*p)->data_size()),
|
static_cast<long>((*p)->data_size()),
|
((*p)->output_section() != NULL
|
((*p)->output_section() != NULL
|
? (*p)->output_section()->name() : "(special)"));
|
? (*p)->output_section()->name() : "(special)"));
|
|
|
// We want to ignore the size of a SHF_TLS or SHT_NOBITS
|
// We want to ignore the size of a SHF_TLS SHT_NOBITS
|
// section. Such a section does not affect the size of a
|
// section. Such a section does not affect the size of a
|
// PT_LOAD segment.
|
// PT_LOAD segment.
|
if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
|
if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
|
|| !(*p)->is_section_type(elfcpp::SHT_NOBITS))
|
|| !(*p)->is_section_type(elfcpp::SHT_NOBITS))
|
off += (*p)->data_size();
|
off += (*p)->data_size();
|