+// A region of memory.
+class Memory_region
+{
+ public:
+ Memory_region(const char* name, size_t namelen, unsigned int attributes,
+ Expression* start, Expression* length)
+ : name_(name, namelen),
+ attributes_(attributes),
+ start_(start),
+ length_(length),
+ current_offset_(0),
+ vma_sections_(),
+ lma_sections_(),
+ last_section_(NULL)
+ { }
+
+ // Return the name of this region.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Return the start address of this region.
+ Expression*
+ start_address() const
+ { return this->start_; }
+
+ // Return the length of this region.
+ Expression*
+ length() const
+ { return this->length_; }
+
+ // Print the region (when debugging).
+ void
+ print(FILE*) const;
+
+ // Return true if <name,namelen> matches this region.
+ bool
+ name_match(const char* name, size_t namelen)
+ {
+ return (this->name_.length() == namelen
+ && strncmp(this->name_.c_str(), name, namelen) == 0);
+ }
+
+ Expression*
+ get_current_address() const
+ {
+ return
+ script_exp_binary_add(this->start_,
+ script_exp_integer(this->current_offset_));
+ }
+
+ void
+ set_address(uint64_t addr, const Symbol_table* symtab, const Layout* layout)
+ {
+ uint64_t start = this->start_->eval(symtab, layout, false);
+ uint64_t len = this->length_->eval(symtab, layout, false);
+ if (addr < start || addr >= start + len)
+ gold_error(_("address 0x%llx is not within region %s"),
+ static_cast<unsigned long long>(addr),
+ this->name_.c_str());
+ else if (addr < start + this->current_offset_)
+ gold_error(_("address 0x%llx moves dot backwards in region %s"),
+ static_cast<unsigned long long>(addr),
+ this->name_.c_str());
+ this->current_offset_ = addr - start;
+ }
+
+ void
+ increment_offset(std::string section_name, uint64_t amount,
+ const Symbol_table* symtab, const Layout* layout)
+ {
+ this->current_offset_ += amount;
+
+ if (this->current_offset_
+ > this->length_->eval(symtab, layout, false))
+ gold_error(_("section %s overflows end of region %s"),
+ section_name.c_str(), this->name_.c_str());
+ }
+
+ // Returns true iff there is room left in this region
+ // for AMOUNT more bytes of data.
+ bool
+ has_room_for(const Symbol_table* symtab, const Layout* layout,
+ uint64_t amount) const
+ {
+ return (this->current_offset_ + amount
+ < this->length_->eval(symtab, layout, false));
+ }
+
+ // Return true if the provided section flags
+ // are compatible with this region's attributes.
+ bool
+ attributes_compatible(elfcpp::Elf_Xword flags, elfcpp::Elf_Xword type) const;
+
+ void
+ add_section(Output_section_definition* sec, bool vma)
+ {
+ if (vma)
+ this->vma_sections_.push_back(sec);
+ else
+ this->lma_sections_.push_back(sec);
+ }
+
+ typedef std::vector<Output_section_definition*> Section_list;
+
+ // Return the start of the list of sections
+ // whose VMAs are taken from this region.
+ Section_list::const_iterator
+ get_vma_section_list_start() const
+ { return this->vma_sections_.begin(); }
+
+ // Return the start of the list of sections
+ // whose LMAs are taken from this region.
+ Section_list::const_iterator
+ get_lma_section_list_start() const
+ { return this->lma_sections_.begin(); }
+
+ // Return the end of the list of sections
+ // whose VMAs are taken from this region.
+ Section_list::const_iterator
+ get_vma_section_list_end() const
+ { return this->vma_sections_.end(); }
+
+ // Return the end of the list of sections
+ // whose LMAs are taken from this region.
+ Section_list::const_iterator
+ get_lma_section_list_end() const
+ { return this->lma_sections_.end(); }
+
+ Output_section_definition*
+ get_last_section() const
+ { return this->last_section_; }
+
+ void
+ set_last_section(Output_section_definition* sec)
+ { this->last_section_ = sec; }
+
+ private:
+
+ std::string name_;
+ unsigned int attributes_;
+ Expression* start_;
+ Expression* length_;
+ // The offset to the next free byte in the region.
+ // Note - for compatibility with GNU LD we only maintain one offset
+ // regardless of whether the region is being used for VMA values,
+ // LMA values, or both.
+ uint64_t current_offset_;
+ // A list of sections whose VMAs are set inside this region.
+ Section_list vma_sections_;
+ // A list of sections whose LMAs are set inside this region.
+ Section_list lma_sections_;
+ // The latest section to make use of this region.
+ Output_section_definition* last_section_;
+};
+
+// Return true if the provided section flags
+// are compatible with this region's attributes.
+
+bool
+Memory_region::attributes_compatible(elfcpp::Elf_Xword flags,
+ elfcpp::Elf_Xword type) const
+{
+ unsigned int attrs = this->attributes_;
+
+ // No attributes means that this region is not compatible with anything.
+ if (attrs == 0)
+ return false;
+
+ bool match = true;
+ do
+ {
+ switch (attrs & - attrs)
+ {
+ case MEM_EXECUTABLE:
+ if ((flags & elfcpp::SHF_EXECINSTR) == 0)
+ match = false;
+ break;
+
+ case MEM_WRITEABLE:
+ if ((flags & elfcpp::SHF_WRITE) == 0)
+ match = false;
+ break;
+
+ case MEM_READABLE:
+ // All sections are presumed readable.
+ break;
+
+ case MEM_ALLOCATABLE:
+ if ((flags & elfcpp::SHF_ALLOC) == 0)
+ match = false;
+ break;
+
+ case MEM_INITIALIZED:
+ if ((type & elfcpp::SHT_NOBITS) != 0)
+ match = false;
+ break;
+ }
+ attrs &= ~ (attrs & - attrs);
+ }
+ while (attrs != 0);
+
+ return match;
+}
+
+// Print a memory region.
+
+void
+Memory_region::print(FILE* f) const
+{
+ fprintf(f, " %s", this->name_.c_str());
+
+ unsigned int attrs = this->attributes_;
+ if (attrs != 0)
+ {
+ fprintf(f, " (");
+ do
+ {
+ switch (attrs & - attrs)
+ {
+ case MEM_EXECUTABLE: fputc('x', f); break;
+ case MEM_WRITEABLE: fputc('w', f); break;
+ case MEM_READABLE: fputc('r', f); break;
+ case MEM_ALLOCATABLE: fputc('a', f); break;
+ case MEM_INITIALIZED: fputc('i', f); break;
+ default:
+ gold_unreachable();
+ }
+ attrs &= ~ (attrs & - attrs);
+ }
+ while (attrs != 0);
+ fputc(')', f);
+ }
+
+ fprintf(f, " : origin = ");
+ this->start_->print(f);
+ fprintf(f, ", length = ");
+ this->length_->print(f);
+ fprintf(f, "\n");
+}
+
+// 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);
+
+ // 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
+ 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_TLS,
+ PLACE_TLS_BSS,
+ PLACE_BSS,
+ PLACE_LAST_ALLOC,
+ 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_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);
+ 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;
+
+ // 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)
+ {
+ 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 ((flags & elfcpp::SHF_TLS) != 0)
+ {
+ if (type == elfcpp::SHT_NOBITS)
+ index = PLACE_TLS_BSS;
+ else
+ index = PLACE_TLS;
+ }
+ 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_DATA:
+ follow = PLACE_RODATA;
+ if (!this->places_[PLACE_RODATA].have_location)
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_BSS:
+ follow = PLACE_LAST_ALLOC;
+ break;
+ case PLACE_REL:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_INTERP:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_TLS:
+ follow = PLACE_DATA;
+ break;
+ case PLACE_TLS_BSS:
+ follow = PLACE_TLS;
+ if (!this->places_[PLACE_TLS].have_location)
+ follow = PLACE_DATA;
+ 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;
+}
+
+// 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.
+
+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;
+}
+