elfcpp/ChangeLog:
* elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_SYMTAB, SHT_GNU_INCREMENTAL_RELOCS. gold/ChangeLog: * archive.cc: Include incremental.h. (Archive::Archive): Initialize incremental_info_. (Archive::include_member): Record archive members in incremental info. (Add_archive_symbols::run): Record begin and end of an archive in incremental info. (Lib_group::include_member): Record objects in incremental info. * archive.h (Incremental_archive_entry): Forward declaration. (Archive::set_incremental_info): New member function. (Archive::incremental_info): New member function. (Archive::Unused_symbol_iterator): New class. (Archive::unused_symbols_begin): New member function. (Archive::unused_symbols_end): New member function. (Archive::incremental_info_): New data member. * incremental-dump.cc (find_input_containing_global): New function. (dump_incremental_inputs): Dump new incremental info sections. * incremental.cc: Include symtab.h. (Output_section_incremental_inputs): New class. (Sized_incremental_binary::do_find_incremental_inputs_sections): Support new incremental info sections. (Sized_incremental_binary::do_check_inputs): Likewise. (Incremental_inputs::report_archive): Remove. (Incremental_inputs::report_archive_begin): New function. (Incremental_inputs::report_archive_end): New function. (Incremental_inputs::report_object): New function. (Incremental_inputs::finalize_inputs): Remove. (Incremental_inputs::report_input_section): New function. (Incremental_inputs::report_script): Rewrite. (Incremental_inputs::finalize): Do nothing but finalize string table. (Incremental_inputs::create_incremental_inputs_section_data): Remove. (Incremental_inputs::sized_create_inputs_section_data): Remove. (Incremental_inputs::create_data_sections): New function. (Incremental_inputs::relocs_entsize): New function. (Output_section_incremental_inputs::set_final_data_size): New function. (Output_section_incremental_inputs::do_write): New function. (Output_section_incremental_inputs::write_header): New function. (Output_section_incremental_inputs::write_input_files): New function. (Output_section_incremental_inputs::write_info_blocks): New function. (Output_section_incremental_inputs::write_symtab): New function. * incremental.h (Incremental_script_entry): Forward declaration. (Incremental_object_entry): Forward declaration. (Incremental_archive_entry): Forward declaration. (Incremental_inputs): Forward declaration. (Incremental_inputs_header_data): Remove. (Incremental_inputs_header): Remove. (Incremental_inputs_header_write): Remove. (Incremental_inputs_entry_data): Remove. (Incremental_inputs_entry): Remove. (Incremental_inputs_entry_write): Remove. (enum Incremental_input_type): Add INCREMENTAL_INPUT_ARCHIVE_MEMBER. (Incremental_binary::find_incremental_inputs_sections): Add parameters. (Incremental_binary::do_find_incremental_inputs_sections): Likewise. (Sized_ncremental_binary::do_find_incremental_inputs_sections): Likewise. (Incremental_input_entry): New class. (Incremental_script_entry): New class. (Incremental_object_entry): New class. (Incremental_archive_entry): New class. (Incremental_inputs::Incremental_inputs): Initialize new data members. (Incremental_inputs::report_inputs): Remove. (Incremental_inputs::report_archive): Remove. (Incremental_inputs::report_archive_begin): New function. (Incremental_inputs::report_archive_end): New function. (Incremental_inputs::report_object): Change prototype. (Incremental_inputs::report_input_section): New function. (Incremental_inputs::report_script): Change prototype. (Incremental_inputs::get_reloc_count): New function. (Incremental_inputs::set_reloc_count): New function. (Incremental_inputs::create_data_sections): New function. (Incremental_inputs::create_incremental_inputs_section_data): Remove. (Incremental_inputs::inputs_section): New function. (Incremental_inputs::symtab_section): New function. (Incremental_inputs::relocs_section): New function. (Incremental_inputs::get_stringpool): Add const. (Incremental_inputs::command_line): Add const. (Incremental_inputs::inputs): Remove. (Incremental_inputs::command_line_key): New function. (Incremental_inputs::input_file_count): New function. (Incremental_inputs::input_files): New function. (Incremental_inputs::relocs_entsize): New function. (Incremental_inputs::sized_create_inputs_section_data): Remove. (Incremental_inputs::finalize_inputs): Remove. (Incremental_inputs::Input_info): Remove. (Incremental_inputs::lock_): Remove. (Incremental_inputs::inputs_): Change type. (Incremental_inputs::inputs_map_): Remove. (Incremental_inputs::current_object_entry_): New data member. (Incremental_inputs::inputs_section_): New data member. (Incremental_inputs::symtab_section_): New data member. (Incremental_inputs::relocs_section_): New data member. (Incremental_inputs::reloc_count_): New data member. (Incremental_inputs_reader): New class. (Incremental_symtab_reader): New class. (Incremental_relocs_reader): New class. * layout.cc (Layout::finalize): Move finalization of incremental info and creation of incremental info sections to follow finalization of symbol table. Set offsets for postprocessing sections. (Layout::create_incremental_info_sections): Call Incremental_inputs::create_data_sections. Add incremental symtab and relocs sections. Set sh_entsize and sh_link fields. Arrange for sections to layout after input sections. * layout.h (struct Timespec): Forward declaration. (Layout::incremental_inputs): Add const. (Layout::create_incremental_info_sections): Add parameter. * main.cc (main): Remove call to Incremental_inputs::report_inputs. * object.cc: Include incremental.h. (Relobj::finalize_incremental_relocs): New function. (Sized_relobj::do_layout): Record input sections in incremental info. * object.h (Object::output_section): New function. (Object::output_section_offset): Moved from Relobj. (Object::get_incremental_reloc_base): New function. (Object::get_incremental_reloc_count): New function. (Object::do_output_section): New function. (Object::do_output_section_offset): Moved from Relobj. (Object::do_get_incremental_reloc_base): New function. (Object::do_get_incremental_reloc_count): New function. (Object::Object): Initialize new data members. (Relobj::output_section): Renamed do_output_section and moved to protected. (Relobj::output_section_offset): Moved to Object. (Relobj::do_get_incremental_reloc_base): New function. (Relobj::do_get_incremental_reloc_count): New function. (Relobj::allocate_incremental_reloc_counts): New function. (Relobj::count_incremental_reloc): New function. (Relobj::finalize_incremental_relocs): New function. (Relobj::next_incremental_reloc_index): New function. (Relobj::reloc_counts_): New data member. (Relobj::reloc_bases_): New data member. (Sized_relobj::do_relocate_sections): Add parameter. Change caller. (Sized_relobj::relocate_sections): Add parameter. Change all callers. (Sized_relobj::incremental_relocs_scan): New function. (Sized_relobj::incremental_relocs_scan_reltype): New function. (Sized_relobj::incremental_relocs_write): New function. (Sized_relobj::incremental_relocs_write_reltype): New function. * plugin.cc (Plugin_manager::add_input_file): Rewrite test for incremental link. * readsyms.cc (Read_symbols::do_read_symbols): Move reporting of archives and object files elsewhere. (Add_symbols::run): Report object files here. (Finish_group::run): Report end of archive at end of group. * reloc.cc: Include layout.h, incremental.h. (Sized_relobj::do_read_relocs): Need relocations for incremental link. (Sized_relobj::do_scan_relocs): Record relocations for incremental link. (Sized_relobj::incremental_relocs_scan): New function. (Sized_relobj::incremental_relocs_scan_reltype): New function. (Sized_relobj::do_relocate_sections): Write incremental relocations. (Sized_relobj::incremental_relocs_write): New function. (Sized_relobj::incremental_relocs_write_reltype): New function. * script.cc (read_input_script): Rewrite test for incremental link. Change call to Incremental_inputs::report_script. * symtab.h (Symbol_table::first_global_index): New function. (Symbol_table::output_count): New function.
This commit is contained in:
parent
98bfdba52e
commit
09ec0418c0
18 changed files with 2355 additions and 656 deletions
|
@ -1,3 +1,8 @@
|
|||
2010-08-12 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_SYMTAB,
|
||||
SHT_GNU_INCREMENTAL_RELOCS.
|
||||
|
||||
2010-08-04 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* i386.h (R_386_IRELATIVE): Define.
|
||||
|
|
|
@ -365,6 +365,8 @@ enum SHT
|
|||
// The remaining values are not in the standard.
|
||||
// Incremental build data.
|
||||
SHT_GNU_INCREMENTAL_INPUTS = 0x6fff4700,
|
||||
SHT_GNU_INCREMENTAL_SYMTAB = 0x6fff4701,
|
||||
SHT_GNU_INCREMENTAL_RELOCS = 0x6fff4702,
|
||||
// Object attributes.
|
||||
SHT_GNU_ATTRIBUTES = 0x6ffffff5,
|
||||
// GNU style dynamic hash table.
|
||||
|
|
154
gold/ChangeLog
154
gold/ChangeLog
|
@ -1,3 +1,157 @@
|
|||
2010-08-12 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* archive.cc: Include incremental.h.
|
||||
(Archive::Archive): Initialize incremental_info_.
|
||||
(Archive::include_member): Record archive members in incremental info.
|
||||
(Add_archive_symbols::run): Record begin and end of an archive in
|
||||
incremental info.
|
||||
(Lib_group::include_member): Record objects in incremental info.
|
||||
* archive.h (Incremental_archive_entry): Forward declaration.
|
||||
(Archive::set_incremental_info): New member function.
|
||||
(Archive::incremental_info): New member function.
|
||||
(Archive::Unused_symbol_iterator): New class.
|
||||
(Archive::unused_symbols_begin): New member function.
|
||||
(Archive::unused_symbols_end): New member function.
|
||||
(Archive::incremental_info_): New data member.
|
||||
* incremental-dump.cc (find_input_containing_global): New function.
|
||||
(dump_incremental_inputs): Dump new incremental info sections.
|
||||
* incremental.cc: Include symtab.h.
|
||||
(Output_section_incremental_inputs): New class.
|
||||
(Sized_incremental_binary::do_find_incremental_inputs_sections): Support
|
||||
new incremental info sections.
|
||||
(Sized_incremental_binary::do_check_inputs): Likewise.
|
||||
(Incremental_inputs::report_archive): Remove.
|
||||
(Incremental_inputs::report_archive_begin): New function.
|
||||
(Incremental_inputs::report_archive_end): New function.
|
||||
(Incremental_inputs::report_object): New function.
|
||||
(Incremental_inputs::finalize_inputs): Remove.
|
||||
(Incremental_inputs::report_input_section): New function.
|
||||
(Incremental_inputs::report_script): Rewrite.
|
||||
(Incremental_inputs::finalize): Do nothing but finalize string table.
|
||||
(Incremental_inputs::create_incremental_inputs_section_data): Remove.
|
||||
(Incremental_inputs::sized_create_inputs_section_data): Remove.
|
||||
(Incremental_inputs::create_data_sections): New function.
|
||||
(Incremental_inputs::relocs_entsize): New function.
|
||||
(Output_section_incremental_inputs::set_final_data_size): New function.
|
||||
(Output_section_incremental_inputs::do_write): New function.
|
||||
(Output_section_incremental_inputs::write_header): New function.
|
||||
(Output_section_incremental_inputs::write_input_files): New function.
|
||||
(Output_section_incremental_inputs::write_info_blocks): New function.
|
||||
(Output_section_incremental_inputs::write_symtab): New function.
|
||||
* incremental.h (Incremental_script_entry): Forward declaration.
|
||||
(Incremental_object_entry): Forward declaration.
|
||||
(Incremental_archive_entry): Forward declaration.
|
||||
(Incremental_inputs): Forward declaration.
|
||||
(Incremental_inputs_header_data): Remove.
|
||||
(Incremental_inputs_header): Remove.
|
||||
(Incremental_inputs_header_write): Remove.
|
||||
(Incremental_inputs_entry_data): Remove.
|
||||
(Incremental_inputs_entry): Remove.
|
||||
(Incremental_inputs_entry_write): Remove.
|
||||
(enum Incremental_input_type): Add INCREMENTAL_INPUT_ARCHIVE_MEMBER.
|
||||
(Incremental_binary::find_incremental_inputs_sections): Add parameters.
|
||||
(Incremental_binary::do_find_incremental_inputs_sections): Likewise.
|
||||
(Sized_ncremental_binary::do_find_incremental_inputs_sections):
|
||||
Likewise.
|
||||
(Incremental_input_entry): New class.
|
||||
(Incremental_script_entry): New class.
|
||||
(Incremental_object_entry): New class.
|
||||
(Incremental_archive_entry): New class.
|
||||
(Incremental_inputs::Incremental_inputs): Initialize new data members.
|
||||
(Incremental_inputs::report_inputs): Remove.
|
||||
(Incremental_inputs::report_archive): Remove.
|
||||
(Incremental_inputs::report_archive_begin): New function.
|
||||
(Incremental_inputs::report_archive_end): New function.
|
||||
(Incremental_inputs::report_object): Change prototype.
|
||||
(Incremental_inputs::report_input_section): New function.
|
||||
(Incremental_inputs::report_script): Change prototype.
|
||||
(Incremental_inputs::get_reloc_count): New function.
|
||||
(Incremental_inputs::set_reloc_count): New function.
|
||||
(Incremental_inputs::create_data_sections): New function.
|
||||
(Incremental_inputs::create_incremental_inputs_section_data): Remove.
|
||||
(Incremental_inputs::inputs_section): New function.
|
||||
(Incremental_inputs::symtab_section): New function.
|
||||
(Incremental_inputs::relocs_section): New function.
|
||||
(Incremental_inputs::get_stringpool): Add const.
|
||||
(Incremental_inputs::command_line): Add const.
|
||||
(Incremental_inputs::inputs): Remove.
|
||||
(Incremental_inputs::command_line_key): New function.
|
||||
(Incremental_inputs::input_file_count): New function.
|
||||
(Incremental_inputs::input_files): New function.
|
||||
(Incremental_inputs::relocs_entsize): New function.
|
||||
(Incremental_inputs::sized_create_inputs_section_data): Remove.
|
||||
(Incremental_inputs::finalize_inputs): Remove.
|
||||
(Incremental_inputs::Input_info): Remove.
|
||||
(Incremental_inputs::lock_): Remove.
|
||||
(Incremental_inputs::inputs_): Change type.
|
||||
(Incremental_inputs::inputs_map_): Remove.
|
||||
(Incremental_inputs::current_object_entry_): New data member.
|
||||
(Incremental_inputs::inputs_section_): New data member.
|
||||
(Incremental_inputs::symtab_section_): New data member.
|
||||
(Incremental_inputs::relocs_section_): New data member.
|
||||
(Incremental_inputs::reloc_count_): New data member.
|
||||
(Incremental_inputs_reader): New class.
|
||||
(Incremental_symtab_reader): New class.
|
||||
(Incremental_relocs_reader): New class.
|
||||
* layout.cc (Layout::finalize): Move finalization of incremental info
|
||||
and creation of incremental info sections to follow finalization of
|
||||
symbol table. Set offsets for postprocessing sections.
|
||||
(Layout::create_incremental_info_sections): Call
|
||||
Incremental_inputs::create_data_sections. Add incremental symtab
|
||||
and relocs sections. Set sh_entsize and sh_link fields. Arrange for
|
||||
sections to layout after input sections.
|
||||
* layout.h (struct Timespec): Forward declaration.
|
||||
(Layout::incremental_inputs): Add const.
|
||||
(Layout::create_incremental_info_sections): Add parameter.
|
||||
* main.cc (main): Remove call to Incremental_inputs::report_inputs.
|
||||
* object.cc: Include incremental.h.
|
||||
(Relobj::finalize_incremental_relocs): New function.
|
||||
(Sized_relobj::do_layout): Record input sections in incremental info.
|
||||
* object.h (Object::output_section): New function.
|
||||
(Object::output_section_offset): Moved from Relobj.
|
||||
(Object::get_incremental_reloc_base): New function.
|
||||
(Object::get_incremental_reloc_count): New function.
|
||||
(Object::do_output_section): New function.
|
||||
(Object::do_output_section_offset): Moved from Relobj.
|
||||
(Object::do_get_incremental_reloc_base): New function.
|
||||
(Object::do_get_incremental_reloc_count): New function.
|
||||
(Object::Object): Initialize new data members.
|
||||
(Relobj::output_section): Renamed do_output_section and moved to
|
||||
protected.
|
||||
(Relobj::output_section_offset): Moved to Object.
|
||||
(Relobj::do_get_incremental_reloc_base): New function.
|
||||
(Relobj::do_get_incremental_reloc_count): New function.
|
||||
(Relobj::allocate_incremental_reloc_counts): New function.
|
||||
(Relobj::count_incremental_reloc): New function.
|
||||
(Relobj::finalize_incremental_relocs): New function.
|
||||
(Relobj::next_incremental_reloc_index): New function.
|
||||
(Relobj::reloc_counts_): New data member.
|
||||
(Relobj::reloc_bases_): New data member.
|
||||
(Sized_relobj::do_relocate_sections): Add parameter. Change caller.
|
||||
(Sized_relobj::relocate_sections): Add parameter. Change all callers.
|
||||
(Sized_relobj::incremental_relocs_scan): New function.
|
||||
(Sized_relobj::incremental_relocs_scan_reltype): New function.
|
||||
(Sized_relobj::incremental_relocs_write): New function.
|
||||
(Sized_relobj::incremental_relocs_write_reltype): New function.
|
||||
* plugin.cc (Plugin_manager::add_input_file): Rewrite test for
|
||||
incremental link.
|
||||
* readsyms.cc (Read_symbols::do_read_symbols): Move reporting of
|
||||
archives and object files elsewhere.
|
||||
(Add_symbols::run): Report object files here.
|
||||
(Finish_group::run): Report end of archive at end of group.
|
||||
* reloc.cc: Include layout.h, incremental.h.
|
||||
(Sized_relobj::do_read_relocs): Need relocations for incremental link.
|
||||
(Sized_relobj::do_scan_relocs): Record relocations for incremental link.
|
||||
(Sized_relobj::incremental_relocs_scan): New function.
|
||||
(Sized_relobj::incremental_relocs_scan_reltype): New function.
|
||||
(Sized_relobj::do_relocate_sections): Write incremental relocations.
|
||||
(Sized_relobj::incremental_relocs_write): New function.
|
||||
(Sized_relobj::incremental_relocs_write_reltype): New function.
|
||||
* script.cc (read_input_script): Rewrite test for incremental link.
|
||||
Change call to Incremental_inputs::report_script.
|
||||
* symtab.h (Symbol_table::first_global_index): New function.
|
||||
(Symbol_table::output_count): New function.
|
||||
|
||||
2010-08-12 Doug Kwan <dougkwan@google.com>
|
||||
|
||||
* arm.cc (Target_arm::merge_object_attributes): Check command line
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "layout.h"
|
||||
#include "archive.h"
|
||||
#include "plugin.h"
|
||||
#include "incremental.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -89,7 +90,8 @@ Archive::Archive(const std::string& name, Input_file* input_file,
|
|||
: name_(name), input_file_(input_file), armap_(), armap_names_(),
|
||||
extended_names_(), armap_checked_(), seen_offsets_(), members_(),
|
||||
is_thin_archive_(is_thin_archive), included_member_(false),
|
||||
nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0)
|
||||
nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0),
|
||||
incremental_info_(NULL)
|
||||
{
|
||||
this->no_export_ =
|
||||
parameters->options().check_excluded_libs(input_file->found_name());
|
||||
|
@ -891,6 +893,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
|
|||
else
|
||||
{
|
||||
{
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
layout->incremental_inputs()->report_object(obj, this);
|
||||
Read_symbols_data sd;
|
||||
obj->read_symbols(&sd);
|
||||
obj->layout(symtab, layout, &sd);
|
||||
|
@ -952,6 +956,11 @@ Add_archive_symbols::locks(Task_locker* tl)
|
|||
void
|
||||
Add_archive_symbols::run(Workqueue* workqueue)
|
||||
{
|
||||
// For an incremental link, begin recording layout information.
|
||||
Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
|
||||
if (incremental_inputs != NULL)
|
||||
incremental_inputs->report_archive_begin(this->archive_);
|
||||
|
||||
bool added = this->archive_->add_symbols(this->symtab_, this->layout_,
|
||||
this->input_objects_,
|
||||
this->mapfile_);
|
||||
|
@ -978,6 +987,11 @@ Add_archive_symbols::run(Workqueue* workqueue)
|
|||
this->input_group_->add_archive(this->archive_);
|
||||
else
|
||||
{
|
||||
// For an incremental link, finish recording the layout information.
|
||||
Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
|
||||
if (incremental_inputs != NULL)
|
||||
incremental_inputs->report_archive_end(this->archive_);
|
||||
|
||||
// We no longer need to know about this archive.
|
||||
delete this->archive_;
|
||||
this->archive_ = NULL;
|
||||
|
@ -1077,6 +1091,9 @@ Lib_group::include_member(Symbol_table* symtab, Layout* layout,
|
|||
obj->lock(this->task_);
|
||||
if (input_objects->add_object(obj))
|
||||
{
|
||||
// FIXME: Record incremental link info for --start-lib/--end-lib.
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
layout->incremental_inputs()->report_object(obj, NULL);
|
||||
obj->layout(symtab, layout, sd);
|
||||
obj->add_symbols(symtab, sd, layout);
|
||||
// Unlock the file for the next task.
|
||||
|
@ -1116,6 +1133,8 @@ void
|
|||
Add_lib_group_symbols::run(Workqueue*)
|
||||
{
|
||||
this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
|
||||
|
||||
// FIXME: Record incremental link info for --start_lib/--end_lib.
|
||||
}
|
||||
|
||||
Add_lib_group_symbols::~Add_lib_group_symbols()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// archive.h -- archive support for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
@ -42,6 +42,7 @@ class Symbol_table;
|
|||
class Object;
|
||||
class Read_symbols_data;
|
||||
class Input_file_lib;
|
||||
class Incremental_archive_entry;
|
||||
|
||||
// An entry in the archive map of offsets to members.
|
||||
struct Archive_member
|
||||
|
@ -164,6 +165,16 @@ class Archive
|
|||
no_export()
|
||||
{ return this->no_export_; }
|
||||
|
||||
// Store a pointer to the incremental link info for the archive.
|
||||
void
|
||||
set_incremental_info(Incremental_archive_entry* info)
|
||||
{ this->incremental_info_ = info; }
|
||||
|
||||
// Return the pointer to the incremental link info for the archive.
|
||||
Incremental_archive_entry*
|
||||
incremental_info() const
|
||||
{ return this->incremental_info_; }
|
||||
|
||||
// When we see a symbol in an archive we might decide to include the member,
|
||||
// not include the member or be undecided. This enum represents these
|
||||
// possibilities.
|
||||
|
@ -180,6 +191,69 @@ class Archive
|
|||
Symbol** symp, std::string* why, char** tmpbufp,
|
||||
size_t* tmpbuflen);
|
||||
|
||||
private:
|
||||
struct Armap_entry;
|
||||
|
||||
public:
|
||||
// Iterator class for unused global symbols. This iterator is used
|
||||
// for incremental links.
|
||||
|
||||
class Unused_symbol_iterator
|
||||
{
|
||||
public:
|
||||
Unused_symbol_iterator(Archive* arch,
|
||||
std::vector<Armap_entry>::const_iterator it)
|
||||
: arch_(arch), it_(it)
|
||||
{ this->skip_used_symbols(); }
|
||||
|
||||
const char*
|
||||
operator*() const
|
||||
{ return this->arch_->armap_names_.data() + this->it_->name_offset; }
|
||||
|
||||
Unused_symbol_iterator&
|
||||
operator++()
|
||||
{
|
||||
++this->it_;
|
||||
this->skip_used_symbols();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Unused_symbol_iterator p) const
|
||||
{ return this->it_ == p.it_; }
|
||||
|
||||
bool
|
||||
operator!=(const Unused_symbol_iterator p) const
|
||||
{ return this->it_ != p.it_; }
|
||||
|
||||
private:
|
||||
// Skip over symbols defined by members that have been included.
|
||||
void
|
||||
skip_used_symbols()
|
||||
{
|
||||
while (this->it_ != this->arch_->armap_.end()
|
||||
&& (this->arch_->seen_offsets_.find(this->it_->file_offset)
|
||||
!= this->arch_->seen_offsets_.end()))
|
||||
++it_;
|
||||
}
|
||||
|
||||
// The underlying archive.
|
||||
Archive* arch_;
|
||||
|
||||
// The underlying iterator over all entries in the archive map.
|
||||
std::vector<Armap_entry>::const_iterator it_;
|
||||
};
|
||||
|
||||
// Return an iterator referring to the first unused symbol.
|
||||
Unused_symbol_iterator
|
||||
unused_symbols_begin()
|
||||
{ return Unused_symbol_iterator(this, this->armap_.begin()); }
|
||||
|
||||
// Return an iterator referring to the end of the unused symbols.
|
||||
Unused_symbol_iterator
|
||||
unused_symbols_end()
|
||||
{ return Unused_symbol_iterator(this, this->armap_.end()); }
|
||||
|
||||
private:
|
||||
Archive(const Archive&);
|
||||
Archive& operator=(const Archive&);
|
||||
|
@ -312,6 +386,8 @@ class Archive
|
|||
unsigned int num_members_;
|
||||
// True if we exclude this library archive from automatic export.
|
||||
bool no_export_;
|
||||
// The incremental link information for this archive.
|
||||
Incremental_archive_entry* incremental_info_;
|
||||
};
|
||||
|
||||
// This class is used to read an archive and pick out the desired
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// inremental.cc -- incremental linking test/deubg tool
|
||||
// incremental.cc -- incremental linking test/debug tool
|
||||
|
||||
// Copyright 2009 Free Software Foundation, Inc.
|
||||
// Copyright 2009, 2010 Free Software Foundation, Inc.
|
||||
// Written by Rafael Avila de Espindola <rafael.espindola@gmail.com>
|
||||
|
||||
// This file is part of gold.
|
||||
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "incremental.h"
|
||||
|
||||
|
@ -42,16 +43,52 @@ namespace gold
|
|||
|
||||
using namespace gold;
|
||||
|
||||
template<int size, bool big_endian>
|
||||
static typename Incremental_inputs_reader<size, big_endian>::
|
||||
Incremental_input_entry_reader
|
||||
find_input_containing_global(
|
||||
Incremental_inputs_reader<size, big_endian>& incremental_inputs,
|
||||
unsigned int offset,
|
||||
unsigned int* symndx)
|
||||
{
|
||||
typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
|
||||
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
|
||||
{
|
||||
typename Inputs_reader::Incremental_input_entry_reader input_file =
|
||||
incremental_inputs.input_file(i);
|
||||
if (input_file.type() != INCREMENTAL_INPUT_OBJECT
|
||||
&& input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
|
||||
continue;
|
||||
unsigned int nsyms = input_file.get_global_symbol_count();
|
||||
if (offset >= input_file.get_symbol_offset(0)
|
||||
&& offset < input_file.get_symbol_offset(nsyms))
|
||||
{
|
||||
*symndx = (offset - input_file.get_symbol_offset(0)) / 16;
|
||||
return input_file;
|
||||
}
|
||||
}
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
static void
|
||||
dump_incremental_inputs(const char* argv0,
|
||||
const char* filename, Incremental_binary* inc)
|
||||
dump_incremental_inputs(const char* argv0, const char* filename,
|
||||
Incremental_binary* inc)
|
||||
{
|
||||
bool t;
|
||||
unsigned int strtab_shndx;
|
||||
Incremental_binary::Location location;
|
||||
unsigned int inputs_shndx;
|
||||
unsigned int isymtab_shndx;
|
||||
unsigned int irelocs_shndx;
|
||||
unsigned int istrtab_shndx;
|
||||
typedef Incremental_binary::Location Location;
|
||||
typedef Incremental_binary::View View;
|
||||
typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
|
||||
typedef typename Inputs_reader::Incremental_input_entry_reader Entry_reader;
|
||||
|
||||
t = inc->find_incremental_inputs_section(&location, &strtab_shndx);
|
||||
// Find the .gnu_incremental_inputs, _symtab, _relocs, and _strtab sections.
|
||||
|
||||
t = inc->find_incremental_inputs_sections(&inputs_shndx, &isymtab_shndx,
|
||||
&irelocs_shndx, &istrtab_shndx);
|
||||
if (!t)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0,
|
||||
|
@ -59,105 +96,306 @@ dump_incremental_inputs(const char* argv0,
|
|||
exit (1);
|
||||
}
|
||||
|
||||
Incremental_binary::View inputs_view(inc->view(location));
|
||||
const unsigned char* p = inputs_view.data();
|
||||
|
||||
Incremental_inputs_header<size, big_endian> incremental_header(p);
|
||||
|
||||
const unsigned char* incremental_inputs_base =
|
||||
(p + sizeof(Incremental_inputs_header_data));
|
||||
|
||||
if (incremental_header.get_version() != 1)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0,
|
||||
filename, incremental_header.get_version());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
|
||||
|
||||
if (elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
|
||||
// Get a view of the .gnu_incremental_inputs section.
|
||||
|
||||
Location inputs_location(elf_file.section_contents(inputs_shndx));
|
||||
View inputs_view(inc->view(inputs_location));
|
||||
|
||||
// Get the .gnu_incremental_strtab section as a string table.
|
||||
|
||||
Location istrtab_location(elf_file.section_contents(istrtab_shndx));
|
||||
View istrtab_view(inc->view(istrtab_location));
|
||||
elfcpp::Elf_strtab istrtab(istrtab_view.data(), istrtab_location.data_size);
|
||||
|
||||
// Create a reader object for the .gnu_incremental_inputs section.
|
||||
|
||||
Incremental_inputs_reader<size, big_endian>
|
||||
incremental_inputs(inputs_view.data(), istrtab);
|
||||
|
||||
if (incremental_inputs.version() != 1)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: %s: invalid string table section %u (type %d != %d)\n",
|
||||
argv0, filename, strtab_shndx,
|
||||
elf_file.section_type(strtab_shndx), elfcpp::SHT_STRTAB);
|
||||
fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0,
|
||||
filename, incremental_inputs.version());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Incremental_binary::Location
|
||||
strtab_location(elf_file.section_contents(strtab_shndx));
|
||||
|
||||
Incremental_binary::View strtab_view(inc->view(strtab_location));
|
||||
p = strtab_view.data();
|
||||
|
||||
elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
|
||||
const char* command_line;
|
||||
elfcpp::Elf_Word command_line_offset =
|
||||
incremental_header.get_command_line_offset();
|
||||
t = strtab.get_c_string(command_line_offset, &command_line);
|
||||
|
||||
if (!t)
|
||||
const char* command_line = incremental_inputs.command_line();
|
||||
if (command_line == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: %s: failed to get link command line: %zu out of range\n",
|
||||
argv0, filename,
|
||||
static_cast<size_t>(command_line_offset));
|
||||
"%s: %s: failed to get link command line\n",
|
||||
argv0, filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Link command line: %s\n", command_line);
|
||||
|
||||
printf("Input files:\n");
|
||||
for (unsigned i = 0; i < incremental_header.get_input_file_count(); ++i)
|
||||
printf("\nInput files:\n");
|
||||
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
|
||||
{
|
||||
const unsigned char* input_p = incremental_inputs_base +
|
||||
i * sizeof(Incremental_inputs_entry_data);
|
||||
Incremental_inputs_entry<size, big_endian> input(input_p);
|
||||
const char* objname;
|
||||
typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
|
||||
typename Inputs_reader::Incremental_input_entry_reader input_file =
|
||||
incremental_inputs.input_file(i);
|
||||
|
||||
t = strtab.get_c_string(input.get_filename_offset(), &objname);
|
||||
if (!t)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: failed to get file name for object %u:"
|
||||
" %zu out of range\n", argv0, filename, i,
|
||||
static_cast<size_t>(input.get_filename_offset()));
|
||||
exit(1);
|
||||
}
|
||||
printf(" %s\n", objname);
|
||||
printf(" Timestamp sec = %llu\n",
|
||||
static_cast<unsigned long long>(input.get_timestamp_sec()));
|
||||
printf(" Timestamp nsec = %d\n", input.get_timestamp_nsec());
|
||||
printf(" Type = ");
|
||||
// TODO: print the data at input->data_offset once we have it.
|
||||
elfcpp::Elf_Word input_type = input.get_input_type();
|
||||
const char* objname = input_file.filename();
|
||||
if (objname == NULL)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
|
||||
argv0, filename, i);
|
||||
exit(1);
|
||||
}
|
||||
printf("[%d] %s\n", i, objname);
|
||||
|
||||
Timespec mtime = input_file.get_mtime();
|
||||
printf(" Timestamp: %llu.%09d %s",
|
||||
static_cast<unsigned long long>(mtime.seconds),
|
||||
mtime.nanoseconds,
|
||||
ctime(&mtime.seconds));
|
||||
|
||||
Incremental_input_type input_type = input_file.type();
|
||||
printf(" Type: ");
|
||||
switch (input_type)
|
||||
{
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
printf("Object\n");
|
||||
break;
|
||||
case INCREMENTAL_INPUT_ARCHIVE:
|
||||
printf("Archive\n");
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
printf("Shared library\n");
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SCRIPT:
|
||||
printf("Linker script\n");
|
||||
if (input.get_data_offset() != 0)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: %u is a script but offset is not zero",
|
||||
argv0, filename, i);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_INVALID:
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid file type for object %u: %d\n",
|
||||
argv0, i, input_type);
|
||||
exit(1);
|
||||
}
|
||||
{
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
{
|
||||
printf("Object\n");
|
||||
printf(" Input section count: %d\n",
|
||||
input_file.get_input_section_count());
|
||||
printf(" Symbol count: %d\n",
|
||||
input_file.get_global_symbol_count());
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
|
||||
{
|
||||
printf("Archive member\n");
|
||||
printf(" Input section count: %d\n",
|
||||
input_file.get_input_section_count());
|
||||
printf(" Symbol count: %d\n",
|
||||
input_file.get_global_symbol_count());
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_ARCHIVE:
|
||||
{
|
||||
printf("Archive\n");
|
||||
printf(" Member count: %d\n", input_file.get_member_count());
|
||||
printf(" Unused symbol count: %d\n",
|
||||
input_file.get_unused_symbol_count());
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
{
|
||||
printf("Shared library\n");
|
||||
printf(" Symbol count: %d\n",
|
||||
input_file.get_global_symbol_count());
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SCRIPT:
|
||||
printf("Linker script\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid file type for object %u: %d\n",
|
||||
argv0, i, input_type);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nInput sections:\n");
|
||||
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
|
||||
{
|
||||
typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
|
||||
typedef typename Inputs_reader::Incremental_input_entry_reader
|
||||
Entry_reader;
|
||||
|
||||
Entry_reader input_file(incremental_inputs.input_file(i));
|
||||
|
||||
if (input_file.type() != INCREMENTAL_INPUT_OBJECT
|
||||
&& input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
|
||||
continue;
|
||||
|
||||
const char* objname = input_file.filename();
|
||||
if (objname == NULL)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
|
||||
argv0, filename, i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[%d] %s\n", i, objname);
|
||||
|
||||
printf(" %3s %6s %8s %8s %s\n",
|
||||
"n", "outndx", "offset", "size", "name");
|
||||
unsigned int nsections = input_file.get_input_section_count();
|
||||
for (unsigned int shndx = 0; shndx < nsections; ++shndx)
|
||||
{
|
||||
typename Entry_reader::Input_section_info info(
|
||||
input_file.get_input_section(shndx));
|
||||
printf(" %3d %6d %8lld %8lld %s\n", shndx,
|
||||
info.output_shndx,
|
||||
static_cast<long long>(info.sh_offset),
|
||||
static_cast<long long>(info.sh_size),
|
||||
info.name);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nGlobal symbols per input file:\n");
|
||||
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
|
||||
{
|
||||
typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
|
||||
typedef typename Inputs_reader::Incremental_input_entry_reader
|
||||
Entry_reader;
|
||||
|
||||
Entry_reader input_file(incremental_inputs.input_file(i));
|
||||
|
||||
if (input_file.type() != INCREMENTAL_INPUT_OBJECT
|
||||
&& input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
|
||||
continue;
|
||||
|
||||
const char* objname = input_file.filename();
|
||||
if (objname == NULL)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
|
||||
argv0, filename, i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[%d] %s\n", i, objname);
|
||||
|
||||
unsigned int nsyms = input_file.get_global_symbol_count();
|
||||
if (nsyms > 0)
|
||||
printf(" %6s %8s %8s %8s %8s\n",
|
||||
"outndx", "offset", "chain", "#relocs", "rbase");
|
||||
for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
|
||||
{
|
||||
typename Entry_reader::Global_symbol_info info(
|
||||
input_file.get_global_symbol_info(symndx));
|
||||
printf(" %6d %8d %8d %8d %8d\n",
|
||||
info.output_symndx,
|
||||
input_file.get_symbol_offset(symndx),
|
||||
info.next_offset,
|
||||
info.reloc_count,
|
||||
info.reloc_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a view of the .symtab section.
|
||||
|
||||
unsigned int symtab_shndx = elf_file.find_section_by_type(elfcpp::SHT_SYMTAB);
|
||||
if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found.
|
||||
{
|
||||
fprintf(stderr, "%s: %s: no symbol table section\n", argv0, filename);
|
||||
exit (1);
|
||||
}
|
||||
Location symtab_location(elf_file.section_contents(symtab_shndx));
|
||||
View symtab_view(inc->view(symtab_location));
|
||||
|
||||
// Get a view of the .strtab section.
|
||||
|
||||
unsigned int strtab_shndx = elf_file.section_link(symtab_shndx);
|
||||
if (strtab_shndx == elfcpp::SHN_UNDEF
|
||||
|| strtab_shndx > elf_file.shnum()
|
||||
|| elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: no string table section\n", argv0, filename);
|
||||
exit (1);
|
||||
}
|
||||
Location strtab_location(elf_file.section_contents(strtab_shndx));
|
||||
View strtab_view(inc->view(strtab_location));
|
||||
elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
|
||||
|
||||
// Get a view of the .gnu_incremental_symtab section.
|
||||
|
||||
Location isymtab_location(elf_file.section_contents(isymtab_shndx));
|
||||
View isymtab_view(inc->view(isymtab_location));
|
||||
|
||||
// Get a view of the .gnu_incremental_relocs section.
|
||||
|
||||
Location irelocs_location(elf_file.section_contents(irelocs_shndx));
|
||||
View irelocs_view(inc->view(irelocs_location));
|
||||
|
||||
// The .gnu_incremental_symtab section contains entries that parallel
|
||||
// the global symbols of the main symbol table. The sh_info field
|
||||
// of the main symbol table's section header tells us how many global
|
||||
// symbols there are, but that count does not include any global
|
||||
// symbols that were forced local during the link. Therefore, we
|
||||
// use the size of the .gnu_incremental_symtab section to deduce
|
||||
// the number of global symbols + forced-local symbols there are
|
||||
// in the symbol table.
|
||||
unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
unsigned int nsyms = symtab_location.data_size / sym_size;
|
||||
unsigned int nglobals = isymtab_location.data_size / 4;
|
||||
unsigned int first_global = nsyms - nglobals;
|
||||
unsigned const char* sym_p = symtab_view.data() + first_global * sym_size;
|
||||
unsigned const char* isym_p = isymtab_view.data();
|
||||
|
||||
Incremental_symtab_reader<big_endian> isymtab(isymtab_view.data());
|
||||
Incremental_relocs_reader<size, big_endian> irelocs(irelocs_view.data());
|
||||
|
||||
printf("\nGlobal symbol table:\n");
|
||||
for (unsigned int i = 0; i < nglobals; i++)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(sym_p);
|
||||
const char* symname;
|
||||
if (!strtab.get_c_string(sym.get_st_name(), &symname))
|
||||
symname = "<unknown>";
|
||||
printf("[%d] %s\n", first_global + i, symname);
|
||||
unsigned int offset = isymtab.get_list_head(i);
|
||||
while (offset > 0)
|
||||
{
|
||||
unsigned int sym_ndx;
|
||||
Entry_reader input_file =
|
||||
find_input_containing_global<size, big_endian>(incremental_inputs,
|
||||
offset, &sym_ndx);
|
||||
typename Entry_reader::Global_symbol_info sym_info(
|
||||
input_file.get_global_symbol_info(sym_ndx));
|
||||
printf(" %s (first reloc: %d, reloc count: %d)",
|
||||
input_file.filename(), sym_info.reloc_offset,
|
||||
sym_info.reloc_count);
|
||||
if (sym_info.output_symndx != first_global + i)
|
||||
printf(" ** wrong output symndx (%d) **", sym_info.output_symndx);
|
||||
printf("\n");
|
||||
// Dump the relocations from this input file for this symbol.
|
||||
unsigned int r_off = sym_info.reloc_offset;
|
||||
for (unsigned int j = 0; j < sym_info.reloc_count; j++)
|
||||
{
|
||||
printf(" %4d relocation type %3d shndx %d"
|
||||
" offset %016llx addend %016llx %s\n",
|
||||
r_off,
|
||||
irelocs.get_r_type(r_off),
|
||||
irelocs.get_r_shndx(r_off),
|
||||
static_cast<long long>(irelocs.get_r_offset(r_off)),
|
||||
static_cast<long long>(irelocs.get_r_addend(r_off)),
|
||||
symname);
|
||||
r_off += irelocs.reloc_size;
|
||||
}
|
||||
offset = sym_info.next_offset;
|
||||
}
|
||||
sym_p += sym_size;
|
||||
isym_p += 4;
|
||||
}
|
||||
|
||||
printf("\nUnused archive symbols:\n");
|
||||
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
|
||||
{
|
||||
Entry_reader input_file(incremental_inputs.input_file(i));
|
||||
|
||||
if (input_file.type() != INCREMENTAL_INPUT_ARCHIVE)
|
||||
continue;
|
||||
|
||||
const char* objname = input_file.filename();
|
||||
if (objname == NULL)
|
||||
{
|
||||
fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
|
||||
argv0, filename, i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[%d] %s\n", i, objname);
|
||||
unsigned int nsyms = input_file.get_unused_symbol_count();
|
||||
for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
|
||||
printf(" %s\n", input_file.get_unused_symbol(symndx));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// inremental.cc -- incremental linking support for gold
|
||||
|
||||
// Copyright 2009 Free Software Foundation, Inc.
|
||||
// Copyright 2009, 2010 Free Software Foundation, Inc.
|
||||
// Written by Mikolaj Zalewski <mikolajz@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "elfcpp.h"
|
||||
#include "output.h"
|
||||
#include "symtab.h"
|
||||
#include "incremental.h"
|
||||
#include "archive.h"
|
||||
#include "output.h"
|
||||
|
@ -38,6 +39,73 @@ namespace gold {
|
|||
// we could think about backward (and forward?) compatibility.
|
||||
const unsigned int INCREMENTAL_LINK_VERSION = 1;
|
||||
|
||||
// This class manages the .gnu_incremental_inputs section, which holds
|
||||
// the header information, a directory of input files, and separate
|
||||
// entries for each input file.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Output_section_incremental_inputs : public Output_section_data
|
||||
{
|
||||
public:
|
||||
Output_section_incremental_inputs(const Incremental_inputs* inputs,
|
||||
const Symbol_table* symtab)
|
||||
: Output_section_data(size / 8), inputs_(inputs), symtab_(symtab)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
// Set the final data size.
|
||||
void
|
||||
set_final_data_size();
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
// Write to a map file.
|
||||
void
|
||||
do_print_to_mapfile(Mapfile* mapfile) const
|
||||
{ mapfile->print_output_data(this, _("** incremental_inputs")); }
|
||||
|
||||
private:
|
||||
// Write the section header.
|
||||
unsigned char*
|
||||
write_header(unsigned char* pov, unsigned int input_file_count,
|
||||
section_offset_type command_line_offset);
|
||||
|
||||
// Write the input file entries.
|
||||
unsigned char*
|
||||
write_input_files(unsigned char* oview, unsigned char* pov,
|
||||
Stringpool* strtab);
|
||||
|
||||
// Write the supplemental information blocks.
|
||||
unsigned char*
|
||||
write_info_blocks(unsigned char* oview, unsigned char* pov,
|
||||
Stringpool* strtab, unsigned int* global_syms,
|
||||
unsigned int global_sym_count);
|
||||
|
||||
// Write the contents of the .gnu_incremental_symtab section.
|
||||
void
|
||||
write_symtab(unsigned char* pov, unsigned int* global_syms,
|
||||
unsigned int global_sym_count);
|
||||
|
||||
// Typedefs for writing the data to the output sections.
|
||||
typedef elfcpp::Swap<size, big_endian> Swap;
|
||||
typedef elfcpp::Swap<16, big_endian> Swap16;
|
||||
typedef elfcpp::Swap<32, big_endian> Swap32;
|
||||
typedef elfcpp::Swap<64, big_endian> Swap64;
|
||||
|
||||
// Sizes of various structures.
|
||||
static const int sizeof_addr = size / 8;
|
||||
static const int header_size = 16;
|
||||
static const int input_entry_size = 24;
|
||||
|
||||
// The Incremental_inputs object.
|
||||
const Incremental_inputs* inputs_;
|
||||
|
||||
// The symbol table.
|
||||
const Symbol_table* symtab_;
|
||||
};
|
||||
|
||||
// Inform the user why we don't do an incremental link. Not called in
|
||||
// the obvious case of missing output file. TODO: Is this helpful?
|
||||
|
||||
|
@ -77,77 +145,101 @@ Incremental_binary::error(const char* format, ...) const
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
// Find the .gnu_incremental_inputs section and related sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
|
||||
Location* location,
|
||||
unsigned int* strtab_shndx)
|
||||
Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_sections(
|
||||
unsigned int* p_inputs_shndx,
|
||||
unsigned int* p_symtab_shndx,
|
||||
unsigned int* p_relocs_shndx,
|
||||
unsigned int* p_strtab_shndx)
|
||||
{
|
||||
unsigned int shndx = this->elf_file_.find_section_by_type(
|
||||
elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
|
||||
if (shndx == elfcpp::SHN_UNDEF) // Not found.
|
||||
unsigned int inputs_shndx =
|
||||
this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
|
||||
if (inputs_shndx == elfcpp::SHN_UNDEF) // Not found.
|
||||
return false;
|
||||
*strtab_shndx = this->elf_file_.section_link(shndx);
|
||||
*location = this->elf_file_.section_contents(shndx);
|
||||
|
||||
unsigned int symtab_shndx =
|
||||
this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_SYMTAB);
|
||||
if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found.
|
||||
return false;
|
||||
if (this->elf_file_.section_link(symtab_shndx) != inputs_shndx)
|
||||
return false;
|
||||
|
||||
unsigned int relocs_shndx =
|
||||
this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_RELOCS);
|
||||
if (relocs_shndx == elfcpp::SHN_UNDEF) // Not found.
|
||||
return false;
|
||||
if (this->elf_file_.section_link(relocs_shndx) != inputs_shndx)
|
||||
return false;
|
||||
|
||||
unsigned int strtab_shndx = this->elf_file_.section_link(inputs_shndx);
|
||||
if (strtab_shndx == elfcpp::SHN_UNDEF
|
||||
|| strtab_shndx > this->elf_file_.shnum()
|
||||
|| this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
|
||||
return false;
|
||||
|
||||
if (p_inputs_shndx != NULL)
|
||||
*p_inputs_shndx = inputs_shndx;
|
||||
if (p_symtab_shndx != NULL)
|
||||
*p_symtab_shndx = symtab_shndx;
|
||||
if (p_relocs_shndx != NULL)
|
||||
*p_relocs_shndx = relocs_shndx;
|
||||
if (p_strtab_shndx != NULL)
|
||||
*p_strtab_shndx = strtab_shndx;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine whether an incremental link based on the existing output file
|
||||
// can be done.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
Sized_incremental_binary<size, big_endian>::do_check_inputs(
|
||||
Incremental_inputs* incremental_inputs)
|
||||
{
|
||||
const int entry_size =
|
||||
Incremental_inputs_entry_write<size, big_endian>::data_size;
|
||||
const int header_size =
|
||||
Incremental_inputs_header_write<size, big_endian>::data_size;
|
||||
|
||||
unsigned int inputs_shndx;
|
||||
unsigned int symtab_shndx;
|
||||
unsigned int relocs_shndx;
|
||||
unsigned int strtab_shndx;
|
||||
Location location;
|
||||
|
||||
if (!do_find_incremental_inputs_section(&location, &strtab_shndx))
|
||||
if (!do_find_incremental_inputs_sections(&inputs_shndx, &symtab_shndx,
|
||||
&relocs_shndx, &strtab_shndx))
|
||||
{
|
||||
explain_no_incremental(_("no incremental data from previous build"));
|
||||
return false;
|
||||
}
|
||||
if (location.data_size < header_size
|
||||
|| strtab_shndx >= this->elf_file_.shnum()
|
||||
|| this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
|
||||
{
|
||||
explain_no_incremental(_("invalid incremental build data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Location inputs_location(this->elf_file_.section_contents(inputs_shndx));
|
||||
Location symtab_location(this->elf_file_.section_contents(symtab_shndx));
|
||||
Location relocs_location(this->elf_file_.section_contents(relocs_shndx));
|
||||
Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
|
||||
View data_view(view(location));
|
||||
View strtab_view(view(strtab_location));
|
||||
elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
|
||||
Incremental_inputs_header<size, big_endian> header(data_view.data());
|
||||
|
||||
if (header.get_version() != INCREMENTAL_LINK_VERSION)
|
||||
View inputs_view(view(inputs_location));
|
||||
View symtab_view(view(symtab_location));
|
||||
View relocs_view(view(relocs_location));
|
||||
View strtab_view(view(strtab_location));
|
||||
|
||||
elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
|
||||
|
||||
Incremental_inputs_reader<size, big_endian>
|
||||
incoming_inputs(inputs_view.data(), strtab);
|
||||
|
||||
if (incoming_inputs.version() != INCREMENTAL_LINK_VERSION)
|
||||
{
|
||||
explain_no_incremental(_("different version of incremental build data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* command_line;
|
||||
// We divide instead of multiplying to make sure there is no integer
|
||||
// overflow.
|
||||
size_t max_input_entries = (location.data_size - header_size) / entry_size;
|
||||
if (header.get_input_file_count() > max_input_entries
|
||||
|| !strtab.get_c_string(header.get_command_line_offset(), &command_line))
|
||||
{
|
||||
explain_no_incremental(_("invalid incremental build data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (incremental_inputs->command_line() != command_line)
|
||||
if (incremental_inputs->command_line() != incoming_inputs.command_line())
|
||||
{
|
||||
explain_no_incremental(_("command line changed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: compare incremental_inputs->inputs() with entries in data_view.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -182,8 +274,8 @@ make_sized_incremental_binary(Output_file* file,
|
|||
|
||||
} // End of anonymous namespace.
|
||||
|
||||
// Create an Incremental_binary object for FILE. Returns NULL is this is not
|
||||
// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
|
||||
// Create an Incremental_binary object for FILE. Returns NULL is this is not
|
||||
// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
|
||||
// should be opened.
|
||||
|
||||
Incremental_binary*
|
||||
|
@ -275,6 +367,8 @@ Incremental_checker::can_incrementally_link_output_file()
|
|||
return binary->check_inputs(this->incremental_inputs_);
|
||||
}
|
||||
|
||||
// Class Incremental_inputs.
|
||||
|
||||
// Add the command line to the string table, setting
|
||||
// command_line_key_. In incremental builds, the command line is
|
||||
// stored in .gnu_incremental_inputs so that the next linker run can
|
||||
|
@ -289,7 +383,7 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
|
|||
// Copied from collect_argv in main.cc.
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
// Adding/removing these options should result in a full relink.
|
||||
// Adding/removing these options should not result in a full relink.
|
||||
if (strcmp(argv[i], "--incremental-changed") == 0
|
||||
|| strcmp(argv[i], "--incremental-unchanged") == 0
|
||||
|| strcmp(argv[i], "--incremental-unknown") == 0)
|
||||
|
@ -315,99 +409,104 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
|
|||
&this->command_line_key_);
|
||||
}
|
||||
|
||||
// Record that the input argument INPUT is an achive ARCHIVE. This is
|
||||
// called by Read_symbols after finding out the type of the file.
|
||||
// Record the input archive file ARCHIVE. This is called by the
|
||||
// Add_archive_symbols task before determining which archive members
|
||||
// to include. We create the Incremental_archive_entry here and
|
||||
// attach it to the Archive, but we do not add it to the list of
|
||||
// input objects until report_archive_end is called.
|
||||
|
||||
void
|
||||
Incremental_inputs::report_archive(const Input_argument* input,
|
||||
Archive* archive)
|
||||
Incremental_inputs::report_archive_begin(Archive* arch)
|
||||
{
|
||||
Hold_lock hl(*this->lock_);
|
||||
Stringpool::Key filename_key;
|
||||
Timespec mtime = arch->file().get_mtime();
|
||||
|
||||
Input_info info;
|
||||
info.type = INCREMENTAL_INPUT_ARCHIVE;
|
||||
info.archive = archive;
|
||||
info.mtime = archive->file().get_mtime();
|
||||
this->inputs_map_.insert(std::make_pair(input, info));
|
||||
this->strtab_->add(arch->filename().c_str(), false, &filename_key);
|
||||
Incremental_archive_entry* entry =
|
||||
new Incremental_archive_entry(filename_key, arch, mtime);
|
||||
arch->set_incremental_info(entry);
|
||||
}
|
||||
|
||||
// Record that the input argument INPUT is an object OBJ. This is
|
||||
// called by Read_symbols after finding out the type of the file.
|
||||
// Finish recording the input archive file ARCHIVE. This is called by the
|
||||
// Add_archive_symbols task after determining which archive members
|
||||
// to include.
|
||||
|
||||
void
|
||||
Incremental_inputs::report_object(const Input_argument* input,
|
||||
Object* obj)
|
||||
Incremental_inputs::report_archive_end(Archive* arch)
|
||||
{
|
||||
Hold_lock hl(*this->lock_);
|
||||
Incremental_archive_entry* entry = arch->incremental_info();
|
||||
|
||||
Input_info info;
|
||||
info.type = (obj->is_dynamic()
|
||||
? INCREMENTAL_INPUT_SHARED_LIBRARY
|
||||
: INCREMENTAL_INPUT_OBJECT);
|
||||
info.object = obj;
|
||||
info.mtime = obj->input_file()->file().get_mtime();
|
||||
this->inputs_map_.insert(std::make_pair(input, info));
|
||||
gold_assert(entry != NULL);
|
||||
|
||||
// Collect unused global symbols.
|
||||
for (Archive::Unused_symbol_iterator p = arch->unused_symbols_begin();
|
||||
p != arch->unused_symbols_end();
|
||||
++p)
|
||||
{
|
||||
Stringpool::Key symbol_key;
|
||||
this->strtab_->add(*p, true, &symbol_key);
|
||||
entry->add_unused_global_symbol(symbol_key);
|
||||
}
|
||||
this->inputs_.push_back(entry);
|
||||
}
|
||||
|
||||
// Record that the input argument INPUT is an script SCRIPT. This is
|
||||
// Record the input object file OBJ. If ARCH is not NULL, attach
|
||||
// the object file to the archive. This is called by the
|
||||
// Add_symbols task after finding out the type of the file.
|
||||
|
||||
void
|
||||
Incremental_inputs::report_object(Object* obj, Archive* arch)
|
||||
{
|
||||
Stringpool::Key filename_key;
|
||||
Timespec mtime = obj->input_file()->file().get_mtime();
|
||||
|
||||
this->strtab_->add(obj->name().c_str(), false, &filename_key);
|
||||
Incremental_object_entry* obj_entry =
|
||||
new Incremental_object_entry(filename_key, obj, mtime);
|
||||
this->inputs_.push_back(obj_entry);
|
||||
|
||||
if (arch != NULL)
|
||||
{
|
||||
Incremental_archive_entry* arch_entry = arch->incremental_info();
|
||||
gold_assert(arch_entry != NULL);
|
||||
arch_entry->add_object(obj_entry);
|
||||
}
|
||||
|
||||
this->current_object_ = obj;
|
||||
this->current_object_entry_ = obj_entry;
|
||||
}
|
||||
|
||||
// Record the input object file OBJ. If ARCH is not NULL, attach
|
||||
// the object file to the archive. This is called by the
|
||||
// Add_symbols task after finding out the type of the file.
|
||||
|
||||
void
|
||||
Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
|
||||
const char* name, off_t sh_size)
|
||||
{
|
||||
Stringpool::Key key = 0;
|
||||
|
||||
if (name != NULL)
|
||||
this->strtab_->add(name, true, &key);
|
||||
|
||||
gold_assert(obj == this->current_object_);
|
||||
this->current_object_entry_->add_input_section(shndx, key, sh_size);
|
||||
}
|
||||
|
||||
// Record that the input argument INPUT is a script SCRIPT. This is
|
||||
// called by read_script after parsing the script and reading the list
|
||||
// of inputs added by this script.
|
||||
|
||||
void
|
||||
Incremental_inputs::report_script(const Input_argument* input,
|
||||
Timespec mtime,
|
||||
Script_info* script)
|
||||
Incremental_inputs::report_script(const std::string& filename,
|
||||
Script_info* script, Timespec mtime)
|
||||
{
|
||||
Hold_lock hl(*this->lock_);
|
||||
Stringpool::Key filename_key;
|
||||
|
||||
Input_info info;
|
||||
info.type = INCREMENTAL_INPUT_SCRIPT;
|
||||
info.script = script;
|
||||
info.mtime = mtime;
|
||||
this->inputs_map_.insert(std::make_pair(input, info));
|
||||
}
|
||||
|
||||
// Compute indexes in the order in which the inputs should appear in
|
||||
// .gnu_incremental_inputs. This needs to be done after all the
|
||||
// scripts are parsed. The function is first called for the command
|
||||
// line inputs arguments and may call itself recursively for e.g. a
|
||||
// list of elements of a group or a list of inputs added by a script.
|
||||
// The [BEGIN; END) interval to analyze and *INDEX is the current
|
||||
// value of the index (that will be updated).
|
||||
|
||||
void
|
||||
Incremental_inputs::finalize_inputs(
|
||||
Input_argument_list::const_iterator begin,
|
||||
Input_argument_list::const_iterator end,
|
||||
unsigned int* index)
|
||||
{
|
||||
for (Input_argument_list::const_iterator p = begin; p != end; ++p)
|
||||
{
|
||||
if (p->is_group())
|
||||
{
|
||||
finalize_inputs(p->group()->begin(), p->group()->end(), index);
|
||||
continue;
|
||||
}
|
||||
|
||||
Inputs_info_map::iterator it = this->inputs_map_.find(&(*p));
|
||||
// TODO: turn it into an assert when the code will be more stable.
|
||||
if (it == this->inputs_map_.end())
|
||||
{
|
||||
gold_error("internal error: %s: incremental build info not provided",
|
||||
(p->is_file() ? p->file().name() : "[group]"));
|
||||
continue;
|
||||
}
|
||||
Input_info* info = &it->second;
|
||||
info->index = *index;
|
||||
(*index)++;
|
||||
this->strtab_->add(p->file().name(), false, &info->filename_key);
|
||||
if (info->type == INCREMENTAL_INPUT_SCRIPT)
|
||||
{
|
||||
finalize_inputs(info->script->inputs()->begin(),
|
||||
info->script->inputs()->end(),
|
||||
index);
|
||||
}
|
||||
}
|
||||
this->strtab_->add(filename.c_str(), false, &filename_key);
|
||||
Incremental_script_entry* entry =
|
||||
new Incremental_script_entry(filename_key, script, mtime);
|
||||
this->inputs_.push_back(entry);
|
||||
}
|
||||
|
||||
// Finalize the incremental link information. Called from
|
||||
|
@ -416,108 +515,425 @@ Incremental_inputs::finalize_inputs(
|
|||
void
|
||||
Incremental_inputs::finalize()
|
||||
{
|
||||
unsigned int index = 0;
|
||||
finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index);
|
||||
|
||||
// Sanity check.
|
||||
for (Inputs_info_map::const_iterator p = this->inputs_map_.begin();
|
||||
p != this->inputs_map_.end();
|
||||
++p)
|
||||
{
|
||||
gold_assert(p->second.filename_key != 0);
|
||||
}
|
||||
|
||||
// Finalize the string table.
|
||||
this->strtab_->set_string_offsets();
|
||||
}
|
||||
|
||||
// Create the content of the .gnu_incremental_inputs section.
|
||||
// Create the .gnu_incremental_inputs, _symtab, and _relocs input sections.
|
||||
|
||||
Output_section_data*
|
||||
Incremental_inputs::create_incremental_inputs_section_data()
|
||||
void
|
||||
Incremental_inputs::create_data_sections(Symbol_table* symtab)
|
||||
{
|
||||
switch (parameters->size_and_endianness())
|
||||
{
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
case Parameters::TARGET_32_LITTLE:
|
||||
return this->sized_create_inputs_section_data<32, false>();
|
||||
this->inputs_section_ =
|
||||
new Output_section_incremental_inputs<32, false>(this, symtab);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
case Parameters::TARGET_32_BIG:
|
||||
return this->sized_create_inputs_section_data<32, true>();
|
||||
this->inputs_section_ =
|
||||
new Output_section_incremental_inputs<32, true>(this, symtab);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
case Parameters::TARGET_64_LITTLE:
|
||||
return this->sized_create_inputs_section_data<64, false>();
|
||||
this->inputs_section_ =
|
||||
new Output_section_incremental_inputs<64, false>(this, symtab);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
case Parameters::TARGET_64_BIG:
|
||||
return this->sized_create_inputs_section_data<64, true>();
|
||||
this->inputs_section_ =
|
||||
new Output_section_incremental_inputs<64, true>(this, symtab);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
this->symtab_section_ = new Output_data_space(4, "** incremental_symtab");
|
||||
this->relocs_section_ = new Output_data_space(4, "** incremental_relocs");
|
||||
}
|
||||
|
||||
// Sized creation of .gnu_incremental_inputs section.
|
||||
// Return the sh_entsize value for the .gnu_incremental_relocs section.
|
||||
unsigned int
|
||||
Incremental_inputs::relocs_entsize() const
|
||||
{
|
||||
return 8 + 2 * parameters->target().get_size() / 8;
|
||||
}
|
||||
|
||||
// Class Output_section_incremental_inputs.
|
||||
|
||||
// Finalize the offsets for each input section and supplemental info block,
|
||||
// and set the final data size of the incremental output sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_section_data*
|
||||
Incremental_inputs::sized_create_inputs_section_data()
|
||||
void
|
||||
Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
|
||||
{
|
||||
const int entry_size =
|
||||
Incremental_inputs_entry_write<size, big_endian>::data_size;
|
||||
const int header_size =
|
||||
Incremental_inputs_header_write<size, big_endian>::data_size;
|
||||
const Incremental_inputs* inputs = this->inputs_;
|
||||
const unsigned int sizeof_addr = size / 8;
|
||||
const unsigned int rel_size = 8 + 2 * sizeof_addr;
|
||||
|
||||
unsigned int sz = header_size + entry_size * this->inputs_map_.size();
|
||||
unsigned char* buffer = new unsigned char[sz];
|
||||
unsigned char* inputs_base = buffer + header_size;
|
||||
// Offset of each input entry.
|
||||
unsigned int input_offset = this->header_size;
|
||||
|
||||
Incremental_inputs_header_write<size, big_endian> header_writer(buffer);
|
||||
gold_assert(this->command_line_key_ > 0);
|
||||
int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_);
|
||||
// Offset of each supplemental info block.
|
||||
unsigned int info_offset = this->header_size;
|
||||
info_offset += this->input_entry_size * inputs->input_file_count();
|
||||
|
||||
header_writer.put_version(INCREMENTAL_LINK_VERSION);
|
||||
header_writer.put_input_file_count(this->inputs_map_.size());
|
||||
header_writer.put_command_line_offset(cmd_offset);
|
||||
header_writer.put_reserved(0);
|
||||
|
||||
for (Inputs_info_map::const_iterator it = this->inputs_map_.begin();
|
||||
it != this->inputs_map_.end();
|
||||
++it)
|
||||
// Count each input file and its supplemental information block.
|
||||
for (Incremental_inputs::Input_list::const_iterator p =
|
||||
inputs->input_files().begin();
|
||||
p != inputs->input_files().end();
|
||||
++p)
|
||||
{
|
||||
gold_assert(it->second.index < this->inputs_map_.size());
|
||||
// Set the offset of the input file entry.
|
||||
(*p)->set_offset(input_offset);
|
||||
input_offset += this->input_entry_size;
|
||||
|
||||
unsigned char* entry_buffer =
|
||||
inputs_base + it->second.index * entry_size;
|
||||
Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer);
|
||||
int filename_offset =
|
||||
this->strtab_->get_offset_from_key(it->second.filename_key);
|
||||
entry.put_filename_offset(filename_offset);
|
||||
switch (it->second.type)
|
||||
{
|
||||
case INCREMENTAL_INPUT_SCRIPT:
|
||||
entry.put_data_offset(0);
|
||||
break;
|
||||
case INCREMENTAL_INPUT_ARCHIVE:
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
// TODO: add per input data. Currently we store
|
||||
// an out-of-bounds offset for future version of gold to reject
|
||||
// such an incremental_inputs section.
|
||||
entry.put_data_offset(0xffffffff);
|
||||
break;
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
entry.put_timestamp_sec(it->second.mtime.seconds);
|
||||
entry.put_timestamp_nsec(it->second.mtime.nanoseconds);
|
||||
entry.put_input_type(it->second.type);
|
||||
entry.put_reserved(0);
|
||||
// Set the offset of the supplemental info block.
|
||||
switch ((*p)->type())
|
||||
{
|
||||
case INCREMENTAL_INPUT_SCRIPT:
|
||||
// No supplemental info for a script.
|
||||
(*p)->set_info_offset(0);
|
||||
break;
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
|
||||
{
|
||||
Incremental_object_entry *entry = (*p)->object_entry();
|
||||
gold_assert(entry != NULL);
|
||||
(*p)->set_info_offset(info_offset);
|
||||
// Input section count + global symbol count.
|
||||
info_offset += 8;
|
||||
// Each input section.
|
||||
info_offset += (entry->get_input_section_count()
|
||||
* (8 + 2 * sizeof_addr));
|
||||
// Each global symbol.
|
||||
const Object::Symbols* syms = entry->object()->get_global_symbols();
|
||||
info_offset += syms->size() * 16;
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
{
|
||||
Incremental_object_entry *entry = (*p)->object_entry();
|
||||
gold_assert(entry != NULL);
|
||||
(*p)->set_info_offset(info_offset);
|
||||
// Global symbol count.
|
||||
info_offset += 4;
|
||||
// Each global symbol.
|
||||
const Object::Symbols* syms = entry->object()->get_global_symbols();
|
||||
unsigned int nsyms = syms != NULL ? syms->size() : 0;
|
||||
info_offset += nsyms * 4;
|
||||
}
|
||||
break;
|
||||
case INCREMENTAL_INPUT_ARCHIVE:
|
||||
{
|
||||
Incremental_archive_entry *entry = (*p)->archive_entry();
|
||||
gold_assert(entry != NULL);
|
||||
(*p)->set_info_offset(info_offset);
|
||||
// Member count + unused global symbol count.
|
||||
info_offset += 8;
|
||||
// Each member.
|
||||
info_offset += (entry->get_member_count() * 4);
|
||||
// Each global symbol.
|
||||
info_offset += (entry->get_unused_global_symbol_count() * 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
return new Output_data_const_buffer(buffer, sz, 8,
|
||||
"** incremental link inputs list");
|
||||
this->set_data_size(info_offset);
|
||||
|
||||
// Set the size of the .gnu_incremental_symtab section.
|
||||
inputs->symtab_section()->set_current_data_size(this->symtab_->output_count()
|
||||
* sizeof(unsigned int));
|
||||
|
||||
// Set the size of the .gnu_incremental_relocs section.
|
||||
inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count()
|
||||
* rel_size);
|
||||
}
|
||||
|
||||
// Write the contents of the .gnu_incremental_inputs and
|
||||
// .gnu_incremental_symtab sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_section_incremental_inputs<size, big_endian>::do_write(Output_file* of)
|
||||
{
|
||||
const Incremental_inputs* inputs = this->inputs_;
|
||||
Stringpool* strtab = inputs->get_stringpool();
|
||||
|
||||
// Get a view into the .gnu_incremental_inputs section.
|
||||
const off_t off = this->offset();
|
||||
const off_t oview_size = this->data_size();
|
||||
unsigned char* const oview = of->get_output_view(off, oview_size);
|
||||
unsigned char* pov = oview;
|
||||
|
||||
// Get a view into the .gnu_incremental_symtab section.
|
||||
const off_t symtab_off = inputs->symtab_section()->offset();
|
||||
const off_t symtab_size = inputs->symtab_section()->data_size();
|
||||
unsigned char* const symtab_view = of->get_output_view(symtab_off,
|
||||
symtab_size);
|
||||
|
||||
// Allocate an array of linked list heads for the .gnu_incremental_symtab
|
||||
// section. Each element corresponds to a global symbol in the output
|
||||
// symbol table, and points to the head of the linked list that threads
|
||||
// through the object file input entries. The value of each element
|
||||
// is the section-relative offset to a global symbol entry in a
|
||||
// supplemental information block.
|
||||
unsigned int global_sym_count = this->symtab_->output_count();
|
||||
unsigned int* global_syms = new unsigned int[global_sym_count];
|
||||
memset(global_syms, 0, global_sym_count * sizeof(unsigned int));
|
||||
|
||||
// Write the section header.
|
||||
Stringpool::Key command_line_key = inputs->command_line_key();
|
||||
pov = this->write_header(pov, inputs->input_file_count(),
|
||||
strtab->get_offset_from_key(command_line_key));
|
||||
|
||||
// Write the list of input files.
|
||||
pov = this->write_input_files(oview, pov, strtab);
|
||||
|
||||
// Write the supplemental information blocks for each input file.
|
||||
pov = this->write_info_blocks(oview, pov, strtab, global_syms,
|
||||
global_sym_count);
|
||||
|
||||
gold_assert(pov - oview == oview_size);
|
||||
|
||||
// Write the .gnu_incremental_symtab section.
|
||||
gold_assert(global_sym_count * 4 == symtab_size);
|
||||
this->write_symtab(symtab_view, global_syms, global_sym_count);
|
||||
|
||||
delete[] global_syms;
|
||||
|
||||
of->write_output_view(off, oview_size, oview);
|
||||
of->write_output_view(symtab_off, symtab_size, symtab_view);
|
||||
}
|
||||
|
||||
// Write the section header: version, input file count, offset of command line
|
||||
// in the string table, and 4 bytes of padding.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
Output_section_incremental_inputs<size, big_endian>::write_header(
|
||||
unsigned char* pov,
|
||||
unsigned int input_file_count,
|
||||
section_offset_type command_line_offset)
|
||||
{
|
||||
Swap32::writeval(pov, INCREMENTAL_LINK_VERSION);
|
||||
Swap32::writeval(pov + 4, input_file_count);
|
||||
Swap32::writeval(pov + 8, command_line_offset);
|
||||
Swap32::writeval(pov + 12, 0);
|
||||
return pov + this->header_size;
|
||||
}
|
||||
|
||||
// Write the input file entries.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
Output_section_incremental_inputs<size, big_endian>::write_input_files(
|
||||
unsigned char* oview,
|
||||
unsigned char* pov,
|
||||
Stringpool* strtab)
|
||||
{
|
||||
const Incremental_inputs* inputs = this->inputs_;
|
||||
|
||||
for (Incremental_inputs::Input_list::const_iterator p =
|
||||
inputs->input_files().begin();
|
||||
p != inputs->input_files().end();
|
||||
++p)
|
||||
{
|
||||
gold_assert(pov - oview == (*p)->get_offset());
|
||||
section_offset_type filename_offset =
|
||||
strtab->get_offset_from_key((*p)->get_filename_key());
|
||||
const Timespec& mtime = (*p)->get_mtime();
|
||||
Swap32::writeval(pov, filename_offset);
|
||||
Swap32::writeval(pov + 4, (*p)->get_info_offset());
|
||||
Swap64::writeval(pov + 8, mtime.seconds);
|
||||
Swap32::writeval(pov + 16, mtime.nanoseconds);
|
||||
Swap16::writeval(pov + 20, (*p)->type());
|
||||
Swap16::writeval(pov + 22, 0);
|
||||
pov += this->input_entry_size;
|
||||
}
|
||||
return pov;
|
||||
}
|
||||
|
||||
// Write the supplemental information blocks.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
|
||||
unsigned char* oview,
|
||||
unsigned char* pov,
|
||||
Stringpool* strtab,
|
||||
unsigned int* global_syms,
|
||||
unsigned int global_sym_count)
|
||||
{
|
||||
const Incremental_inputs* inputs = this->inputs_;
|
||||
unsigned int first_global_index = this->symtab_->first_global_index();
|
||||
|
||||
for (Incremental_inputs::Input_list::const_iterator p =
|
||||
inputs->input_files().begin();
|
||||
p != inputs->input_files().end();
|
||||
++p)
|
||||
{
|
||||
switch ((*p)->type())
|
||||
{
|
||||
case INCREMENTAL_INPUT_SCRIPT:
|
||||
// No supplemental info for a script.
|
||||
break;
|
||||
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
|
||||
{
|
||||
gold_assert(pov - oview == (*p)->get_info_offset());
|
||||
Incremental_object_entry* entry = (*p)->object_entry();
|
||||
gold_assert(entry != NULL);
|
||||
const Object* obj = entry->object();
|
||||
const Object::Symbols* syms = obj->get_global_symbols();
|
||||
// Write the input section count and global symbol count.
|
||||
unsigned int nsections = entry->get_input_section_count();
|
||||
unsigned int nsyms = syms->size();
|
||||
Swap32::writeval(pov, nsections);
|
||||
Swap32::writeval(pov + 4, nsyms);
|
||||
pov += 8;
|
||||
|
||||
// For each input section, write the name, output section index,
|
||||
// offset within output section, and input section size.
|
||||
for (unsigned int i = 0; i < nsections; i++)
|
||||
{
|
||||
Stringpool::Key key = entry->get_input_section_name_key(i);
|
||||
off_t name_offset = 0;
|
||||
if (key != 0)
|
||||
name_offset = strtab->get_offset_from_key(key);
|
||||
int out_shndx = 0;
|
||||
off_t out_offset = 0;
|
||||
off_t sh_size = 0;
|
||||
Output_section* os = obj->output_section(i);
|
||||
if (os != NULL)
|
||||
{
|
||||
out_shndx = os->out_shndx();
|
||||
out_offset = obj->output_section_offset(i);
|
||||
sh_size = entry->get_input_section_size(i);
|
||||
}
|
||||
Swap32::writeval(pov, name_offset);
|
||||
Swap32::writeval(pov + 4, out_shndx);
|
||||
Swap::writeval(pov + 8, out_offset);
|
||||
Swap::writeval(pov + 8 + sizeof_addr, sh_size);
|
||||
pov += 8 + 2 * sizeof_addr;
|
||||
}
|
||||
|
||||
// For each global symbol, write its associated relocations,
|
||||
// add it to the linked list of globals, then write the
|
||||
// supplemental information: global symbol table index,
|
||||
// linked list chain pointer, relocation count, and offset
|
||||
// to the relocations.
|
||||
for (unsigned int i = 0; i < nsyms; i++)
|
||||
{
|
||||
const Symbol* sym = (*syms)[i];
|
||||
unsigned int symtab_index = sym->symtab_index();
|
||||
unsigned int chain = 0;
|
||||
unsigned int first_reloc = 0;
|
||||
unsigned int nrelocs = obj->get_incremental_reloc_count(i);
|
||||
if (nrelocs > 0)
|
||||
{
|
||||
gold_assert(symtab_index != -1U
|
||||
&& (symtab_index - first_global_index
|
||||
< global_sym_count));
|
||||
first_reloc = obj->get_incremental_reloc_base(i);
|
||||
chain = global_syms[symtab_index - first_global_index];
|
||||
global_syms[symtab_index - first_global_index] =
|
||||
pov - oview;
|
||||
}
|
||||
Swap32::writeval(pov, symtab_index);
|
||||
Swap32::writeval(pov + 4, chain);
|
||||
Swap32::writeval(pov + 8, nrelocs);
|
||||
Swap32::writeval(pov + 12, first_reloc * 3 * sizeof_addr);
|
||||
pov += 16;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
{
|
||||
gold_assert(pov - oview == (*p)->get_info_offset());
|
||||
Incremental_object_entry* entry = (*p)->object_entry();
|
||||
gold_assert(entry != NULL);
|
||||
const Object* obj = entry->object();
|
||||
const Object::Symbols* syms = obj->get_global_symbols();
|
||||
|
||||
// Write the global symbol count.
|
||||
unsigned int nsyms = syms != NULL ? syms->size() : 0;
|
||||
Swap32::writeval(pov, nsyms);
|
||||
pov += 4;
|
||||
|
||||
// For each global symbol, write the global symbol table index.
|
||||
for (unsigned int i = 0; i < nsyms; i++)
|
||||
{
|
||||
const Symbol* sym = (*syms)[i];
|
||||
Swap32::writeval(pov, sym->symtab_index());
|
||||
pov += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INCREMENTAL_INPUT_ARCHIVE:
|
||||
{
|
||||
gold_assert(pov - oview == (*p)->get_info_offset());
|
||||
Incremental_archive_entry* entry = (*p)->archive_entry();
|
||||
gold_assert(entry != NULL);
|
||||
|
||||
// Write the member count and unused global symbol count.
|
||||
unsigned int nmembers = entry->get_member_count();
|
||||
unsigned int nsyms = entry->get_unused_global_symbol_count();
|
||||
Swap32::writeval(pov, nmembers);
|
||||
Swap32::writeval(pov + 4, nsyms);
|
||||
pov += 8;
|
||||
|
||||
// For each member, write the offset to its input file entry.
|
||||
for (unsigned int i = 0; i < nmembers; ++i)
|
||||
{
|
||||
Incremental_object_entry* member = entry->get_member(i);
|
||||
Swap32::writeval(pov, member->get_offset());
|
||||
pov += 4;
|
||||
}
|
||||
|
||||
// For each global symbol, write the name offset.
|
||||
for (unsigned int i = 0; i < nsyms; ++i)
|
||||
{
|
||||
Stringpool::Key key = entry->get_unused_global_symbol(i);
|
||||
Swap32::writeval(pov, strtab->get_offset_from_key(key));
|
||||
pov += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
return pov;
|
||||
}
|
||||
|
||||
// Write the contents of the .gnu_incremental_symtab section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_section_incremental_inputs<size, big_endian>::write_symtab(
|
||||
unsigned char* pov,
|
||||
unsigned int* global_syms,
|
||||
unsigned int global_sym_count)
|
||||
{
|
||||
for (unsigned int i = 0; i < global_sym_count; ++i)
|
||||
{
|
||||
Swap32::writeval(pov, global_syms[i]);
|
||||
pov += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the templates we need.
|
||||
|
|
1002
gold/incremental.h
1002
gold/incremental.h
File diff suppressed because it is too large
Load diff
|
@ -974,7 +974,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
|||
if (this->debug_abbrev_)
|
||||
this->debug_info_->set_abbreviations(this->debug_abbrev_);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// FIXME: const_cast is ugly.
|
||||
Target* target = const_cast<Target*>(¶meters->target());
|
||||
|
@ -1886,12 +1886,6 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
this->set_dynamic_symbol_size(symtab);
|
||||
}
|
||||
|
||||
if (this->incremental_inputs_)
|
||||
{
|
||||
this->incremental_inputs_->finalize();
|
||||
this->create_incremental_info_sections();
|
||||
}
|
||||
|
||||
// Create segment headers.
|
||||
Output_segment_headers* segment_headers =
|
||||
(parameters->options().relocatable()
|
||||
|
@ -1951,6 +1945,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
// be called after the symbol table has been finalized.
|
||||
this->script_options_->finalize_symbols(symtab, this);
|
||||
|
||||
// Create the incremental inputs sections.
|
||||
if (this->incremental_inputs_)
|
||||
{
|
||||
this->incremental_inputs_->finalize();
|
||||
this->create_incremental_info_sections(symtab);
|
||||
}
|
||||
|
||||
// Create the .shstrtab section.
|
||||
Output_section* shstrtab_section = this->create_shstrtab();
|
||||
|
||||
|
@ -1968,8 +1969,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
// If there are no sections which require postprocessing, we can
|
||||
// handle the section names now, and avoid a resize later.
|
||||
if (!this->any_postprocessing_sections_)
|
||||
off = this->set_section_offsets(off,
|
||||
{
|
||||
off = this->set_section_offsets(off,
|
||||
POSTPROCESSING_SECTIONS_PASS);
|
||||
off =
|
||||
this->set_section_offsets(off,
|
||||
STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS);
|
||||
}
|
||||
|
||||
file_header->set_section_info(this->section_headers_, shstrtab_section);
|
||||
|
||||
|
@ -2294,37 +2300,65 @@ Layout::link_stabs_sections()
|
|||
}
|
||||
}
|
||||
|
||||
// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
|
||||
// Create .gnu_incremental_inputs and related sections needed
|
||||
// for the next run of incremental linking to check what has changed.
|
||||
|
||||
void
|
||||
Layout::create_incremental_info_sections()
|
||||
Layout::create_incremental_info_sections(Symbol_table* symtab)
|
||||
{
|
||||
gold_assert(this->incremental_inputs_ != NULL);
|
||||
Incremental_inputs* incr = this->incremental_inputs_;
|
||||
|
||||
gold_assert(incr != NULL);
|
||||
|
||||
// Create the .gnu_incremental_inputs, _symtab, and _relocs input sections.
|
||||
incr->create_data_sections(symtab);
|
||||
|
||||
// Add the .gnu_incremental_inputs section.
|
||||
const char *incremental_inputs_name =
|
||||
this->namepool_.add(".gnu_incremental_inputs", false, NULL);
|
||||
Output_section* inputs_os =
|
||||
Output_section* incremental_inputs_os =
|
||||
this->make_output_section(incremental_inputs_name,
|
||||
elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0,
|
||||
ORDER_INVALID, false);
|
||||
Output_section_data* posd =
|
||||
this->incremental_inputs_->create_incremental_inputs_section_data();
|
||||
inputs_os->add_output_section_data(posd);
|
||||
|
||||
incremental_inputs_os->add_output_section_data(incr->inputs_section());
|
||||
|
||||
// Add the .gnu_incremental_symtab section.
|
||||
const char *incremental_symtab_name =
|
||||
this->namepool_.add(".gnu_incremental_symtab", false, NULL);
|
||||
Output_section* incremental_symtab_os =
|
||||
this->make_output_section(incremental_symtab_name,
|
||||
elfcpp::SHT_GNU_INCREMENTAL_SYMTAB, 0,
|
||||
ORDER_INVALID, false);
|
||||
incremental_symtab_os->add_output_section_data(incr->symtab_section());
|
||||
incremental_symtab_os->set_entsize(4);
|
||||
|
||||
// Add the .gnu_incremental_relocs section.
|
||||
const char *incremental_relocs_name =
|
||||
this->namepool_.add(".gnu_incremental_relocs", false, NULL);
|
||||
Output_section* incremental_relocs_os =
|
||||
this->make_output_section(incremental_relocs_name,
|
||||
elfcpp::SHT_GNU_INCREMENTAL_RELOCS, 0,
|
||||
ORDER_INVALID, false);
|
||||
incremental_relocs_os->add_output_section_data(incr->relocs_section());
|
||||
incremental_relocs_os->set_entsize(incr->relocs_entsize());
|
||||
|
||||
// Add the .gnu_incremental_strtab section.
|
||||
const char *incremental_strtab_name =
|
||||
this->namepool_.add(".gnu_incremental_strtab", false, NULL);
|
||||
Output_section* strtab_os = this->make_output_section(incremental_strtab_name,
|
||||
elfcpp::SHT_STRTAB,
|
||||
0, ORDER_INVALID,
|
||||
false);
|
||||
Output_section* incremental_strtab_os = this->make_output_section(incremental_strtab_name,
|
||||
elfcpp::SHT_STRTAB, 0,
|
||||
ORDER_INVALID, false);
|
||||
Output_data_strtab* strtab_data =
|
||||
new Output_data_strtab(this->incremental_inputs_->get_stringpool());
|
||||
strtab_os->add_output_section_data(strtab_data);
|
||||
|
||||
inputs_os->set_link_section(strtab_data);
|
||||
new Output_data_strtab(incr->get_stringpool());
|
||||
incremental_strtab_os->add_output_section_data(strtab_data);
|
||||
|
||||
incremental_inputs_os->set_after_input_sections();
|
||||
incremental_symtab_os->set_after_input_sections();
|
||||
incremental_relocs_os->set_after_input_sections();
|
||||
|
||||
incremental_inputs_os->set_link_section(incremental_strtab_os);
|
||||
incremental_symtab_os->set_link_section(incremental_inputs_os);
|
||||
incremental_relocs_os->set_link_section(incremental_inputs_os);
|
||||
}
|
||||
|
||||
// Return whether SEG1 should be before SEG2 in the output file. This
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// layout.h -- lay out output file sections for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
@ -58,6 +58,7 @@ class Output_reduced_debug_abbrev_section;
|
|||
class Output_reduced_debug_info_section;
|
||||
class Eh_frame;
|
||||
class Target;
|
||||
struct Timespec;
|
||||
|
||||
// Return TRUE if SECNAME is the name of a compressed debug section.
|
||||
extern bool
|
||||
|
@ -662,7 +663,7 @@ class Layout
|
|||
// Return the object managing inputs in incremental build. NULL in
|
||||
// non-incremental builds.
|
||||
Incremental_inputs*
|
||||
incremental_inputs()
|
||||
incremental_inputs() const
|
||||
{ return this->incremental_inputs_; }
|
||||
|
||||
// For the target-specific code to add dynamic tags which are common
|
||||
|
@ -800,7 +801,7 @@ class Layout
|
|||
// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
|
||||
// for the next run of incremental linking to check what has changed.
|
||||
void
|
||||
create_incremental_info_sections();
|
||||
create_incremental_info_sections(Symbol_table*);
|
||||
|
||||
// Find the first read-only PT_LOAD segment, creating one if
|
||||
// necessary.
|
||||
|
|
|
@ -229,10 +229,7 @@ main(int argc, char** argv)
|
|||
&command_line.script_options());
|
||||
|
||||
if (layout.incremental_inputs() != NULL)
|
||||
{
|
||||
layout.incremental_inputs()->report_command_line(argc, argv);
|
||||
layout.incremental_inputs()->report_inputs(command_line.inputs());
|
||||
}
|
||||
layout.incremental_inputs()->report_command_line(argc, argv);
|
||||
|
||||
if (parameters->options().section_ordering_file())
|
||||
layout.read_layout_from_file();
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "dynobj.h"
|
||||
#include "plugin.h"
|
||||
#include "compressed_output.h"
|
||||
#include "incremental.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -346,6 +347,30 @@ Relobj::is_section_name_included(const char* name)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Finalize the incremental relocation information. Allocates a block
|
||||
// of relocation entries for each symbol, and sets the reloc_bases_
|
||||
// array to point to the first entry in each block. Returns the next
|
||||
// available reloation index.
|
||||
|
||||
void
|
||||
Relobj::finalize_incremental_relocs(Layout* layout)
|
||||
{
|
||||
unsigned int nsyms = this->get_global_symbols()->size();
|
||||
this->reloc_bases_ = new unsigned int[nsyms];
|
||||
|
||||
gold_assert(this->reloc_bases_ != NULL);
|
||||
gold_assert(layout->incremental_inputs() != NULL);
|
||||
|
||||
unsigned int rindex = layout->incremental_inputs()->get_reloc_count();
|
||||
for (unsigned int i = 0; i < nsyms; ++i)
|
||||
{
|
||||
this->reloc_bases_[i] = rindex;
|
||||
rindex += this->reloc_counts_[i];
|
||||
this->reloc_counts_[i] = 0;
|
||||
}
|
||||
layout->incremental_inputs()->set_reloc_count(rindex);
|
||||
}
|
||||
|
||||
// Class Sized_relobj.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
@ -1237,6 +1262,13 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||
}
|
||||
}
|
||||
|
||||
// Add the section to the incremental inputs layout.
|
||||
Incremental_inputs* incremental_inputs = layout->incremental_inputs();
|
||||
if (incremental_inputs != NULL)
|
||||
incremental_inputs->report_input_section(this, i,
|
||||
discard ? NULL : name,
|
||||
shdr.get_sh_size());
|
||||
|
||||
if (discard)
|
||||
{
|
||||
// Do not include this section in the link.
|
||||
|
|
171
gold/object.h
171
gold/object.h
|
@ -387,6 +387,18 @@ class Object
|
|||
section_addralign(unsigned int shndx)
|
||||
{ return this->do_section_addralign(shndx); }
|
||||
|
||||
// Return the output section given a section index.
|
||||
Output_section*
|
||||
output_section(unsigned int shndx) const
|
||||
{ return this->do_output_section(shndx); }
|
||||
|
||||
// Given a section index, return the offset in the Output_section.
|
||||
// The return value will be -1U if the section is specially mapped,
|
||||
// such as a merge section.
|
||||
uint64_t
|
||||
output_section_offset(unsigned int shndx) const
|
||||
{ return this->do_output_section_offset(shndx); }
|
||||
|
||||
// Read the symbol information.
|
||||
void
|
||||
read_symbols(Read_symbols_data* sd)
|
||||
|
@ -525,6 +537,16 @@ class Object
|
|||
section_size_type* uncompressed_size) const
|
||||
{ return this->do_section_is_compressed(shndx, uncompressed_size); }
|
||||
|
||||
// Return the index of the first incremental relocation for symbol SYMNDX.
|
||||
unsigned int
|
||||
get_incremental_reloc_base(unsigned int symndx) const
|
||||
{ return this->do_get_incremental_reloc_base(symndx); }
|
||||
|
||||
// Return the number of incremental relocations for symbol SYMNDX.
|
||||
unsigned int
|
||||
get_incremental_reloc_count(unsigned int symndx) const
|
||||
{ return this->do_get_incremental_reloc_count(symndx); }
|
||||
|
||||
protected:
|
||||
// Returns NULL for Objects that are not plugin objects. This method
|
||||
// is overridden in the Pluginobj class.
|
||||
|
@ -590,6 +612,17 @@ class Object
|
|||
virtual uint64_t
|
||||
do_section_addralign(unsigned int shndx) = 0;
|
||||
|
||||
// Return the output section given a section index--implemented
|
||||
// by child class.
|
||||
virtual Output_section*
|
||||
do_output_section(unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Get the offset of a section--implemented by child class.
|
||||
virtual uint64_t
|
||||
do_output_section_offset(unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Return the Xindex structure to use.
|
||||
virtual Xindex*
|
||||
do_initialize_xindex() = 0;
|
||||
|
@ -641,6 +674,18 @@ class Object
|
|||
do_section_is_compressed(unsigned int, section_size_type*) const
|
||||
{ return false; }
|
||||
|
||||
// Return the index of the first incremental relocation for symbol SYMNDX--
|
||||
// implemented by child class.
|
||||
virtual unsigned int
|
||||
do_get_incremental_reloc_base(unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Return the number of incremental relocations for symbol SYMNDX--
|
||||
// implemented by child class.
|
||||
virtual unsigned int
|
||||
do_get_incremental_reloc_count(unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
private:
|
||||
// This class may not be copied.
|
||||
Object(const Object&);
|
||||
|
@ -685,7 +730,9 @@ class Relobj : public Object
|
|||
map_to_relocatable_relocs_(NULL),
|
||||
object_merge_map_(NULL),
|
||||
relocs_must_follow_section_writes_(false),
|
||||
sd_(NULL)
|
||||
sd_(NULL),
|
||||
reloc_counts_(NULL),
|
||||
reloc_bases_(NULL)
|
||||
{ }
|
||||
|
||||
// During garbage collection, the Read_symbols_data pass for
|
||||
|
@ -781,16 +828,6 @@ class Relobj : public Object
|
|||
return this->output_sections_[shndx] != NULL;
|
||||
}
|
||||
|
||||
// Given a section index, return the corresponding Output_section.
|
||||
// The return value will be NULL if the section is not included in
|
||||
// the link.
|
||||
Output_section*
|
||||
output_section(unsigned int shndx) const
|
||||
{
|
||||
gold_assert(shndx < this->output_sections_.size());
|
||||
return this->output_sections_[shndx];
|
||||
}
|
||||
|
||||
// The the output section of the input section with index SHNDX.
|
||||
// This is only used currently to remove a section from the link in
|
||||
// relaxation.
|
||||
|
@ -801,13 +838,6 @@ class Relobj : public Object
|
|||
this->output_sections_[shndx] = os;
|
||||
}
|
||||
|
||||
// Given a section index, return the offset in the Output_section.
|
||||
// The return value will be -1U if the section is specially mapped,
|
||||
// such as a merge section.
|
||||
uint64_t
|
||||
output_section_offset(unsigned int shndx) const
|
||||
{ return this->do_output_section_offset(shndx); }
|
||||
|
||||
// Set the offset of an input section within its output section.
|
||||
void
|
||||
set_section_offset(unsigned int shndx, uint64_t off)
|
||||
|
@ -856,6 +886,16 @@ class Relobj : public Object
|
|||
layout_deferred_sections(Layout* layout)
|
||||
{ this->do_layout_deferred_sections(layout); }
|
||||
|
||||
// Return the index of the first incremental relocation for symbol SYMNDX.
|
||||
virtual unsigned int
|
||||
do_get_incremental_reloc_base(unsigned int symndx) const
|
||||
{ return this->reloc_bases_[symndx]; }
|
||||
|
||||
// Return the number of incremental relocations for symbol SYMNDX.
|
||||
virtual unsigned int
|
||||
do_get_incremental_reloc_count(unsigned int symndx) const
|
||||
{ return this->reloc_counts_[symndx]; }
|
||||
|
||||
protected:
|
||||
// The output section to be used for each input section, indexed by
|
||||
// the input section number. The output section is NULL if the
|
||||
|
@ -902,10 +942,6 @@ class Relobj : public Object
|
|||
virtual void
|
||||
do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of) = 0;
|
||||
|
||||
// Get the offset of a section--implemented by child class.
|
||||
virtual uint64_t
|
||||
do_output_section_offset(unsigned int shndx) const = 0;
|
||||
|
||||
// Set the offset of a section--implemented by child class.
|
||||
virtual void
|
||||
do_set_section_offset(unsigned int shndx, uint64_t off) = 0;
|
||||
|
@ -915,6 +951,16 @@ class Relobj : public Object
|
|||
virtual void
|
||||
do_layout_deferred_sections(Layout*) = 0;
|
||||
|
||||
// Given a section index, return the corresponding Output_section.
|
||||
// The return value will be NULL if the section is not included in
|
||||
// the link.
|
||||
Output_section*
|
||||
do_output_section(unsigned int shndx) const
|
||||
{
|
||||
gold_assert(shndx < this->output_sections_.size());
|
||||
return this->output_sections_[shndx];
|
||||
}
|
||||
|
||||
// Return the vector mapping input sections to output sections.
|
||||
Output_sections&
|
||||
output_sections()
|
||||
|
@ -938,6 +984,46 @@ class Relobj : public Object
|
|||
set_relocs_must_follow_section_writes()
|
||||
{ this->relocs_must_follow_section_writes_ = true; }
|
||||
|
||||
// Allocate the array for counting incremental relocations.
|
||||
void
|
||||
allocate_incremental_reloc_counts()
|
||||
{
|
||||
unsigned int nsyms = this->do_get_global_symbols()->size();
|
||||
this->reloc_counts_ = new unsigned int[nsyms];
|
||||
gold_assert(this->reloc_counts_ != NULL);
|
||||
memset(this->reloc_counts_, 0, nsyms * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
// Record a relocation in this object referencing global symbol SYMNDX.
|
||||
// Used for tracking incremental link information.
|
||||
void
|
||||
count_incremental_reloc(unsigned int symndx)
|
||||
{
|
||||
unsigned int nsyms = this->do_get_global_symbols()->size();
|
||||
gold_assert(symndx < nsyms);
|
||||
gold_assert(this->reloc_counts_ != NULL);
|
||||
++this->reloc_counts_[symndx];
|
||||
}
|
||||
|
||||
// Finalize the incremental relocation information.
|
||||
void
|
||||
finalize_incremental_relocs(Layout* layout);
|
||||
|
||||
// Return the index of the next relocation to be written for global symbol
|
||||
// SYMNDX. Only valid after finalize_incremental_relocs() has been called.
|
||||
unsigned int
|
||||
next_incremental_reloc_index(unsigned int symndx)
|
||||
{
|
||||
unsigned int nsyms = this->do_get_global_symbols()->size();
|
||||
|
||||
gold_assert(this->reloc_counts_ != NULL);
|
||||
gold_assert(this->reloc_bases_ != NULL);
|
||||
gold_assert(symndx < nsyms);
|
||||
|
||||
unsigned int counter = this->reloc_counts_[symndx]++;
|
||||
return this->reloc_bases_[symndx] + counter;
|
||||
}
|
||||
|
||||
private:
|
||||
// Mapping from input sections to output section.
|
||||
Output_sections output_sections_;
|
||||
|
@ -957,6 +1043,10 @@ class Relobj : public Object
|
|||
// Again used during garbage collection when laying out referenced
|
||||
// sections.
|
||||
gold::Symbols_data *sd_;
|
||||
// Per-symbol counts of relocations, for incremental links.
|
||||
unsigned int* reloc_counts_;
|
||||
// Per-symbol base indexes of relocations, for incremental links.
|
||||
unsigned int* reloc_bases_;
|
||||
};
|
||||
|
||||
// This class is used to handle relocations against a section symbol
|
||||
|
@ -1792,7 +1882,8 @@ class Sized_relobj : public Relobj
|
|||
// This may be overriden by a child class.
|
||||
virtual void
|
||||
do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
|
||||
const unsigned char* pshdrs, Views* pviews);
|
||||
const unsigned char* pshdrs, Output_file* of,
|
||||
Views* pviews);
|
||||
|
||||
// Allow a child to set output local symbol count.
|
||||
void
|
||||
|
@ -1880,8 +1971,9 @@ class Sized_relobj : public Relobj
|
|||
// Relocate the sections in the output file.
|
||||
void
|
||||
relocate_sections(const Symbol_table* symtab, const Layout* layout,
|
||||
const unsigned char* pshdrs, Views* pviews)
|
||||
{ this->do_relocate_sections(symtab, layout, pshdrs, pviews); }
|
||||
const unsigned char* pshdrs, Output_file* of,
|
||||
Views* pviews)
|
||||
{ this->do_relocate_sections(symtab, layout, pshdrs, of, pviews); }
|
||||
|
||||
// Scan the input relocations for --emit-relocs.
|
||||
void
|
||||
|
@ -1918,6 +2010,35 @@ class Sized_relobj : public Relobj
|
|||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size);
|
||||
|
||||
// Scan the input relocations for --incremental.
|
||||
void
|
||||
incremental_relocs_scan(const Read_relocs_data::Relocs_list::iterator&);
|
||||
|
||||
// Scan the input relocations for --incremental, templatized on the
|
||||
// type of the relocation section.
|
||||
template<int sh_type>
|
||||
void
|
||||
incremental_relocs_scan_reltype(
|
||||
const Read_relocs_data::Relocs_list::iterator&);
|
||||
|
||||
void
|
||||
incremental_relocs_write(const Relocate_info<size, big_endian>*,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section*,
|
||||
Address output_offset,
|
||||
Output_file*);
|
||||
|
||||
template<int sh_type>
|
||||
void
|
||||
incremental_relocs_write_reltype(const Relocate_info<size, big_endian>*,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section*,
|
||||
Address output_offset,
|
||||
Output_file*);
|
||||
|
||||
// A type shared by split_stack_adjust_reltype and find_functions.
|
||||
typedef std::map<section_offset_type, section_size_type> Function_offsets;
|
||||
|
||||
|
|
|
@ -451,7 +451,7 @@ Plugin_manager::add_input_file(const char *pathname, bool is_lib)
|
|||
Input_argument* input_argument = new Input_argument(file);
|
||||
Task_token* next_blocker = new Task_token(true);
|
||||
next_blocker->add_blocker();
|
||||
if (this->layout_->incremental_inputs())
|
||||
if (parameters->options().incremental())
|
||||
gold_error(_("input files added by plug-ins in --incremental mode not "
|
||||
"supported yet"));
|
||||
this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
|
||||
|
|
|
@ -302,12 +302,6 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
|
|||
this->dirpath_, this);
|
||||
arch->setup();
|
||||
|
||||
if (this->layout_->incremental_inputs())
|
||||
{
|
||||
const Input_argument* ia = this->input_argument_;
|
||||
this->layout_->incremental_inputs()->report_archive(ia, arch);
|
||||
}
|
||||
|
||||
// Unlock the archive so it can be used in the next task.
|
||||
arch->unlock(this);
|
||||
|
||||
|
@ -389,12 +383,6 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
|
|||
Read_symbols_data* sd = new Read_symbols_data;
|
||||
obj->read_symbols(sd);
|
||||
|
||||
if (this->layout_->incremental_inputs())
|
||||
{
|
||||
const Input_argument* ia = this->input_argument_;
|
||||
this->layout_->incremental_inputs()->report_object(ia, obj);
|
||||
}
|
||||
|
||||
// Opening the file locked it, so now we need to unlock it. We
|
||||
// need to unlock it before queuing the Add_symbols task,
|
||||
// because the workqueue doesn't know about our lock on the
|
||||
|
@ -599,6 +587,10 @@ Add_symbols::run(Workqueue*)
|
|||
}
|
||||
else
|
||||
{
|
||||
Incremental_inputs* incremental_inputs =
|
||||
this->layout_->incremental_inputs();
|
||||
if (incremental_inputs != NULL)
|
||||
incremental_inputs->report_object(this->object_, NULL);
|
||||
this->object_->layout(this->symtab_, this->layout_, this->sd_);
|
||||
this->object_->add_symbols(this->symtab_, this->sd_, this->layout_);
|
||||
delete this->sd_;
|
||||
|
@ -688,11 +680,20 @@ Finish_group::run(Workqueue*)
|
|||
}
|
||||
}
|
||||
|
||||
// Delete all the archives now that we no longer need them.
|
||||
// Now that we're done with the archives, record the incremental layout
|
||||
// information, then delete them.
|
||||
for (Input_group::const_iterator p = this->input_group_->begin();
|
||||
p != this->input_group_->end();
|
||||
++p)
|
||||
delete *p;
|
||||
{
|
||||
// For an incremental link, finish recording the layout information.
|
||||
Incremental_inputs* incremental_inputs =
|
||||
this->layout_->incremental_inputs();
|
||||
if (incremental_inputs != NULL)
|
||||
incremental_inputs->report_archive_end(*p);
|
||||
|
||||
delete *p;
|
||||
}
|
||||
delete this->input_group_;
|
||||
}
|
||||
|
||||
|
|
193
gold/reloc.cc
193
gold/reloc.cc
|
@ -25,6 +25,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "workqueue.h"
|
||||
#include "layout.h"
|
||||
#include "symtab.h"
|
||||
#include "output.h"
|
||||
#include "merge.h"
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "reloc.h"
|
||||
#include "icf.h"
|
||||
#include "compressed_output.h"
|
||||
#include "incremental.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -300,7 +302,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
|
|||
!= 0);
|
||||
if (!is_section_allocated
|
||||
&& !parameters->options().relocatable()
|
||||
&& !parameters->options().emit_relocs())
|
||||
&& !parameters->options().emit_relocs()
|
||||
&& !parameters->options().incremental())
|
||||
continue;
|
||||
|
||||
if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
|
||||
|
@ -424,6 +427,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
|
|||
else
|
||||
local_symbols = rd->local_symbols->data();
|
||||
|
||||
// For incremental links, allocate the counters for incremental relocations.
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
this->allocate_incremental_reloc_counts();
|
||||
|
||||
for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
|
||||
p != rd->relocs.end();
|
||||
++p)
|
||||
|
@ -451,6 +458,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
|
|||
local_symbols);
|
||||
if (parameters->options().emit_relocs())
|
||||
this->emit_relocs_scan(symtab, layout, local_symbols, p);
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
this->incremental_relocs_scan(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -472,6 +481,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
|
|||
p->contents = NULL;
|
||||
}
|
||||
|
||||
// For incremental links, finalize the allocation of relocations.
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
this->finalize_incremental_relocs(layout);
|
||||
|
||||
if (rd->local_symbols != NULL)
|
||||
{
|
||||
delete rd->local_symbols;
|
||||
|
@ -567,6 +580,54 @@ Sized_relobj<size, big_endian>::emit_relocs_scan_reltype(
|
|||
rr);
|
||||
}
|
||||
|
||||
// Scan the input relocations for --incremental.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::incremental_relocs_scan(
|
||||
const Read_relocs_data::Relocs_list::iterator& p)
|
||||
{
|
||||
if (p->sh_type == elfcpp::SHT_REL)
|
||||
this->incremental_relocs_scan_reltype<elfcpp::SHT_REL>(p);
|
||||
else
|
||||
{
|
||||
gold_assert(p->sh_type == elfcpp::SHT_RELA);
|
||||
this->incremental_relocs_scan_reltype<elfcpp::SHT_RELA>(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the input relocation for --emit-relocs, templatized on the
|
||||
// type of the relocation section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
template<int sh_type>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::incremental_relocs_scan_reltype(
|
||||
const Read_relocs_data::Relocs_list::iterator& p)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
|
||||
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
const unsigned char* prelocs = p->contents->data();
|
||||
size_t reloc_count = p->reloc_count;
|
||||
|
||||
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||
{
|
||||
Reltype reloc(prelocs);
|
||||
|
||||
if (p->needs_special_offset_handling
|
||||
&& !p->output_section->is_input_address_mapped(this, p->data_shndx,
|
||||
reloc.get_r_offset()))
|
||||
continue;
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info =
|
||||
reloc.get_r_info();
|
||||
const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
|
||||
if (r_sym >= this->local_symbol_count_)
|
||||
this->count_incremental_reloc(r_sym - this->local_symbol_count_);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate the input sections and write out the local symbols.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
@ -597,7 +658,7 @@ Sized_relobj<size, big_endian>::do_relocate(const Symbol_table* symtab,
|
|||
|
||||
// Apply relocations.
|
||||
|
||||
this->relocate_sections(symtab, layout, pshdrs, &views);
|
||||
this->relocate_sections(symtab, layout, pshdrs, of, &views);
|
||||
|
||||
// After we've done the relocations, we release the hash tables,
|
||||
// since we no longer need them.
|
||||
|
@ -827,6 +888,7 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
|
|||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
const unsigned char* pshdrs,
|
||||
Output_file* of,
|
||||
Views* pviews)
|
||||
{
|
||||
unsigned int shnum = this->shnum();
|
||||
|
@ -938,6 +1000,9 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
|
|||
this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
|
||||
os, output_offset, view, address, view_size,
|
||||
(*pviews)[i].view, (*pviews)[i].view_size);
|
||||
if (parameters->options().incremental())
|
||||
this->incremental_relocs_write(&relinfo, sh_type, prelocs,
|
||||
reloc_count, os, output_offset, of);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1020,6 +1085,126 @@ Sized_relobj<size, big_endian>::emit_relocs_reltype(
|
|||
reloc_view_size);
|
||||
}
|
||||
|
||||
// Write the incremental relocs.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::incremental_relocs_write(
|
||||
const Relocate_info<size, big_endian>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
Address output_offset,
|
||||
Output_file* of)
|
||||
{
|
||||
if (sh_type == elfcpp::SHT_REL)
|
||||
this->incremental_relocs_write_reltype<elfcpp::SHT_REL>(
|
||||
relinfo,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
output_offset,
|
||||
of);
|
||||
else
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_RELA);
|
||||
this->incremental_relocs_write_reltype<elfcpp::SHT_RELA>(
|
||||
relinfo,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
output_offset,
|
||||
of);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the incremental relocs, templatized on the type of the
|
||||
// relocation section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
template<int sh_type>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::incremental_relocs_write_reltype(
|
||||
const Relocate_info<size, big_endian>* relinfo,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
Address output_offset,
|
||||
Output_file* of)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reloc;
|
||||
const unsigned int reloc_size =
|
||||
Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
const unsigned int sizeof_addr = size / 8;
|
||||
const unsigned int incr_reloc_size = 8 + 2 * sizeof_addr;
|
||||
|
||||
unsigned int out_shndx = output_section->out_shndx();
|
||||
|
||||
// Get a view for the .gnu_incremental_relocs section.
|
||||
|
||||
Incremental_inputs* inputs = relinfo->layout->incremental_inputs();
|
||||
gold_assert(inputs != NULL);
|
||||
const off_t relocs_off = inputs->relocs_section()->offset();
|
||||
const off_t relocs_size = inputs->relocs_section()->data_size();
|
||||
unsigned char* const view = of->get_output_view(relocs_off, relocs_size);
|
||||
|
||||
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||
{
|
||||
Reloc reloc(prelocs);
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
|
||||
const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
|
||||
|
||||
if (r_sym < this->local_symbol_count_)
|
||||
continue;
|
||||
|
||||
// Get the new offset--the location in the output section where
|
||||
// this relocation should be applied.
|
||||
|
||||
Address offset = reloc.get_r_offset();
|
||||
if (output_offset != invalid_address)
|
||||
offset += output_offset;
|
||||
else
|
||||
{
|
||||
section_offset_type sot_offset =
|
||||
convert_types<section_offset_type, Address>(offset);
|
||||
section_offset_type new_sot_offset =
|
||||
output_section->output_offset(relinfo->object,
|
||||
relinfo->data_shndx,
|
||||
sot_offset);
|
||||
gold_assert(new_sot_offset != -1);
|
||||
offset += new_sot_offset;
|
||||
}
|
||||
|
||||
// Get the addend.
|
||||
typename elfcpp::Elf_types<size>::Elf_Swxword addend;
|
||||
if (sh_type == elfcpp::SHT_RELA)
|
||||
addend =
|
||||
Reloc_types<sh_type, size, big_endian>::get_reloc_addend(&reloc);
|
||||
else
|
||||
{
|
||||
// FIXME: Get the addend for SHT_REL.
|
||||
addend = 0;
|
||||
}
|
||||
|
||||
// Get the index of the output relocation.
|
||||
|
||||
unsigned int reloc_index =
|
||||
this->next_incremental_reloc_index(r_sym - this->local_symbol_count_);
|
||||
|
||||
// Write the relocation.
|
||||
|
||||
unsigned char* pov = view + reloc_index * incr_reloc_size;
|
||||
elfcpp::Swap<32, big_endian>::writeval(pov, r_type);
|
||||
elfcpp::Swap<32, big_endian>::writeval(pov + 4, out_shndx);
|
||||
elfcpp::Swap<size, big_endian>::writeval(pov + 8, offset);
|
||||
elfcpp::Swap<size, big_endian>::writeval(pov + 8 + sizeof_addr, addend);
|
||||
of->write_output_view(pov - view, incr_reloc_size, view);
|
||||
}
|
||||
}
|
||||
|
||||
// Create merge hash tables for the local symbols. These are used to
|
||||
// speed up relocations.
|
||||
|
||||
|
@ -1556,6 +1741,7 @@ Sized_relobj<32, false>::do_relocate_sections(
|
|||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
const unsigned char* pshdrs,
|
||||
Output_file* of,
|
||||
Views* pviews);
|
||||
#endif
|
||||
|
||||
|
@ -1566,6 +1752,7 @@ Sized_relobj<32, true>::do_relocate_sections(
|
|||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
const unsigned char* pshdrs,
|
||||
Output_file* of,
|
||||
Views* pviews);
|
||||
#endif
|
||||
|
||||
|
@ -1576,6 +1763,7 @@ Sized_relobj<64, false>::do_relocate_sections(
|
|||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
const unsigned char* pshdrs,
|
||||
Output_file* of,
|
||||
Views* pviews);
|
||||
#endif
|
||||
|
||||
|
@ -1586,6 +1774,7 @@ Sized_relobj<64, true>::do_relocate_sections(
|
|||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
const unsigned char* pshdrs,
|
||||
Output_file* of,
|
||||
Views* pviews);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1462,16 +1462,16 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
|
|||
this_blocker = nb;
|
||||
}
|
||||
|
||||
if (layout->incremental_inputs())
|
||||
if (layout->incremental_inputs() != NULL)
|
||||
{
|
||||
// Like new Read_symbols(...) above, we rely on close.inputs()
|
||||
// Like new Read_symbols(...) above, we rely on closure.inputs()
|
||||
// getting leaked by closure.
|
||||
const std::string& filename = input_file->filename();
|
||||
Script_info* info = new Script_info(closure.inputs());
|
||||
layout->incremental_inputs()->report_script(
|
||||
input_argument,
|
||||
input_file->file().get_mtime(),
|
||||
info);
|
||||
Timespec mtime = input_file->file().get_mtime();
|
||||
layout->incremental_inputs()->report_script(filename, info, mtime);
|
||||
}
|
||||
|
||||
*used_next_blocker = true;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1468,6 +1468,16 @@ class Symbol_table
|
|||
compute_final_value(const Sized_symbol<size>* sym,
|
||||
Compute_final_value_status* pstatus) const;
|
||||
|
||||
// Return the index of the first global symbol.
|
||||
unsigned int
|
||||
first_global_index() const
|
||||
{ return this->first_global_index_; }
|
||||
|
||||
// Return the total number of symbols in the symbol table.
|
||||
unsigned int
|
||||
output_count() const
|
||||
{ return this->output_count_; }
|
||||
|
||||
// Write out the global symbols.
|
||||
void
|
||||
write_globals(const Stringpool*, const Stringpool*,
|
||||
|
|
Loading…
Reference in a new issue