// object.h -- support for an object file for linking in gold -*- C++ -*-
-// Copyright (C) 2006-2015 Free Software Foundation, Inc.
+// Copyright (C) 2006-2019 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
class Task;
class Cref;
class Layout;
+class Kept_section;
class Output_data;
class Output_section;
class Output_section_data;
Got_offset_list* got_next_;
};
+// The Local_got_entry_key used to index the GOT offsets for local
+// non-TLS symbols, and tp-relative offsets for TLS symbols.
+
+class Local_got_entry_key
+{
+ public:
+ Local_got_entry_key(unsigned int symndx, uint64_t addend)
+ : symndx_(symndx), addend_(addend)
+ {}
+
+ // Whether this equals to another Local_got_entry_key.
+ bool
+ eq(const Local_got_entry_key& key) const
+ {
+ return (this->symndx_ == key.symndx_ && this->addend_ == key.addend_);
+ }
+
+ // Compute a hash value for this using 64-bit FNV-1a hash.
+ size_t
+ hash_value() const
+ {
+ uint64_t h = 14695981039346656037ULL; // FNV offset basis.
+ uint64_t prime = 1099511628211ULL;
+ h = (h ^ static_cast<uint64_t>(this->symndx_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->addend_)) * prime;
+ return h;
+ }
+
+ // Functors for associative containers.
+ struct equal_to
+ {
+ bool
+ operator()(const Local_got_entry_key& key1,
+ const Local_got_entry_key& key2) const
+ { return key1.eq(key2); }
+ };
+
+ struct hash
+ {
+ size_t
+ operator()(const Local_got_entry_key& key) const
+ { return key.hash_value(); }
+ };
+
+ private:
+ // The local symbol index.
+ unsigned int symndx_;
+ // The addend.
+ uint64_t addend_;
+};
+
// Type for mapping section index to uncompressed size and contents.
struct Compressed_section_info
{
section_size_type size;
elfcpp::Elf_Xword flag;
+ uint64_t addralign;
const unsigned char* contents;
};
typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
set_as_needed()
{ this->as_needed_ = true; }
+ // Clear flag that this object was linked with --as-needed.
+ void
+ clear_as_needed()
+ { this->as_needed_ = false; }
+
// Return whether this object was linked with --as-needed.
bool
as_needed() const
bool
section_is_compressed(unsigned int shndx,
- section_size_type* uncompressed_size) const
+ section_size_type* uncompressed_size,
+ elfcpp::Elf_Xword* palign = NULL) const
{
if (this->compressed_sections_ == NULL)
return false;
{
if (uncompressed_size != NULL)
*uncompressed_size = p->second.size;
+ if (palign != NULL)
+ *palign = p->second.addralign;
return true;
}
return false;
// by the caller.
const unsigned char*
decompressed_section_contents(unsigned int shndx, section_size_type* plen,
- bool* is_cached);
+ bool* is_cached, uint64_t* palign = NULL);
// Discard any buffers of decompressed sections. This is done
// at the end of the Add_symbols task.
get_incremental_reloc_count(unsigned int symndx) const
{ return this->do_get_incremental_reloc_count(symndx); }
+ // Return the output view for section SHNDX.
+ unsigned char*
+ get_output_view(unsigned int shndx, section_size_type* plen) const
+ { return this->do_get_output_view(shndx, plen); }
+
protected:
// Returns NULL for Objects that are not dynamic objects. This method
// is overridden in the Dynobj class.
do_get_incremental_reloc_count(unsigned int) const
{ gold_unreachable(); }
+ // Return the output view for a section.
+ virtual unsigned char*
+ do_get_output_view(unsigned int, section_size_type*) const
+ { gold_unreachable(); }
+
void
set_compressed_sections(Compressed_section_map* compressed_sections)
{ this->compressed_sections_ = compressed_sections; }
// GOT_TYPE.
bool
local_has_got_offset(unsigned int symndx, unsigned int got_type) const
- { return this->do_local_has_got_offset(symndx, got_type); }
+ { return this->do_local_has_got_offset(symndx, got_type, 0); }
+
+ // Return whether the local symbol SYMNDX plus ADDEND has a GOT offset
+ // of type GOT_TYPE.
+ bool
+ local_has_got_offset(unsigned int symndx, unsigned int got_type,
+ uint64_t addend) const
+ { return this->do_local_has_got_offset(symndx, got_type, addend); }
// Return the GOT offset of type GOT_TYPE of the local symbol
// SYMNDX. It is an error to call this if the symbol does not have
// a GOT offset of the specified type.
unsigned int
local_got_offset(unsigned int symndx, unsigned int got_type) const
- { return this->do_local_got_offset(symndx, got_type); }
+ { return this->do_local_got_offset(symndx, got_type, 0); }
+
+ // Return the GOT offset of type GOT_TYPE of the local symbol
+ // SYMNDX plus ADDEND. It is an error to call this if the symbol
+ // does not have a GOT offset of the specified type.
+ unsigned int
+ local_got_offset(unsigned int symndx, unsigned int got_type,
+ uint64_t addend) const
+ { return this->do_local_got_offset(symndx, got_type, addend); }
// Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
// to GOT_OFFSET.
void
set_local_got_offset(unsigned int symndx, unsigned int got_type,
unsigned int got_offset)
- { this->do_set_local_got_offset(symndx, got_type, got_offset); }
+ { this->do_set_local_got_offset(symndx, got_type, got_offset, 0); }
+
+ // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
+ // plus ADDEND to GOT_OFFSET.
+ void
+ set_local_got_offset(unsigned int symndx, unsigned int got_type,
+ unsigned int got_offset, uint64_t addend)
+ { this->do_set_local_got_offset(symndx, got_type, got_offset, addend); }
// Return whether the local symbol SYMNDX is a TLS symbol.
bool
virtual unsigned int
do_local_plt_offset(unsigned int symndx) const = 0;
- // Return whether a local symbol has a GOT offset of a given type.
+ // Return whether a local symbol plus addend has a GOT offset
+ // of a given type.
virtual bool
do_local_has_got_offset(unsigned int symndx,
- unsigned int got_type) const = 0;
+ unsigned int got_type, uint64_t addend) const = 0;
- // Return the GOT offset of a given type of a local symbol.
+ // Return the GOT offset of a given type of a local symbol plus addend.
virtual unsigned int
- do_local_got_offset(unsigned int symndx, unsigned int got_type) const = 0;
+ do_local_got_offset(unsigned int symndx, unsigned int got_type,
+ uint64_t addend) const = 0;
- // Set the GOT offset with a given type for a local symbol.
+ // Set the GOT offset with a given type for a local symbol plus addend.
virtual void
do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
- unsigned int got_offset) = 0;
+ unsigned int got_offset, uint64_t addend) = 0;
// Return whether local symbol SYMNDX is a TLS symbol.
virtual bool
: convert_types<Address, uint64_t>(off));
}
- // Return whether the local symbol SYMNDX has a GOT offset of type
- // GOT_TYPE.
+ // Return whether the local symbol SYMNDX plus ADDEND has a GOT offset
+ // of type GOT_TYPE.
bool
- do_local_has_got_offset(unsigned int symndx, unsigned int got_type) const
+ do_local_has_got_offset(unsigned int symndx, unsigned int got_type,
+ uint64_t addend) const
{
+ Local_got_entry_key key(symndx, addend);
Local_got_offsets::const_iterator p =
- this->local_got_offsets_.find(symndx);
+ this->local_got_offsets_.find(key);
return (p != this->local_got_offsets_.end()
&& p->second->get_offset(got_type) != -1U);
}
// Return the GOT offset of type GOT_TYPE of the local symbol
- // SYMNDX.
+ // SYMNDX plus ADDEND.
unsigned int
- do_local_got_offset(unsigned int symndx, unsigned int got_type) const
+ do_local_got_offset(unsigned int symndx, unsigned int got_type,
+ uint64_t addend) const
{
+ Local_got_entry_key key(symndx, addend);
Local_got_offsets::const_iterator p =
- this->local_got_offsets_.find(symndx);
+ this->local_got_offsets_.find(key);
gold_assert(p != this->local_got_offsets_.end());
unsigned int off = p->second->get_offset(got_type);
gold_assert(off != -1U);
}
// Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
- // to GOT_OFFSET.
+ // plus ADDEND to GOT_OFFSET.
void
do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
- unsigned int got_offset)
+ unsigned int got_offset, uint64_t addend)
{
+ Local_got_entry_key key(symndx, addend);
Local_got_offsets::const_iterator p =
- this->local_got_offsets_.find(symndx);
+ this->local_got_offsets_.find(key);
if (p != this->local_got_offsets_.end())
p->second->set_offset(got_type, got_offset);
else
{
Got_offset_list* g = new Got_offset_list(got_type, got_offset);
std::pair<Local_got_offsets::iterator, bool> ins =
- this->local_got_offsets_.insert(std::make_pair(symndx, g));
+ this->local_got_offsets_.insert(std::make_pair(key, g));
gold_assert(ins.second);
}
}
private:
// The GOT offsets of local symbols. This map also stores GOT offsets
// for tp-relative offsets for TLS symbols.
- typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
+ typedef Unordered_map<Local_got_entry_key, Got_offset_list*,
+ Local_got_entry_key::hash,
+ Local_got_entry_key::equal_to> Local_got_offsets;
// GOT offsets for local non-TLS symbols, and tp-relative offsets
- // for TLS symbols, indexed by symbol number.
+ // for TLS symbols, indexed by local got entry key class.
Local_got_offsets local_got_offsets_;
// For each input section, the offset of the input section in its
// output section. This is INVALID_ADDRESS if the input section requires a
// and return its output address. This is used only for relocations in
// debugging sections.
Address
- map_to_kept_section(unsigned int shndx, bool* found) const;
+ map_to_kept_section(unsigned int shndx, std::string& section_name,
+ bool* found) const;
+
+ // Look for a kept section corresponding to the given discarded section,
+ // and return its object file.
+ Relobj*
+ find_kept_section_object(unsigned int shndx, unsigned int* symndx_p) const;
+
+ // Return the name of symbol SYMNDX.
+ const char*
+ get_symbol_name(unsigned int symndx);
// Compute final local symbol value. R_SYM is the local symbol index.
// LV_IN points to a local symbol value containing the input value.
const unsigned char* pshdrs, Output_file* of,
Views* pviews);
+ // Relocate section data for a range of sections.
+ void
+ relocate_section_range(const Symbol_table* symtab, const Layout* layout,
+ const unsigned char* pshdrs, Output_file* of,
+ Views* pviews, unsigned int start_shndx,
+ unsigned int end_shndx);
+
// Adjust this local symbol value. Return false if the symbol
// should be discarded from the output file.
virtual bool
set_output_local_symbol_count(unsigned int value)
{ this->output_local_symbol_count_ = value; }
+ // Return the output view for a section.
+ unsigned char*
+ do_get_output_view(unsigned int, section_size_type*) const;
+
private:
// For convenience.
typedef Sized_relobj_file<size, big_endian> This;
static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
typedef elfcpp::Shdr<size, big_endian> Shdr;
+ typedef elfcpp::Shdr_write<size, big_endian> Shdr_write;
// To keep track of discarded comdat sections, we need to map a member
// section index to the object and section index of the corresponding
// kept section.
struct Kept_comdat_section
{
- Kept_comdat_section(Relobj* a_object, unsigned int a_shndx)
- : object(a_object), shndx(a_shndx)
+ Kept_comdat_section(uint64_t a_sh_size, Kept_section* a_kept_section,
+ unsigned int a_symndx, bool a_is_comdat)
+ : sh_size(a_sh_size), kept_section(a_kept_section),
+ symndx (a_symndx), is_comdat(a_is_comdat)
{ }
- Relobj* object;
- unsigned int shndx;
+ uint64_t sh_size; // Section size
+ Kept_section* kept_section; // Kept section info
+ unsigned int symndx; // Index of key symbol
+ bool is_comdat; // True if comdat group, false if linkonce
};
typedef std::map<unsigned int, Kept_comdat_section>
Kept_comdat_section_table;
// Layout an input section.
void
layout_section(Layout* layout, unsigned int shndx, const char* name,
- const typename This::Shdr& shdr, unsigned int reloc_shndx,
- unsigned int reloc_type);
+ const typename This::Shdr& shdr, unsigned int sh_type,
+ unsigned int reloc_shndx, unsigned int reloc_type);
// Layout an input .eh_frame section.
void
unsigned int shndx, const typename This::Shdr&,
unsigned int reloc_shndx, unsigned int reloc_type);
+ // Layout an input .note.gnu.property section.
+ void
+ layout_gnu_property_section(Layout* layout, unsigned int shndx);
+
// Write section data to the output file. Record the views and
// sizes in VIEWS for use when relocating.
void
unsigned int sh_type, unsigned int shndx,
const unsigned char* prelocs, size_t reloc_count,
unsigned char* view, section_size_type view_size,
- Reloc_symbol_changes** reloc_map);
+ Reloc_symbol_changes** reloc_map,
+ const Sized_target<size, big_endian>* target);
template<int sh_type>
void
unsigned int shndx, const unsigned char* prelocs,
size_t reloc_count, unsigned char* view,
section_size_type view_size,
- Reloc_symbol_changes** reloc_map);
+ Reloc_symbol_changes** reloc_map,
+ const Sized_target<size, big_endian>* target);
// Find all functions in a section.
void
// Record a mapping from discarded section SHNDX to the corresponding
// kept section.
void
- set_kept_comdat_section(unsigned int shndx, Relobj* kept_object,
- unsigned int kept_shndx)
+ set_kept_comdat_section(unsigned int shndx, bool is_comdat,
+ unsigned int symndx, uint64_t sh_size,
+ Kept_section* kept_section)
{
- Kept_comdat_section kept(kept_object, kept_shndx);
+ Kept_comdat_section kept(sh_size, kept_section, symndx, is_comdat);
this->kept_comdat_sections_.insert(std::make_pair(shndx, kept));
}
// Find the kept section corresponding to the discarded section
// SHNDX. Return true if found.
bool
- get_kept_comdat_section(unsigned int shndx, Relobj** kept_object,
- unsigned int* kept_shndx) const
+ get_kept_comdat_section(unsigned int shndx, bool* is_comdat,
+ unsigned int *symndx, uint64_t* sh_size,
+ Kept_section** kept_section) const
{
typename Kept_comdat_section_table::const_iterator p =
this->kept_comdat_sections_.find(shndx);
if (p == this->kept_comdat_sections_.end())
return false;
- *kept_object = p->second.object;
- *kept_shndx = p->second.shndx;
+ *is_comdat = p->second.is_comdat;
+ *symndx = p->second.symndx;
+ *sh_size = p->second.sh_size;
+ *kept_section = p->second.kept_section;
return true;
}
{
static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
Deferred_layout(unsigned int shndx, const char* name,
+ unsigned int sh_type,
const unsigned char* pshdr,
unsigned int reloc_shndx, unsigned int reloc_type)
- : shndx_(shndx), name_(name), reloc_shndx_(reloc_shndx),
+ : name_(name), shndx_(shndx), reloc_shndx_(reloc_shndx),
reloc_type_(reloc_type)
{
+ typename This::Shdr_write shdr(this->shdr_data_);
memcpy(this->shdr_data_, pshdr, shdr_size);
+ shdr.put_sh_type(sh_type);
}
- unsigned int shndx_;
std::string name_;
+ unsigned int shndx_;
unsigned int reloc_shndx_;
unsigned int reloc_type_;
unsigned char shdr_data_[shdr_size];
Kept_comdat_section_table kept_comdat_sections_;
// Whether this object has a GNU style .eh_frame section.
bool has_eh_frame_;
- // If this object has a GNU style .eh_frame section that is discarded in
- // output, record the index here. Otherwise it is -1U.
- unsigned int discarded_eh_frame_shndx_;
// True if the layout of this object was deferred, waiting for plugin
// replacement files.
bool is_deferred_layout_;
std::vector<Deferred_layout> deferred_layout_;
// The list of relocation sections whose layout was deferred.
std::vector<Deferred_layout> deferred_layout_relocs_;
+ // Pointer to the list of output views; valid only during do_relocate().
+ const Views* output_views_;
};
// A class to manage the list of all objects.
// The list of dynamic objects included in the link.
Dynobj_list dynobj_list_;
// SONAMEs that we have seen.
- Unordered_set<std::string> sonames_;
+ Unordered_map<std::string, Object*> sonames_;
// Manage cross-references if requested.
Cref* cref_;
};
unsigned int reloc_shndx;
// Section header of relocation section.
const unsigned char* reloc_shdr;
+ // Info about how relocs should be handled
+ Relocatable_relocs* rr;
// Section index of section being relocated.
unsigned int data_shndx;
// Section header of data section.