}
}
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ set_tls_offset(uint64_t tls_base)
+ { this->do_set_tls_offset(tls_base); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ tls_offset() const
+ { return this->do_tls_offset(); }
+
// Write the data to the output file. This is called after
// Layout::finalize is complete.
void
set_final_data_size()
{ gold_unreachable(); }
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ virtual void
+ do_set_tls_offset(uint64_t)
+ { gold_unreachable(); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ virtual uint64_t
+ do_tls_offset() const
+ { gold_unreachable(); }
+
// Functions that child classes may call.
// Whether the address is valid.
off_t *poutput) const
{ return this->do_output_offset(object, shndx, offset, poutput); }
+ // Write the contents to a buffer. This is used for sections which
+ // require postprocessing, such as compression.
+ void
+ write_to_buffer(unsigned char* buffer)
+ { this->do_write_to_buffer(buffer); }
+
protected:
// The child class must implement do_write.
do_output_offset(const Relobj*, unsigned int, off_t, off_t*) const
{ return false; }
+ // The child class may implement write_to_buffer. Most child
+ // classes can not appear in a compressed section, and they do not
+ // implement this.
+ virtual void
+ do_write_to_buffer(unsigned char*)
+ { gold_unreachable(); }
+
// Return the required alignment.
uint64_t
do_addralign() const
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->data_.data(), this->data_.size()); }
+
private:
std::string data_;
};
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->p_, this->data_size()); }
+
private:
const unsigned char* p_;
};
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { this->strtab_->write_to_buffer(buffer, this->data_size()); }
+
private:
Stringpool* strtab_;
};
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address)
- : address_(address), local_sym_index_(GSYM_CODE), type_(type),
- shndx_(INVALID_CODE)
- {
- this->u1_.gsym = gsym;
- this->u2_.od = od;
- }
+ Address address, bool is_relative);
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
- unsigned int shndx, Address address)
- : address_(address), local_sym_index_(GSYM_CODE), type_(type),
- shndx_(shndx)
- {
- gold_assert(shndx != INVALID_CODE);
- this->u1_.gsym = gsym;
- this->u2_.relobj = relobj;
- }
+ unsigned int shndx, Address address, bool is_relative);
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type,
- Output_data* od,
- Address address)
- : address_(address), local_sym_index_(local_sym_index), type_(type),
- shndx_(INVALID_CODE)
- {
- gold_assert(local_sym_index != GSYM_CODE
- && local_sym_index != INVALID_CODE);
- this->u1_.relobj = relobj;
- this->u2_.od = od;
- }
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, bool is_relative);
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type,
- unsigned int shndx,
- Address address)
- : address_(address), local_sym_index_(local_sym_index), type_(type),
- shndx_(shndx)
- {
- gold_assert(local_sym_index != GSYM_CODE
- && local_sym_index != INVALID_CODE);
- gold_assert(shndx != INVALID_CODE);
- this->u1_.relobj = relobj;
- this->u2_.relobj = relobj;
- }
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address, bool is_relative);
// A reloc against the STT_SECTION symbol of an output section.
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
- Address address)
- : address_(address), local_sym_index_(SECTION_CODE), type_(type),
- shndx_(INVALID_CODE)
- {
- this->u1_.os = os;
- this->u2_.od = od;
- }
+ Address address);
Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
- unsigned int shndx, Address address)
- : address_(address), local_sym_index_(SECTION_CODE), type_(type),
- shndx_(shndx)
- {
- gold_assert(shndx != INVALID_CODE);
- this->u1_.os = os;
- this->u2_.relobj = relobj;
- }
+ unsigned int shndx, Address address);
+
+ // Return TRUE if this is a RELATIVE relocation.
+ bool
+ is_relative() const
+ { return this->is_relative_; }
+
+ // Get the value of the symbol referred to by a Rel relocation.
+
+ Address
+ symbol_value() const;
// Write the reloc entry to an output view.
void
// for a global symbol, or INVALID_CODE for an uninitialized value.
unsigned int local_sym_index_;
// The reloc type--a processor specific code.
- unsigned int type_;
+ unsigned int type_ : 31;
+ // True if the relocation is a RELATIVE relocation.
+ bool is_relative_ : 1;
// If the reloc address is an input section in an object, the
// section index. This is INVALID_CODE if the reloc address is
// specified in some other way.
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address, Addend addend)
- : rel_(gsym, type, od, address), addend_(addend)
+ Address address, Addend addend, bool is_relative)
+ : rel_(gsym, type, od, address, is_relative), addend_(addend)
{ }
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
- unsigned int shndx, Address address, Addend addend)
- : rel_(gsym, type, relobj, shndx, address), addend_(addend)
+ unsigned int shndx, Address address, Addend addend,
+ bool is_relative)
+ : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend)
{ }
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type, Output_data* od, Address address,
- Addend addend)
- : rel_(relobj, local_sym_index, type, od, address), addend_(addend)
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address,
+ Addend addend, bool is_relative)
+ : rel_(relobj, local_sym_index, type, od, address, is_relative),
+ addend_(addend)
{ }
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type,
- unsigned int shndx,
- Address address,
- Addend addend)
- : rel_(relobj, local_sym_index, type, shndx, address),
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address,
+ Addend addend, bool is_relative)
+ : rel_(relobj, local_sym_index, type, shndx, address, is_relative),
addend_(addend)
{ }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
- { this->add(od, Output_reloc_type(gsym, type, od, address)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
unsigned int shndx, Address address)
- { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address)); }
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false)); }
+
+ // Add a RELATIVE reloc against a global symbol. The final relocation
+ // will not reference the symbol.
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, true)); }
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Relobj* relobj, unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ true)); }
// Add a reloc against a local symbol.
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- address)); }
+ address, false)); }
void
add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address)); }
+ address, false)); }
+
+ // Add a RELATIVE reloc against a local symbol.
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+ address, true)); }
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, true)); }
// A reloc against the STT_SECTION symbol of an output section.
// OS is the Output_section that the relocation refers to; OD is
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, od, address, addend)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+ false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
unsigned int shndx, Address address,
Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- addend)); }
+ addend, false)); }
+
+ // Add a RELATIVE reloc against a global symbol. The final output
+ // relocation will not reference the symbol, but we must keep the symbol
+ // information long enough to set the addend of the relocation correctly
+ // when it is written.
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); }
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Relobj* relobj, unsigned int shndx, Address address,
+ Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, true)); }
// Add a reloc against a local symbol.
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
- addend));
+ addend, false));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, addend));
+ address, addend, false));
+ }
+
+ // Add a RELATIVE reloc against a local symbol.
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, true));
+ }
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, addend, true));
}
// A reloc against the STT_SECTION symbol of an output section.
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian> Rel_dyn;
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Rela_dyn;
Output_data_got()
: Output_section_data_build(Output_data::default_alignment_for_size(size)),
bool
add_global(Symbol* gsym);
+ // Add an entry for a global symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_global_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, unsigned int r_type);
+
+ void
+ add_global_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, unsigned int r_type);
+
// Add an entry for a local symbol to the GOT. This returns true if
// this is a new GOT entry, false if the symbol already has a GOT
// entry.
bool
add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index);
+ // Add an entry for a global symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_local_with_rel(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_local_with_rela(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
// Add an entry (or pair of entries) for a global TLS symbol to the GOT.
// Return true if this is a new GOT entry, false if the symbol was
// already in the GOT.
bool
add_global_tls(Symbol* gsym, bool need_pair);
+ // Add an entry for a global TLS symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE.
+ void
+ add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
+ // Add a pair of entries for a global TLS symbol to the GOT, and add
+ // dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively.
+ void
+ add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type);
+
+ void
+ add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type);
+
// Add an entry (or pair of entries) for a local TLS symbol to the GOT.
// This returns true if this is a new GOT entry, false if the symbol
// already has a GOT entry.
add_local_tls(Sized_relobj<size, big_endian>* object,
unsigned int sym_index, bool need_pair);
+ // Add an entry (or pair of entries) for a local TLS symbol to the GOT,
+ // and add a dynamic relocation of type R_TYPE for the first GOT entry.
+ // Because this is a local symbol, the first GOT entry can be relocated
+ // relative to a section symbol, and the second GOT entry will have an
+ // dtv-relative value that can be computed at link time.
+ void
+ add_local_tls_with_rel(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, unsigned int shndx,
+ bool need_pair, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_local_tls_with_rela(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, unsigned int shndx,
+ bool need_pair, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
// Add a constant to the GOT. This returns the offset of the new
// entry from the start of the GOT.
unsigned int
requires_postprocessing() const
{ return this->requires_postprocessing_; }
- // Record that this section requires postprocessing after all
- // relocations have been applied.
+ // If a section requires postprocessing, return the buffer to use.
+ unsigned char*
+ postprocessing_buffer() const
+ {
+ gold_assert(this->postprocessing_buffer_ != NULL);
+ return this->postprocessing_buffer_;
+ }
+
+ // If a section requires postprocessing, create the buffer to use.
void
- set_requires_postprocessing()
- { this->requires_postprocessing_ = true; }
+ create_postprocessing_buffer();
+
+ // If a section requires postprocessing, this is the size of the
+ // buffer to which relocations should be applied.
+ off_t
+ postprocessing_buffer_size() const
+ { return this->current_data_size_for_child(); }
// Return whether the offset OFFSET in the input section SHNDX in
// object OBJECT is being included in the link.
// Output_section, there is nothing to do, but if there are any
// Output_section_data objects we need to set their final addresses
// here.
- void
+ virtual void
set_final_data_size();
// Write the data to the file. For a typical Output_section, this
// 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.
- void
+ virtual void
do_write(Output_file*);
// Return the address alignment--function required by parent class.
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
{ return (this->flags_ & flag) != 0; }
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ do_set_tls_offset(uint64_t tls_base);
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ do_tls_offset() const
+ { return this->tls_offset_; }
+
+ // Modify the section name. This is only permitted for an
+ // unallocated section, and only before the size has been finalized.
+ // Otherwise the name will not get into Layout::namepool_.
+ void
+ set_name(const char* newname)
+ {
+ gold_assert((this->flags_ & elfcpp::SHF_ALLOC) == 0);
+ gold_assert(!this->is_data_size_valid());
+ this->name_ = newname;
+ }
+
+ // This may be implemented by a child class.
+ virtual void
+ do_finalize_name(Layout*)
+ { }
+
+ // Record that this section requires postprocessing after all
+ // relocations have been applied. This is called by a child class.
+ void
+ set_requires_postprocessing()
+ {
+ this->requires_postprocessing_ = true;
+ this->after_input_sections_ = true;
+ }
+
+ // Write all the data of an Output_section into the postprocessing
+ // buffer.
+ void
+ write_to_postprocessing_buffer();
+
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
}
// Set the address and file offset. This is called during
- // Layout::finalize. SECOFF is the file offset of the enclosing
- // section.
+ // 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);
+
+ // Finalize the data size.
void
- set_address(uint64_t addr, off_t off, off_t secoff);
+ finalize_data_size();
// Add an input section, for SHF_MERGE sections.
bool
void
write(Output_file*);
+ // Write the data to a buffer. This does nothing for an input
+ // section.
+ void
+ write_to_buffer(unsigned char*);
+
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.
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
- const char* const name_;
+ const char* name_;
// The section address is in the parent class.
// The section alignment.
uint64_t addralign_;
// often will need fill sections without needing to keep track of
// input sections.
Fill_list fills_;
+ // If the section requires postprocessing, this buffer holds the
+ // section contents during relocation.
+ unsigned char* postprocessing_buffer_;
// Whether this output section needs a STT_SECTION symbol in the
// normal symbol table. This will be true if there is a relocation
// which needs it.
// Whether this section requires post processing after all
// relocations have been applied.
bool requires_postprocessing_ : 1;
+ // For SHT_TLS sections, the offset of this section relative to the base
+ // of the TLS segment.
+ uint64_t tls_offset_;
};
// An output segment. PT_LOAD segments are built from collections of
void
set_offset();
+ // Set the TLS offsets of the sections contained in the PT_TLS segment.
+ void
+ set_tls_offsets();
+
// Return the number of output sections.
unsigned int
output_section_count() const;
void
resize(off_t file_size);
- // Close the output file and make sure there are no error.
+ // Close the output file (flushing all buffered data) and make sure
+ // there are no errors.
void
close();
{ }
private:
- // Map the file into memory.
+ // Map the file into memory and return a pointer to the map.
void
map();
+ // Unmap the file from memory (and flush to disk buffers).
+ void
+ unmap();
+
+
// General options.
const General_options& options_;
// Target.
off_t file_size_;
// Base of file mapped into memory.
unsigned char* base_;
+ // True iff base_ points to a memory buffer rather than an output file.
+ bool map_is_anonymous_;
};
} // End namespace gold.