aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elfcpp/ChangeLog5
-rw-r--r--elfcpp/elfcpp.h2
-rw-r--r--gold/ChangeLog154
-rw-r--r--gold/archive.cc21
-rw-r--r--gold/archive.h78
-rw-r--r--gold/incremental-dump.cc404
-rw-r--r--gold/incremental.cc786
-rw-r--r--gold/incremental.h982
-rw-r--r--gold/layout.cc82
-rw-r--r--gold/layout.h7
-rw-r--r--gold/main.cc5
-rw-r--r--gold/object.cc32
-rw-r--r--gold/object.h171
-rw-r--r--gold/plugin.cc2
-rw-r--r--gold/readsyms.cc29
-rw-r--r--gold/reloc.cc193
-rw-r--r--gold/script.cc12
-rw-r--r--gold/symtab.h10
18 files changed, 2337 insertions, 638 deletions
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index 782b3cf..7488984 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -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.
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 52b8b25..c46fbf5 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -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.
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 90510b5..c77f2d7 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,157 @@
+2010-08-12 Cary Coutant <ccoutant@google.com>
+
+ * archive.cc: Include incremental.h.
+ (Archive::Archive): Initialize incremental_info_.
+ (Archive::include_member): Record archive members in incremental info.
+ (Add_archive_symbols::run): Record begin and end of an archive in
+ incremental info.
+ (Lib_group::include_member): Record objects in incremental info.
+ * archive.h (Incremental_archive_entry): Forward declaration.
+ (Archive::set_incremental_info): New member function.
+ (Archive::incremental_info): New member function.
+ (Archive::Unused_symbol_iterator): New class.
+ (Archive::unused_symbols_begin): New member function.
+ (Archive::unused_symbols_end): New member function.
+ (Archive::incremental_info_): New data member.
+ * incremental-dump.cc (find_input_containing_global): New function.
+ (dump_incremental_inputs): Dump new incremental info sections.
+ * incremental.cc: Include symtab.h.
+ (Output_section_incremental_inputs): New class.
+ (Sized_incremental_binary::do_find_incremental_inputs_sections): Support
+ new incremental info sections.
+ (Sized_incremental_binary::do_check_inputs): Likewise.
+ (Incremental_inputs::report_archive): Remove.
+ (Incremental_inputs::report_archive_begin): New function.
+ (Incremental_inputs::report_archive_end): New function.
+ (Incremental_inputs::report_object): New function.
+ (Incremental_inputs::finalize_inputs): Remove.
+ (Incremental_inputs::report_input_section): New function.
+ (Incremental_inputs::report_script): Rewrite.
+ (Incremental_inputs::finalize): Do nothing but finalize string table.
+ (Incremental_inputs::create_incremental_inputs_section_data): Remove.
+ (Incremental_inputs::sized_create_inputs_section_data): Remove.
+ (Incremental_inputs::create_data_sections): New function.
+ (Incremental_inputs::relocs_entsize): New function.
+ (Output_section_incremental_inputs::set_final_data_size): New function.
+ (Output_section_incremental_inputs::do_write): New function.
+ (Output_section_incremental_inputs::write_header): New function.
+ (Output_section_incremental_inputs::write_input_files): New function.
+ (Output_section_incremental_inputs::write_info_blocks): New function.
+ (Output_section_incremental_inputs::write_symtab): New function.
+ * incremental.h (Incremental_script_entry): Forward declaration.
+ (Incremental_object_entry): Forward declaration.
+ (Incremental_archive_entry): Forward declaration.
+ (Incremental_inputs): Forward declaration.
+ (Incremental_inputs_header_data): Remove.
+ (Incremental_inputs_header): Remove.
+ (Incremental_inputs_header_write): Remove.
+ (Incremental_inputs_entry_data): Remove.
+ (Incremental_inputs_entry): Remove.
+ (Incremental_inputs_entry_write): Remove.
+ (enum Incremental_input_type): Add INCREMENTAL_INPUT_ARCHIVE_MEMBER.
+ (Incremental_binary::find_incremental_inputs_sections): Add parameters.
+ (Incremental_binary::do_find_incremental_inputs_sections): Likewise.
+ (Sized_ncremental_binary::do_find_incremental_inputs_sections):
+ Likewise.
+ (Incremental_input_entry): New class.
+ (Incremental_script_entry): New class.
+ (Incremental_object_entry): New class.
+ (Incremental_archive_entry): New class.
+ (Incremental_inputs::Incremental_inputs): Initialize new data members.
+ (Incremental_inputs::report_inputs): Remove.
+ (Incremental_inputs::report_archive): Remove.
+ (Incremental_inputs::report_archive_begin): New function.
+ (Incremental_inputs::report_archive_end): New function.
+ (Incremental_inputs::report_object): Change prototype.
+ (Incremental_inputs::report_input_section): New function.
+ (Incremental_inputs::report_script): Change prototype.
+ (Incremental_inputs::get_reloc_count): New function.
+ (Incremental_inputs::set_reloc_count): New function.
+ (Incremental_inputs::create_data_sections): New function.
+ (Incremental_inputs::create_incremental_inputs_section_data): Remove.
+ (Incremental_inputs::inputs_section): New function.
+ (Incremental_inputs::symtab_section): New function.
+ (Incremental_inputs::relocs_section): New function.
+ (Incremental_inputs::get_stringpool): Add const.
+ (Incremental_inputs::command_line): Add const.
+ (Incremental_inputs::inputs): Remove.
+ (Incremental_inputs::command_line_key): New function.
+ (Incremental_inputs::input_file_count): New function.
+ (Incremental_inputs::input_files): New function.
+ (Incremental_inputs::relocs_entsize): New function.
+ (Incremental_inputs::sized_create_inputs_section_data): Remove.
+ (Incremental_inputs::finalize_inputs): Remove.
+ (Incremental_inputs::Input_info): Remove.
+ (Incremental_inputs::lock_): Remove.
+ (Incremental_inputs::inputs_): Change type.
+ (Incremental_inputs::inputs_map_): Remove.
+ (Incremental_inputs::current_object_entry_): New data member.
+ (Incremental_inputs::inputs_section_): New data member.
+ (Incremental_inputs::symtab_section_): New data member.
+ (Incremental_inputs::relocs_section_): New data member.
+ (Incremental_inputs::reloc_count_): New data member.
+ (Incremental_inputs_reader): New class.
+ (Incremental_symtab_reader): New class.
+ (Incremental_relocs_reader): New class.
+ * layout.cc (Layout::finalize): Move finalization of incremental info
+ and creation of incremental info sections to follow finalization of
+ symbol table. Set offsets for postprocessing sections.
+ (Layout::create_incremental_info_sections): Call
+ Incremental_inputs::create_data_sections. Add incremental symtab
+ and relocs sections. Set sh_entsize and sh_link fields. Arrange for
+ sections to layout after input sections.
+ * layout.h (struct Timespec): Forward declaration.
+ (Layout::incremental_inputs): Add const.
+ (Layout::create_incremental_info_sections): Add parameter.
+ * main.cc (main): Remove call to Incremental_inputs::report_inputs.
+ * object.cc: Include incremental.h.
+ (Relobj::finalize_incremental_relocs): New function.
+ (Sized_relobj::do_layout): Record input sections in incremental info.
+ * object.h (Object::output_section): New function.
+ (Object::output_section_offset): Moved from Relobj.
+ (Object::get_incremental_reloc_base): New function.
+ (Object::get_incremental_reloc_count): New function.
+ (Object::do_output_section): New function.
+ (Object::do_output_section_offset): Moved from Relobj.
+ (Object::do_get_incremental_reloc_base): New function.
+ (Object::do_get_incremental_reloc_count): New function.
+ (Object::Object): Initialize new data members.
+ (Relobj::output_section): Renamed do_output_section and moved to
+ protected.
+ (Relobj::output_section_offset): Moved to Object.
+ (Relobj::do_get_incremental_reloc_base): New function.
+ (Relobj::do_get_incremental_reloc_count): New function.
+ (Relobj::allocate_incremental_reloc_counts): New function.
+ (Relobj::count_incremental_reloc): New function.
+ (Relobj::finalize_incremental_relocs): New function.
+ (Relobj::next_incremental_reloc_index): New function.
+ (Relobj::reloc_counts_): New data member.
+ (Relobj::reloc_bases_): New data member.
+ (Sized_relobj::do_relocate_sections): Add parameter. Change caller.
+ (Sized_relobj::relocate_sections): Add parameter. Change all callers.
+ (Sized_relobj::incremental_relocs_scan): New function.
+ (Sized_relobj::incremental_relocs_scan_reltype): New function.
+ (Sized_relobj::incremental_relocs_write): New function.
+ (Sized_relobj::incremental_relocs_write_reltype): New function.
+ * plugin.cc (Plugin_manager::add_input_file): Rewrite test for
+ incremental link.
+ * readsyms.cc (Read_symbols::do_read_symbols): Move reporting of
+ archives and object files elsewhere.
+ (Add_symbols::run): Report object files here.
+ (Finish_group::run): Report end of archive at end of group.
+ * reloc.cc: Include layout.h, incremental.h.
+ (Sized_relobj::do_read_relocs): Need relocations for incremental link.
+ (Sized_relobj::do_scan_relocs): Record relocations for incremental link.
+ (Sized_relobj::incremental_relocs_scan): New function.
+ (Sized_relobj::incremental_relocs_scan_reltype): New function.
+ (Sized_relobj::do_relocate_sections): Write incremental relocations.
+ (Sized_relobj::incremental_relocs_write): New function.
+ (Sized_relobj::incremental_relocs_write_reltype): New function.
+ * script.cc (read_input_script): Rewrite test for incremental link.
+ Change call to Incremental_inputs::report_script.
+ * symtab.h (Symbol_table::first_global_index): New function.
+ (Symbol_table::output_count): New function.
+
2010-08-12 Doug Kwan <dougkwan@google.com>
* arm.cc (Target_arm::merge_object_attributes): Check command line
diff --git a/gold/archive.cc b/gold/archive.cc
index f1000a1..8c34d55 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -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()
diff --git a/gold/archive.h b/gold/archive.h
index bff3457..9107d1e 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -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.
@@ -181,6 +192,69 @@ class Archive
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
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index e174b99..98555cd 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -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"
@@ -43,15 +44,51 @@ 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;
-
- t = inc->find_incremental_inputs_section(&location, &strtab_shndx);
+ 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;
+
+ // 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();
+ elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
+
+ // 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.
- Incremental_inputs_header<size, big_endian> incremental_header(p);
+ 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);
- const unsigned char* incremental_inputs_base =
- (p + sizeof(Incremental_inputs_header_data));
+ // Create a reader object for the .gnu_incremental_inputs section.
- if (incremental_header.get_version() != 1)
+ Incremental_inputs_reader<size, big_endian>
+ incremental_inputs(inputs_view.data(), istrtab);
+
+ if (incremental_inputs.version() != 1)
{
fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0,
- filename, incremental_header.get_version());
+ filename, incremental_inputs.version());
exit(1);
}
- elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
-
- if (elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
+ const char* command_line = incremental_inputs.command_line();
+ if (command_line == NULL)
{
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);
+ "%s: %s: failed to get link command line\n",
+ argv0, filename);
exit(1);
}
+ printf("Link command line: %s\n", command_line);
- Incremental_binary::Location
- strtab_location(elf_file.section_contents(strtab_shndx));
+ printf("\nInput files:\n");
+ for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+ {
+ typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+ typename Inputs_reader::Incremental_input_entry_reader input_file =
+ incremental_inputs.input_file(i);
+
+ 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");
+ 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);
+ }
+ }
- Incremental_binary::View strtab_view(inc->view(strtab_location));
- p = strtab_view.data();
+ 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);
+ }
+ }
- 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);
+ 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);
+ }
+ }
- if (!t)
+ // 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: failed to get link command line: %zu out of range\n",
- argv0, filename,
- static_cast<size_t>(command_line_offset));
- exit(1);
+ 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));
- printf("Link command line: %s\n", command_line);
+ // Get a view of the .strtab section.
- printf("Input files:\n");
- for (unsigned i = 0; i < incremental_header.get_input_file_count(); ++i)
+ 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)
{
- 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;
+ 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.
- t = strtab.get_c_string(input.get_filename_offset(), &objname);
- if (!t)
+ 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)
{
- 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();
- 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);
- }
+ 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
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 01be470..b279c72 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -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;
+
+ 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;
- *strtab_shndx = this->elf_file_.section_link(shndx);
- *location = this->elf_file_.section_contents(shndx);
+
+ 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 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_header<size, big_endian> header(data_view.data());
- if (header.get_version() != INCREMENTAL_LINK_VERSION)
- {
- explain_no_incremental(_("different version of incremental build data"));
- return false;
- }
+ Incremental_inputs_reader<size, big_endian>
+ incoming_inputs(inputs_view.data(), strtab);
- 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))
+ if (incoming_inputs.version() != INCREMENTAL_LINK_VERSION)
{
- explain_no_incremental(_("invalid incremental build data"));
+ explain_no_incremental(_("different version of 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_);
-
- 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));
+ Incremental_archive_entry* entry = arch->incremental_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
-// called by read_script after parsing the script and reading the list
-// of inputs added by this script.
+// 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_script(const Input_argument* input,
- Timespec mtime,
- Script_info* script)
+Incremental_inputs::report_object(Object* obj, Archive* arch)
{
- Hold_lock hl(*this->lock_);
+ 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);
- Input_info info;
- info.type = INCREMENTAL_INPUT_SCRIPT;
- info.script = script;
- info.mtime = mtime;
- this->inputs_map_.insert(std::make_pair(input, info));
+ 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;
}
-// 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).
+// 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::finalize_inputs(
- Input_argument_list::const_iterator begin,
- Input_argument_list::const_iterator end,
- unsigned int* index)
+Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
+ const char* name, off_t sh_size)
{
- 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;
- }
+ Stringpool::Key key = 0;
- 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);
- }
- }
+ 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 std::string& filename,
+ Script_info* script, Timespec mtime)
+{
+ Stringpool::Key filename_key;
+
+ 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;
-
- 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;
-
- 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_);
-
- 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)
+ const Incremental_inputs* inputs = this->inputs_;
+ const unsigned int sizeof_addr = size / 8;
+ const unsigned int rel_size = 8 + 2 * sizeof_addr;
+
+ // Offset of each input entry.
+ unsigned int input_offset = this->header_size;
+
+ // Offset of each supplemental info block.
+ unsigned int info_offset = this->header_size;
+ info_offset += this->input_entry_size * inputs->input_file_count();
+
+ // 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());
-
- 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 input file entry.
+ (*p)->set_offset(input_offset);
+ input_offset += this->input_entry_size;
+
+ // 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.
diff --git a/gold/incremental.h b/gold/incremental.h
index a94f397..6fb1a32 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -1,6 +1,6 @@
// inremental.h -- incremental linking support for gold -*- C++ -*-
-// 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.
@@ -38,221 +38,21 @@ namespace gold
class Archive;
class Input_argument;
class Incremental_inputs_checker;
+class Incremental_script_entry;
+class Incremental_object_entry;
+class Incremental_archive_entry;
+class Incremental_inputs;
class Object;
-class Output_section_data;
// Incremental input type as stored in .gnu_incremental_inputs.
enum Incremental_input_type
{
- INCREMENTAL_INPUT_INVALID = 0,
INCREMENTAL_INPUT_OBJECT = 1,
- INCREMENTAL_INPUT_ARCHIVE = 2,
- INCREMENTAL_INPUT_SHARED_LIBRARY = 3,
- INCREMENTAL_INPUT_SCRIPT = 4
-};
-
-// Header of the .gnu_incremental_input section.
-struct Incremental_inputs_header_data
-{
- // Incremental linker version.
- elfcpp::Elf_Word version;
-
- // Numer of input files in the link.
- elfcpp::Elf_Word input_file_count;
-
- // Offset of command line options in .gnu_incremental_strtab.
- elfcpp::Elf_Word command_line_offset;
-
- // Padding.
- elfcpp::Elf_Word reserved;
-};
-
-// Reader class for .gnu_incremental_inputs header. See
-// Incremental_inputs_header_data for fields descriptions.
-
-template<int size, bool big_endian>
-class Incremental_inputs_header
-{
- private:
- typedef Incremental_inputs_header_data Data_type;
- typedef elfcpp::Convert<32, big_endian> Convert32;
-
- public:
- Incremental_inputs_header(const unsigned char *p)
- : p_(reinterpret_cast<const Data_type*>(p))
- { }
-
- static const int data_size = sizeof(Data_type);
-
- elfcpp::Elf_Word
- get_version() const
- { return Convert32::convert_host(this->p_->version); }
-
- elfcpp::Elf_Word
- get_input_file_count() const
- { return Convert32::convert_host(this->p_->input_file_count); }
-
- elfcpp::Elf_Word
- get_command_line_offset() const
- { return Convert32::convert_host(this->p_->command_line_offset); }
-
- elfcpp::Elf_Word
- get_reserved() const
- { return Convert32::convert_host(this->p_->reserved); }
-
- private:
- const Data_type* p_;
-};
-
-// Writer class for .gnu_incremental_inputs header. See
-// Incremental_inputs_header_data for fields descriptions.
-
-template<int size, bool big_endian>
-class Incremental_inputs_header_write
-{
- private:
- typedef Incremental_inputs_header_data Data_type;
- typedef elfcpp::Convert<32, big_endian> Convert32;
-
- public:
- Incremental_inputs_header_write(unsigned char *p)
- : p_(reinterpret_cast<Data_type*>(p))
- { }
-
- static const int data_size = sizeof(Data_type);
-
- void
- put_version(elfcpp::Elf_Word v)
- { this->p_->version = Convert32::convert_host(v); }
-
- void
- put_input_file_count(elfcpp::Elf_Word v)
- { this->p_->input_file_count = Convert32::convert_host(v); }
-
- void
- put_command_line_offset(elfcpp::Elf_Word v)
- { this->p_->command_line_offset = Convert32::convert_host(v); }
-
- void
- put_reserved(elfcpp::Elf_Word v)
- { this->p_->reserved = Convert32::convert_host(v); }
-
- private:
- Data_type* p_;
-};
-
-// Data stored in .gnu_incremental_input after the header for each of the
-// Incremental_input_header_data::input_file_count input entries.
-struct Incremental_inputs_entry_data
-{
- // Offset of file name in .gnu_incremental_strtab section.
- elfcpp::Elf_Word filename_offset;
-
- // Offset of data in .gnu_incremental_input.
- elfcpp::Elf_Word data_offset;
-
- // Timestamp (in seconds).
- elfcpp::Elf_Xword timestamp_sec;
-
- // Nano-second part of timestamp (if supported).
- elfcpp::Elf_Word timestamp_nsec;
-
- // Type of the input entry.
- elfcpp::Elf_Half input_type;
-
- // Padding.
- elfcpp::Elf_Half reserved;
-};
-
-// Reader class for an .gnu_incremental_inputs entry. See
-// Incremental_inputs_entry_data for fields descriptions.
-template<int size, bool big_endian>
-class Incremental_inputs_entry
-{
- private:
- typedef Incremental_inputs_entry_data Data_type;
- typedef elfcpp::Convert<32, big_endian> Convert32;
- typedef elfcpp::Convert<64, big_endian> Convert64;
-
- public:
- Incremental_inputs_entry(const unsigned char *p)
- : p_(reinterpret_cast<const Data_type*>(p))
- { }
-
- static const int data_size = sizeof(Data_type);
-
- elfcpp::Elf_Word
- get_filename_offset()
- { return Convert32::convert_host(this->p_->filename_offset); }
-
- elfcpp::Elf_Word
- get_data_offset()
- { return Convert32::convert_host(this->p_->data_offset); }
-
- elfcpp::Elf_Xword
- get_timestamp_sec()
- { return Convert64::convert_host(this->p_->timestamp_sec); }
-
- elfcpp::Elf_Word
- get_timestamp_nsec()
- { return Convert32::convert_host(this->p_->timestamp_nsec); }
-
- elfcpp::Elf_Word
- get_input_type()
- { return Convert32::convert_host(this->p_->input_type); }
-
- elfcpp::Elf_Word
- get_reserved()
- { return Convert32::convert_host(this->p_->reserved); }
-
- private:
- const Data_type* p_;
-};
-
-// Writer class for an .gnu_incremental_inputs entry. See
-// Incremental_inputs_entry_data for fields descriptions.
-template<int size, bool big_endian>
-class Incremental_inputs_entry_write
-{
- private:
- typedef Incremental_inputs_entry_data Data_type;
- typedef elfcpp::Convert<32, big_endian> Convert32;
- typedef elfcpp::Convert<64, big_endian> Convert64;
-
- public:
- Incremental_inputs_entry_write(unsigned char *p)
- : p_(reinterpret_cast<Data_type*>(p))
- { }
-
- static const int data_size = sizeof(Data_type);
-
- void
- put_filename_offset(elfcpp::Elf_Word v)
- { this->p_->filename_offset = Convert32::convert_host(v); }
-
- void
- put_data_offset(elfcpp::Elf_Word v)
- { this->p_->data_offset = Convert32::convert_host(v); }
-
- void
- put_timestamp_sec(elfcpp::Elf_Xword v)
- { this->p_->timestamp_sec = Convert64::convert_host(v); }
-
- void
- put_timestamp_nsec(elfcpp::Elf_Word v)
- { this->p_->timestamp_nsec = Convert32::convert_host(v); }
-
- void
- put_input_type(elfcpp::Elf_Word v)
- { this->p_->input_type = Convert32::convert_host(v); }
-
- void
- put_reserved(elfcpp::Elf_Word v)
- { this->p_->reserved = Convert32::convert_host(v); }
-
- private:
- Data_type* p_;
+ INCREMENTAL_INPUT_ARCHIVE_MEMBER = 2,
+ INCREMENTAL_INPUT_ARCHIVE = 3,
+ INCREMENTAL_INPUT_SHARED_LIBRARY = 4,
+ INCREMENTAL_INPUT_SCRIPT = 5
};
// An object representing the ELF file we edit during an incremental build.
@@ -315,20 +115,27 @@ class Incremental_binary
};
// Get a View given a Location.
- View view(Location loc)
+ View
+ view(Location loc)
{ return View(this->view(loc.file_offset, loc.data_size)); }
// Report an error.
void
error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
- // Find the .gnu_incremental_inputs section. It selects the first section
- // of type SHT_GNU_INCREMENTAL_INPUTS. Returns false if such a section
- // is not found.
+ // Find the .gnu_incremental_inputs and related sections. It selects the
+ // first section of type SHT_GNU_INCREMENTAL_INPUTS,
+ // SHT_GNU_INCRMENTAL_SYMTAB, and SHT_GNU_INCREMENTAL_RELOCS.
+ // Returns false if the sections are not found.
bool
- find_incremental_inputs_section(Location* location,
- unsigned int* strtab_shndx)
- { return do_find_incremental_inputs_section(location, strtab_shndx); }
+ find_incremental_inputs_sections(unsigned int* p_inputs_shndx,
+ unsigned int* p_symtab_shndx,
+ unsigned int* p_relocs_shndx,
+ unsigned int* p_strtab_shndx)
+ {
+ return do_find_incremental_inputs_sections(p_inputs_shndx, p_symtab_shndx,
+ p_relocs_shndx, p_strtab_shndx);
+ }
// Check the .gnu_incremental_inputs section to see whether an incremental
// build is possible.
@@ -343,8 +150,10 @@ class Incremental_binary
protected:
// Find incremental inputs section.
virtual bool
- do_find_incremental_inputs_section(Location* location,
- unsigned int* strtab_shndx) = 0;
+ 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) = 0;
// Check the .gnu_incremental_inputs section to see whether an incremental
// build is possible.
@@ -370,8 +179,10 @@ class Sized_incremental_binary : public Incremental_binary
protected:
virtual bool
- do_find_incremental_inputs_section(Location* location,
- unsigned int* strtab_shndx);
+ 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);
virtual bool
do_check_inputs(Incremental_inputs* incremental_inputs);
@@ -383,11 +194,13 @@ class Sized_incremental_binary : public Incremental_binary
// 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.
+
Incremental_binary*
open_incremental_binary(Output_file* file);
// Code invoked early during an incremental link that checks what files need
// to be relinked.
+
class Incremental_checker
{
public:
@@ -415,135 +228,726 @@ class Incremental_checker
Incremental_inputs* incremental_inputs_;
};
+// Base class for recording each input file.
+
+class Incremental_input_entry
+{
+ public:
+ Incremental_input_entry(Stringpool::Key filename_key, Timespec mtime)
+ : filename_key_(filename_key), offset_(0), info_offset_(0), mtime_(mtime)
+ { }
+
+ // Return the type of input file.
+ Incremental_input_type
+ type() const
+ { return this->do_type(); }
+
+ // Set the section offset of this input file entry.
+ void
+ set_offset(unsigned int offset)
+ { this->offset_ = offset; }
+
+ // Set the section offset of the supplemental information for this entry.
+ void
+ set_info_offset(unsigned int info_offset)
+ { this->info_offset_ = info_offset; }
+
+ // Get the section offset of this input file entry.
+ unsigned int
+ get_offset() const
+ { return this->offset_; }
+
+ // Get the section offset of the supplemental information for this entry.
+ unsigned int
+ get_info_offset() const
+ { return this->info_offset_; }
+
+ // Get the stringpool key for the input filename.
+ Stringpool::Key
+ get_filename_key() const
+ { return this->filename_key_; }
+
+ // Get the modification time of the input file.
+ const Timespec&
+ get_mtime() const
+ { return this->mtime_; }
+
+ // Return a pointer to the derived Incremental_script_entry object.
+ // Return NULL for input entries that are not script files.
+ Incremental_script_entry*
+ script_entry()
+ { return this->do_script_entry(); }
+
+ // Return a pointer to the derived Incremental_object_entry object.
+ // Return NULL for input entries that are not object files.
+ Incremental_object_entry*
+ object_entry()
+ { return this->do_object_entry(); }
+
+ // Return a pointer to the derived Incremental_archive_entry object.
+ // Return NULL for input entries that are not archive files.
+ Incremental_archive_entry*
+ archive_entry()
+ { return this->do_archive_entry(); }
+
+ protected:
+ // Return the type of input file.
+ virtual Incremental_input_type
+ do_type() const = 0;
+
+ // Return a pointer to the derived Incremental_script_entry object.
+ // Return NULL for input entries that are not script files.
+ virtual Incremental_script_entry*
+ do_script_entry()
+ { return NULL; }
+
+ // Return a pointer to the derived Incremental_object_entry object.
+ // Return NULL for input entries that are not object files.
+ virtual Incremental_object_entry*
+ do_object_entry()
+ { return NULL; }
+
+ // Return a pointer to the derived Incremental_archive_entry object.
+ // Return NULL for input entries that are not archive files.
+ virtual Incremental_archive_entry*
+ do_archive_entry()
+ { return NULL; }
+
+ private:
+ // Key of the filename string in the section stringtable.
+ Stringpool::Key filename_key_;
+
+ // Offset of the entry in the output section.
+ unsigned int offset_;
+
+ // Offset of the extra information in the output section.
+ unsigned int info_offset_;
+
+ // Last modification time of the file.
+ Timespec mtime_;
+};
+
+// Class for recording input scripts.
+
+class Incremental_script_entry : public Incremental_input_entry
+{
+ public:
+ Incremental_script_entry(Stringpool::Key filename_key, Script_info* script,
+ Timespec mtime)
+ : Incremental_input_entry(filename_key, mtime), script_(script)
+ { }
+
+ protected:
+ virtual Incremental_input_type
+ do_type() const
+ { return INCREMENTAL_INPUT_SCRIPT; }
+
+ // Return a pointer to the derived Incremental_script_entry object.
+ virtual Incremental_script_entry*
+ do_script_entry()
+ { return this; }
+
+ private:
+ // Information about the script file.
+ Script_info* script_;
+};
+
+// Class for recording input object files.
+
+class Incremental_object_entry : public Incremental_input_entry
+{
+ public:
+ Incremental_object_entry(Stringpool::Key filename_key, Object* obj,
+ Timespec mtime)
+ : Incremental_input_entry(filename_key, mtime), obj_(obj),
+ is_member_(false), sections_()
+ {
+ if (!obj_->is_dynamic())
+ this->sections_.reserve(obj->shnum());
+ }
+
+ // Get the object.
+ Object*
+ object() const
+ { return this->obj_; }
+
+ // Record that this object is an archive member.
+ void
+ set_is_member()
+ { this->is_member_ = true; }
+
+ // Return true if this object is an archive member.
+ bool
+ is_member() const
+ { return this->is_member_; }
+
+ // Add an input section.
+ void
+ add_input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size)
+ {
+ if (shndx >= this->sections_.size())
+ this->sections_.resize(shndx + 1);
+ this->sections_[shndx].name_key = name_key;
+ this->sections_[shndx].sh_size = sh_size;
+ }
+
+ // Return the number of input sections in this object.
+ unsigned int
+ get_input_section_count() const
+ { return this->sections_.size(); }
+
+ // Return the stringpool key of the Nth input section.
+ Stringpool::Key
+ get_input_section_name_key(unsigned int n) const
+ { return this->sections_[n].name_key; }
+
+ // Return the size of the Nth input section.
+ off_t
+ get_input_section_size(unsigned int n) const
+ { return this->sections_[n].sh_size; }
+
+ protected:
+ virtual Incremental_input_type
+ do_type() const
+ {
+ return (this->is_member_
+ ? INCREMENTAL_INPUT_ARCHIVE_MEMBER
+ : (this->obj_->is_dynamic()
+ ? INCREMENTAL_INPUT_SHARED_LIBRARY
+ : INCREMENTAL_INPUT_OBJECT));
+ }
+
+ // Return a pointer to the derived Incremental_object_entry object.
+ virtual Incremental_object_entry*
+ do_object_entry()
+ { return this; }
+
+ private:
+ // The object file itself.
+ Object* obj_;
+
+ // Whether this object is an archive member.
+ bool is_member_;
+
+ // Input sections.
+ struct Input_section
+ {
+ Stringpool::Key name_key;
+ off_t sh_size;
+ };
+ std::vector<Input_section> sections_;
+};
+
+// Class for recording archive library input files.
+
+class Incremental_archive_entry : public Incremental_input_entry
+{
+ public:
+ Incremental_archive_entry(Stringpool::Key filename_key, Archive*,
+ Timespec mtime)
+ : Incremental_input_entry(filename_key, mtime), members_(), unused_syms_()
+ { }
+
+ // Add a member object to the archive.
+ void
+ add_object(Incremental_object_entry* obj_entry)
+ {
+ this->members_.push_back(obj_entry);
+ obj_entry->set_is_member();
+ }
+
+ // Add an unused global symbol to the archive.
+ void
+ add_unused_global_symbol(Stringpool::Key symbol_key)
+ { this->unused_syms_.push_back(symbol_key); }
+
+ // Return the number of member objects included in the link.
+ unsigned int
+ get_member_count()
+ { return this->members_.size(); }
+
+ // Return the Nth member object.
+ Incremental_object_entry*
+ get_member(unsigned int n)
+ { return this->members_[n]; }
+
+ // Return the number of unused global symbols in this archive.
+ unsigned int
+ get_unused_global_symbol_count()
+ { return this->unused_syms_.size(); }
+
+ // Return the Nth unused global symbol.
+ Stringpool::Key
+ get_unused_global_symbol(unsigned int n)
+ { return this->unused_syms_[n]; }
+
+ protected:
+ virtual Incremental_input_type
+ do_type() const
+ { return INCREMENTAL_INPUT_ARCHIVE; }
+
+ // Return a pointer to the derived Incremental_archive_entry object.
+ virtual Incremental_archive_entry*
+ do_archive_entry()
+ { return this; }
+
+ private:
+ // Members of the archive that have been included in the link.
+ std::vector<Incremental_object_entry*> members_;
+
+ // Unused global symbols from this archive.
+ std::vector<Stringpool::Key> unused_syms_;
+};
+
// This class contains the information needed during an incremental
// build about the inputs necessary to build the .gnu_incremental_inputs.
+
class Incremental_inputs
{
public:
+ typedef std::vector<Incremental_input_entry*> Input_list;
+
Incremental_inputs()
- : lock_(new Lock()), inputs_(NULL), command_line_key_(0),
- strtab_(new Stringpool())
+ : inputs_(), command_line_(), command_line_key_(0),
+ strtab_(new Stringpool()), current_object_(NULL),
+ current_object_entry_(NULL), inputs_section_(NULL),
+ symtab_section_(NULL), relocs_section_(NULL),
+ reloc_count_(0)
{ }
+
~Incremental_inputs() { delete this->strtab_; }
// Record the command line.
void
report_command_line(int argc, const char* const* argv);
- // Record the input arguments obtained from parsing the command line.
+ // Record the initial info for archive file ARCHIVE.
+ void
+ report_archive_begin(Archive* arch);
+
+ // Record the final info for archive file ARCHIVE.
+ void
+ report_archive_end(Archive* arch);
+
+ // Record the info for object file OBJ. If ARCH is not NULL,
+ // attach the object file to the archive.
void
- report_inputs(const Input_arguments& inputs)
- { this->inputs_ = &inputs; }
+ report_object(Object* obj, Archive* arch);
- // Record that the input argument INPUT is an archive ARCHIVE.
+ // Record an input section belonging to object file OBJ.
void
- report_archive(const Input_argument* input, Archive* archive);
+ report_input_section(Object* obj, unsigned int shndx, const char* name,
+ off_t sh_size);
- // Record that the input argument INPUT is to an object OBJ.
+ // Record the info for input script SCRIPT.
void
- report_object(const Input_argument* input, Object* obj);
+ report_script(const std::string& filename, Script_info* script,
+ Timespec mtime);
+
+ // Return the running count of incremental relocations.
+ unsigned int
+ get_reloc_count() const
+ { return this->reloc_count_; }
- // Record that the input argument INPUT is to an script SCRIPT.
+ // Update the running count of incremental relocations.
void
- report_script(const Input_argument* input, Timespec mtime,
- Script_info* script);
+ set_reloc_count(unsigned int count)
+ { this->reloc_count_ = count; }
// Prepare for layout. Called from Layout::finalize.
void
finalize();
- // Create the content of the .gnu_incremental_inputs section.
+ // Create the .gnu_incremental_inputs and related sections.
+ void
+ create_data_sections(Symbol_table* symtab);
+
+ // Return the .gnu_incremental_inputs section.
Output_section_data*
- create_incremental_inputs_section_data();
+ inputs_section() const
+ { return this->inputs_section_; }
+
+ // Return the .gnu_incremental_symtab section.
+ Output_data_space*
+ symtab_section() const
+ { return this->symtab_section_; }
+
+ // Return the .gnu_incremental_relocs section.
+ Output_data_space*
+ relocs_section() const
+ { return this->relocs_section_; }
// Return the .gnu_incremental_strtab stringpool.
Stringpool*
- get_stringpool()
+ get_stringpool() const
{ return this->strtab_; }
// Return the canonical form of the command line, as will be stored in
// .gnu_incremental_strtab.
const std::string&
- command_line()
+ command_line() const
{ return this->command_line_; }
- // Return the input files found in the command line.
- const Input_arguments*
- inputs()
+ // Return the stringpool key of the command line.
+ Stringpool::Key
+ command_line_key() const
+ { return this->command_line_key_; }
+
+ // Return the number of input files.
+ int
+ input_file_count() const
+ { return this->inputs_.size(); }
+
+ // Return the input files.
+ const Input_list&
+ input_files() const
{ return this->inputs_; }
+ // Return the sh_entsize value for the .gnu_incremental_relocs section.
+ unsigned int
+ relocs_entsize() const;
+
private:
- // Code for each of the four possible variants of create_inputs_section_data.
- template<int size, bool big_endian>
- Output_section_data*
- sized_create_inputs_section_data();
+ // The list of input files.
+ Input_list inputs_;
- // Compute indexes in the order in which the inputs should appear in
- // .gnu_incremental_inputs and put file names to the stringtable.
- // This needs to be done after all the scripts are parsed.
+ // Canonical form of the command line, as will be stored in
+ // .gnu_incremental_strtab.
+ std::string command_line_;
- void
- finalize_inputs(Input_argument_list::const_iterator begin,
- Input_argument_list::const_iterator end,
- unsigned int* index);
+ // The key of the command line string in the string pool.
+ Stringpool::Key command_line_key_;
+
+ // The .gnu_incremental_strtab string pool associated with the
+ // .gnu_incremental_inputs.
+ Stringpool* strtab_;
+
+ // Keep track of the object currently being processed.
+ Object* current_object_;
+ Incremental_object_entry* current_object_entry_;
+
+ // The .gnu_incremental_inputs section.
+ Output_section_data* inputs_section_;
- // Additional data about an input needed for an incremental link.
- // None of these pointers is owned by the structure.
- struct Input_info
+ // The .gnu_incremental_symtab section.
+ Output_data_space* symtab_section_;
+
+ // The .gnu_incremental_relocs section.
+ Output_data_space* relocs_section_;
+
+ // Total count of incremental relocations. Updated during Scan_relocs
+ // phase at the completion of each object file.
+ unsigned int reloc_count_;
+};
+
+// Reader class for .gnu_incremental_inputs section.
+
+template<int size, bool big_endian>
+class Incremental_inputs_reader
+{
+ private:
+ 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;
+
+ public:
+ Incremental_inputs_reader(const unsigned char* p, elfcpp::Elf_strtab& strtab)
+ : p_(p), strtab_(strtab)
+ { this->input_file_count_ = Swap32::readval(this->p_ + 4); }
+
+ // Return the version number.
+ unsigned int
+ version() const
+ { return Swap32::readval(this->p_); }
+
+ // Return the count of input file entries.
+ unsigned int
+ input_file_count() const
+ { return this->input_file_count_; }
+
+ // Return the command line.
+ const char*
+ command_line() const
{
- Input_info()
- : type(INCREMENTAL_INPUT_INVALID), archive(NULL), filename_key(0),
- index(0)
- { }
+ unsigned int offset = Swap32::readval(this->p_ + 8);
+ return this->get_string(offset);
+ }
- // Type of the file pointed by this argument.
- Incremental_input_type type;
+ // Reader class for an input file entry and its supplemental info.
+ class Incremental_input_entry_reader
+ {
+ public:
+ Incremental_input_entry_reader(const Incremental_inputs_reader* inputs,
+ unsigned int offset)
+ : inputs_(inputs), offset_(offset)
+ {
+ this->info_offset_ = Swap32::readval(inputs->p_ + offset + 4);
+ int type = Swap16::readval(this->inputs_->p_ + offset + 20);
+ this->type_ = static_cast<Incremental_input_type>(type);
+ }
+
+ // Return the filename.
+ const char*
+ filename() const
+ {
+ unsigned int offset = Swap32::readval(this->inputs_->p_ + this->offset_);
+ return this->inputs_->get_string(offset);
+ }
- union
+ // Return the timestamp.
+ Timespec
+ get_mtime() const
+ {
+ Timespec t;
+ const unsigned char* p = this->inputs_->p_ + this->offset_ + 8;
+ t.seconds = Swap64::readval(p);
+ t.nanoseconds = Swap32::readval(p+8);
+ return t;
+ }
+
+ // Return the type of input file.
+ Incremental_input_type
+ type() const
+ { return this->type_; }
+
+ // Return the input section count -- for objects only.
+ unsigned int
+ get_input_section_count() const
{
- // Present if type == INCREMENTAL_INPUT_ARCHIVE.
- Archive* archive;
+ gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT
+ || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_);
+ }
+
+ // Return the offset of the supplemental info for symbol SYMNDX --
+ // for objects only.
+ unsigned int
+ get_symbol_offset(unsigned int symndx) const
+ {
+ gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT
+ || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+
+ unsigned int section_count = this->get_input_section_count();
+ return (this->info_offset_ + 8
+ + section_count * input_section_entry_size
+ + symndx * 16);
+ }
+
+ // Return the global symbol count -- for objects & shared libraries only.
+ unsigned int
+ get_global_symbol_count() const
+ {
+ switch (this->type_)
+ {
+ case INCREMENTAL_INPUT_OBJECT:
+ case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
+ case INCREMENTAL_INPUT_SHARED_LIBRARY:
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_);
+ default:
+ gold_unreachable();
+ }
+ }
+
+ // Return the member count -- for archives only.
+ unsigned int
+ get_member_count() const
+ {
+ gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_);
+ }
- // Present if type == INCREMENTAL_INPUT_OBJECT or
- // INCREMENTAL_INPUT_SHARED_LIBRARY.
- Object* object;
+ // Return the unused symbol count -- for archives only.
+ unsigned int
+ get_unused_symbol_count() const
+ {
+ gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
+ }
- // Present if type == INCREMENTAL_INPUT_SCRIPT.
- Script_info* script;
+ // Return the input file offset for archive member N -- for archives only.
+ unsigned int
+ get_member_offset(unsigned int n) const
+ {
+ gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_
+ + 8 + n * 4);
+ }
+
+ // Return the Nth unused global symbol -- for archives only.
+ const char*
+ get_unused_symbol(unsigned int n) const
+ {
+ gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+ unsigned int member_count = this->get_member_count();
+ unsigned int offset = Swap32::readval(this->inputs_->p_
+ + this->info_offset_ + 8
+ + member_count * 4
+ + n * 4);
+ return this->inputs_->get_string(offset);
+ }
+
+ // Information about an input section.
+ struct Input_section_info
+ {
+ const char* name;
+ unsigned int output_shndx;
+ off_t sh_offset;
+ off_t sh_size;
};
- // Key of the filename string in the section stringtable.
- Stringpool::Key filename_key;
+ // Return info about the Nth input section -- for objects only.
+ Input_section_info
+ get_input_section(unsigned int n) const
+ {
+ Input_section_info info;
+ const unsigned char* p = (this->inputs_->p_
+ + this->info_offset_ + 8
+ + n * input_section_entry_size);
+ unsigned int name_offset = Swap32::readval(p);
+ info.name = this->inputs_->get_string(name_offset);
+ info.output_shndx = Swap32::readval(p + 4);
+ info.sh_offset = Swap::readval(p + 8);
+ info.sh_size = Swap::readval(p + 8 + size / 8);
+ return info;
+ }
+
+ // Information about a global symbol.
+ struct Global_symbol_info
+ {
+ unsigned int output_symndx;
+ unsigned int next_offset;
+ unsigned int reloc_count;
+ unsigned int reloc_offset;
+ };
- // Position of the entry information in the output section.
- unsigned int index;
+ // Return info about the Nth global symbol -- for objects only.
+ Global_symbol_info
+ get_global_symbol_info(unsigned int n) const
+ {
+ Global_symbol_info info;
+ unsigned int section_count = this->get_input_section_count();
+ const unsigned char* p = (this->inputs_->p_
+ + this->info_offset_ + 8
+ + section_count * input_section_entry_size
+ + n * 16);
+ info.output_symndx = Swap32::readval(p);
+ info.next_offset = Swap32::readval(p + 4);
+ info.reloc_count = Swap::readval(p + 8);
+ info.reloc_offset = Swap::readval(p + 12);
+ return info;
+ }
- // Last modification time of the file.
- Timespec mtime;
+ private:
+ // Size of an input section entry.
+ static const unsigned int input_section_entry_size = 8 + 2 * size / 8;
+ // The reader instance for the containing section.
+ const Incremental_inputs_reader* inputs_;
+ // The type of input file.
+ Incremental_input_type type_;
+ // Section offset to the input file entry.
+ unsigned int offset_;
+ // Section offset to the supplemental info for the input file.
+ unsigned int info_offset_;
};
- typedef std::map<const Input_argument*, Input_info> Inputs_info_map;
+ // Return a reader for the Nth input file entry.
+ Incremental_input_entry_reader
+ input_file(unsigned int n) const
+ {
+ gold_assert(n < this->input_file_count_);
+ Incremental_input_entry_reader input(this, 16 + n * 24);
+ return input;
+ }
+
+ private:
+ // Lookup a string in the ELF string table.
+ const char* get_string(unsigned int offset) const
+ {
+ const char* s;
+ if (this->strtab_.get_c_string(offset, &s))
+ return s;
+ return NULL;
+ }
+
+ // Base address of the .gnu_incremental_inputs section.
+ const unsigned char* p_;
+ // The associated ELF string table.
+ elfcpp::Elf_strtab strtab_;
+ // The number of input file entries in this section.
+ unsigned int input_file_count_;
+};
+
+// Reader class for the .gnu_incremental_symtab section.
- // A lock guarding access to inputs_ during the first phase of linking, when
- // report_ function may be called from multiple threads.
- Lock* lock_;
+template<bool big_endian>
+class Incremental_symtab_reader
+{
+ public:
+ Incremental_symtab_reader(const unsigned char* p) : p_(p)
+ { }
- // The list of input arguments obtained from parsing the command line.
- const Input_arguments* inputs_;
+ // Return the list head for symbol table entry N.
+ unsigned int get_list_head(unsigned int n)
+ { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); }
- // A map containing additional information about the input elements.
- Inputs_info_map inputs_map_;
+ private:
+ // Base address of the .gnu_incremental_relocs section.
+ const unsigned char* p_;
+};
- // Canonical form of the command line, as will be stored in
- // .gnu_incremental_strtab.
- std::string command_line_;
+// Reader class for the .gnu_incremental_relocs section.
- // The key of the command line string in the string pool.
- Stringpool::Key command_line_key_;
+template<int size, bool big_endian>
+class Incremental_relocs_reader
+{
+ private:
+ // Size of each field.
+ static const unsigned int field_size = size / 8;
- // The .gnu_incremental_strtab string pool associated with the
- // .gnu_incremental_inputs.
- Stringpool* strtab_;
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend;
+
+ // Size of each entry.
+ static const unsigned int reloc_size = 8 + 2 * field_size;
+
+ Incremental_relocs_reader(const unsigned char* p) : p_(p)
+ { }
+
+ // Return the relocation type for relocation entry at offset OFF.
+ unsigned int
+ get_r_type(unsigned int off)
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->p_ + off);
+ }
+
+ // Return the output section index for relocation entry at offset OFF.
+ unsigned int
+ get_r_shndx(unsigned int off)
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4);
+ }
+
+ // Return the output section offset for relocation entry at offset OFF.
+ Address
+ get_r_offset(unsigned int off)
+ {
+ return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8);
+ }
+
+ // Return the addend for relocation entry at offset OFF.
+ Addend
+ get_r_addend(unsigned int off)
+ {
+ return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8
+ + this->field_size);
+ }
+
+ private:
+ // Base address of the .gnu_incremental_relocs section.
+ const unsigned char* p_;
};
} // End namespace gold.
diff --git a/gold/layout.cc b/gold/layout.cc
index 3a01e92..eb1322a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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
diff --git a/gold/layout.h b/gold/layout.h
index 6a3a16c..87ee09e 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -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.
diff --git a/gold/main.cc b/gold/main.cc
index 631f1ac..91d5193 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -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();
diff --git a/gold/object.cc b/gold/object.cc
index 1bf7367..b3d9870 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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.
diff --git a/gold/object.h b/gold/object.h
index 59b723f..99ceabf 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -387,6 +387,18 @@ class Object
section_addralign(unsigned int shndx)
{ return this->do_section_addralign(shndx); }
+ // Return the output section given a section index.
+ Output_section*
+ output_section(unsigned int shndx) const
+ { return this->do_output_section(shndx); }
+
+ // Given a section index, return the offset in the Output_section.
+ // The return value will be -1U if the section is specially mapped,
+ // such as a merge section.
+ uint64_t
+ output_section_offset(unsigned int shndx) const
+ { return this->do_output_section_offset(shndx); }
+
// Read the symbol information.
void
read_symbols(Read_symbols_data* sd)
@@ -525,6 +537,16 @@ class Object
section_size_type* uncompressed_size) const
{ return this->do_section_is_compressed(shndx, uncompressed_size); }
+ // Return the index of the first incremental relocation for symbol SYMNDX.
+ unsigned int
+ get_incremental_reloc_base(unsigned int symndx) const
+ { return this->do_get_incremental_reloc_base(symndx); }
+
+ // Return the number of incremental relocations for symbol SYMNDX.
+ unsigned int
+ get_incremental_reloc_count(unsigned int symndx) const
+ { return this->do_get_incremental_reloc_count(symndx); }
+
protected:
// Returns NULL for Objects that are not plugin objects. This method
// is overridden in the Pluginobj class.
@@ -590,6 +612,17 @@ class Object
virtual uint64_t
do_section_addralign(unsigned int shndx) = 0;
+ // Return the output section given a section index--implemented
+ // by child class.
+ virtual Output_section*
+ do_output_section(unsigned int) const
+ { gold_unreachable(); }
+
+ // Get the offset of a section--implemented by child class.
+ virtual uint64_t
+ do_output_section_offset(unsigned int) const
+ { gold_unreachable(); }
+
// Return the Xindex structure to use.
virtual Xindex*
do_initialize_xindex() = 0;
@@ -641,6 +674,18 @@ class Object
do_section_is_compressed(unsigned int, section_size_type*) const
{ return false; }
+ // Return the index of the first incremental relocation for symbol SYMNDX--
+ // implemented by child class.
+ virtual unsigned int
+ do_get_incremental_reloc_base(unsigned int) const
+ { gold_unreachable(); }
+
+ // Return the number of incremental relocations for symbol SYMNDX--
+ // implemented by child class.
+ virtual unsigned int
+ do_get_incremental_reloc_count(unsigned int) const
+ { gold_unreachable(); }
+
private:
// This class may not be copied.
Object(const Object&);
@@ -685,7 +730,9 @@ class Relobj : public Object
map_to_relocatable_relocs_(NULL),
object_merge_map_(NULL),
relocs_must_follow_section_writes_(false),
- sd_(NULL)
+ sd_(NULL),
+ reloc_counts_(NULL),
+ reloc_bases_(NULL)
{ }
// During garbage collection, the Read_symbols_data pass for
@@ -781,16 +828,6 @@ class Relobj : public Object
return this->output_sections_[shndx] != NULL;
}
- // Given a section index, return the corresponding Output_section.
- // The return value will be NULL if the section is not included in
- // the link.
- Output_section*
- output_section(unsigned int shndx) const
- {
- gold_assert(shndx < this->output_sections_.size());
- return this->output_sections_[shndx];
- }
-
// The the output section of the input section with index SHNDX.
// This is only used currently to remove a section from the link in
// relaxation.
@@ -801,13 +838,6 @@ class Relobj : public Object
this->output_sections_[shndx] = os;
}
- // Given a section index, return the offset in the Output_section.
- // The return value will be -1U if the section is specially mapped,
- // such as a merge section.
- uint64_t
- output_section_offset(unsigned int shndx) const
- { return this->do_output_section_offset(shndx); }
-
// Set the offset of an input section within its output section.
void
set_section_offset(unsigned int shndx, uint64_t off)
@@ -856,6 +886,16 @@ class Relobj : public Object
layout_deferred_sections(Layout* layout)
{ this->do_layout_deferred_sections(layout); }
+ // Return the index of the first incremental relocation for symbol SYMNDX.
+ virtual unsigned int
+ do_get_incremental_reloc_base(unsigned int symndx) const
+ { return this->reloc_bases_[symndx]; }
+
+ // Return the number of incremental relocations for symbol SYMNDX.
+ virtual unsigned int
+ do_get_incremental_reloc_count(unsigned int symndx) const
+ { return this->reloc_counts_[symndx]; }
+
protected:
// The output section to be used for each input section, indexed by
// the input section number. The output section is NULL if the
@@ -902,10 +942,6 @@ class Relobj : public Object
virtual void
do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of) = 0;
- // Get the offset of a section--implemented by child class.
- virtual uint64_t
- do_output_section_offset(unsigned int shndx) const = 0;
-
// Set the offset of a section--implemented by child class.
virtual void
do_set_section_offset(unsigned int shndx, uint64_t off) = 0;
@@ -915,6 +951,16 @@ class Relobj : public Object
virtual void
do_layout_deferred_sections(Layout*) = 0;
+ // Given a section index, return the corresponding Output_section.
+ // The return value will be NULL if the section is not included in
+ // the link.
+ Output_section*
+ do_output_section(unsigned int shndx) const
+ {
+ gold_assert(shndx < this->output_sections_.size());
+ return this->output_sections_[shndx];
+ }
+
// Return the vector mapping input sections to output sections.
Output_sections&
output_sections()
@@ -938,6 +984,46 @@ class Relobj : public Object
set_relocs_must_follow_section_writes()
{ this->relocs_must_follow_section_writes_ = true; }
+ // Allocate the array for counting incremental relocations.
+ void
+ allocate_incremental_reloc_counts()
+ {
+ unsigned int nsyms = this->do_get_global_symbols()->size();
+ this->reloc_counts_ = new unsigned int[nsyms];
+ gold_assert(this->reloc_counts_ != NULL);
+ memset(this->reloc_counts_, 0, nsyms * sizeof(unsigned int));
+ }
+
+ // Record a relocation in this object referencing global symbol SYMNDX.
+ // Used for tracking incremental link information.
+ void
+ count_incremental_reloc(unsigned int symndx)
+ {
+ unsigned int nsyms = this->do_get_global_symbols()->size();
+ gold_assert(symndx < nsyms);
+ gold_assert(this->reloc_counts_ != NULL);
+ ++this->reloc_counts_[symndx];
+ }
+
+ // Finalize the incremental relocation information.
+ void
+ finalize_incremental_relocs(Layout* layout);
+
+ // Return the index of the next relocation to be written for global symbol
+ // SYMNDX. Only valid after finalize_incremental_relocs() has been called.
+ unsigned int
+ next_incremental_reloc_index(unsigned int symndx)
+ {
+ unsigned int nsyms = this->do_get_global_symbols()->size();
+
+ gold_assert(this->reloc_counts_ != NULL);
+ gold_assert(this->reloc_bases_ != NULL);
+ gold_assert(symndx < nsyms);
+
+ unsigned int counter = this->reloc_counts_[symndx]++;
+ return this->reloc_bases_[symndx] + counter;
+ }
+
private:
// Mapping from input sections to output section.
Output_sections output_sections_;
@@ -957,6 +1043,10 @@ class Relobj : public Object
// Again used during garbage collection when laying out referenced
// sections.
gold::Symbols_data *sd_;
+ // Per-symbol counts of relocations, for incremental links.
+ unsigned int* reloc_counts_;
+ // Per-symbol base indexes of relocations, for incremental links.
+ unsigned int* reloc_bases_;
};
// This class is used to handle relocations against a section symbol
@@ -1792,7 +1882,8 @@ class Sized_relobj : public Relobj
// This may be overriden by a child class.
virtual void
do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
- const unsigned char* pshdrs, Views* pviews);
+ const unsigned char* pshdrs, Output_file* of,
+ Views* pviews);
// Allow a child to set output local symbol count.
void
@@ -1880,8 +1971,9 @@ class Sized_relobj : public Relobj
// Relocate the sections in the output file.
void
relocate_sections(const Symbol_table* symtab, const Layout* layout,
- const unsigned char* pshdrs, Views* pviews)
- { this->do_relocate_sections(symtab, layout, pshdrs, pviews); }
+ const unsigned char* pshdrs, Output_file* of,
+ Views* pviews)
+ { this->do_relocate_sections(symtab, layout, pshdrs, of, pviews); }
// Scan the input relocations for --emit-relocs.
void
@@ -1918,6 +2010,35 @@ class Sized_relobj : public Relobj
unsigned char* reloc_view,
section_size_type reloc_view_size);
+ // Scan the input relocations for --incremental.
+ void
+ incremental_relocs_scan(const Read_relocs_data::Relocs_list::iterator&);
+
+ // Scan the input relocations for --incremental, templatized on the
+ // type of the relocation section.
+ template<int sh_type>
+ void
+ incremental_relocs_scan_reltype(
+ const Read_relocs_data::Relocs_list::iterator&);
+
+ void
+ incremental_relocs_write(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section*,
+ Address output_offset,
+ Output_file*);
+
+ template<int sh_type>
+ void
+ incremental_relocs_write_reltype(const Relocate_info<size, big_endian>*,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section*,
+ Address output_offset,
+ Output_file*);
+
// A type shared by split_stack_adjust_reltype and find_functions.
typedef std::map<section_offset_type, section_size_type> Function_offsets;
diff --git a/gold/plugin.cc b/gold/plugin.cc
index 1c86c03..4680067 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -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_,
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index d8af99b..1cec3b3 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -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_;
}
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 9f7355e..8938988 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -25,6 +25,7 @@
#include <algorithm>
#include "workqueue.h"
+#include "layout.h"
#include "symtab.h"
#include "output.h"
#include "merge.h"
@@ -33,6 +34,7 @@
#include "reloc.h"
#include "icf.h"
#include "compressed_output.h"
+#include "incremental.h"
namespace gold
{
@@ -300,7 +302,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
!= 0);
if (!is_section_allocated
&& !parameters->options().relocatable()
- && !parameters->options().emit_relocs())
+ && !parameters->options().emit_relocs()
+ && !parameters->options().incremental())
continue;
if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
@@ -424,6 +427,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
else
local_symbols = rd->local_symbols->data();
+ // For incremental links, allocate the counters for incremental relocations.
+ if (layout->incremental_inputs() != NULL)
+ this->allocate_incremental_reloc_counts();
+
for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
p != rd->relocs.end();
++p)
@@ -451,6 +458,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
local_symbols);
if (parameters->options().emit_relocs())
this->emit_relocs_scan(symtab, layout, local_symbols, p);
+ if (layout->incremental_inputs() != NULL)
+ this->incremental_relocs_scan(p);
}
else
{
@@ -472,6 +481,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
p->contents = NULL;
}
+ // For incremental links, finalize the allocation of relocations.
+ if (layout->incremental_inputs() != NULL)
+ this->finalize_incremental_relocs(layout);
+
if (rd->local_symbols != NULL)
{
delete rd->local_symbols;
@@ -567,6 +580,54 @@ Sized_relobj<size, big_endian>::emit_relocs_scan_reltype(
rr);
}
+// Scan the input relocations for --incremental.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_scan(
+ const Read_relocs_data::Relocs_list::iterator& p)
+{
+ if (p->sh_type == elfcpp::SHT_REL)
+ this->incremental_relocs_scan_reltype<elfcpp::SHT_REL>(p);
+ else
+ {
+ gold_assert(p->sh_type == elfcpp::SHT_RELA);
+ this->incremental_relocs_scan_reltype<elfcpp::SHT_RELA>(p);
+ }
+}
+
+// Scan the input relocation for --emit-relocs, templatized on the
+// type of the relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_scan_reltype(
+ const Read_relocs_data::Relocs_list::iterator& p)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const unsigned char* prelocs = p->contents->data();
+ size_t reloc_count = p->reloc_count;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ if (p->needs_special_offset_handling
+ && !p->output_section->is_input_address_mapped(this, p->data_shndx,
+ reloc.get_r_offset()))
+ continue;
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+ reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+
+ if (r_sym >= this->local_symbol_count_)
+ this->count_incremental_reloc(r_sym - this->local_symbol_count_);
+ }
+}
+
// Relocate the input sections and write out the local symbols.
template<int size, bool big_endian>
@@ -597,7 +658,7 @@ Sized_relobj<size, big_endian>::do_relocate(const Symbol_table* symtab,
// Apply relocations.
- this->relocate_sections(symtab, layout, pshdrs, &views);
+ this->relocate_sections(symtab, layout, pshdrs, of, &views);
// After we've done the relocations, we release the hash tables,
// since we no longer need them.
@@ -827,6 +888,7 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
Views* pviews)
{
unsigned int shnum = this->shnum();
@@ -938,6 +1000,9 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
os, output_offset, view, address, view_size,
(*pviews)[i].view, (*pviews)[i].view_size);
+ if (parameters->options().incremental())
+ this->incremental_relocs_write(&relinfo, sh_type, prelocs,
+ reloc_count, os, output_offset, of);
}
else
{
@@ -1020,6 +1085,126 @@ Sized_relobj<size, big_endian>::emit_relocs_reltype(
reloc_view_size);
}
+// Write the incremental relocs.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_write(
+ const Relocate_info<size, big_endian>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ Address output_offset,
+ Output_file* of)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ this->incremental_relocs_write_reltype<elfcpp::SHT_REL>(
+ relinfo,
+ prelocs,
+ reloc_count,
+ output_section,
+ output_offset,
+ of);
+ else
+ {
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+ this->incremental_relocs_write_reltype<elfcpp::SHT_RELA>(
+ relinfo,
+ prelocs,
+ reloc_count,
+ output_section,
+ output_offset,
+ of);
+ }
+}
+
+// Write the incremental relocs, templatized on the type of the
+// relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_write_reltype(
+ const Relocate_info<size, big_endian>* relinfo,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ Address output_offset,
+ Output_file* of)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reloc;
+ const unsigned int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const unsigned int sizeof_addr = size / 8;
+ const unsigned int incr_reloc_size = 8 + 2 * sizeof_addr;
+
+ unsigned int out_shndx = output_section->out_shndx();
+
+ // Get a view for the .gnu_incremental_relocs section.
+
+ Incremental_inputs* inputs = relinfo->layout->incremental_inputs();
+ gold_assert(inputs != NULL);
+ const off_t relocs_off = inputs->relocs_section()->offset();
+ const off_t relocs_size = inputs->relocs_section()->data_size();
+ unsigned char* const view = of->get_output_view(relocs_off, relocs_size);
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reloc reloc(prelocs);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ if (r_sym < this->local_symbol_count_)
+ continue;
+
+ // Get the new offset--the location in the output section where
+ // this relocation should be applied.
+
+ Address offset = reloc.get_r_offset();
+ if (output_offset != invalid_address)
+ offset += output_offset;
+ else
+ {
+ section_offset_type sot_offset =
+ convert_types<section_offset_type, Address>(offset);
+ section_offset_type new_sot_offset =
+ output_section->output_offset(relinfo->object,
+ relinfo->data_shndx,
+ sot_offset);
+ gold_assert(new_sot_offset != -1);
+ offset += new_sot_offset;
+ }
+
+ // Get the addend.
+ typename elfcpp::Elf_types<size>::Elf_Swxword addend;
+ if (sh_type == elfcpp::SHT_RELA)
+ addend =
+ Reloc_types<sh_type, size, big_endian>::get_reloc_addend(&reloc);
+ else
+ {
+ // FIXME: Get the addend for SHT_REL.
+ addend = 0;
+ }
+
+ // Get the index of the output relocation.
+
+ unsigned int reloc_index =
+ this->next_incremental_reloc_index(r_sym - this->local_symbol_count_);
+
+ // Write the relocation.
+
+ unsigned char* pov = view + reloc_index * incr_reloc_size;
+ elfcpp::Swap<32, big_endian>::writeval(pov, r_type);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, out_shndx);
+ elfcpp::Swap<size, big_endian>::writeval(pov + 8, offset);
+ elfcpp::Swap<size, big_endian>::writeval(pov + 8 + sizeof_addr, addend);
+ of->write_output_view(pov - view, incr_reloc_size, view);
+ }
+}
+
// Create merge hash tables for the local symbols. These are used to
// speed up relocations.
@@ -1556,6 +1741,7 @@ Sized_relobj<32, false>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
Views* pviews);
#endif
@@ -1566,6 +1752,7 @@ Sized_relobj<32, true>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
Views* pviews);
#endif
@@ -1576,6 +1763,7 @@ Sized_relobj<64, false>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
Views* pviews);
#endif
@@ -1586,6 +1774,7 @@ Sized_relobj<64, true>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
Views* pviews);
#endif
diff --git a/gold/script.cc b/gold/script.cc
index e0b9359..d09781a 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -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;
diff --git a/gold/symtab.h b/gold/symtab.h
index 8178e2c..4e5b7b0 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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*,