// layout.cc -- lay out output file sections for gold
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
#include "dynobj.h"
#include "ehframe.h"
#include "compressed_output.h"
+#include "reduced_debug_output.h"
#include "reloc.h"
+#include "descriptors.h"
+#include "plugin.h"
+#include "incremental.h"
#include "layout.h"
namespace gold
// Layout methods.
-Layout::Layout(const General_options& options, Script_options* script_options)
- : options_(options),
+Layout::Layout(int number_of_input_files, Script_options* script_options)
+ : number_of_input_files_(number_of_input_files),
script_options_(script_options),
namepool_(),
sympool_(),
segment_list_(),
section_list_(),
unattached_section_list_(),
- sections_are_attached_(false),
special_output_list_(),
section_headers_(NULL),
tls_segment_(NULL),
added_eh_frame_data_(false),
eh_frame_hdr_section_(NULL),
build_id_note_(NULL),
+ debug_abbrev_(NULL),
+ debug_info_(NULL),
group_signatures_(),
output_file_size_(-1),
+ sections_are_attached_(false),
input_requires_executable_stack_(false),
input_with_gnu_stack_note_(false),
input_without_gnu_stack_note_(false),
has_static_tls_(false),
- any_postprocessing_sections_(false)
+ any_postprocessing_sections_(false),
+ resized_signatures_(false),
+ incremental_inputs_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
// We expect two unattached Output_data objects: the file header and
// the segment headers.
this->special_output_list_.reserve(2);
+
+ // Initialize structure needed for an incremental build.
+ if (parameters->options().incremental())
+ this->incremental_inputs_ = new Incremental_inputs;
}
// Hash a key we use to look up an output section mapping.
return k.first + k.second.first + k.second.second;
}
-// Return whether PREFIX is a prefix of STR.
-
-static inline bool
-is_prefix_of(const char* prefix, const char* str)
-{
- return strncmp(prefix, str, strlen(prefix)) == 0;
-}
-
// Returns whether the given section is in the list of
// debug-sections-used-by-some-version-of-gdb. Currently,
// we've checked versions of gdb up to and including 6.7.1.
".debug_str",
};
+static const char* lines_only_debug_sections[] =
+{ ".debug_abbrev",
+ // ".debug_aranges", // not used by gdb as of 6.7.1
+ // ".debug_frame",
+ ".debug_info",
+ ".debug_line",
+ // ".debug_loc",
+ // ".debug_macinfo",
+ // ".debug_pubnames", // not used by gdb as of 6.7.1
+ // ".debug_ranges",
+ ".debug_str",
+};
+
static inline bool
is_gdb_debug_section(const char* str)
{
return false;
}
+static inline bool
+is_lines_only_debug_section(const char* str)
+{
+ // We can do this faster: binary search or a hashtable. But why bother?
+ for (size_t i = 0;
+ i < sizeof(lines_only_debug_sections)/sizeof(*lines_only_debug_sections);
+ ++i)
+ if (strcmp(str, lines_only_debug_sections[i]) == 0)
+ return true;
+ return false;
+}
+
// Whether to include this section in the link.
template<int size, bool big_endian>
Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr)
{
+ if (shdr.get_sh_flags() & elfcpp::SHF_EXCLUDE)
+ return false;
+
switch (shdr.get_sh_type())
{
case elfcpp::SHT_NULL:
case elfcpp::SHT_SYMTAB:
case elfcpp::SHT_DYNSYM:
- case elfcpp::SHT_STRTAB:
case elfcpp::SHT_HASH:
case elfcpp::SHT_DYNAMIC:
case elfcpp::SHT_SYMTAB_SHNDX:
return false;
+ case elfcpp::SHT_STRTAB:
+ // Discard the sections which have special meanings in the ELF
+ // ABI. Keep others (e.g., .stabstr). We could also do this by
+ // checking the sh_link fields of the appropriate sections.
+ return (strcmp(name, ".dynstr") != 0
+ && strcmp(name, ".strtab") != 0
+ && strcmp(name, ".shstrtab") != 0);
+
case elfcpp::SHT_RELA:
case elfcpp::SHT_REL:
case elfcpp::SHT_GROUP:
if (is_debug_info_section(name))
return false;
}
+ if (parameters->options().strip_debug_non_line()
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ // Debugging sections can only be recognized by name.
+ if (is_prefix_of(".debug", name)
+ && !is_lines_only_debug_section(name))
+ return false;
+ }
if (parameters->options().strip_debug_gdb()
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
{
&& !is_gdb_debug_section(name))
return false;
}
+ if (parameters->options().strip_lto_sections()
+ && !parameters->options().relocatable()
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ // Ignore LTO sections containing intermediate code.
+ if (is_prefix_of(".gnu.lto_", name))
+ return false;
+ }
return true;
default:
// output section.
size_t len = strlen(name);
- if (is_input_section && !parameters->options().relocatable())
+ if (is_input_section
+ && !this->script_options_->saw_sections_clause()
+ && !parameters->options().relocatable())
name = Layout::output_section_name(name, &len);
Stringpool::Key name_key;
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx, unsigned int, off_t* off)
{
+ *off = 0;
+
if (!this->include_section(object, name, shdr))
return NULL;
os->set_info_symndx(sym);
else
{
+ // Reserve some space to minimize reallocations.
+ if (this->group_signatures_.empty())
+ this->group_signatures_.reserve(this->number_of_input_files_ * 16);
+
// We will wind up using a symbol whose name is the signature.
// So just put the signature in the symbol name pool to save it.
signature = symtab->canonicalize_name(signature);
this->eh_frame_section_ = os;
this->eh_frame_data_ = new Eh_frame();
- if (this->options_.eh_frame_hdr())
+ if (parameters->options().eh_frame_hdr())
{
Output_section* hdr_os =
this->choose_output_section(NULL,
{
Output_section* os;
if ((flags & elfcpp::SHF_ALLOC) == 0
- && strcmp(this->options_.compress_debug_sections(), "none") != 0
+ && strcmp(parameters->options().compress_debug_sections(), "none") != 0
&& is_compressible_debug_section(name))
- os = new Output_compressed_section(&this->options_, name, type, flags);
- else
+ os = new Output_compressed_section(¶meters->options(), name, type,
+ flags);
+
+ else if ((flags & elfcpp::SHF_ALLOC) == 0
+ && parameters->options().strip_debug_non_line()
+ && strcmp(".debug_abbrev", name) == 0)
+ {
+ os = this->debug_abbrev_ = new Output_reduced_debug_abbrev_section(
+ name, type, flags);
+ if (this->debug_info_)
+ this->debug_info_->set_abbreviations(this->debug_abbrev_);
+ }
+ else if ((flags & elfcpp::SHF_ALLOC) == 0
+ && parameters->options().strip_debug_non_line()
+ && strcmp(".debug_info", name) == 0)
+ {
+ os = this->debug_info_ = new Output_reduced_debug_info_section(
+ name, type, flags);
+ if (this->debug_abbrev_)
+ this->debug_info_->set_abbreviations(this->debug_abbrev_);
+ }
+ else
os = new Output_section(name, type, flags);
this->section_list_.push_back(os);
++p)
{
if ((*p)->type() == elfcpp::PT_LOAD
- && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
+ && (parameters->options().omagic()
+ || ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W)))
{
// If -Tbss was specified, we need to separate the data
// and BSS segments.
- if (this->options_.user_set_Tbss())
+ if (parameters->options().user_set_Tbss())
{
if ((os->type() == elfcpp::SHT_NOBITS)
== (*p)->has_any_data_sections())
if ((flags & elfcpp::SHF_TLS) != 0)
{
if (this->tls_segment_ == NULL)
- this->tls_segment_ = this->make_output_segment(elfcpp::PT_TLS,
- seg_flags);
+ this->make_output_segment(elfcpp::PT_TLS, seg_flags);
this->tls_segment_->add_output_section(os, seg_flags);
}
{
gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
if (this->relro_segment_ == NULL)
- this->relro_segment_ = this->make_output_segment(elfcpp::PT_GNU_RELRO,
- seg_flags);
+ this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags);
this->relro_segment_->add_output_section(os, seg_flags);
}
}
{
if ((*p)->type() == elfcpp::PT_LOAD
&& ((*p)->flags() & elfcpp::PF_R) != 0
- && ((*p)->flags() & elfcpp::PF_W) == 0)
+ && (parameters->options().omagic()
+ || ((*p)->flags() & elfcpp::PF_W) == 0))
return *p;
}
this->create_version_sections(&versions, symtab, local_dynamic_count,
dynamic_symbols, dynstr);
}
+
+ if (this->incremental_inputs_)
+ {
+ this->incremental_inputs_->finalize();
+ this->create_incremental_info_sections();
+ }
// If there is a SECTIONS clause, put all the input sections into
// the required order.
else
load_seg = this->find_first_load_seg();
- if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
+ if (parameters->options().oformat_enum()
+ != General_options::OBJECT_FORMAT_ELF)
load_seg = NULL;
gold_assert(phdr_seg == NULL || load_seg != NULL);
// Lay out the file header.
Output_file_header* file_header;
file_header = new Output_file_header(target, symtab, segment_headers,
- this->options_.entry());
+ parameters->options().entry());
if (load_seg != NULL)
load_seg->add_initial_output_data(file_header);
// *TRAILING_PADDING to the number of trailing zero bytes required.
Output_section*
-Layout::create_note(const char* name, int note_type, size_t descsz,
+Layout::create_note(const char* name, int note_type,
+ const char* section_name, size_t descsz,
bool allocate, size_t* trailing_padding)
{
// Authorities all agree that the values in a .note field should
memcpy(buffer + 3 * (size / 8), name, namesz);
- const char* note_name = this->namepool_.add(".note", false, NULL);
+ const char *note_name = this->namepool_.add(section_name, false, NULL);
elfcpp::Elf_Xword flags = 0;
if (allocate)
flags = elfcpp::SHF_ALLOC;
size_t trailing_padding;
Output_section *os = this->create_note("GNU", elfcpp::NT_GNU_GOLD_VERSION,
- desc.size(), false, &trailing_padding);
+ ".note.gnu.gold-version", desc.size(),
+ false, &trailing_padding);
Output_section_data* posd = new Output_data_const(desc, 4);
os->add_output_section_data(posd);
Layout::create_executable_stack_info(const Target* target)
{
bool is_stack_executable;
- if (this->options_.is_execstack_set())
- is_stack_executable = this->options_.is_stack_executable();
+ if (parameters->options().is_execstack_set())
+ is_stack_executable = parameters->options().is_stack_executable();
else if (!this->input_with_gnu_stack_note_)
return;
else
char buffer[uuidsz];
memset(buffer, 0, uuidsz);
- int descriptor = ::open("/dev/urandom", O_RDONLY);
+ int descriptor = open_descriptor(-1, "/dev/urandom", O_RDONLY);
if (descriptor < 0)
gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"),
strerror(errno));
else
{
ssize_t got = ::read(descriptor, buffer, uuidsz);
- ::close(descriptor);
+ release_descriptor(descriptor, true);
if (got < 0)
gold_error(_("/dev/urandom: read failed: %s"), strerror(errno));
else if (static_cast<size_t>(got) != uuidsz)
// Create the note.
size_t trailing_padding;
Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_BUILD_ID,
- descsz, true, &trailing_padding);
+ ".note.gnu.build-id", descsz, true,
+ &trailing_padding);
if (!desc.empty())
{
}
}
+// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
+// for the next run of incremental linking to check what has changed.
+
+void
+Layout::create_incremental_info_sections()
+{
+ gold_assert(this->incremental_inputs_ != NULL);
+
+ // Add the .gnu_incremental_inputs section.
+ const char *incremental_inputs_name =
+ this->namepool_.add(".gnu_incremental_inputs", false, NULL);
+ Output_section* inputs_os =
+ this->make_output_section(incremental_inputs_name,
+ elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0);
+ Output_section_data* posd =
+ this->incremental_inputs_->create_incremental_inputs_section_data();
+ inputs_os->add_output_section_data(posd);
+
+ // Add the .gnu_incremental_strtab section.
+ const char *incremental_strtab_name =
+ this->namepool_.add(".gnu_incremental_strtab", false, NULL);
+ Output_section* strtab_os = this->make_output_section(incremental_strtab_name,
+ elfcpp::SHT_STRTAB,
+ 0);
+ Output_data_strtab* strtab_data =
+ new Output_data_strtab(this->incremental_inputs_->get_stringpool());
+ strtab_os->add_output_section_data(strtab_data);
+
+ inputs_os->set_link_section(strtab_data);
+}
+
// Return whether SEG1 should be before SEG2 in the output file. This
// is based entirely on the segment type and flags. When this is
// called the segment addresses has normally not yet been set.
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
uint64_t addr;
- if (this->options_.user_set_Ttext())
- addr = this->options_.Ttext();
+ if (parameters->options().user_set_Ttext())
+ addr = parameters->options().Ttext();
else if (parameters->options().shared())
addr = 0;
else
}
}
+ const bool check_sections = parameters->options().check_sections();
+ Output_segment* last_load_segment = NULL;
+
bool was_readonly = false;
for (Segment_list::iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
// the physical address.
addr = (*p)->paddr();
}
- else if (this->options_.user_set_Tdata()
+ else if (parameters->options().user_set_Tdata()
&& ((*p)->flags() & elfcpp::PF_W) != 0
- && (!this->options_.user_set_Tbss()
+ && (!parameters->options().user_set_Tbss()
|| (*p)->has_any_data_sections()))
{
- addr = this->options_.Tdata();
+ addr = parameters->options().Tdata();
are_addresses_set = true;
}
- else if (this->options_.user_set_Tbss()
+ else if (parameters->options().user_set_Tbss()
&& ((*p)->flags() & elfcpp::PF_W) != 0
&& !(*p)->has_any_data_sections())
{
- addr = this->options_.Tbss();
+ addr = parameters->options().Tbss();
are_addresses_set = true;
}
uint64_t aligned_addr = 0;
uint64_t abi_pagesize = target->abi_pagesize();
+ uint64_t common_pagesize = target->common_pagesize();
- // FIXME: This should depend on the -n and -N options.
- (*p)->set_minimum_p_align(target->common_pagesize());
+ if (!parameters->options().nmagic()
+ && !parameters->options().omagic())
+ (*p)->set_minimum_p_align(common_pagesize);
if (are_addresses_set)
{
- // Adjust the file offset to the same address modulo the
- // page size.
- uint64_t unsigned_off = off;
- uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1))
- | (addr & (abi_pagesize - 1)));
- if (aligned_off < unsigned_off)
- aligned_off += abi_pagesize;
- off = aligned_off;
+ if (!parameters->options().nmagic()
+ && !parameters->options().omagic())
+ {
+ // Adjust the file offset to the same address modulo
+ // the page size.
+ uint64_t unsigned_off = off;
+ uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1))
+ | (addr & (abi_pagesize - 1)));
+ if (aligned_off < unsigned_off)
+ aligned_off += abi_pagesize;
+ off = aligned_off;
+ }
}
else
{
if (!are_addresses_set && aligned_addr != addr)
{
- uint64_t common_pagesize = target->common_pagesize();
uint64_t first_off = (common_pagesize
- (aligned_addr
& (common_pagesize - 1)));
if (((*p)->flags() & elfcpp::PF_W) == 0)
was_readonly = true;
+
+ // Implement --check-sections. We know that the segments
+ // are sorted by LMA.
+ if (check_sections && last_load_segment != NULL)
+ {
+ gold_assert(last_load_segment->paddr() <= (*p)->paddr());
+ if (last_load_segment->paddr() + last_load_segment->memsz()
+ > (*p)->paddr())
+ {
+ unsigned long long lb1 = last_load_segment->paddr();
+ unsigned long long le1 = lb1 + last_load_segment->memsz();
+ unsigned long long lb2 = (*p)->paddr();
+ unsigned long long le2 = lb2 + (*p)->memsz();
+ gold_error(_("load segment overlap [0x%llx -> 0x%llx] and "
+ "[0x%llx -> 0x%llx]"),
+ lb1, le1, lb2, le2);
+ }
+ }
+ last_load_segment = *p;
}
}
void
Layout::create_interp(const Target* target)
{
- const char* interp = this->options_.dynamic_linker();
+ const char* interp = parameters->options().dynamic_linker();
if (interp == NULL)
{
interp = target->dynamic_linker();
if (parameters->options().shared())
{
- const char* soname = this->options_.soname();
+ const char* soname = parameters->options().soname();
if (soname != NULL)
odyn->add_string(elfcpp::DT_SONAME, soname);
}
// FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
// Add a DT_RPATH entry if needed.
- const General_options::Dir_list& rpath(this->options_.rpath());
+ const General_options::Dir_list& rpath(parameters->options().rpath());
if (!rpath.empty())
{
std::string rpath_val;
}
if (parameters->options().shared() && this->has_static_tls())
flags |= elfcpp::DF_STATIC_TLS;
+ if (parameters->options().origin())
+ flags |= elfcpp::DF_ORIGIN;
odyn->add_constant(elfcpp::DT_FLAGS, flags);
flags = 0;
flags &= ~(elfcpp::DF_1_INITFIRST
| elfcpp::DF_1_NODELETE
| elfcpp::DF_1_NOOPEN);
+ if (parameters->options().origin())
+ flags |= elfcpp::DF_1_ORIGIN;
if (flags)
odyn->add_constant(elfcpp::DT_FLAGS_1, flags);
}
// initial '.', we use the name unchanged (i.e., "mysection" and
// ".text" are unchanged).
+ // If the name starts with '.note', we keep it unchanged (e.g. to
+ // avoid truncating '.note.ABI-tag' to '.note').
+
// If the name starts with ".data.rel.ro.local" we use
// ".data.rel.ro.local".
const char* sdot = strchr(s, '.');
if (sdot == NULL)
return name;
+ if (strncmp(name, ".note.", 6) == 0)
+ return name;
const char* const data_rel_ro_local = ".data.rel.ro.local";
if (strncmp(name, data_rel_ro_local, strlen(data_rel_ro_local)) == 0)
return name;
}
-// Record the signature of a comdat section, and return whether to
-// include it in the link. If GROUP is true, this is a regular
-// section group. If GROUP is false, this is a group signature
-// derived from the name of a linkonce section. We want linkonce
-// signatures and group signatures to block each other, but we don't
-// want a linkonce signature to block another linkonce signature.
+// 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, the CANDIDATE signature is recorded for
+// this NAME in the layout object, *KEPT_SECTION is set to the
+// internal copy and the function return false. In some cases, with
+// CANDIDATE->GROUP_ being false, KEPT_SECTION can point back to
+// CANDIDATE.
bool
-Layout::add_comdat(Relobj* object, unsigned int shndx,
- const std::string& signature, bool group)
+Layout::find_or_add_kept_section(const std::string& name,
+ Kept_section* candidate,
+ Kept_section** kept_section)
{
- Kept_section kept(object, shndx, group);
+ // It's normal to see a couple of entries here, for the x86 thunk
+ // sections. If we see more than a few, we're linking a C++
+ // program, and we resize to get more space to minimize rehashing.
+ if (this->signatures_.size() > 4
+ && !this->resized_signatures_)
+ {
+ reserve_unordered_map(&this->signatures_,
+ this->number_of_input_files_ * 64);
+ this->resized_signatures_ = true;
+ }
+
std::pair<Signatures::iterator, bool> ins(
- this->signatures_.insert(std::make_pair(signature, kept)));
+ this->signatures_.insert(std::make_pair(name, *candidate)));
+ if (kept_section)
+ *kept_section = &ins.first->second;
if (ins.second)
{
// This is the first time we've seen this signature.
return true;
}
- if (ins.first->second.group_)
+ if (ins.first->second.is_group)
{
// We've already seen a real section group with this signature.
+ // If the kept group is from a plugin object, and we're in
+ // the replacement phase, accept the new one as a replacement.
+ if (ins.first->second.object == NULL
+ && parameters->options().plugins()->in_replacement_phase())
+ {
+ ins.first->second = *candidate;
+ return true;
+ }
return false;
}
- else if (group)
+ else if (candidate->is_group)
{
// This is a real section group, and we've already seen a
// linkonce section with this signature. Record that we've seen
// a section group, and don't include this section group.
- ins.first->second.group_ = true;
+ ins.first->second.is_group = true;
return false;
}
else
// We've already seen a linkonce section and this is a linkonce
// section. These don't block each other--this may be the same
// symbol name with different section types.
+ *kept_section = candidate;
return true;
}
}
if (p == this->signatures_.end())
return NULL;
if (pshndx != NULL)
- *pshndx = p->second.shndx_;
- return p->second.object_;
+ *pshndx = p->second.shndx;
+ return p->second.object;
}
// Store the allocated sections into the section list.
gold_assert(!parameters->options().relocatable());
Output_segment* oseg = new Output_segment(type, flags);
this->segment_list_.push_back(oseg);
+
+ if (type == elfcpp::PT_TLS)
+ this->tls_segment_ = oseg;
+ else if (type == elfcpp::PT_GNU_RELRO)
+ this->relro_segment_ = oseg;
+
return oseg;
}
{
off_t off = this->output_file_size_;
off = this->set_section_offsets(off, POSTPROCESSING_SECTIONS_PASS);
-
+
// Now that we've finalized the names, we can finalize the shstrab.
off =
this->set_section_offsets(off,
void
Layout::write_binary(Output_file* in) const
{
- gold_assert(this->options_.oformat_enum()
+ gold_assert(parameters->options().oformat_enum()
== General_options::OBJECT_FORMAT_BINARY);
// Get the size of the binary file.
void
Write_symbols_task::run(Workqueue*)
{
- this->symtab_->write_globals(this->input_objects_, this->sympool_,
- this->dynpool_, this->layout_->symtab_xindex(),
+ this->symtab_->write_globals(this->sympool_, this->dynpool_,
+ this->layout_->symtab_xindex(),
this->layout_->dynsym_xindex(), this->of_);
}