+// 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;
+}
+