aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog23
-rw-r--r--gold/script-sections.cc513
-rw-r--r--gold/script-sections.h22
3 files changed, 376 insertions, 182 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 5e19718..9dd8787 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,26 @@
+2009-03-18 Ian Lance Taylor <iant@google.com>
+
+ * script-sections.h: Include <list>.
+ (class Script_sections): Change Sections_elements from std::vector
+ to std::list. Typedef public Elements_iterator. Add
+ orphan_section_placement_, data_segment_align_start_, and
+ saw_data_segment_align_ fields. Remove data_segment_align_index_
+ field.
+ * script-sections.cc (class Orphan_section_placement): New class.
+ (class Sections_element): Add virtual functions is_relro and
+ orphan_section_init. Remove virtual function place_orphan_here.
+ (class Output_section_definition): Add is_relro and
+ orphan_section_init. Remove place_orphan_here.
+ (class Orphan_output_section): Likewise.
+ (Script_sections::Script_sections): Update for field changes.
+ (Script_sections::data_segment_align): Set saw_data_segment_align_
+ and data_segment_align_start_, not data_segment_align_index.
+ (Script_sections::data_segment_relro_end): Check
+ saw_data_segment_align_. Use data_segment_align_start_ rather
+ than data_segment_align_index_.
+ (Script_sections::place_orphan): Rewrite to use
+ Orphan_section_placement.
+
2009-03-17 Ian Lance Taylor <iant@google.com>
* archive.cc (Archive::add_symbols): Check for a version attached
diff --git a/gold/script-sections.cc b/gold/script-sections.cc
index 990a1a2..9daf9ec 100644
--- a/gold/script-sections.cc
+++ b/gold/script-sections.cc
@@ -1,6 +1,6 @@
// script-sections.cc -- linker script SECTIONS for gold
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -43,6 +43,259 @@
namespace gold
{
+// Manage orphan sections. This is intended to be largely compatible
+// with the GNU linker. The Linux kernel implicitly relies on
+// something similar to the GNU linker's orphan placement. We
+// originally used a simpler scheme here, but it caused the kernel
+// build to fail, and was also rather inefficient.
+
+class Orphan_section_placement
+{
+ private:
+ typedef Script_sections::Elements_iterator Elements_iterator;
+
+ public:
+ Orphan_section_placement();
+
+ // Handle an output section during initialization of this mapping.
+ void
+ output_section_init(const std::string& name, Output_section*,
+ Elements_iterator location);
+
+ // Initialize the last location.
+ void
+ last_init(Elements_iterator location);
+
+ // Set *PWHERE to the address of an iterator pointing to the
+ // location to use for an orphan section. Return true if the
+ // iterator has a value, false otherwise.
+ bool
+ find_place(Output_section*, Elements_iterator** pwhere);
+
+ // Return the iterator being used for sections at the very end of
+ // the linker script.
+ Elements_iterator
+ last_place() const;
+
+ private:
+ // The places that we specifically recognize. This list is copied
+ // from the GNU linker.
+ enum Place_index
+ {
+ PLACE_TEXT,
+ PLACE_RODATA,
+ PLACE_DATA,
+ PLACE_BSS,
+ PLACE_REL,
+ PLACE_INTERP,
+ PLACE_NONALLOC,
+ PLACE_LAST,
+ PLACE_MAX
+ };
+
+ // The information we keep for a specific place.
+ struct Place
+ {
+ // The name of sections for this place.
+ const char* name;
+ // Whether we have a location for this place.
+ bool have_location;
+ // The iterator for this place.
+ Elements_iterator location;
+ };
+
+ // Initialize one place element.
+ void
+ initialize_place(Place_index, const char*);
+
+ // The places.
+ Place places_[PLACE_MAX];
+ // True if this is the first call to output_section_init.
+ bool first_init_;
+};
+
+// Initialize Orphan_section_placement.
+
+Orphan_section_placement::Orphan_section_placement()
+ : first_init_(true)
+{
+ this->initialize_place(PLACE_TEXT, ".text");
+ this->initialize_place(PLACE_RODATA, ".rodata");
+ this->initialize_place(PLACE_DATA, ".data");
+ this->initialize_place(PLACE_BSS, ".bss");
+ this->initialize_place(PLACE_REL, NULL);
+ this->initialize_place(PLACE_INTERP, ".interp");
+ this->initialize_place(PLACE_NONALLOC, NULL);
+ this->initialize_place(PLACE_LAST, NULL);
+}
+
+// Initialize one place element.
+
+void
+Orphan_section_placement::initialize_place(Place_index index, const char* name)
+{
+ this->places_[index].name = name;
+ this->places_[index].have_location = false;
+}
+
+// While initializing the Orphan_section_placement information, this
+// is called once for each output section named in the linker script.
+// If we found an output section during the link, it will be passed in
+// OS.
+
+void
+Orphan_section_placement::output_section_init(const std::string& name,
+ Output_section* os,
+ Elements_iterator location)
+{
+ bool first_init = this->first_init_;
+ this->first_init_ = false;
+
+ for (int i = 0; i < PLACE_MAX; ++i)
+ {
+ if (this->places_[i].name != NULL && this->places_[i].name == name)
+ {
+ if (this->places_[i].have_location)
+ {
+ // We have already seen a section with this name.
+ return;
+ }
+
+ this->places_[i].location = location;
+ this->places_[i].have_location = true;
+
+ // If we just found the .bss section, restart the search for
+ // an unallocated section. This follows the GNU linker's
+ // behaviour.
+ if (i == PLACE_BSS)
+ this->places_[PLACE_NONALLOC].have_location = false;
+
+ return;
+ }
+ }
+
+ // Relocation sections.
+ if (!this->places_[PLACE_REL].have_location
+ && os != NULL
+ && (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA)
+ && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ this->places_[PLACE_REL].location = location;
+ this->places_[PLACE_REL].have_location = true;
+ }
+
+ // We find the location for unallocated sections by finding the
+ // first debugging or comment section after the BSS section (if
+ // there is one).
+ if (!this->places_[PLACE_NONALLOC].have_location
+ && (name == ".comment" || Layout::is_debug_info_section(name.c_str())))
+ {
+ // We add orphan sections after the location in PLACES_. We
+ // want to store unallocated sections before LOCATION. If this
+ // is the very first section, we can't use it.
+ if (!first_init)
+ {
+ --location;
+ this->places_[PLACE_NONALLOC].location = location;
+ this->places_[PLACE_NONALLOC].have_location = true;
+ }
+ }
+}
+
+// Initialize the last location.
+
+void
+Orphan_section_placement::last_init(Elements_iterator location)
+{
+ this->places_[PLACE_LAST].location = location;
+ this->places_[PLACE_LAST].have_location = true;
+}
+
+// Set *PWHERE to the address of an iterator pointing to the location
+// to use for an orphan section. Return true if the iterator has a
+// value, false otherwise.
+
+bool
+Orphan_section_placement::find_place(Output_section* os,
+ Elements_iterator** pwhere)
+{
+ // Figure out where OS should go. This is based on the GNU linker
+ // code. FIXME: The GNU linker handles small data sections
+ // specially, but we don't.
+ elfcpp::Elf_Word type = os->type();
+ elfcpp::Elf_Xword flags = os->flags();
+ Place_index index;
+ if ((flags & elfcpp::SHF_ALLOC) == 0
+ && !Layout::is_debug_info_section(os->name()))
+ index = PLACE_NONALLOC;
+ else if ((flags & elfcpp::SHF_ALLOC) == 0)
+ index = PLACE_LAST;
+ else if (type == elfcpp::SHT_NOTE)
+ index = PLACE_INTERP;
+ else if (type == elfcpp::SHT_NOBITS)
+ index = PLACE_BSS;
+ else if ((flags & elfcpp::SHF_WRITE) != 0)
+ index = PLACE_DATA;
+ else if (type == elfcpp::SHT_REL || type == elfcpp::SHT_RELA)
+ index = PLACE_REL;
+ else if ((flags & elfcpp::SHF_EXECINSTR) == 0)
+ index = PLACE_RODATA;
+ else
+ index = PLACE_TEXT;
+
+ // If we don't have a location yet, try to find one based on a
+ // plausible ordering of sections.
+ if (!this->places_[index].have_location)
+ {
+ Place_index follow;
+ switch (index)
+ {
+ default:
+ follow = PLACE_MAX;
+ break;
+ case PLACE_RODATA:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_BSS:
+ follow = PLACE_DATA;
+ break;
+ case PLACE_REL:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_INTERP:
+ follow = PLACE_TEXT;
+ break;
+ }
+ if (follow != PLACE_MAX && this->places_[follow].have_location)
+ {
+ // Set the location of INDEX to the location of FOLLOW. The
+ // location of INDEX will then be incremented by the caller,
+ // so anything in INDEX will continue to be after anything
+ // in FOLLOW.
+ this->places_[index].location = this->places_[follow].location;
+ this->places_[index].have_location = true;
+ }
+ }
+
+ *pwhere = &this->places_[index].location;
+ bool ret = this->places_[index].have_location;
+
+ // The caller will set the location.
+ this->places_[index].have_location = true;
+
+ return ret;
+}
+
+// Return the iterator being used for sections at the very end of the
+// linker script.
+
+Orphan_section_placement::Elements_iterator
+Orphan_section_placement::last_place() const
+{
+ gold_assert(this->places_[PLACE_LAST].have_location);
+ return this->places_[PLACE_LAST].location;
+}
+
// An element in a SECTIONS clause.
class Sections_element
@@ -54,6 +307,11 @@ class Sections_element
virtual ~Sections_element()
{ }
+ // Return whether an output section is relro.
+ virtual bool
+ is_relro() const
+ { return false; }
+
// Record that an output section is relro.
virtual void
set_is_relro()
@@ -82,11 +340,11 @@ class Sections_element
output_section_name(const char*, const char*, Output_section***)
{ return NULL; }
- // Return whether to place an orphan output section after this
- // element.
- virtual bool
- place_orphan_here(const Output_section *, bool*, bool*) const
- { return false; }
+ // Initialize OSP with an output section.
+ virtual void
+ orphan_section_init(Orphan_section_placement*,
+ Script_sections::Elements_iterator)
+ { }
// Set section addresses. This includes applying assignments if the
// the expression is an absolute value.
@@ -1241,6 +1499,11 @@ class Output_section_definition : public Sections_element
void
add_input_section(const Input_section_spec* spec, bool keep);
+ // Return whether the output section is relro.
+ bool
+ is_relro() const
+ { return this->is_relro_; }
+
// Record that the output section is relro.
void
set_is_relro()
@@ -1264,9 +1527,11 @@ class Output_section_definition : public Sections_element
output_section_name(const char* file_name, const char* section_name,
Output_section***);
- // Return whether to place an orphan section after this one.
- bool
- place_orphan_here(const Output_section *os, bool* exact, bool*) const;
+ // Initialize OSP with an output section.
+ void
+ orphan_section_init(Orphan_section_placement* osp,
+ Script_sections::Elements_iterator p)
+ { osp->output_section_init(this->name_, this->output_section_, p); }
// Set the section address.
void
@@ -1538,124 +1803,6 @@ Output_section_definition::output_section_name(const char* file_name,
return NULL;
}
-// Return whether to place an orphan output section after this
-// section.
-
-bool
-Output_section_definition::place_orphan_here(const Output_section *os,
- bool* exact,
- bool* is_relro) const
-{
- *is_relro = this->is_relro_;
-
- // Check for the simple case first.
- if (this->output_section_ != NULL
- && this->output_section_->type() == os->type()
- && this->output_section_->flags() == os->flags())
- {
- *exact = true;
- return true;
- }
-
- // Otherwise use some heuristics.
-
- if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
- return false;
-
- if (os->type() == elfcpp::SHT_NOBITS)
- {
- if (this->name_ == ".bss")
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_NOBITS)
- return true;
- }
- else if (os->type() == elfcpp::SHT_NOTE)
- {
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_NOTE)
- {
- *exact = true;
- return true;
- }
- if (this->name_.compare(0, 5, ".note") == 0)
- {
- *exact = true;
- return true;
- }
- if (this->name_ == ".interp")
- return true;
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_PROGBITS
- && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
- return true;
- }
- else if (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA)
- {
- if (this->name_.compare(0, 4, ".rel") == 0)
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && (this->output_section_->type() == elfcpp::SHT_REL
- || this->output_section_->type() == elfcpp::SHT_RELA))
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_PROGBITS
- && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
- return true;
- }
- else if (os->type() == elfcpp::SHT_PROGBITS
- && (os->flags() & elfcpp::SHF_WRITE) != 0)
- {
- if (this->name_ == ".data")
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_PROGBITS
- && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
- return true;
- }
- else if (os->type() == elfcpp::SHT_PROGBITS
- && (os->flags() & elfcpp::SHF_EXECINSTR) != 0)
- {
- if (this->name_ == ".text")
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_PROGBITS
- && (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) != 0)
- return true;
- }
- else if (os->type() == elfcpp::SHT_PROGBITS
- || (os->type() != elfcpp::SHT_PROGBITS
- && (os->flags() & elfcpp::SHF_WRITE) == 0))
- {
- if (this->name_ == ".rodata")
- {
- *exact = true;
- return true;
- }
- if (this->output_section_ != NULL
- && this->output_section_->type() == elfcpp::SHT_PROGBITS
- && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
- return true;
- }
-
- return false;
-}
-
// Set the section address. Note that the OUTPUT_SECTION_ field will
// be NULL if no input sections were mapped to this output section.
// We still have to adjust dot and process symbol assignments.
@@ -2008,9 +2155,19 @@ class Orphan_output_section : public Sections_element
: os_(os)
{ }
- // Return whether to place an orphan section after this one.
+ // Return whether the orphan output section is relro. We can just
+ // check the output section because we always set the flag, if
+ // needed, just after we create the Orphan_output_section.
bool
- place_orphan_here(const Output_section *os, bool* exact, bool*) const;
+ is_relro() const
+ { return this->os_->is_relro(); }
+
+ // Initialize OSP with an output section. This should have been
+ // done already.
+ void
+ orphan_section_init(Orphan_section_placement*,
+ Script_sections::Elements_iterator)
+ { gold_unreachable(); }
// Set section addresses.
void
@@ -2038,23 +2195,6 @@ class Orphan_output_section : public Sections_element
Output_section* os_;
};
-// Whether to place another orphan section after this one.
-
-bool
-Orphan_output_section::place_orphan_here(const Output_section* os,
- bool* exact,
- bool* is_relro) const
-{
- if (this->os_->type() == os->type()
- && this->os_->flags() == os->flags())
- {
- *exact = true;
- *is_relro = this->os_->is_relro();
- return true;
- }
- return false;
-}
-
// Set section addresses.
void
@@ -2256,7 +2396,9 @@ Script_sections::Script_sections()
sections_elements_(NULL),
output_section_(NULL),
phdrs_elements_(NULL),
- data_segment_align_index_(-1U),
+ orphan_section_placement_(NULL),
+ data_segment_align_start_(),
+ saw_data_segment_align_(false),
saw_relro_end_(false)
{
}
@@ -2391,9 +2533,13 @@ Script_sections::add_input_section(const Input_section_spec* spec, bool keep)
void
Script_sections::data_segment_align()
{
- if (this->data_segment_align_index_ != -1U)
+ if (this->saw_data_segment_align_)
gold_error(_("DATA_SEGMENT_ALIGN may only appear once in a linker script"));
- this->data_segment_align_index_ = this->sections_elements_->size();
+ gold_assert(!this->sections_elements_->empty());
+ Sections_elements::iterator p = this->sections_elements_->end();
+ --p;
+ this->data_segment_align_start_ = p;
+ this->saw_data_segment_align_ = true;
}
// This is called when we see DATA_SEGMENT_RELRO_END. It means that
@@ -2407,14 +2553,13 @@ Script_sections::data_segment_relro_end()
"in a linker script"));
this->saw_relro_end_ = true;
- if (this->data_segment_align_index_ == -1U)
+ if (!this->saw_data_segment_align_)
gold_error(_("DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"));
else
{
- for (size_t i = this->data_segment_align_index_;
- i < this->sections_elements_->size();
- ++i)
- (*this->sections_elements_)[i]->set_is_relro();
+ Sections_elements::iterator p = this->data_segment_align_start_;
+ for (++p; p != this->sections_elements_->end(); ++p)
+ (*p)->set_is_relro();
}
}
@@ -2500,35 +2645,49 @@ Script_sections::output_section_name(const char* file_name,
void
Script_sections::place_orphan(Output_section* os)
{
- // Look for an output section definition which matches the output
- // section. Put a marker after that section.
- bool is_relro = false;
- Sections_elements::iterator place = this->sections_elements_->end();
- for (Sections_elements::iterator p = this->sections_elements_->begin();
- p != this->sections_elements_->end();
- ++p)
+ Orphan_section_placement* osp = this->orphan_section_placement_;
+ if (osp == NULL)
{
- bool exact = false;
- bool is_relro_here;
- if ((*p)->place_orphan_here(os, &exact, &is_relro_here))
- {
- place = p;
- is_relro = is_relro_here;
- if (exact)
- break;
- }
+ // Initialize the Orphan_section_placement structure.
+ osp = new Orphan_section_placement();
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->orphan_section_init(osp, p);
+ gold_assert(!this->sections_elements_->empty());
+ Sections_elements::iterator last = this->sections_elements_->end();
+ --last;
+ osp->last_init(last);
+ this->orphan_section_placement_ = osp;
}
- // The insert function puts the new element before the iterator.
- if (place != this->sections_elements_->end())
- ++place;
+ Orphan_output_section* orphan = new Orphan_output_section(os);
- this->sections_elements_->insert(place, new Orphan_output_section(os));
+ // Look for where to put ORPHAN.
+ Sections_elements::iterator* where;
+ if (osp->find_place(os, &where))
+ {
+ if ((**where)->is_relro())
+ os->set_is_relro();
+ else
+ os->clear_is_relro();
- if (is_relro)
- os->set_is_relro();
+ // We want to insert ORPHAN after *WHERE, and then update *WHERE
+ // so that the next one goes after this one.
+ Sections_elements::iterator p = *where;
+ gold_assert(p != this->sections_elements_->end());
+ ++p;
+ *where = this->sections_elements_->insert(p, orphan);
+ }
else
- os->clear_is_relro();
+ {
+ os->clear_is_relro();
+ // We don't have a place to put this orphan section. Put it,
+ // and all other sections like it, at the end, but before the
+ // sections which always come at the end.
+ Sections_elements::iterator last = osp->last_place();
+ *where = this->sections_elements_->insert(last, orphan);
+ }
}
// Set the addresses of all the output sections. Walk through all the
diff --git a/gold/script-sections.h b/gold/script-sections.h
index 465c24e..390c350 100644
--- a/gold/script-sections.h
+++ b/gold/script-sections.h
@@ -1,6 +1,6 @@
// script-sections.h -- linker script SECTIONS for gold -*- C++ -*-
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -26,6 +26,7 @@
#define GOLD_SCRIPT_SECTIONS_H
#include <cstdio>
+#include <list>
#include <vector>
namespace gold
@@ -41,9 +42,15 @@ class Output_data;
class Output_section_definition;
class Output_section;
class Output_segment;
+class Orphan_section_placement;
class Script_sections
{
+ private:
+ // This is a list, not a vector, because we insert orphan sections
+ // in the middle.
+ typedef std::list<Sections_element*> Sections_elements;
+
public:
Script_sections();
@@ -184,9 +191,10 @@ class Script_sections
void
print(FILE*) const;
- private:
- typedef std::vector<Sections_element*> Sections_elements;
+ // Used for orphan sections.
+ typedef Sections_elements::iterator Elements_iterator;
+ private:
typedef std::vector<Phdrs_element*> Phdrs_elements;
// Create segments.
@@ -232,9 +240,13 @@ class Script_sections
Output_section_definition* output_section_;
// The list of program headers in the PHDRS clause.
Phdrs_elements* phdrs_elements_;
- // The index of the next Sections_element when we see
+ // Where to put orphan sections.
+ Orphan_section_placement* orphan_section_placement_;
+ // A pointer to the last Sections_element when we see
// DATA_SEGMENT_ALIGN.
- size_t data_segment_align_index_;
+ Sections_elements::iterator data_segment_align_start_;
+ // Whether we have seen DATA_SEGMENT_ALIGN.
+ bool saw_data_segment_align_;
// Whether we have seen DATA_SEGMENT_RELRO_END.
bool saw_relro_end_;
};