+ // The next few calls are for linker script support.
+
+ // In some cases we need to keep a list of the input sections
+ // associated with this output section. We only need the list if we
+ // might have to change the offsets of the input section within the
+ // output section after we add the input section. The ordinary
+ // input sections will be written out when we process the object
+ // file, and as such we don't need to track them here. We do need
+ // to track Output_section_data objects here. We store instances of
+ // this structure in a std::vector, so it must be a POD. There can
+ // be many instances of this structure, so we use a union to save
+ // some space.
+ class Input_section
+ {
+ public:
+ Input_section()
+ : shndx_(0), p2align_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.object = NULL;
+ }
+
+ // For an ordinary input section.
+ Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ section_order_index_(0)
+ {
+ gold_assert(shndx != OUTPUT_SECTION_CODE
+ && shndx != MERGE_DATA_SECTION_CODE
+ && shndx != MERGE_STRING_SECTION_CODE
+ && shndx != RELAXED_INPUT_SECTION_CODE);
+ this->u1_.data_size = data_size;
+ this->u2_.object = object;
+ }
+
+ // For a non-merge output section.
+ Input_section(Output_section_data* posd)
+ : shndx_(OUTPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.posd = posd;
+ }
+
+ // For a merge section.
+ Input_section(Output_section_data* posd, bool is_string, uint64_t entsize)
+ : shndx_(is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE),
+ p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.entsize = entsize;
+ this->u2_.posd = posd;
+ }
+
+ // For a relaxed input section.
+ Input_section(Output_relaxed_input_section* psection)
+ : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.poris = psection;
+ }
+
+ unsigned int
+ section_order_index() const
+ {
+ return this->section_order_index_;
+ }
+
+ void
+ set_section_order_index(unsigned int number)
+ {
+ this->section_order_index_ = number;
+ }
+
+ // The required alignment.
+ uint64_t
+ addralign() const
+ {
+ if (this->p2align_ != 0)
+ return static_cast<uint64_t>(1) << (this->p2align_ - 1);
+ else if (!this->is_input_section())
+ return this->u2_.posd->addralign();
+ else
+ return 0;
+ }
+
+ // Set the required alignment, which must be either 0 or a power of 2.
+ // For input sections that are sub-classes of Output_section_data, a
+ // alignment of zero means asking the underlying object for alignment.
+ void
+ set_addralign(uint64_t addralign)
+ {
+ if (addralign == 0)
+ this->p2align_ = 0;
+ else
+ {
+ gold_assert((addralign & (addralign - 1)) == 0);
+ this->p2align_ = ffsll(static_cast<long long>(addralign));
+ }
+ }
+
+ // Return the current required size, without finalization.
+ off_t
+ current_data_size() const;
+
+ // Return the required size.
+ off_t
+ data_size() const;
+
+ // Whether this is an input section.
+ bool
+ is_input_section() const
+ {
+ return (this->shndx_ != OUTPUT_SECTION_CODE
+ && this->shndx_ != MERGE_DATA_SECTION_CODE
+ && this->shndx_ != MERGE_STRING_SECTION_CODE
+ && this->shndx_ != RELAXED_INPUT_SECTION_CODE);
+ }
+
+ // Return whether this is a merge section which matches the
+ // parameters.
+ bool
+ is_merge_section(bool is_string, uint64_t entsize,
+ uint64_t addralign) const
+ {
+ return (this->shndx_ == (is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE)
+ && this->u1_.entsize == entsize
+ && this->addralign() == addralign);
+ }
+
+ // Return whether this is a merge section for some input section.
+ bool
+ is_merge_section() const
+ {
+ return (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ }
+
+ // Return whether this is a relaxed input section.
+ bool
+ is_relaxed_input_section() const
+ { return this->shndx_ == RELAXED_INPUT_SECTION_CODE; }
+
+ // Return whether this is a generic Output_section_data.
+ bool
+ is_output_section_data() const
+ {
+ return this->shndx_ == OUTPUT_SECTION_CODE;
+ }
+
+ // Return the object for an input section.
+ Relobj*
+ relobj() const;
+
+ // Return the input section index for an input section.
+ unsigned int
+ shndx() const;
+
+ // For non-input-sections, return the associated Output_section_data
+ // object.
+ Output_section_data*
+ output_section_data() const
+ {
+ gold_assert(!this->is_input_section());
+ return this->u2_.posd;
+ }
+
+ // For a merge section, return the Output_merge_base pointer.
+ Output_merge_base*
+ output_merge_base() const
+ {
+ gold_assert(this->is_merge_section());
+ return this->u2_.pomb;
+ }
+
+ // Return the Output_relaxed_input_section object.
+ Output_relaxed_input_section*
+ relaxed_input_section() const
+ {
+ gold_assert(this->is_relaxed_input_section());
+ return this->u2_.poris;
+ }
+
+ // Set the output section.
+ void
+ set_output_section(Output_section* os)
+ {
+ gold_assert(!this->is_input_section());
+ Output_section_data* posd =
+ this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd;
+ posd->set_output_section(os);
+ }
+
+ // Set the address and file offset. This is called during
+ // Layout::finalize. SECTION_FILE_OFFSET is the file offset of
+ // the enclosing section.
+ void
+ set_address_and_file_offset(uint64_t address, off_t file_offset,
+ off_t section_file_offset);
+
+ // Reset the address and file offset.
+ void
+ reset_address_and_file_offset();
+
+ // Finalize the data size.
+ void
+ finalize_data_size();
+
+ // Add an input section, for SHF_MERGE sections.
+ bool
+ add_input_section(Relobj* object, unsigned int shndx)
+ {
+ gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ return this->u2_.posd->add_input_section(object, shndx);
+ }
+
+ // Given an input OBJECT, an input section index SHNDX within that
+ // object, and an OFFSET relative to the start of that input
+ // section, return whether or not the output offset is known. If
+ // this function returns true, it sets *POUTPUT to the offset in
+ // the output section, relative to the start of the input section
+ // in the output section. *POUTPUT may be different from OFFSET
+ // for a merged section.
+ bool
+ output_offset(const Relobj* object, unsigned int shndx,
+ section_offset_type offset,
+ section_offset_type* poutput) const;
+
+ // Return whether this is the merge section for the input section
+ // SHNDX in OBJECT.
+ bool
+ is_merge_section_for(const Relobj* object, unsigned int shndx) const;
+
+ // Write out the data. This does nothing for an input section.
+ void
+ write(Output_file*);
+
+ // Write the data to a buffer. This does nothing for an input
+ // section.
+ void
+ write_to_buffer(unsigned char*);
+
+ // Print to a map file.
+ void
+ print_to_mapfile(Mapfile*) const;
+
+ // Print statistics about merge sections to stderr.
+ void
+ print_merge_stats(const char* section_name)
+ {
+ if (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE)
+ this->u2_.posd->print_merge_stats(section_name);
+ }
+
+ private:
+ // Code values which appear in shndx_. If the value is not one of
+ // these codes, it is the input section index in the object file.
+ enum
+ {
+ // An Output_section_data.
+ OUTPUT_SECTION_CODE = -1U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS not set.
+ MERGE_DATA_SECTION_CODE = -2U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS set.
+ MERGE_STRING_SECTION_CODE = -3U,
+ // An Output_section_data for a relaxed input section.
+ RELAXED_INPUT_SECTION_CODE = -4U
+ };
+
+ // For an ordinary input section, this is the section index in the
+ // input file. For an Output_section_data, this is
+ // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE.
+ unsigned int shndx_;
+ // The required alignment, stored as a power of 2.
+ unsigned int p2align_;
+ union
+ {
+ // For an ordinary input section, the section size.
+ off_t data_size;
+ // For OUTPUT_SECTION_CODE or RELAXED_INPUT_SECTION_CODE, this is not
+ // used. For MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
+ // entity size.
+ uint64_t entsize;
+ } u1_;
+ union
+ {
+ // For an ordinary input section, the object which holds the
+ // input section.
+ Relobj* object;
+ // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE, the data.
+ Output_section_data* posd;
+ Output_merge_base* pomb;
+ // For RELAXED_INPUT_SECTION_CODE, the data.
+ Output_relaxed_input_section* poris;
+ } u2_;
+ // The line number of the pattern it matches in the --section-ordering-file
+ // file. It is 0 if does not match any pattern.
+ unsigned int section_order_index_;
+ };
+
+ // Store the list of input sections for this Output_section into the
+ // list passed in. This removes the input sections, leaving only
+ // any Output_section_data elements. This returns the size of those
+ // Output_section_data elements. ADDRESS is the address of this
+ // output section. FILL is the fill value to use, in case there are
+ // any spaces between the remaining Output_section_data elements.
+ uint64_t
+ get_input_sections(uint64_t address, const std::string& fill,
+ std::list<Input_section>*);
+
+ // Add a script input section. A script input section can either be
+ // a plain input section or a sub-class of Output_section_data.
+ void
+ add_script_input_section(const Input_section& input_section);
+
+ // Set the current size of the output section.
+ void
+ set_current_data_size(off_t size)
+ { this->set_current_data_size_for_child(size); }
+
+ // End of linker script support.
+
+ // Save states before doing section layout.
+ // This is used for relaxation.
+ void
+ save_states();
+
+ // Restore states prior to section layout.
+ void
+ restore_states();
+
+ // Discard states.
+ void
+ discard_states();
+
+ // Convert existing input sections to relaxed input sections.
+ void
+ convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& sections);
+
+ // Find a relaxed input section to an input section in OBJECT
+ // with index SHNDX. Return NULL if none is found.
+ const Output_relaxed_input_section*
+ find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+
+ // Whether section offsets need adjustment due to relaxation.
+ bool
+ section_offsets_need_adjustment() const
+ { return this->section_offsets_need_adjustment_; }
+
+ // Set section_offsets_need_adjustment to be true.
+ void
+ set_section_offsets_need_adjustment()
+ { this->section_offsets_need_adjustment_ = true; }
+
+ // Adjust section offsets of input sections in this. This is
+ // requires if relaxation caused some input sections to change sizes.
+ void
+ adjust_section_offsets();
+
+ // Whether this is a NOLOAD section.
+ bool
+ is_noload() const
+ { return this->is_noload_; }
+
+ // Set NOLOAD flag.
+ void
+ set_is_noload()
+ { this->is_noload_ = true; }
+
+ // Print merge statistics to stderr.
+ void
+ print_merge_stats();
+
+ // Set a fixed layout for the section. Used for incremental update links.
+ void
+ set_fixed_layout(uint64_t sh_addr, off_t sh_offset, off_t sh_size,
+ uint64_t sh_addralign);
+
+ // Return TRUE if the section has a fixed layout.
+ bool
+ has_fixed_layout() const
+ { return this->has_fixed_layout_; }
+
+ // Reserve space within the fixed layout for the section. Used for
+ // incremental update links.
+ void
+ reserve(uint64_t sh_offset, uint64_t sh_size);
+
+ // Allocate space from the free list for the section. Used for
+ // incremental update links.
+ off_t
+ allocate(off_t len, uint64_t addralign);
+