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:
Cary Coutant 2010-08-12 22:01:11 +00:00
parent 98bfdba52e
commit 09ec0418c0
18 changed files with 2355 additions and 656 deletions

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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.

File diff suppressed because it is too large Load diff

View file

@ -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*>(&parameters->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

View file

@ -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.

View file

@ -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();

View 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.

View file

@ -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;

View file

@ -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_,

View file

@ -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_;
}

View file

@ -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

View file

@ -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;

View file

@ -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*,