aboutsummaryrefslogtreecommitdiff
path: root/gold/output.h
diff options
context:
space:
mode:
Diffstat (limited to 'gold/output.h')
-rw-r--r--gold/output.h415
1 files changed, 380 insertions, 35 deletions
diff --git a/gold/output.h b/gold/output.h
index e036b98..5c72c02 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -5,6 +5,7 @@
#include <cassert>
#include <list>
+#include <vector>
#include "elfcpp.h"
#include "layout.h"
@@ -31,17 +32,21 @@ class Output_data
virtual
~Output_data();
- // Return the address.
+ // Return the address. This is only valid after Layout::finalize is
+ // finished.
uint64_t
address() const
{ return this->address_; }
- // Return the size of the data.
+ // Return the size of the data. This must be valid after
+ // Layout::finalize calls set_address, but need not be valid before
+ // then.
off_t
data_size() const
{ return this->data_size_; }
- // Return the file offset.
+ // Return the file offset. This is only valid after
+ // Layout::finalize is finished.
off_t
offset() const
{ return this->offset_; }
@@ -67,11 +72,23 @@ class Output_data
is_section_flag_set(elfcpp::Elf_Xword shf) const
{ return this->do_is_section_flag_set(shf); }
- // Set the address and file offset of this data.
+ // Return the output section index, if there is an output section.
+ unsigned int
+ out_shndx() const
+ { return this->do_out_shndx(); }
+
+ // Set the output section index, if this is an output section.
+ void
+ set_out_shndx(unsigned int shndx)
+ { this->do_set_out_shndx(shndx); }
+
+ // Set the address and file offset of this data. This is called
+ // during Layout::finalize.
void
set_address(uint64_t addr, off_t off);
- // Write the data to the output file.
+ // Write the data to the output file. This is called after
+ // Layout::finalize is complete.
void
write(Output_file* file)
{ this->do_write(file); }
@@ -104,6 +121,16 @@ class Output_data
do_is_section_flag_set(elfcpp::Elf_Xword) const
{ return false; }
+ // Return the output section index, if there is an output section.
+ virtual unsigned int
+ do_out_shndx() const
+ { abort(); }
+
+ // Set the output section index, if this is an output section.
+ virtual void
+ do_set_out_shndx(unsigned int)
+ { abort(); }
+
// Set the address and file offset of the data. This only needs to
// be implemented if the child needs to know.
virtual void
@@ -270,6 +297,198 @@ class Output_file_header : public Output_data
const Output_section* shstrtab_;
};
+// Output sections are mainly comprised of input sections. However,
+// there are cases where we have data to write out which is not in an
+// input section. Output_section_data is used in such cases. This is
+// an abstract base class.
+
+class Output_section_data : public Output_data
+{
+ public:
+ Output_section_data(off_t data_size, uint64_t addralign)
+ : Output_data(data_size), output_section_(NULL), addralign_(addralign)
+ { }
+
+ Output_section_data(uint64_t addralign)
+ : Output_data(0), output_section_(NULL), addralign_(addralign)
+ { }
+
+ // Record the output section.
+ void
+ set_output_section(Output_section* os)
+ {
+ assert(this->output_section_ == NULL);
+ this->output_section_ = os;
+ }
+
+ protected:
+ // The child class must implement do_write.
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return the section index of the output section.
+ unsigned int
+ do_out_shndx() const;
+
+ private:
+ // The output section for this section.
+ const Output_section* output_section_;
+ // The required alignment.
+ uint64_t addralign_;
+};
+
+// Output_section_common is used to handle the common symbols. This
+// is quite simple.
+
+class Output_section_common : public Output_section_data
+{
+ public:
+ Output_section_common(uint64_t addralign)
+ : Output_section_data(addralign)
+ { }
+
+ // Set the size.
+ void
+ set_common_size(off_t common_size)
+ { this->set_data_size(common_size); }
+
+ // Write out the data--there is nothing to do, as common symbols are
+ // always zero and are stored in the BSS.
+ void
+ do_write(Output_file*)
+ { }
+};
+
+// Output_section_got is used to manage a GOT. Each entry in the GOT
+// is for one symbol--either a global symbol or a local symbol in an
+// object. The target specific code adds entries to the GOT as
+// needed. The GOT code is then responsible for writing out the data
+// and for generating relocs as required.
+
+template<int size, bool big_endian>
+class Output_section_got : public Output_section_data
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+
+ Output_section_got()
+ : Output_section_data(Output_data::default_alignment(size)),
+ entries_()
+ { }
+
+ // Add an entry for a global symbol to the GOT. This returns the
+ // offset of the new entry from the start of the GOT.
+ unsigned int
+ add_global(Symbol* gsym)
+ {
+ this->entries_.push_back(Got_entry(gsym));
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+
+ // Add an entry for a local symbol to the GOT. This returns the
+ // offset of the new entry from the start of the GOT.
+ unsigned int
+ add_local(Object* object, unsigned int sym_index)
+ {
+ this->entries_.push_back(Got_entry(object, sym_index));
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+
+ // Add a constant to the GOT. This returns the offset of the new
+ // entry from the start of the GOT.
+ unsigned int
+ add_constant(Valtype constant)
+ {
+ this->entries_.push_back(Got_entry(constant));
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+
+ // Write out the GOT table.
+ void
+ do_write(Output_file*);
+
+ private:
+ // This POD class holds a single GOT entry.
+ class Got_entry
+ {
+ public:
+ // Create a zero entry.
+ Got_entry()
+ : local_sym_index_(CONSTANT_CODE)
+ { this->u_.constant = 0; }
+
+ // Create a global symbol entry.
+ Got_entry(Symbol* gsym)
+ : local_sym_index_(GSYM_CODE)
+ { this->u_.gsym = gsym; }
+
+ // Create a local symbol entry.
+ Got_entry(Object* object, unsigned int local_sym_index)
+ : local_sym_index_(local_sym_index)
+ {
+ assert(local_sym_index != GSYM_CODE
+ && local_sym_index != CONSTANT_CODE);
+ this->u_.object = object;
+ }
+
+ // Create a constant entry. The constant is a host value--it will
+ // be swapped, if necessary, when it is written out.
+ Got_entry(Valtype constant)
+ : local_sym_index_(CONSTANT_CODE)
+ { this->u_.constant = constant; }
+
+ // Write the GOT entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ private:
+ enum
+ {
+ GSYM_CODE = -1U,
+ CONSTANT_CODE = -2U
+ };
+
+ union
+ {
+ // For a local symbol, the object.
+ Object* object;
+ // For a global symbol, the symbol.
+ Symbol* gsym;
+ // For a constant, the constant.
+ Valtype constant;
+ } u_;
+ // For a local symbol, the local symbol index. This is -1U for a
+ // global symbol, or -2U for a constant.
+ unsigned int local_sym_index_;
+ };
+
+ typedef std::vector<Got_entry> Got_entries;
+
+ // Return the offset into the GOT of GOT entry I.
+ unsigned int
+ got_offset(unsigned int i) const
+ { return i * (size / 8); }
+
+ // Return the offset into the GOT of the last entry added.
+ unsigned int
+ last_got_offset() const
+ { return this->got_offset(this->entries_.size() - 1); }
+
+ // Set the size of the section.
+ void
+ set_got_size()
+ { this->set_data_size(this->got_offset(this->entries_.size())); }
+
+ // The list of GOT entries.
+ Got_entries entries_;
+};
+
// An output section. We don't expect to have too many output
// sections, so we don't bother to do a template on the size.
@@ -278,16 +497,20 @@ class Output_section : public Output_data
public:
// Create an output section, giving the name, type, and flags.
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
- unsigned int shndx);
+ bool may_add_data);
virtual ~Output_section();
- // Add a new input section named NAME with header SHDR from object
- // OBJECT. Return the offset within the output section.
+ // Add a new input section SHNDX, named NAME, with header SHDR, from
+ // object OBJECT. Return the offset within the output section.
template<int size, bool big_endian>
off_t
- add_input_section(Object* object, const char *name,
+ add_input_section(Object* object, unsigned int shndx, const char *name,
const elfcpp::Shdr<size, big_endian>& shdr);
+ // Add generated data ODATA to this output section.
+ virtual void
+ add_output_section_data(Output_section_data* posd);
+
// Return the section name.
const char*
name() const
@@ -303,15 +526,15 @@ class Output_section : public Output_data
flags() const
{ return this->flags_; }
- // Return the address alignment.
- uint64_t
- addralign() const
- { return this->addralign_; }
-
- // Return the section index.
+ // Return the section index in the output file.
unsigned int
- shndx() const
- { return this->shndx_; }
+ do_out_shndx() const
+ { return this->out_shndx_; }
+
+ // Set the output section index.
+ void
+ do_set_out_shndx(unsigned int shndx)
+ { this->out_shndx_ = shndx; }
// Set the entsize field.
void
@@ -333,12 +556,19 @@ class Output_section : public Output_data
set_addralign(uint64_t v)
{ this->addralign_ = v; }
+ // Set the address of the Output_section. For a typical
+ // Output_section, there is nothing to do, but if there are any
+ // Output_section_data objects we need to set the final addresses
+ // here.
+ void
+ do_set_address(uint64_t, off_t);
+
// Write the data to the file. For a typical Output_section, this
- // does nothing. We write out the data by looping over all the
- // input sections.
+ // does nothing: the data is written out by calling Object::Relocate
+ // on each input object. But if there are any Output_section_data
+ // objects we do need to write them out here.
virtual void
- do_write(Output_file*)
- { }
+ do_write(Output_file*);
// Return the address alignment--function required by parent class.
uint64_t
@@ -366,6 +596,83 @@ class Output_section : public Output_data
write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
private:
+ // 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), data_size_(0)
+ { this->u_.object = NULL; }
+
+ Input_section(Object* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ data_size_(data_size)
+ {
+ assert(shndx != -1U);
+ this->u_.object = object;
+ }
+
+ Input_section(Output_section_data* posd)
+ : shndx_(-1U),
+ p2align_(ffsll(static_cast<long long>(posd->addralign()))),
+ data_size_(0)
+ { this->u_.posd = posd; }
+
+ // The required alignment.
+ uint64_t
+ addralign() const
+ { return static_cast<uint64_t>(1) << this->p2align_; }
+
+ // Return the required size.
+ off_t
+ data_size() const;
+
+ // Set the address and file offset. This is called during
+ // Layout::finalize. SECOFF is the file offset of the enclosing
+ // section.
+ void
+ set_address(uint64_t addr, off_t off, off_t secoff);
+
+ // Write out the data. This does nothing for an input section.
+ void
+ write(Output_file*);
+
+ private:
+ // Whether this is an input section.
+ bool
+ is_input_section() const
+ { return this->shndx_ != -1U; }
+
+ // For an ordinary input section, this is the section index in
+ // the input file. For an Output_section_data, this is -1U.
+ unsigned int shndx_;
+ // The required alignment, stored as a power of 2.
+ unsigned int p2align_;
+ // For an ordinary input section, the section size.
+ off_t data_size_;
+ union
+ {
+ // If shndx_ != -1U, this points to the object which holds the
+ // input section.
+ Object* object;
+ // If shndx_ == -1U, this is the data to write out.
+ Output_section_data* posd;
+ } u_;
+ };
+
+ typedef std::vector<Input_section> Input_section_list;
+
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
@@ -385,16 +692,35 @@ class Output_section : public Output_data
// The section flags.
elfcpp::Elf_Xword flags_;
// The section index.
- unsigned int shndx_;
+ unsigned int out_shndx_;
+ // The input sections. This will be empty in cases where we don't
+ // need to keep track of them.
+ Input_section_list input_sections_;
+ // The offset of the first entry in input_sections_.
+ off_t first_input_offset_;
+ // Whether we permit adding data.
+ bool may_add_data_;
};
// A special Output_section which represents the symbol table
-// (SHT_SYMTAB).
+// (SHT_SYMTAB). The actual data is written out by
+// Symbol_table::write_globals.
class Output_section_symtab : public Output_section
{
public:
- Output_section_symtab(const char* name, off_t size, unsigned int shndx);
+ Output_section_symtab(const char* name, off_t size);
+
+ // The data is written out by Symbol_table::write_globals. We don't
+ // do anything here.
+ void
+ do_write(Output_file*)
+ { }
+
+ // We don't expect to see any input sections or data here.
+ void
+ add_output_section_data(Output_section_data*)
+ { abort(); }
};
// A special Output_section which holds a string table.
@@ -402,13 +728,17 @@ class Output_section_symtab : public Output_section
class Output_section_strtab : public Output_section
{
public:
- Output_section_strtab(const char* name, Stringpool* contents,
- unsigned int shndx);
+ Output_section_strtab(const char* name, Stringpool* contents);
// Write out the data.
void
do_write(Output_file*);
+ // We don't expect to see any input sections or data here.
+ void
+ add_output_section_data(Output_section_data*)
+ { abort(); }
+
private:
Stringpool* contents_;
};
@@ -448,9 +778,14 @@ class Output_segment
memsz() const
{ return this->memsz_; }
+ // Return the file size.
+ off_t
+ filesz() const
+ { return this->filesz_; }
+
// Return the maximum alignment of the Output_data.
uint64_t
- max_data_align() const;
+ addralign();
// Add an Output_section to this segment.
void
@@ -463,11 +798,12 @@ class Output_segment
// Set the address of the segment to ADDR and the offset to *POFF
// (aligned if necessary), and set the addresses and offsets of all
- // contained output sections accordingly. Return the address of the
- // immediately following segment. Update *POFF. This should only
- // be called for a PT_LOAD segment.
+ // contained output sections accordingly. Set the section indexes
+ // of all contained output sections starting with *PSHNDX. Return
+ // the address of the immediately following segment. Update *POFF
+ // and *PSHNDX. This should only be called for a PT_LOAD segment.
uint64_t
- set_section_addresses(uint64_t addr, off_t* poff);
+ set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
// Set the offset of this segment based on the section. This should
// only be called for a non-PT_LOAD segment.
@@ -481,13 +817,14 @@ class Output_segment
// Write the segment header into *OPHDR.
template<int size, bool big_endian>
void
- write_header(elfcpp::Phdr_write<size, big_endian>*) const;
+ write_header(elfcpp::Phdr_write<size, big_endian>*);
// Write the section headers of associated sections into V.
template<int size, bool big_endian>
unsigned char*
write_section_headers(const Stringpool*,
- unsigned char* v ACCEPT_SIZE_ENDIAN) const;
+ unsigned char* v,
+ unsigned int* pshndx ACCEPT_SIZE_ENDIAN) const;
private:
Output_segment(const Output_segment&);
@@ -495,9 +832,14 @@ class Output_segment
typedef std::list<Output_data*> Output_data_list;
+ // Find the maximum alignment in an Output_data_list.
+ static uint64_t
+ maximum_alignment(const Output_data_list*);
+
// Set the section addresses in an Output_data_list.
uint64_t
- set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff);
+ set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
+ unsigned int* pshndx);
// Return the number of Output_sections in an Output_data_list.
unsigned int
@@ -507,7 +849,8 @@ class Output_segment
template<int size, bool big_endian>
unsigned char*
write_section_headers_list(const Stringpool*, const Output_data_list*,
- unsigned char* v ACCEPT_SIZE_ENDIAN) const;
+ unsigned char* v,
+ unsigned int* pshdx ACCEPT_SIZE_ENDIAN) const;
// The list of output data with contents attached to this segment.
Output_data_list output_data_;
@@ -529,6 +872,8 @@ class Output_segment
elfcpp::Elf_Word type_;
// The segment flags.
elfcpp::Elf_Word flags_;
+ // Whether we have set align_.
+ bool is_align_known_;
};
// This class represents the output file.