{
class General_options;
+class Task;
class Layout;
class Output_section;
class Output_file;
class Dynobj;
+class Object_merge_map;
template<typename Stringpool_char>
class Stringpool_template;
// Section names.
File_view* section_names;
// Size of section name data in bytes.
- off_t section_names_size;
+ section_size_type section_names_size;
// Symbol data.
File_view* symbols;
// Size of symbol data in bytes.
- off_t symbols_size;
+ section_size_type symbols_size;
// Offset of external symbols within symbol data. This structure
// sometimes contains only external symbols, in which case this will
// be zero. Sometimes it contains all symbols.
- off_t external_symbols_offset;
+ section_offset_type external_symbols_offset;
// Symbol names.
File_view* symbol_names;
// Size of symbol name data in bytes.
- off_t symbol_names_size;
+ section_size_type symbol_names_size;
// Version information. This is only used on dynamic objects.
// Version symbol data (from SHT_GNU_versym section).
File_view* versym;
- off_t versym_size;
+ section_size_type versym_size;
// Version definition data (from SHT_GNU_verdef section).
File_view* verdef;
- off_t verdef_size;
+ section_size_type verdef_size;
unsigned int verdef_info;
// Needed version data (from SHT_GNU_verneed section).
File_view* verneed;
- off_t verneed_size;
+ section_size_type verneed_size;
unsigned int verneed_info;
};
// Lock the underlying file.
void
- lock()
- { this->input_file_->file().lock(); }
+ lock(const Task* t)
+ { this->input_file()->file().lock(t); }
// Unlock the underlying file.
void
- unlock()
- { this->input_file_->file().unlock(); }
+ unlock(const Task* t)
+ { this->input_file()->file().unlock(t); }
// Return whether the underlying file is locked.
bool
is_locked() const
- { return this->input_file_->file().is_locked(); }
+ { return this->input_file()->file().is_locked(); }
+
+ // Return the token, so that the task can be queued.
+ Task_token*
+ token()
+ { return this->input_file()->file().token(); }
+
+ // Release the underlying file.
+ void
+ release()
+ { this->input_file_->file().release(); }
// Return the sized target structure associated with this object.
// This is like the target method but it returns a pointer of
// appropriate checked type.
template<int size, bool big_endian>
Sized_target<size, big_endian>*
- sized_target(ACCEPT_SIZE_ENDIAN_ONLY);
+ sized_target(ACCEPT_SIZE_ENDIAN_ONLY) const;
// Get the number of sections.
unsigned int
// Return a view of the contents of a section. Set *PLEN to the
// size. CACHE is a hint as in File_read::get_view.
const unsigned char*
- section_contents(unsigned int shndx, off_t* plen, bool cache);
+ section_contents(unsigned int shndx, section_size_type* plen, bool cache);
// Return the name of a section given a section index. This is only
// used for error messages.
// Return a View.
View
- view(off_t file_offset, off_t data_size)
+ view(off_t file_offset, section_size_type data_size)
{ return View(this->get_view(file_offset, data_size, true)); }
// Report an error.
off_t file_offset;
off_t data_size;
- Location(off_t fo, off_t ds)
+ Location(off_t fo, section_size_type ds)
: file_offset(fo), data_size(ds)
{ }
};
virtual unsigned int
do_section_info(unsigned int shndx) = 0;
- // Get the file.
+ // Get the file. We pass on const-ness.
Input_file*
+ input_file()
+ { return this->input_file_; }
+
+ const Input_file*
input_file() const
{ return this->input_file_; }
// Get a view into the underlying file.
const unsigned char*
- get_view(off_t start, off_t size, bool cache)
+ get_view(off_t start, section_size_type size, bool cache)
{
- return this->input_file_->file().get_view(start + this->offset_, size,
- cache);
+ return this->input_file()->file().get_view(start + this->offset_, size,
+ cache);
}
// Get a lasting view into the underlying file.
File_view*
- get_lasting_view(off_t start, off_t size, bool cache)
+ get_lasting_view(off_t start, section_size_type size, bool cache)
{
- return this->input_file_->file().get_lasting_view(start + this->offset_,
- size, cache);
+ return this->input_file()->file().get_lasting_view(start + this->offset_,
+ size, cache);
}
// Read data from the underlying file.
void
- read(off_t start, off_t size, void* p)
- { this->input_file_->file().read(start + this->offset_, size, p); }
+ read(off_t start, section_size_type size, void* p) const
+ { this->input_file()->file().read(start + this->offset_, size, p); }
// Set the target.
void
template<int size, bool big_endian>
inline Sized_target<size, big_endian>*
-Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY)
+Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY) const
{
gold_assert(this->target_->get_size() == size);
gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
{
public:
Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
- : Object(name, input_file, false, offset)
+ : Object(name, input_file, false, offset),
+ map_to_output_(),
+ object_merge_map_(NULL),
+ relocs_must_follow_section_writes_(false)
{ }
// Read the relocs.
Layout* layout, Read_relocs_data* rd)
{ return this->do_scan_relocs(options, symtab, layout, rd); }
- // Initial local symbol processing: set the offset where local
- // symbol information will be stored; add local symbol names to
- // *POOL; return the new local symbol index.
+ // The number of local symbols in the input symbol table.
+ virtual unsigned int
+ local_symbol_count() const
+ { return this->do_local_symbol_count(); }
+
+ // Initial local symbol processing: count the number of local symbols
+ // in the output symbol table and dynamic symbol table; add local symbol
+ // names to *POOL and *DYNPOOL.
+ void
+ count_local_symbols(Stringpool_template<char>* pool,
+ Stringpool_template<char>* dynpool)
+ { return this->do_count_local_symbols(pool, dynpool); }
+
+ // Set the values of the local symbols, set the output symbol table
+ // indexes for the local variables, and set the offset where local
+ // symbol information will be stored. Returns the new local symbol index.
+ unsigned int
+ finalize_local_symbols(unsigned int index, off_t off)
+ { return this->do_finalize_local_symbols(index, off); }
+
+ // Set the output dynamic symbol table indexes for the local variables.
+ unsigned int
+ set_local_dynsym_indexes(unsigned int index)
+ { return this->do_set_local_dynsym_indexes(index); }
+
+ // Set the offset where local dynamic symbol information will be stored.
unsigned int
- finalize_local_symbols(unsigned int index, off_t off,
- Stringpool_template<char>* pool)
- { return this->do_finalize_local_symbols(index, off, pool); }
+ set_local_dynsym_offset(off_t off)
+ { return this->do_set_local_dynsym_offset(off); }
// Relocate the input sections and write out the local symbols.
void
// and set *POFF to the offset within that section. *POFF will be
// set to -1 if the section requires special handling.
inline Output_section*
- output_section(unsigned int shndx, off_t* poff) const;
+ output_section(unsigned int shndx, section_offset_type* poff) const;
// Set the offset of an input section within its output section.
void
- set_section_offset(unsigned int shndx, off_t off)
+ set_section_offset(unsigned int shndx, section_offset_type off)
{
gold_assert(shndx < this->map_to_output_.size());
this->map_to_output_[shndx].offset = off;
// any relocations for sections which require special handling, such
// as the exception frame section.
bool
- relocs_must_follow_section_writes()
+ relocs_must_follow_section_writes() const
{ return this->relocs_must_follow_section_writes_; }
+ // Return the object merge map.
+ Object_merge_map*
+ merge_map() const
+ { return this->object_merge_map_; }
+
+ // Set the object merge map.
+ void
+ set_merge_map(Object_merge_map* object_merge_map)
+ {
+ gold_assert(this->object_merge_map_ == NULL);
+ this->object_merge_map_ = object_merge_map;
+ }
+
protected:
// What we need to know to map an input section to an output
// section. We keep an array of these, one for each input section,
Output_section* output_section;
// The offset within the output section. This is -1 if the
// section requires special handling.
- off_t offset;
+ section_offset_type offset;
};
// Read the relocs--implemented by child class.
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
Read_relocs_data*) = 0;
- // Finalize local symbols--implemented by child class.
+ // Return the number of local symbols--implemented by child class.
virtual unsigned int
- do_finalize_local_symbols(unsigned int, off_t,
+ do_local_symbol_count() const = 0;
+
+ // Count local symbols--implemented by child class.
+ virtual void
+ do_count_local_symbols(Stringpool_template<char>*,
Stringpool_template<char>*) = 0;
+ // Finalize the local symbols. Set the output symbol table indexes for the local variables, and set the
+ // offset where local symbol information will be stored.
+ virtual unsigned int
+ do_finalize_local_symbols(unsigned int, off_t) = 0;
+
+ // Set the output dynamic symbol table indexes for the local variables.
+ virtual unsigned int
+ do_set_local_dynsym_indexes(unsigned int) = 0;
+
+ // Set the offset where local dynamic symbol information will be stored.
+ virtual unsigned int
+ do_set_local_dynsym_offset(off_t) = 0;
+
// Relocate the input sections and write out the local
// symbols--implemented by child class.
virtual void
private:
// Mapping from input sections to output section.
std::vector<Map_to_output> map_to_output_;
+ // Mappings for merge sections. This is managed by the code in the
+ // Merge_map class.
+ Object_merge_map* object_merge_map_;
// Whether we need to wait for output sections to be written before
// we can apply relocations.
bool relocs_must_follow_section_writes_;
// Implement Object::output_section inline for efficiency.
inline Output_section*
-Relobj::output_section(unsigned int shndx, off_t* poff) const
+Relobj::output_section(unsigned int shndx, section_offset_type* poff) const
{
gold_assert(shndx < this->map_to_output_.size());
const Map_to_output& mo(this->map_to_output_[shndx]);
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
Symbol_value()
- : output_symtab_index_(0), input_shndx_(0), is_section_symbol_(false),
+ : output_symtab_index_(0), output_dynsym_index_(-1U), input_shndx_(0),
+ is_section_symbol_(false), is_tls_symbol_(false),
needs_output_address_(false), value_(0)
{ }
this->needs_output_address_ = false;
}
- // If this symbol is mapped to an output section which requires
- // special handling to determine the output value, we store the
- // value of the symbol in the input file. This is used for
+ // Set the value of the symbol from the input file. This value
+ // will usually be replaced during finalization with the output
+ // value, but if the symbol is mapped to an output section which
+ // requires special handling to determine the output value, we
+ // leave the input value in place until later. This is used for
// SHF_MERGE sections.
void
set_input_value(Value value)
this->needs_output_address_ = true;
}
+ // Return the input value.
+ Value
+ input_value() const
+ {
+ gold_assert(this->needs_output_address_);
+ return this->value_;
+ }
+
// Return whether this symbol should go into the output symbol
// table.
bool
needs_output_symtab_entry() const
- {
- gold_assert(this->output_symtab_index_ != 0);
- return this->output_symtab_index_ != -1U;
- }
+ { return this->output_symtab_index_ != -1U; }
// Return the index in the output symbol table.
unsigned int
this->output_symtab_index_ = -1U;
}
+ // Set the index in the output dynamic symbol table.
+ void
+ set_needs_output_dynsym_entry()
+ {
+ this->output_dynsym_index_ = 0;
+ }
+
+ // Return whether this symbol should go into the output symbol
+ // table.
+ bool
+ needs_output_dynsym_entry() const
+ {
+ return this->output_dynsym_index_ != -1U;
+ }
+
+ // Record that this symbol should go into the dynamic symbol table.
+ void
+ set_output_dynsym_index(unsigned int i)
+ {
+ gold_assert(this->output_dynsym_index_ == 0);
+ this->output_dynsym_index_ = i;
+ }
+
+ // Return the index in the output dynamic symbol table.
+ unsigned int
+ output_dynsym_index() const
+ {
+ gold_assert(this->output_dynsym_index_ != 0);
+ return this->output_dynsym_index_;
+ }
+
// Set the index of the input section in the input file.
void
set_input_shndx(unsigned int i)
{
this->input_shndx_ = i;
+ // input_shndx_ field is a bitfield, so make sure that the value
+ // fits.
gold_assert(this->input_shndx_ == i);
}
+ // Return the index of the input section in the input file.
+ unsigned int
+ input_shndx() const
+ { return this->input_shndx_; }
+
// Record that this is a section symbol.
void
set_is_section_symbol()
{ this->is_section_symbol_ = true; }
+ // Record that this is a TLS symbol.
+ void
+ set_is_tls_symbol()
+ { this->is_tls_symbol_ = true; }
+
+ // Return TRUE if this is a TLS symbol.
+ bool
+ is_tls_symbol() const
+ { return this->is_tls_symbol_; }
+
private:
// The index of this local symbol in the output symbol table. This
// will be -1 if the symbol should not go into the symbol table.
unsigned int output_symtab_index_;
+ // The index of this local symbol in the dynamic symbol table. This
+ // will be -1 if the symbol should not go into the symbol table.
+ unsigned int output_dynsym_index_;
// The section index in the input file in which this symbol is
// defined.
- unsigned int input_shndx_ : 30;
+ unsigned int input_shndx_ : 29;
// Whether this is a STT_SECTION symbol.
bool is_section_symbol_ : 1;
+ // Whether this is a STT_TLS symbol.
+ bool is_tls_symbol_ : 1;
// Whether getting the value of this symbol requires calling an
// Output_section method. For example, this will be true of a
// symbol in a SHF_MERGE section.
void
setup(const typename elfcpp::Ehdr<size, big_endian>&);
- // Return the number of local symbols.
- unsigned int
- local_symbol_count() const
- { return this->local_symbol_count_; }
-
// If SYM is the index of a global symbol in the object file's
// symbol table, return the Symbol object. Otherwise, return NULL.
Symbol*
return this->local_values_[sym].output_symtab_index();
}
+ // Return the index of local symbol SYM in the dynamic symbol
+ // table. A value of -1U means that the symbol is not being output.
+ unsigned int
+ dynsym_index(unsigned int sym) const
+ {
+ gold_assert(sym < this->local_values_.size());
+ return this->local_values_[sym].output_dynsym_index();
+ }
+
// Return the appropriate Sized_target structure.
Sized_target<size, big_endian>*
sized_target()
local_value(unsigned int shndx, Address value, bool is_section_symbol,
Address addend) const;
+ void
+ set_needs_output_dynsym_entry(unsigned int sym)
+ {
+ gold_assert(sym < this->local_values_.size());
+ this->local_values_[sym].set_needs_output_dynsym_entry();
+ }
+
// Return whether the local symbol SYMNDX has a GOT offset.
+ // For TLS symbols, the GOT entry will hold its tp-relative offset.
bool
local_has_got_offset(unsigned int symndx) const
{
gold_assert(ins.second);
}
+ // Return whether the local TLS symbol SYMNDX has a GOT offset.
+ // The GOT entry at this offset will contain a module index. If
+ // NEED_PAIR is true, a second entry immediately following the first
+ // will contain the dtv-relative offset.
+ bool
+ local_has_tls_got_offset(unsigned int symndx, bool need_pair) const
+ {
+ typename Local_tls_got_offsets::const_iterator p =
+ this->local_tls_got_offsets_.find(symndx);
+ if (p == this->local_tls_got_offsets_.end()
+ || (need_pair && !p->second.have_pair_))
+ return false;
+ return true;
+ }
+
+ // Return the offset of the GOT entry for the local TLS symbol SYMNDX.
+ // If NEED_PAIR is true, we need the offset of a pair of GOT entries;
+ // otherwise we need the offset of the GOT entry for the module index.
+ unsigned int
+ local_tls_got_offset(unsigned int symndx, bool need_pair) const
+ {
+ typename Local_tls_got_offsets::const_iterator p =
+ this->local_tls_got_offsets_.find(symndx);
+ gold_assert(p != this->local_tls_got_offsets_.end());
+ gold_assert(!need_pair || p->second.have_pair_);
+ return p->second.got_offset_;
+ }
+
+ // Set the offset of the GOT entry for the local TLS symbol SYMNDX
+ // to GOT_OFFSET. If HAVE_PAIR is true, we have a pair of GOT entries;
+ // otherwise, we have just a single entry for the module index.
+ void
+ set_local_tls_got_offset(unsigned int symndx, unsigned int got_offset,
+ bool have_pair)
+ {
+ typename Local_tls_got_offsets::iterator p =
+ this->local_tls_got_offsets_.find(symndx);
+ if (p != this->local_tls_got_offsets_.end())
+ {
+ // An entry already existed for this symbol. This can happen
+ // if we see a relocation asking for the module index before
+ // a relocation asking for the pair. In that case, the original
+ // GOT entry will remain, but won't get used by any further
+ // relocations.
+ p->second.got_offset_ = got_offset;
+ gold_assert(have_pair);
+ p->second.have_pair_ = true;
+ }
+ else
+ {
+ std::pair<typename Local_tls_got_offsets::iterator, bool> ins =
+ this->local_tls_got_offsets_.insert(
+ std::make_pair(symndx, Tls_got_entry(got_offset, have_pair)));
+ gold_assert(ins.second);
+ }
+ }
+
// Return the name of the symbol that spans the given offset in the
// specified section in this object. This is used only for error
// messages and is not particularly efficient.
get_symbol_location_info(unsigned int shndx, off_t offset,
Symbol_location_info* info);
+ protected:
// Read the symbols.
void
do_read_symbols(Read_symbols_data*);
+ // Return the number of local symbols.
+ unsigned int
+ do_local_symbol_count() const
+ { return this->local_symbol_count_; }
+
// Lay out the input sections.
void
do_layout(Symbol_table*, Layout*, Read_symbols_data*);
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
Read_relocs_data*);
+ // Count the local symbols.
+ void
+ do_count_local_symbols(Stringpool_template<char>*,
+ Stringpool_template<char>*);
+
// Finalize the local symbols.
unsigned int
- do_finalize_local_symbols(unsigned int, off_t,
- Stringpool_template<char>*);
+ do_finalize_local_symbols(unsigned int, off_t);
+
+ // Set the offset where local dynamic symbol information will be stored.
+ unsigned int
+ do_set_local_dynsym_indexes(unsigned int);
+
+ // Set the offset where local dynamic symbol information will be stored.
+ unsigned int
+ do_set_local_dynsym_offset(off_t);
// Relocate the input sections and write out the local symbols.
void
// a GNU style exception frame section.
bool
find_eh_frame(const unsigned char* pshdrs, const char* names,
- off_t names_size) const;
+ section_size_type names_size) const;
// Whether to include a section group in the link.
bool
unsigned char* view;
typename elfcpp::Elf_types<size>::Elf_Addr address;
off_t offset;
- off_t view_size;
+ section_size_type view_size;
bool is_input_output_view;
+ bool is_postprocessing_view;
};
typedef std::vector<View_size> Views;
// Write section data to the output file. Record the views and
// sizes in VIEWS for use when relocating.
void
- write_sections(const unsigned char* pshdrs, Output_file*, Views*);
+ write_sections(const unsigned char* pshdrs, Output_file*, Views*) const;
// Relocate the sections in the output file.
void
// Write out the local symbols.
void
write_local_symbols(Output_file*,
+ const Stringpool_template<char>*,
const Stringpool_template<char>*);
- // The GOT offsets of local symbols.
+ // The GOT offsets of local symbols. This map also stores GOT offsets
+ // for tp-relative offsets for TLS symbols.
typedef Unordered_map<unsigned int, unsigned int> Local_got_offsets;
+ // The TLS GOT offsets of local symbols. The map stores the offsets
+ // for either a single GOT entry that holds the module index of a TLS
+ // symbol, or a pair of GOT entries containing the module index and
+ // dtv-relative offset.
+ struct Tls_got_entry
+ {
+ Tls_got_entry(int got_offset, bool have_pair)
+ : got_offset_(got_offset),
+ have_pair_(have_pair)
+ { }
+ int got_offset_;
+ bool have_pair_;
+ };
+ typedef Unordered_map<unsigned int, Tls_got_entry> Local_tls_got_offsets;
+
// General access to the ELF file.
elfcpp::Elf_file<size, big_endian, Object> elf_file_;
// Index of SHT_SYMTAB section.
unsigned int local_symbol_count_;
// The number of local symbols which go into the output file.
unsigned int output_local_symbol_count_;
+ // The number of local symbols which go into the output file's dynamic
+ // symbol table.
+ unsigned int output_local_dynsym_count_;
// The entries in the symbol table for the external symbols.
Symbols symbols_;
// File offset for local symbols.
off_t local_symbol_offset_;
+ // File offset for local dynamic symbols.
+ off_t local_dynsym_offset_;
// Values of local symbols.
Local_values local_values_;
- // GOT offsets for local symbols, indexed by symbol number.
+ // GOT offsets for local non-TLS symbols, and tp-relative offsets
+ // for TLS symbols, indexed by symbol number.
Local_got_offsets local_got_offsets_;
+ // GOT offsets for local TLS symbols, indexed by symbol number
+ // and GOT entry type.
+ Local_tls_got_offsets local_tls_got_offsets_;
// Whether this object has a GNU style .eh_frame section.
bool has_eh_frame_;
};
{
public:
Input_objects()
- : relobj_list_(), dynobj_list_(), target_(NULL), sonames_()
+ : relobj_list_(), dynobj_list_(), target_(NULL), sonames_(),
+ system_library_directory_()
{ }
// The type of the list of input relocateable objects.
target() const
{ return this->target_; }
+ // For each dynamic object, check whether we've seen all of its
+ // explicit dependencies.
+ void
+ check_dynamic_dependencies() const;
+
+ // Return whether an object was found in the system library
+ // directory.
+ bool
+ found_in_system_library_directory(const Object*) const;
+
// Iterate over all regular objects.
Relobj_iterator
Target* target_;
// SONAMEs that we have seen.
Unordered_set<std::string> sonames_;
+ // The directory in which we find the libc.so.
+ std::string system_library_directory_;
};
// Some of the information we pass to the relocation routines. We
extern Object*
make_elf_object(const std::string& name, Input_file*,
off_t offset, const unsigned char* p,
- off_t bytes);
+ section_offset_type bytes);
} // end namespace gold