* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
* incremental-dump.cc (dump_incremental_inputs): Mask high-order bit when checking got_type. * incremental.cc (Sized_incremental_binary::setup_readers): Store symbol table and string table locations; initialize bit vector of file status flags. (Sized_incremental_binary::do_reserve_layout): Set bit flag for unchanged files. (Sized_incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::get_symtab_view): Use stored locations. (Output_section_incremental_inputs::set_final_data_size): Record file index for each input file. (Output_section_incremental_inputs::write_got_plt): Store file index instead of input entry offset for each GOT entry. * incremental.h (Incremental_input_entry::Incremental_input_entry): Initialize new data member. (Incremental_input_entry::set_offset): Store file index. (Incremental_input_entry::get_file_index): New function. (Incremental_input_entry::file_index_): New data member. (Incremental_binary::process_got_plt): New function. (Incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::Sized_incremental_binary): Initialize new data members. (Sized_incremental_binary::~Sized_incremental_binary): New destructor. (Sized_incremental_binary::set_file_is_unchanged): New function. (Sized_incremental_binary::file_is_unchanged): New function. (Sized_incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::file_status_): New data member. (Sized_incremental_binary::main_symtab_loc_): New data member. (Sized_incremental_binary::main_strtab_loc_): New data member. * output.cc (Output_data_got::Got_entry::write): Add case RESERVED_CODE. (Output_data_got::add_global): Call add_got_entry. (Output_data_got::add_global_plt): Likewise. (Output_data_got::add_global_with_rel): Likewise. (Output_data_got::add_global_with_rela): Likewise. (Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair. (Output_data_got::add_global_pair_with_rela): Likewise. (Output_data_got::add_local): Call add_got_entry. (Output_data_got::add_local_plt): Likewise. (Output_data_got::add_local_with_rel): Likewise. (Output_data_got::add_local_with_rela): Likewise. (Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair. (Output_data_got::add_local_pair_with_rela): Likewise. (Output_data_got::reserve_slot): New function. (Output_data_got::reserve_slot_for_global): New function. (Output_data_got::add_got_entry): New function. (Output_data_got::add_got_entry_pair): New function. (Output_section::add_output_section_data): Edit FIXME. * output.h (Output_section_data_build::Output_section_data_build): New constructor with size parameter. (Output_data_space::Output_data_space): Likewise. (Output_data_got::Output_data_got): Initialize new data member; new constructor with size parameter. (Output_data_got::add_constant): Call add_got_entry. (Output_data_got::reserve_slot): New function. (Output_data_got::reserve_slot_for_global): New function. (class Output_data_got::Got_entry): Add RESERVED_CODE. (Output_data_got::add_got_entry): New function. (Output_data_got::add_got_entry_pair): New function. (Output_data_got::free_list_): New data member. * target.h (Sized_target::init_got_plt_for_update): New function. (Sized_target::register_global_plt_entry): New function. * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize new data member; call init; add constructor with PLT count. (Output_data_plt_x86_64::init): New function. (Output_data_plt_x86_64::add_relocation): New function. (Output_data_plt_x86_64::reserve_slot): New function. (Output_data_plt_x86_64::free_list_): New data member. (Target_x86_64::init_got_plt_for_update): New function. (Target_x86_64::register_global_plt_entry): New function. (Output_data_plt_x86_64::add_entry): Allocate from free list for incremental updates. (Output_data_plt_x86_64::add_relocation): New function. * testsuite/object_unittest.cc (Object_test): Set default options.
This commit is contained in:
parent
dd931b2ff2
commit
4829d394de
@ -1,3 +1,83 @@
|
||||
2011-05-23 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
|
||||
* incremental-dump.cc (dump_incremental_inputs): Mask high-order
|
||||
bit when checking got_type.
|
||||
* incremental.cc (Sized_incremental_binary::setup_readers):
|
||||
Store symbol table and string table locations; initialize bit vector
|
||||
of file status flags.
|
||||
(Sized_incremental_binary::do_reserve_layout): Set bit flag for
|
||||
unchanged files.
|
||||
(Sized_incremental_binary::do_process_got_plt): New function.
|
||||
(Sized_incremental_binary::get_symtab_view): Use stored locations.
|
||||
(Output_section_incremental_inputs::set_final_data_size): Record
|
||||
file index for each input file.
|
||||
(Output_section_incremental_inputs::write_got_plt): Store file index
|
||||
instead of input entry offset for each GOT entry.
|
||||
* incremental.h
|
||||
(Incremental_input_entry::Incremental_input_entry): Initialize new
|
||||
data member.
|
||||
(Incremental_input_entry::set_offset): Store file index.
|
||||
(Incremental_input_entry::get_file_index): New function.
|
||||
(Incremental_input_entry::file_index_): New data member.
|
||||
(Incremental_binary::process_got_plt): New function.
|
||||
(Incremental_binary::do_process_got_plt): New function.
|
||||
(Sized_incremental_binary::Sized_incremental_binary): Initialize new
|
||||
data members.
|
||||
(Sized_incremental_binary::~Sized_incremental_binary): New destructor.
|
||||
(Sized_incremental_binary::set_file_is_unchanged): New function.
|
||||
(Sized_incremental_binary::file_is_unchanged): New function.
|
||||
(Sized_incremental_binary::do_process_got_plt): New function.
|
||||
(Sized_incremental_binary::file_status_): New data member.
|
||||
(Sized_incremental_binary::main_symtab_loc_): New data member.
|
||||
(Sized_incremental_binary::main_strtab_loc_): New data member.
|
||||
* output.cc (Output_data_got::Got_entry::write): Add case
|
||||
RESERVED_CODE.
|
||||
(Output_data_got::add_global): Call add_got_entry.
|
||||
(Output_data_got::add_global_plt): Likewise.
|
||||
(Output_data_got::add_global_with_rel): Likewise.
|
||||
(Output_data_got::add_global_with_rela): Likewise.
|
||||
(Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
|
||||
(Output_data_got::add_global_pair_with_rela): Likewise.
|
||||
(Output_data_got::add_local): Call add_got_entry.
|
||||
(Output_data_got::add_local_plt): Likewise.
|
||||
(Output_data_got::add_local_with_rel): Likewise.
|
||||
(Output_data_got::add_local_with_rela): Likewise.
|
||||
(Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
|
||||
(Output_data_got::add_local_pair_with_rela): Likewise.
|
||||
(Output_data_got::reserve_slot): New function.
|
||||
(Output_data_got::reserve_slot_for_global): New function.
|
||||
(Output_data_got::add_got_entry): New function.
|
||||
(Output_data_got::add_got_entry_pair): New function.
|
||||
(Output_section::add_output_section_data): Edit FIXME.
|
||||
* output.h
|
||||
(Output_section_data_build::Output_section_data_build): New
|
||||
constructor with size parameter.
|
||||
(Output_data_space::Output_data_space): Likewise.
|
||||
(Output_data_got::Output_data_got): Initialize new data member; new
|
||||
constructor with size parameter.
|
||||
(Output_data_got::add_constant): Call add_got_entry.
|
||||
(Output_data_got::reserve_slot): New function.
|
||||
(Output_data_got::reserve_slot_for_global): New function.
|
||||
(class Output_data_got::Got_entry): Add RESERVED_CODE.
|
||||
(Output_data_got::add_got_entry): New function.
|
||||
(Output_data_got::add_got_entry_pair): New function.
|
||||
(Output_data_got::free_list_): New data member.
|
||||
* target.h (Sized_target::init_got_plt_for_update): New function.
|
||||
(Sized_target::register_global_plt_entry): New function.
|
||||
* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
|
||||
Initialize new data member; call init; add constructor with PLT count.
|
||||
(Output_data_plt_x86_64::init): New function.
|
||||
(Output_data_plt_x86_64::add_relocation): New function.
|
||||
(Output_data_plt_x86_64::reserve_slot): New function.
|
||||
(Output_data_plt_x86_64::free_list_): New data member.
|
||||
(Target_x86_64::init_got_plt_for_update): New function.
|
||||
(Target_x86_64::register_global_plt_entry): New function.
|
||||
(Output_data_plt_x86_64::add_entry): Allocate from free list for
|
||||
incremental updates.
|
||||
(Output_data_plt_x86_64::add_relocation): New function.
|
||||
* testsuite/object_unittest.cc (Object_test): Set default options.
|
||||
|
||||
2011-05-16 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* options.h (class General_options): Make -i a synonym for -r.
|
||||
|
@ -630,6 +630,13 @@ queue_middle_tasks(const General_options& options,
|
||||
}
|
||||
}
|
||||
|
||||
// For incremental updates, record the existing GOT and PLT entries.
|
||||
if (parameters->incremental_update())
|
||||
{
|
||||
Incremental_binary* ibase = layout->incremental_base();
|
||||
ibase->process_got_plt(symtab, layout);
|
||||
}
|
||||
|
||||
if (is_debugging_enabled(DEBUG_SCRIPT))
|
||||
layout->script_options()->print(stderr);
|
||||
|
||||
|
@ -370,7 +370,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
|
||||
unsigned int got_type = igot_plt.get_got_type(i);
|
||||
unsigned int got_desc = igot_plt.get_got_desc(i);
|
||||
printf("[%d] type %02x, ", i, got_type & 0x7f);
|
||||
if (got_type == 0x7f)
|
||||
if ((got_type & 0x7f) == 0x7f)
|
||||
printf("reserved");
|
||||
else if (got_type & 0x80)
|
||||
{
|
||||
|
@ -258,6 +258,19 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
|
||||
this->got_plt_reader_ =
|
||||
Incremental_got_plt_reader<big_endian>(got_plt_view.data());
|
||||
|
||||
// Find the main symbol table.
|
||||
unsigned int main_symtab_shndx =
|
||||
this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB);
|
||||
gold_assert(main_symtab_shndx != elfcpp::SHN_UNDEF);
|
||||
this->main_symtab_loc_ = this->elf_file_.section_contents(main_symtab_shndx);
|
||||
|
||||
// Find the main symbol string table.
|
||||
unsigned int main_strtab_shndx =
|
||||
this->elf_file_.section_link(main_symtab_shndx);
|
||||
gold_assert(main_strtab_shndx != elfcpp::SHN_UNDEF
|
||||
&& main_strtab_shndx < this->elf_file_.shnum());
|
||||
this->main_strtab_loc_ = this->elf_file_.section_contents(main_strtab_shndx);
|
||||
|
||||
// Walk the list of input files (a) to setup an Input_reader for each
|
||||
// input file, and (b) to record maps of files added from archive
|
||||
// libraries and scripts.
|
||||
@ -314,6 +327,10 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
|
||||
unsigned int nglobals = this->symtab_reader_.symbol_count();
|
||||
this->symbol_map_.resize(nglobals);
|
||||
|
||||
// Initialize the status of each input file.
|
||||
this->file_status_ = new unsigned char[(count + 7) / 8];
|
||||
memset(this->file_status_, 0, (count + 7) / 8);
|
||||
|
||||
this->has_incremental_info_ = true;
|
||||
}
|
||||
|
||||
@ -507,6 +524,8 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout(
|
||||
Input_entry_reader input_file =
|
||||
this->inputs_reader_.input_file(input_file_index);
|
||||
|
||||
this->set_file_is_unchanged(input_file_index);
|
||||
|
||||
if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
|
||||
return;
|
||||
|
||||
@ -523,6 +542,83 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout(
|
||||
}
|
||||
}
|
||||
|
||||
// Process the GOT and PLT entries from the existing output file.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_incremental_binary<size, big_endian>::do_process_got_plt(
|
||||
Symbol_table* symtab,
|
||||
Layout* layout)
|
||||
{
|
||||
Incremental_got_plt_reader<big_endian> got_plt_reader(this->got_plt_reader());
|
||||
Sized_target<size, big_endian>* target =
|
||||
parameters->sized_target<size, big_endian>();
|
||||
|
||||
// Get the number of symbols in the main symbol table and in the
|
||||
// incremental symbol table. The difference between the two counts
|
||||
// is the index of the first forced-local or global symbol in the
|
||||
// main symbol table.
|
||||
unsigned int symtab_count =
|
||||
this->main_symtab_loc_.data_size / elfcpp::Elf_sizes<size>::sym_size;
|
||||
unsigned int isym_count = this->symtab_reader_.symbol_count();
|
||||
unsigned int first_global = symtab_count - isym_count;
|
||||
|
||||
// Tell the target how big the GOT and PLT sections are.
|
||||
unsigned int got_count = got_plt_reader.get_got_entry_count();
|
||||
unsigned int plt_count = got_plt_reader.get_plt_entry_count();
|
||||
Output_data_got<size, big_endian>* got =
|
||||
target->init_got_plt_for_update(symtab, layout, got_count, plt_count);
|
||||
|
||||
// Read the GOT entries from the base file and build the outgoing GOT.
|
||||
for (unsigned int i = 0; i < got_count; ++i)
|
||||
{
|
||||
unsigned int got_type = got_plt_reader.get_got_type(i);
|
||||
if ((got_type & 0x7f) == 0x7f)
|
||||
{
|
||||
// This is the second entry of a pair.
|
||||
got->reserve_slot(i);
|
||||
continue;
|
||||
}
|
||||
unsigned int got_desc = got_plt_reader.get_got_desc(i);
|
||||
if (got_type & 0x80)
|
||||
{
|
||||
// This is an entry for a local symbol. GOT_DESC is the index
|
||||
// of the object file entry in the list of input files. Ignore
|
||||
// this entry if the object file was replaced.
|
||||
gold_debug(DEBUG_INCREMENTAL,
|
||||
"GOT entry %d, type %02x: (local symbol)",
|
||||
i, got_type & 0x7f);
|
||||
if (this->file_is_unchanged(got_desc))
|
||||
got->reserve_slot(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an entry for a global symbol. GOT_DESC is the symbol
|
||||
// table index.
|
||||
// FIXME: This should really be a fatal error (corrupt input).
|
||||
gold_assert(got_desc >= first_global && got_desc < symtab_count);
|
||||
Symbol* sym = this->global_symbol(got_desc - first_global);
|
||||
gold_debug(DEBUG_INCREMENTAL,
|
||||
"GOT entry %d, type %02x: %s",
|
||||
i, got_type, sym->name());
|
||||
got->reserve_slot_for_global(i, sym, got_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the PLT entries from the base file and pass each to the target.
|
||||
for (unsigned int i = 0; i < plt_count; ++i)
|
||||
{
|
||||
unsigned int plt_desc = got_plt_reader.get_plt_desc(i);
|
||||
// FIXME: This should really be a fatal error (corrupt input).
|
||||
gold_assert(plt_desc >= first_global && plt_desc < symtab_count);
|
||||
Symbol* sym = this->global_symbol(plt_desc - first_global);
|
||||
gold_debug(DEBUG_INCREMENTAL,
|
||||
"PLT entry %d: %s",
|
||||
i, sym->name());
|
||||
target->register_global_plt_entry(i, sym);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply incremental relocations for symbols whose values have changed.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -628,20 +724,12 @@ Sized_incremental_binary<size, big_endian>::get_symtab_view(
|
||||
unsigned int* nsyms,
|
||||
elfcpp::Elf_strtab* strtab)
|
||||
{
|
||||
unsigned int symtab_shndx =
|
||||
this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB);
|
||||
gold_assert(symtab_shndx != elfcpp::SHN_UNDEF);
|
||||
Location symtab_location(this->elf_file_.section_contents(symtab_shndx));
|
||||
*symtab_view = this->view(symtab_location);
|
||||
*nsyms = symtab_location.data_size / elfcpp::Elf_sizes<size>::sym_size;
|
||||
*symtab_view = this->view(this->main_symtab_loc_);
|
||||
*nsyms = this->main_symtab_loc_.data_size / elfcpp::Elf_sizes<size>::sym_size;
|
||||
|
||||
unsigned int strtab_shndx = this->elf_file_.section_link(symtab_shndx);
|
||||
gold_assert(strtab_shndx != elfcpp::SHN_UNDEF
|
||||
&& strtab_shndx < this->elf_file_.shnum());
|
||||
|
||||
Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
|
||||
View strtab_view(this->view(strtab_location));
|
||||
*strtab = elfcpp::Elf_strtab(strtab_view.data(), strtab_location.data_size);
|
||||
View strtab_view(this->view(this->main_strtab_loc_));
|
||||
*strtab = elfcpp::Elf_strtab(strtab_view.data(),
|
||||
this->main_strtab_loc_.data_size);
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -1022,6 +1110,7 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
|
||||
unsigned int input_offset = this->header_size;
|
||||
|
||||
// Offset of each supplemental info block.
|
||||
unsigned int file_index = 0;
|
||||
unsigned int info_offset = this->header_size;
|
||||
info_offset += this->input_entry_size * inputs->input_file_count();
|
||||
|
||||
@ -1031,8 +1120,9 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
|
||||
p != inputs->input_files().end();
|
||||
++p)
|
||||
{
|
||||
// Set the offset of the input file entry.
|
||||
(*p)->set_offset(input_offset);
|
||||
// Set the index and offset of the input file entry.
|
||||
(*p)->set_offset(file_index, input_offset);
|
||||
++file_index;
|
||||
input_offset += this->input_entry_size;
|
||||
|
||||
// Set the offset of the supplemental info block.
|
||||
@ -1655,7 +1745,7 @@ Output_section_incremental_inputs<size, big_endian>::write_got_plt(
|
||||
gold_assert(entry != NULL);
|
||||
const Object* obj = entry->object();
|
||||
gold_assert(obj != NULL);
|
||||
view_info.got_descriptor = (*p)->get_offset();
|
||||
view_info.got_descriptor = (*p)->get_file_index();
|
||||
Got_visitor v(view_info);
|
||||
obj->for_all_local_got_entries(&v);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ class Incremental_input_entry
|
||||
public:
|
||||
Incremental_input_entry(Stringpool::Key filename_key, unsigned int arg_serial,
|
||||
Timespec mtime)
|
||||
: filename_key_(filename_key), offset_(0), info_offset_(0),
|
||||
: filename_key_(filename_key), file_index_(0), offset_(0), info_offset_(0),
|
||||
arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false)
|
||||
{ }
|
||||
|
||||
@ -92,16 +92,24 @@ class Incremental_input_entry
|
||||
type() const
|
||||
{ return this->do_type(); }
|
||||
|
||||
// Set the section offset of this input file entry.
|
||||
// Set the index and section offset of this input file entry.
|
||||
void
|
||||
set_offset(unsigned int offset)
|
||||
{ this->offset_ = offset; }
|
||||
set_offset(unsigned int file_index, unsigned int offset)
|
||||
{
|
||||
this->file_index_ = file_index;
|
||||
this->offset_ = offset;
|
||||
}
|
||||
|
||||
// Set the section offset of the supplemental information for this entry.
|
||||
void
|
||||
set_info_offset(unsigned int info_offset)
|
||||
{ this->info_offset_ = info_offset; }
|
||||
|
||||
// Get the index of this input file entry.
|
||||
unsigned int
|
||||
get_file_index() const
|
||||
{ return this->file_index_; }
|
||||
|
||||
// Get the section offset of this input file entry.
|
||||
unsigned int
|
||||
get_offset() const
|
||||
@ -182,6 +190,9 @@ class Incremental_input_entry
|
||||
// Key of the filename string in the section stringtable.
|
||||
Stringpool::Key filename_key_;
|
||||
|
||||
// Index of the entry in the output section.
|
||||
unsigned int file_index_;
|
||||
|
||||
// Offset of the entry in the output section.
|
||||
unsigned int offset_;
|
||||
|
||||
@ -1235,6 +1246,11 @@ class Incremental_binary
|
||||
reserve_layout(unsigned int input_file_index)
|
||||
{ this->do_reserve_layout(input_file_index); }
|
||||
|
||||
// Process the GOT and PLT entries from the existing output file.
|
||||
void
|
||||
process_got_plt(Symbol_table* symtab, Layout* layout)
|
||||
{ this->do_process_got_plt(symtab, layout); }
|
||||
|
||||
// Apply incremental relocations for symbols whose values have changed.
|
||||
void
|
||||
apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
|
||||
@ -1313,6 +1329,10 @@ class Incremental_binary
|
||||
virtual void
|
||||
do_reserve_layout(unsigned int input_file_index) = 0;
|
||||
|
||||
// Process the GOT and PLT entries from the existing output file.
|
||||
virtual void
|
||||
do_process_got_plt(Symbol_table* symtab, Layout* layout) = 0;
|
||||
|
||||
// Apply incremental relocations for symbols whose values have changed.
|
||||
virtual void
|
||||
do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0;
|
||||
@ -1345,29 +1365,53 @@ class Sized_incremental_binary : public Incremental_binary
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr,
|
||||
Target* target)
|
||||
: Incremental_binary(output, target), elf_file_(this, ehdr),
|
||||
section_map_(), symbol_map_(), has_incremental_info_(false),
|
||||
inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(),
|
||||
file_status_(NULL), section_map_(), symbol_map_(), main_symtab_loc_(),
|
||||
main_strtab_loc_(), has_incremental_info_(false), inputs_reader_(),
|
||||
symtab_reader_(), relocs_reader_(), got_plt_reader_(),
|
||||
input_entry_readers_()
|
||||
{ this->setup_readers(); }
|
||||
|
||||
virtual
|
||||
~Sized_incremental_binary()
|
||||
{
|
||||
if (this->file_status_ != NULL)
|
||||
delete[] this->file_status_;
|
||||
}
|
||||
|
||||
// Returns TRUE if the file contains incremental info.
|
||||
bool
|
||||
has_incremental_info() const
|
||||
{ return this->has_incremental_info_; }
|
||||
|
||||
// Set the flag for input file N to indicate that the file is unchanged.
|
||||
void
|
||||
set_file_is_unchanged(unsigned int n)
|
||||
{
|
||||
gold_assert(this->file_status_ != NULL);
|
||||
this->file_status_[n / 8] |= 1U << (n % 8);
|
||||
}
|
||||
|
||||
// Returns TRUE if input file N is unchanged.
|
||||
bool
|
||||
file_is_unchanged(unsigned int n) const
|
||||
{
|
||||
gold_assert(this->file_status_ != NULL);
|
||||
return (this->file_status_[n / 8] & (1U << (n % 8))) != 0;
|
||||
}
|
||||
|
||||
// Return the Output_section for section index SHNDX.
|
||||
Output_section*
|
||||
output_section(unsigned int shndx)
|
||||
{ return this->section_map_[shndx]; }
|
||||
|
||||
// Map a symbol table entry from the input file to the output symbol table.
|
||||
// Map a symbol table entry from the base file to the output symbol table.
|
||||
// SYMNDX is relative to the first forced-local or global symbol in the
|
||||
// input file symbol table.
|
||||
void
|
||||
add_global_symbol(unsigned int symndx, Symbol* gsym)
|
||||
{ this->symbol_map_[symndx] = gsym; }
|
||||
|
||||
// Map a symbol table entry from the input file to the output symbol table.
|
||||
// Map a symbol table entry from the base file to the output symbol table.
|
||||
// SYMNDX is relative to the first forced-local or global symbol in the
|
||||
// input file symbol table.
|
||||
Symbol*
|
||||
@ -1418,6 +1462,10 @@ class Sized_incremental_binary : public Incremental_binary
|
||||
virtual void
|
||||
do_reserve_layout(unsigned int input_file_index);
|
||||
|
||||
// Process the GOT and PLT entries from the existing output file.
|
||||
virtual void
|
||||
do_process_got_plt(Symbol_table* symtab, Layout* layout);
|
||||
|
||||
// Apply incremental relocations for symbols whose values have changed.
|
||||
virtual void
|
||||
do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
|
||||
@ -1489,12 +1537,21 @@ class Sized_incremental_binary : public Incremental_binary
|
||||
// Output as an ELF file.
|
||||
elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
|
||||
|
||||
// Status flags for each input file. Each bit represents one input file;
|
||||
// 0 indicates that the file was replaced; 1 indicates that the file was
|
||||
// unchanged.
|
||||
unsigned char* file_status_;
|
||||
|
||||
// Map section index to an Output_section in the updated layout.
|
||||
std::vector<Output_section*> section_map_;
|
||||
|
||||
// Map global symbols from the input file to the symbol table.
|
||||
std::vector<Symbol*> symbol_map_;
|
||||
|
||||
// Locations of the main symbol table and symbol string table.
|
||||
Location main_symtab_loc_;
|
||||
Location main_strtab_loc_;
|
||||
|
||||
// Readers for the incremental info sections.
|
||||
bool has_incremental_info_;
|
||||
Incremental_inputs_reader<size, big_endian> inputs_reader_;
|
||||
|
173
gold/output.cc
173
gold/output.cc
@ -1358,6 +1358,13 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
|
||||
val = this->u_.constant;
|
||||
break;
|
||||
|
||||
case RESERVED_CODE:
|
||||
// If we're doing an incremental update, don't touch this GOT entry.
|
||||
if (parameters->incremental_update())
|
||||
return;
|
||||
val = this->u_.constant;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const Sized_relobj<size, big_endian>* object = this->u_.object;
|
||||
@ -1393,9 +1400,8 @@ Output_data_got<size, big_endian>::add_global(
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return false;
|
||||
|
||||
this->entries_.push_back(Got_entry(gsym, false));
|
||||
this->set_got_size();
|
||||
gsym->set_got_offset(got_type, this->last_got_offset());
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry(gsym, false));
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1409,9 +1415,8 @@ Output_data_got<size, big_endian>::add_global_plt(Symbol* gsym,
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return false;
|
||||
|
||||
this->entries_.push_back(Got_entry(gsym, true));
|
||||
this->set_got_size();
|
||||
gsym->set_got_offset(got_type, this->last_got_offset());
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry(gsym, true));
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1429,9 +1434,7 @@ Output_data_got<size, big_endian>::add_global_with_rel(
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
this->set_got_size();
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry());
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
rel_dyn->add_global(gsym, r_type, this, got_offset);
|
||||
}
|
||||
@ -1447,9 +1450,7 @@ Output_data_got<size, big_endian>::add_global_with_rela(
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
this->set_got_size();
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry());
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
|
||||
}
|
||||
@ -1469,19 +1470,12 @@ Output_data_got<size, big_endian>::add_global_pair_with_rel(
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry_pair(Got_entry(), Got_entry());
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
rel_dyn->add_global(gsym, r_type_1, this, got_offset);
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
if (r_type_2 != 0)
|
||||
{
|
||||
got_offset = this->last_got_offset();
|
||||
rel_dyn->add_global(gsym, r_type_2, this, got_offset);
|
||||
}
|
||||
|
||||
this->set_got_size();
|
||||
rel_dyn->add_global(gsym, r_type_2, this, got_offset + size / 8);
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -1496,19 +1490,12 @@ Output_data_got<size, big_endian>::add_global_pair_with_rela(
|
||||
if (gsym->has_got_offset(got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry_pair(Got_entry(), Got_entry());
|
||||
gsym->set_got_offset(got_type, got_offset);
|
||||
rela_dyn->add_global(gsym, r_type_1, this, got_offset, 0);
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
if (r_type_2 != 0)
|
||||
{
|
||||
got_offset = this->last_got_offset();
|
||||
rela_dyn->add_global(gsym, r_type_2, this, got_offset, 0);
|
||||
}
|
||||
|
||||
this->set_got_size();
|
||||
rela_dyn->add_global(gsym, r_type_2, this, got_offset + size / 8, 0);
|
||||
}
|
||||
|
||||
// Add an entry for a local symbol to the GOT. This returns true if
|
||||
@ -1525,9 +1512,9 @@ Output_data_got<size, big_endian>::add_local(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return false;
|
||||
|
||||
this->entries_.push_back(Got_entry(object, symndx, false));
|
||||
this->set_got_size();
|
||||
object->set_local_got_offset(symndx, got_type, this->last_got_offset());
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
|
||||
false));
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1543,9 +1530,9 @@ Output_data_got<size, big_endian>::add_local_plt(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return false;
|
||||
|
||||
this->entries_.push_back(Got_entry(object, symndx, true));
|
||||
this->set_got_size();
|
||||
object->set_local_got_offset(symndx, got_type, this->last_got_offset());
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
|
||||
true));
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1564,9 +1551,7 @@ Output_data_got<size, big_endian>::add_local_with_rel(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
this->set_got_size();
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry());
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
rel_dyn->add_local(object, symndx, r_type, this, got_offset);
|
||||
}
|
||||
@ -1583,9 +1568,7 @@ Output_data_got<size, big_endian>::add_local_with_rela(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
this->set_got_size();
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry());
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
rela_dyn->add_local(object, symndx, r_type, this, got_offset, 0);
|
||||
}
|
||||
@ -1607,20 +1590,15 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset =
|
||||
this->add_got_entry_pair(Got_entry(),
|
||||
Got_entry(object, symndx, false));
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
Output_section* os = object->output_section(shndx);
|
||||
rel_dyn->add_output_section(os, r_type_1, this, got_offset);
|
||||
|
||||
this->entries_.push_back(Got_entry(object, symndx, false));
|
||||
if (r_type_2 != 0)
|
||||
{
|
||||
got_offset = this->last_got_offset();
|
||||
rel_dyn->add_output_section(os, r_type_2, this, got_offset);
|
||||
}
|
||||
|
||||
this->set_got_size();
|
||||
rel_dyn->add_output_section(os, r_type_2, this, got_offset + size / 8);
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -1637,20 +1615,37 @@ Output_data_got<size, big_endian>::add_local_pair_with_rela(
|
||||
if (object->local_has_got_offset(symndx, got_type))
|
||||
return;
|
||||
|
||||
this->entries_.push_back(Got_entry());
|
||||
unsigned int got_offset = this->last_got_offset();
|
||||
unsigned int got_offset =
|
||||
this->add_got_entry_pair(Got_entry(),
|
||||
Got_entry(object, symndx, false));
|
||||
object->set_local_got_offset(symndx, got_type, got_offset);
|
||||
Output_section* os = object->output_section(shndx);
|
||||
rela_dyn->add_output_section(os, r_type_1, this, got_offset, 0);
|
||||
|
||||
this->entries_.push_back(Got_entry(object, symndx, false));
|
||||
if (r_type_2 != 0)
|
||||
{
|
||||
got_offset = this->last_got_offset();
|
||||
rela_dyn->add_output_section(os, r_type_2, this, got_offset, 0);
|
||||
}
|
||||
rela_dyn->add_output_section(os, r_type_2, this, got_offset + size / 8, 0);
|
||||
}
|
||||
|
||||
this->set_got_size();
|
||||
// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_data_got<size, big_endian>::reserve_slot(unsigned int i)
|
||||
{
|
||||
this->free_list_.remove(i * size / 8, (i + 1) * size / 8);
|
||||
}
|
||||
|
||||
// Reserve a slot in the GOT for a global symbol.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_data_got<size, big_endian>::reserve_slot_for_global(
|
||||
unsigned int i,
|
||||
Symbol* gsym,
|
||||
unsigned int got_type)
|
||||
{
|
||||
this->free_list_.remove(i * size / 8, (i + 1) * size / 8);
|
||||
gsym->set_got_offset(got_type, this->got_offset(i));
|
||||
}
|
||||
|
||||
// Write out the GOT.
|
||||
@ -1682,6 +1677,63 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
|
||||
this->entries_.clear();
|
||||
}
|
||||
|
||||
// Create a new GOT entry and return its offset.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Output_data_got<size, big_endian>::add_got_entry(Got_entry got_entry)
|
||||
{
|
||||
if (!this->is_data_size_valid())
|
||||
{
|
||||
this->entries_.push_back(got_entry);
|
||||
this->set_got_size();
|
||||
return this->last_got_offset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// For an incremental update, find an available slot.
|
||||
off_t got_offset = this->free_list_.allocate(size / 8, size / 8, 0);
|
||||
if (got_offset == -1)
|
||||
gold_fatal(_("out of patch space (GOT);"
|
||||
" relink with --incremental-full"));
|
||||
unsigned int got_index = got_offset / (size / 8);
|
||||
gold_assert(got_index < this->entries_.size());
|
||||
this->entries_[got_index] = got_entry;
|
||||
return static_cast<unsigned int>(got_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a pair of new GOT entries and return the offset of the first.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Output_data_got<size, big_endian>::add_got_entry_pair(Got_entry got_entry_1,
|
||||
Got_entry got_entry_2)
|
||||
{
|
||||
if (!this->is_data_size_valid())
|
||||
{
|
||||
unsigned int got_offset;
|
||||
this->entries_.push_back(got_entry_1);
|
||||
got_offset = this->last_got_offset();
|
||||
this->entries_.push_back(got_entry_2);
|
||||
this->set_got_size();
|
||||
return got_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For an incremental update, find an available pair of slots.
|
||||
off_t got_offset = this->free_list_.allocate(2 * size / 8, size / 8, 0);
|
||||
if (got_offset == -1)
|
||||
gold_fatal(_("out of patch space (GOT);"
|
||||
" relink with --incremental-full"));
|
||||
unsigned int got_index = got_offset / (size / 8);
|
||||
gold_assert(got_index < this->entries_.size());
|
||||
this->entries_[got_index] = got_entry_1;
|
||||
this->entries_[got_index + 1] = got_entry_2;
|
||||
return static_cast<unsigned int>(got_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Output_data_dynamic::Dynamic_entry methods.
|
||||
|
||||
// Write out the entry.
|
||||
@ -2335,7 +2387,8 @@ Output_section::add_output_section_data(Output_section_data* posd)
|
||||
uint64_t addr = this->address();
|
||||
posd->set_address(addr);
|
||||
posd->set_file_offset(0);
|
||||
// FIXME: Mark *POSD as part of a fixed-layout section.
|
||||
// FIXME: This should eventually be unreachable.
|
||||
// gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,6 +764,10 @@ class Output_section_data_build : public Output_section_data
|
||||
: Output_section_data(addralign)
|
||||
{ }
|
||||
|
||||
Output_section_data_build(off_t data_size, uint64_t addralign)
|
||||
: Output_section_data(data_size, addralign, false)
|
||||
{ }
|
||||
|
||||
// Set the current data size.
|
||||
void
|
||||
set_current_data_size(off_t data_size)
|
||||
@ -890,6 +894,12 @@ class Output_data_space : public Output_section_data_build
|
||||
map_name_(map_name)
|
||||
{ }
|
||||
|
||||
explicit Output_data_space(off_t data_size, uint64_t addralign,
|
||||
const char* map_name)
|
||||
: Output_section_data_build(data_size, addralign),
|
||||
map_name_(map_name)
|
||||
{ }
|
||||
|
||||
// Set the alignment.
|
||||
void
|
||||
set_space_alignment(uint64_t align)
|
||||
@ -1942,9 +1952,20 @@ class Output_data_got : public Output_section_data_build
|
||||
|
||||
Output_data_got()
|
||||
: Output_section_data_build(Output_data::default_alignment_for_size(size)),
|
||||
entries_()
|
||||
entries_(), free_list_()
|
||||
{ }
|
||||
|
||||
Output_data_got(off_t data_size)
|
||||
: Output_section_data_build(data_size,
|
||||
Output_data::default_alignment_for_size(size)),
|
||||
entries_(), free_list_()
|
||||
{
|
||||
// For an incremental update, we have an existing GOT section.
|
||||
// Initialize the list of entries and the free list.
|
||||
this->entries_.resize(data_size / (size / 8));
|
||||
this->free_list_.init(data_size, false);
|
||||
}
|
||||
|
||||
// Add an entry for a global symbol to the GOT. Return true if this
|
||||
// is a new GOT entry, false if the symbol was already in the GOT.
|
||||
bool
|
||||
@ -2021,11 +2042,18 @@ class Output_data_got : public Output_section_data_build
|
||||
unsigned int
|
||||
add_constant(Valtype constant)
|
||||
{
|
||||
this->entries_.push_back(Got_entry(constant));
|
||||
this->set_got_size();
|
||||
return this->last_got_offset();
|
||||
unsigned int got_offset = this->add_got_entry(Got_entry(constant));
|
||||
return got_offset;
|
||||
}
|
||||
|
||||
// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
|
||||
void
|
||||
reserve_slot(unsigned int i);
|
||||
|
||||
// Reserve a slot in the GOT for a global symbol.
|
||||
void
|
||||
reserve_slot_for_global(unsigned int i, Symbol* gsym, unsigned int got_type);
|
||||
|
||||
protected:
|
||||
// Write out the GOT table.
|
||||
void
|
||||
@ -2043,7 +2071,7 @@ class Output_data_got : public Output_section_data_build
|
||||
public:
|
||||
// Create a zero entry.
|
||||
Got_entry()
|
||||
: local_sym_index_(CONSTANT_CODE), use_plt_offset_(false)
|
||||
: local_sym_index_(RESERVED_CODE), use_plt_offset_(false)
|
||||
{ this->u_.constant = 0; }
|
||||
|
||||
// Create a global symbol entry.
|
||||
@ -2058,6 +2086,7 @@ class Output_data_got : public Output_section_data_build
|
||||
{
|
||||
gold_assert(local_sym_index != GSYM_CODE
|
||||
&& local_sym_index != CONSTANT_CODE
|
||||
&& local_sym_index != RESERVED_CODE
|
||||
&& local_sym_index == this->local_sym_index_);
|
||||
this->u_.object = object;
|
||||
}
|
||||
@ -2076,7 +2105,8 @@ class Output_data_got : public Output_section_data_build
|
||||
enum
|
||||
{
|
||||
GSYM_CODE = 0x7fffffff,
|
||||
CONSTANT_CODE = 0x7ffffffe
|
||||
CONSTANT_CODE = 0x7ffffffe,
|
||||
RESERVED_CODE = 0x7ffffffd
|
||||
};
|
||||
|
||||
union
|
||||
@ -2097,6 +2127,14 @@ class Output_data_got : public Output_section_data_build
|
||||
|
||||
typedef std::vector<Got_entry> Got_entries;
|
||||
|
||||
// Create a new GOT entry and return its offset.
|
||||
unsigned int
|
||||
add_got_entry(Got_entry got_entry);
|
||||
|
||||
// Create a pair of new GOT entries and return the offset of the first.
|
||||
unsigned int
|
||||
add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2);
|
||||
|
||||
// Return the offset into the GOT of GOT entry I.
|
||||
unsigned int
|
||||
got_offset(unsigned int i) const
|
||||
@ -2114,6 +2152,10 @@ class Output_data_got : public Output_section_data_build
|
||||
|
||||
// The list of GOT entries.
|
||||
Got_entries entries_;
|
||||
|
||||
// List of available regions within the section, for incremental
|
||||
// update links.
|
||||
Free_list free_list_;
|
||||
};
|
||||
|
||||
// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
|
||||
|
@ -54,6 +54,8 @@ template<int size>
|
||||
class Sized_symbol;
|
||||
class Symbol_table;
|
||||
class Output_data;
|
||||
template<int size, bool big_endian>
|
||||
class Output_data_got;
|
||||
class Output_section;
|
||||
class Input_objects;
|
||||
class Task;
|
||||
@ -795,6 +797,24 @@ class Sized_target : public Target
|
||||
plt_entry_size() const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Create the GOT and PLT sections for an incremental update.
|
||||
// A target needs to implement this to support incremental linking.
|
||||
|
||||
virtual Output_data_got<size, big_endian>*
|
||||
init_got_plt_for_update(Symbol_table*,
|
||||
Layout*,
|
||||
unsigned int /* got_count */,
|
||||
unsigned int /* plt_count */)
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Register an existing PLT entry for a global symbol.
|
||||
// A target needs to implement this to support incremental linking.
|
||||
|
||||
virtual void
|
||||
register_global_plt_entry(unsigned int /* plt_index */,
|
||||
Symbol*)
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Apply an incremental relocation.
|
||||
|
||||
virtual void
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "gold.h"
|
||||
|
||||
#include "object.h"
|
||||
#include "options.h"
|
||||
#include "parameters.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "testfile.h"
|
||||
@ -62,8 +64,11 @@ Sized_object_test(const unsigned char* test_file, unsigned int test_file_size)
|
||||
bool
|
||||
Object_test(Test_report*)
|
||||
{
|
||||
General_options options;
|
||||
int fail = 0;
|
||||
|
||||
set_parameters_options(&options);
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
if (!Sized_object_test<32, false>(test_file_1_32_little,
|
||||
test_file_1_size_32_little))
|
||||
|
208
gold/x86_64.cc
208
gold/x86_64.cc
@ -53,8 +53,31 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
public:
|
||||
typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
|
||||
|
||||
Output_data_plt_x86_64(Symbol_table*, Layout*, Output_data_got<64, false>*,
|
||||
Output_data_space*);
|
||||
Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(0), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{ this->init(symtab, layout); }
|
||||
|
||||
Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt,
|
||||
unsigned int plt_count)
|
||||
: Output_section_data((plt_count + 1) * plt_entry_size, 8, false),
|
||||
tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(plt_count), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{
|
||||
this->init(symtab, layout);
|
||||
|
||||
// Initialize the free list and reserve the first entry.
|
||||
this->free_list_.init((plt_count + 1) * plt_entry_size, false);
|
||||
this->free_list_.remove(0, plt_entry_size);
|
||||
}
|
||||
|
||||
// Initialize the PLT section.
|
||||
void
|
||||
init(Symbol_table* symtab, Layout* layout);
|
||||
|
||||
// Add an entry to the PLT.
|
||||
void
|
||||
@ -65,6 +88,10 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
|
||||
unsigned int local_sym_index);
|
||||
|
||||
// Add the relocation for a PLT entry.
|
||||
void
|
||||
add_relocation(Symbol* gsym, unsigned int got_offset);
|
||||
|
||||
// Add the reserved TLSDESC_PLT entry to the PLT.
|
||||
void
|
||||
reserve_tlsdesc_entry(unsigned int got_offset)
|
||||
@ -109,6 +136,14 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
get_plt_entry_size()
|
||||
{ return plt_entry_size; }
|
||||
|
||||
// Reserve a slot in the PLT for an existing symbol in an incremental update.
|
||||
void
|
||||
reserve_slot(unsigned int plt_index)
|
||||
{
|
||||
this->free_list_.remove((plt_index + 1) * plt_entry_size,
|
||||
(plt_index + 2) * plt_entry_size);
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os);
|
||||
@ -154,6 +189,9 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
unsigned int count_;
|
||||
// Offset of the reserved TLSDESC_GOT entry when needed.
|
||||
unsigned int tlsdesc_got_offset_;
|
||||
// List of available regions within the section, for incremental
|
||||
// update links.
|
||||
Free_list free_list_;
|
||||
};
|
||||
|
||||
// The x86_64 target class.
|
||||
@ -345,6 +383,18 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
||||
unsigned int
|
||||
plt_entry_size() const;
|
||||
|
||||
// Create the GOT section for an incremental update.
|
||||
Output_data_got<64, false>*
|
||||
init_got_plt_for_update(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
unsigned int got_count,
|
||||
unsigned int plt_count);
|
||||
|
||||
// Register an existing PLT entry for a global symbol.
|
||||
// A target needs to implement this to support incremental linking.
|
||||
void
|
||||
register_global_plt_entry(unsigned int plt_index, Symbol* gsym);
|
||||
|
||||
// Apply an incremental relocation.
|
||||
void
|
||||
apply_relocation(const Relocate_info<64, false>* relinfo,
|
||||
@ -779,16 +829,10 @@ Target_x86_64::rela_dyn_section(Layout* layout)
|
||||
return this->rela_dyn_;
|
||||
}
|
||||
|
||||
// Create the PLT section. The ordinary .got section is an argument,
|
||||
// since we need to refer to the start. We also create our own .got
|
||||
// section just for PLT entries.
|
||||
// Initialize the PLT section.
|
||||
|
||||
Output_data_plt_x86_64::Output_data_plt_x86_64(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(0), tlsdesc_got_offset_(-1U)
|
||||
void
|
||||
Output_data_plt_x86_64::init(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
@ -827,31 +871,47 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
||||
{
|
||||
gold_assert(!gsym->has_plt_offset());
|
||||
|
||||
// Note that when setting the PLT offset we skip the initial
|
||||
// reserved PLT entry.
|
||||
gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
|
||||
unsigned int plt_index;
|
||||
off_t plt_offset;
|
||||
section_offset_type got_offset;
|
||||
|
||||
++this->count_;
|
||||
if (!this->is_data_size_valid())
|
||||
{
|
||||
// Note that when setting the PLT offset we skip the initial
|
||||
// reserved PLT entry.
|
||||
plt_index = this->count_ + 1;
|
||||
plt_offset = plt_index * plt_entry_size;
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
++this->count_;
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry (this will be changed by the dynamic linker, normally
|
||||
// lazily when the function is called).
|
||||
this->got_plt_->set_current_data_size(got_offset + 8);
|
||||
got_offset = (plt_index - 1 + 3) * 8;
|
||||
gold_assert(got_offset == this->got_plt_->current_data_size());
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_plt_, got_offset, 0);
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry (this will be changed by the dynamic linker, normally
|
||||
// lazily when the function is called).
|
||||
this->got_plt_->set_current_data_size(got_offset + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsym->set_needs_dynsym_entry();
|
||||
this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
|
||||
got_offset, 0);
|
||||
// For incremental updates, find an available slot.
|
||||
plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0);
|
||||
if (plt_offset == -1)
|
||||
gold_fatal(_("out of patch space (PLT);"
|
||||
" relink with --incremental-full"));
|
||||
|
||||
// The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
|
||||
// can be calculated from the PLT index, adjusting for the three
|
||||
// reserved entries at the beginning of the GOT.
|
||||
plt_index = plt_offset / plt_entry_size - 1;
|
||||
got_offset = (plt_index - 1 + 3) * 8;
|
||||
}
|
||||
|
||||
gsym->set_plt_offset(plt_offset);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
this->add_relocation(gsym, got_offset);
|
||||
|
||||
// Note that we don't need to save the symbol. The contents of the
|
||||
// PLT are independent of which symbols are used. The symbols only
|
||||
// appear in the relocations.
|
||||
@ -881,6 +941,23 @@ Output_data_plt_x86_64::add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
// Add the relocation for a PLT entry.
|
||||
|
||||
void
|
||||
Output_data_plt_x86_64::add_relocation(Symbol* gsym, unsigned int got_offset)
|
||||
{
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_plt_, got_offset, 0);
|
||||
else
|
||||
{
|
||||
gsym->set_needs_dynsym_entry();
|
||||
this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
|
||||
got_offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Return where the TLSDESC relocations should go, creating it if
|
||||
// necessary. These follow the JUMP_SLOT relocations.
|
||||
|
||||
@ -1129,6 +1206,81 @@ Target_x86_64::plt_entry_size() const
|
||||
return Output_data_plt_x86_64::get_plt_entry_size();
|
||||
}
|
||||
|
||||
// Create the GOT and PLT sections for an incremental update.
|
||||
|
||||
Output_data_got<64, false>*
|
||||
Target_x86_64::init_got_plt_for_update(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
unsigned int got_count,
|
||||
unsigned int plt_count)
|
||||
{
|
||||
gold_assert(this->got_ == NULL);
|
||||
|
||||
this->got_ = new Output_data_got<64, false>(got_count * 8);
|
||||
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE),
|
||||
this->got_, ORDER_RELRO_LAST,
|
||||
true);
|
||||
|
||||
// Add the three reserved entries.
|
||||
this->got_plt_ = new Output_data_space((plt_count + 3) * 8, 8, "** GOT PLT");
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE),
|
||||
this->got_plt_, ORDER_NON_RELRO_FIRST,
|
||||
false);
|
||||
|
||||
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
|
||||
this->global_offset_table_ =
|
||||
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->got_plt_,
|
||||
0, 0, elfcpp::STT_OBJECT,
|
||||
elfcpp::STB_LOCAL,
|
||||
elfcpp::STV_HIDDEN, 0,
|
||||
false, false);
|
||||
|
||||
// If there are any TLSDESC relocations, they get GOT entries in
|
||||
// .got.plt after the jump slot entries.
|
||||
// FIXME: Get the count for TLSDESC entries.
|
||||
this->got_tlsdesc_ = new Output_data_got<64, false>(0);
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
|
||||
this->got_tlsdesc_,
|
||||
ORDER_NON_RELRO_FIRST, false);
|
||||
|
||||
// Create the PLT section.
|
||||
this->plt_ = new Output_data_plt_x86_64(symtab, layout, this->got_,
|
||||
this->got_plt_, plt_count);
|
||||
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
|
||||
this->plt_, ORDER_PLT, false);
|
||||
|
||||
// Make the sh_info field of .rela.plt point to .plt.
|
||||
Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
|
||||
rela_plt_os->set_info_section(this->plt_->output_section());
|
||||
|
||||
return this->got_;
|
||||
}
|
||||
|
||||
// Register an existing PLT entry for a global symbol.
|
||||
|
||||
void
|
||||
Target_x86_64::register_global_plt_entry(unsigned int plt_index,
|
||||
Symbol* gsym)
|
||||
{
|
||||
gold_assert(this->plt_ != NULL);
|
||||
gold_assert(!gsym->has_plt_offset());
|
||||
|
||||
this->plt_->reserve_slot(plt_index);
|
||||
|
||||
gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
|
||||
|
||||
unsigned int got_offset = (plt_index + 3) * 8;
|
||||
this->plt_->add_relocation(gsym, got_offset);
|
||||
}
|
||||
|
||||
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
|
||||
|
||||
void
|
||||
|
Loading…
x
Reference in New Issue
Block a user