// script-sections.cc -- linker script SECTIONS for gold
-// Copyright (C) 2008-2016 Free Software Foundation, Inc.
+// Copyright (C) 2008-2020 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
attrs &= ~ (attrs & - attrs);
}
while (attrs != 0);
-
+
return match;
}
-
+
// Print a memory region.
void
bool
find_place(Output_section*, Elements_iterator** pwhere);
+ // Update PLACE_LAST_ALLOC.
+ void
+ update_last_alloc(Elements_iterator where);
+
// Return the iterator being used for sections at the very end of
// the linker script.
Elements_iterator
PLACE_TLS,
PLACE_TLS_BSS,
PLACE_BSS,
+ PLACE_LAST_ALLOC,
PLACE_REL,
PLACE_INTERP,
PLACE_NONALLOC,
this->initialize_place(PLACE_TLS, NULL);
this->initialize_place(PLACE_TLS_BSS, NULL);
this->initialize_place(PLACE_BSS, ".bss");
+ this->initialize_place(PLACE_LAST_ALLOC, NULL);
this->initialize_place(PLACE_REL, NULL);
this->initialize_place(PLACE_INTERP, ".interp");
this->initialize_place(PLACE_NONALLOC, NULL);
bool first_init = this->first_init_;
this->first_init_ = false;
+ // Remember the last allocated section. Any orphan bss sections
+ // will be placed after it.
+ if (os != NULL
+ && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ this->places_[PLACE_LAST_ALLOC].location = location;
+ this->places_[PLACE_LAST_ALLOC].have_location = true;
+ }
+
for (int i = 0; i < PLACE_MAX; ++i)
{
if (this->places_[i].name != NULL && this->places_[i].name == name)
case PLACE_RODATA:
follow = PLACE_TEXT;
break;
+ case PLACE_DATA:
+ follow = PLACE_RODATA;
+ if (!this->places_[PLACE_RODATA].have_location)
+ follow = PLACE_TEXT;
+ break;
case PLACE_BSS:
- follow = PLACE_DATA;
+ follow = PLACE_LAST_ALLOC;
break;
case PLACE_REL:
follow = PLACE_TEXT;
return ret;
}
+// Update PLACE_LAST_ALLOC.
+void
+Orphan_section_placement::update_last_alloc(Elements_iterator elem)
+{
+ Elements_iterator prev = elem;
+ --prev;
+ if (this->places_[PLACE_LAST_ALLOC].have_location
+ && this->places_[PLACE_LAST_ALLOC].location == prev)
+ {
+ this->places_[PLACE_LAST_ALLOC].have_location = true;
+ this->places_[PLACE_LAST_ALLOC].location = elem;
+ }
+}
+
// Return the iterator being used for sections at the very end of the
// linker script.
// Output_section_definition.
virtual const char*
output_section_name(const char*, const char*, Output_section***,
- Script_sections::Section_type*, bool*)
+ Script_sections::Section_type*, bool*, bool)
{ return NULL; }
// Initialize OSP with an output section.
private:
// Input section, can be a relaxed section.
Output_section::Input_section input_section_;
- // Name of the section.
+ // Name of the section.
std::string section_name_;
// Section size.
uint64_t size_;
operator()(const Input_section_info&, const Input_section_info&) const;
private:
+ static unsigned long
+ get_init_priority(const char*);
+
Sort_wildcard filename_sort_;
Sort_wildcard section_sort_;
};
+// Return a relative priority of the section with the specified NAME
+// (a lower value meand a higher priority), or 0 if it should be compared
+// with others as strings.
+// The implementation of this function is copied from ld/ldlang.c.
+
+unsigned long
+Input_section_sorter::get_init_priority(const char* name)
+{
+ char* end;
+ unsigned long init_priority;
+
+ // GCC uses the following section names for the init_priority
+ // attribute with numerical values 101 and 65535 inclusive. A
+ // lower value means a higher priority.
+ //
+ // 1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the
+ // decimal numerical value of the init_priority attribute.
+ // The order of execution in .init_array is forward and
+ // .fini_array is backward.
+ // 2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the
+ // decimal numerical value of the init_priority attribute.
+ // The order of execution in .ctors is backward and .dtors
+ // is forward.
+
+ if (strncmp(name, ".init_array.", 12) == 0
+ || strncmp(name, ".fini_array.", 12) == 0)
+ {
+ init_priority = strtoul(name + 12, &end, 10);
+ return *end ? 0 : init_priority;
+ }
+ else if (strncmp(name, ".ctors.", 7) == 0
+ || strncmp(name, ".dtors.", 7) == 0)
+ {
+ init_priority = strtoul(name + 7, &end, 10);
+ return *end ? 0 : 65535 - init_priority;
+ }
+
+ return 0;
+}
+
bool
Input_section_sorter::operator()(const Input_section_info& isi1,
const Input_section_info& isi2) const
{
+ if (this->section_sort_ == SORT_WILDCARD_BY_INIT_PRIORITY)
+ {
+ unsigned long ip1 = get_init_priority(isi1.section_name().c_str());
+ unsigned long ip2 = get_init_priority(isi2.section_name().c_str());
+ if (ip1 != 0 && ip2 != 0 && ip1 != ip2)
+ return ip1 < ip2;
+ }
if (this->section_sort_ == SORT_WILDCARD_BY_NAME
|| this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
|| (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
- && isi1.addralign() == isi2.addralign()))
+ && isi1.addralign() == isi2.addralign())
+ || this->section_sort_ == SORT_WILDCARD_BY_INIT_PRIORITY)
{
if (isi1.section_name() != isi2.section_name())
return isi1.section_name() < isi2.section_name();
while (p != input_sections->end())
{
Relobj* relobj = p->relobj();
- unsigned int shndx = p->shndx();
+ unsigned int shndx = p->shndx();
Input_section_info isi(*p);
// Calling section_name and section_addralign is not very
p != matching_sections[i].end();
++p)
{
- // Override the original address alignment if SUBALIGN is specified
- // and is greater than the original alignment. We need to make a
- // copy of the input section to modify the alignment.
+ // Override the original address alignment if SUBALIGN is specified.
+ // We need to make a copy of the input section to modify the
+ // alignment.
Output_section::Input_section sis(p->input_section());
uint64_t this_subalign = sis.addralign();
if (!sis.is_input_section())
- sis.output_section_data()->finalize_data_size();
+ sis.output_section_data()->finalize_data_size();
uint64_t data_size = sis.data_size();
- if (this_subalign < subalign)
+ if (subalign > 0)
{
this_subalign = subalign;
sis.set_addralign(subalign);
fprintf(f, "SORT_BY_ALIGNMENT(SORT_BY_NAME(");
close_parens = 2;
break;
+ case SORT_WILDCARD_BY_INIT_PRIORITY:
+ fprintf(f, "SORT_BY_INIT_PRIORITY(");
+ close_parens = 1;
+ break;
default:
gold_unreachable();
}
const char*
output_section_name(const char* file_name, const char* section_name,
Output_section***, Script_sections::Section_type*,
- bool*);
+ bool*, bool);
// Initialize OSP with an output section.
void
void
set_section_vma(Expression* address)
{ this->address_ = address; }
-
+
void
set_section_lma(Expression* address)
{ this->load_address_ = address; }
const std::string&
get_section_name() const
{ return this->name_; }
-
+
private:
static const char*
script_section_type_name(Script_section_type);
const char* section_name,
Output_section*** slot,
Script_sections::Section_type* psection_type,
- bool* keep)
+ bool* keep,
+ bool match_input_spec)
{
+ // If the section is a linker-created output section, just look for a match
+ // on the output section name.
+ if (!match_input_spec && this->name_ != "/DISCARD/")
+ {
+ if (this->name_ != section_name)
+ return NULL;
+ *slot = &this->output_section_;
+ *psection_type = this->section_type();
+ return this->name_.c_str();
+ }
+
// Ask each element whether it matches NAME.
for (Output_section_elements::const_iterator p = this->elements_.begin();
p != this->elements_.end();
uint64_t old_load_address = *load_address;
// If input section sorting is requested via --section-ordering-file or
- // linker plugins, then do it here. This is important because we want
+ // linker plugins, then do it here. This is important because we want
// any sorting specified in the linker scripts, which will be done after
- // this, to take precedence. The final order of input sections is then
+ // this, to take precedence. The final order of input sections is then
// guaranteed to be according to the linker script specification.
if (this->output_section_ != NULL
&& this->output_section_->input_section_order_specified())
this->output_section_->set_addralign(align);
}
+ uint64_t subalign;
+ if (this->subalign_ == NULL)
+ subalign = 0;
+ else
+ {
+ Output_section* subalign_section;
+ subalign = this->subalign_->eval_with_dot(symtab, layout, true,
+ *dot_value, NULL,
+ &subalign_section, NULL,
+ false);
+ if (subalign_section != NULL)
+ gold_warning(_("subalign of section %s is not absolute"),
+ this->name_.c_str());
+
+ // Reserve a value of 0 to mean there is no SUBALIGN property.
+ if (subalign == 0)
+ subalign = 1;
+
+ // The external alignment of the output section must be at least
+ // as large as that of the input sections. If there is no
+ // explicit ALIGN property, we set the output section alignment
+ // to match the input section alignment.
+ if (align < subalign || this->align_ == NULL)
+ {
+ align = subalign;
+ this->output_section_->set_addralign(align);
+ }
+ }
+
address = align_address(address, align);
uint64_t start_address = address;
// The LMA address was explicitly set to the given region.
laddr = lma_region->get_current_address()->eval(symtab, layout,
false);
- else
+ else
{
// We are not going to use the discovered lma_region, so
// make sure that we do not update it in the code below.
this->evaluated_load_address_ = laddr;
- uint64_t subalign;
- if (this->subalign_ == NULL)
- subalign = 0;
- else
- {
- Output_section* subalign_section;
- subalign = this->subalign_->eval_with_dot(symtab, layout, true,
- *dot_value, NULL,
- &subalign_section, NULL,
- false);
- if (subalign_section != NULL)
- gold_warning(_("subalign of section %s is not absolute"),
- this->name_.c_str());
- }
-
std::string fill;
if (this->fill_ != NULL)
{
address = align_address(address, this->os_->addralign());
// If input section sorting is requested via --section-ordering-file or
- // linker plugins, then do it here. This is important because we want
+ // linker plugins, then do it here. This is important because we want
// any sorting specified in the linker scripts, which will be done after
- // this, to take precedence. The final order of input sections is then
+ // this, to take precedence. The final order of input sections is then
// guaranteed to be according to the linker script specification.
if (this->os_ != NULL
&& this->os_->input_section_order_specified())
{
uint64_t addralign = p->addralign();
if (!p->is_input_section())
- p->output_section_data()->finalize_data_size();
+ p->output_section_data()->finalize_data_size();
uint64_t size = p->data_size();
address = align_address(address, addralign);
this->os_->add_script_input_section(*p);
const char* section_name,
Output_section*** output_section_slot,
Script_sections::Section_type* psection_type,
- bool* keep)
+ bool* keep,
+ bool is_input_section)
{
for (Sections_elements::const_iterator p = this->sections_elements_->begin();
p != this->sections_elements_->end();
{
const char* ret = (*p)->output_section_name(file_name, section_name,
output_section_slot,
- psection_type, keep);
+ psection_type, keep,
+ is_input_section);
if (ret != NULL)
{
}
}
- // If we couldn't find a mapping for the name, the output section
- // gets the name of the input section.
-
+ // We have an orphan section.
*output_section_slot = NULL;
*psection_type = Script_sections::ST_NONE;
+ *keep = false;
+ General_options::Orphan_handling orphan_handling =
+ parameters->options().orphan_handling_enum();
+ if (orphan_handling == General_options::ORPHAN_DISCARD)
+ return NULL;
+ if (orphan_handling == General_options::ORPHAN_ERROR)
+ {
+ if (file_name == NULL)
+ gold_error(_("unplaced orphan section '%s'"), section_name);
+ else
+ gold_error(_("unplaced orphan section '%s' from '%s'"),
+ section_name, file_name);
+ return NULL;
+ }
+ if (orphan_handling == General_options::ORPHAN_WARN)
+ {
+ if (file_name == NULL)
+ gold_warning(_("orphan section '%s' is being placed in section '%s'"),
+ section_name, section_name);
+ else
+ gold_warning(_("orphan section '%s' from '%s' is being placed "
+ "in section '%s'"),
+ section_name, file_name, section_name);
+ }
+
+ // If we couldn't find a mapping for the name, the output section
+ // gets the name of the input section.
return section_name;
}
Sections_elements::iterator last = osp->last_place();
*where = this->sections_elements_->insert(last, orphan);
}
+
+ if ((os->flags() & elfcpp::SHF_ALLOC) != 0)
+ osp->update_last_alloc(*where);
}
// Set the addresses of all the output sections. Walk through all the
Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
{
gold_assert(this->saw_sections_clause_);
-
+
// Implement ONLY_IF_RO/ONLY_IF_RW constraints. These are a pain
// for our representation.
for (Sections_elements::iterator p = this->sections_elements_->begin();
Output_section* os = (*p)->get_output_section();
// Handle -Ttext, -Tdata and -Tbss options. We do this by looking for
- // the special sections by names and doing dot assignments.
+ // the special sections by names and doing dot assignments.
if (use_tsection_options
&& os != NULL
&& (os->flags() & elfcpp::SHF_ALLOC) != 0)
(*p)->set_section_addresses(symtab, layout, &dot_value, &dot_alignment,
&load_address);
- }
+ }
if (this->phdrs_elements_ != NULL)
{
layout->get_allocated_sections(§ions);
// Sort the sections by address.
- std::stable_sort(sections.begin(), sections.end(),
+ std::stable_sort(sections.begin(), sections.end(),
Sort_output_sections(this->sections_elements_));
this->create_note_and_tls_segments(layout, §ions);
Output_segment* first_seg = NULL;
Output_segment* current_seg = NULL;
bool is_current_seg_readonly = true;
- Layout::Section_list::iterator plast = sections.end();
uint64_t last_vma = 0;
uint64_t last_lma = 0;
uint64_t last_size = 0;
+ bool in_bss = false;
for (Layout::Section_list::iterator p = sections.begin();
p != sections.end();
++p)
// skipping a page.
need_new_segment = true;
}
- else if (is_bss_section(*plast) && !is_bss_section(*p))
+ else if (in_bss && !is_bss_section(*p))
{
// A non-BSS section can not follow a BSS section in the
// same segment.
if (first_seg == NULL)
first_seg = current_seg;
is_current_seg_readonly = true;
+ in_bss = false;
}
current_seg->add_output_section_to_load(layout, *p, seg_flags);
if (((*p)->flags() & elfcpp::SHF_WRITE) != 0)
is_current_seg_readonly = false;
- plast = p;
+ if (is_bss_section(*p) && size > 0)
+ in_bss = true;
+
last_vma = vma;
last_lma = lma;
last_size = size;
// Output sections in the script which do not list segments are
// attached to the same set of segments as the immediately preceding
// output section.
-
+
String_list* phdr_names = NULL;
bool load_segments_only = false;
for (Sections_elements::const_iterator p = this->sections_elements_->begin();
// filtering.
if (old_phdr_names != phdr_names)
load_segments_only = false;
-
+
// If this is an orphan section--one that was not explicitly
// mentioned in the linker script--then it should not inherit
// any segment type other than PT_LOAD. Otherwise, e.g., the
++p)
(*p)->release_segment();
}
+ this->segments_created_ = false;
}
// Print the SECTIONS clause to F for debugging.