diff --git a/gold/ChangeLog b/gold/ChangeLog index f8ea0e51e1..3841da2933 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,31 @@ +2009-04-21 Mikolaj Zalewski + + * incremental.cc (Incremental_inputs_header_data): Renamed from + Incremental_input_header_data. + (Incremental_inputs_header_data::data_size): New field. + (Incremental_inputs_header_data::put_input_file_count): Renamed + from input_file_count. + (Incremental_inputs_header_data::put_command_line_offset): Renamed + from command_line_offset. + (Incremental_inputs_header_data::put_reserved): Renamed from + put_reserved. + (Incremental_inputs_entry_data): Renamed from + Incremental_input_entry_data. + (Incremental_inputs_entry_data::data_size): New field. + (Incremental_inputs::report_command_line): New method. + (Incremental_inputs::finalize): New method. + (Incremental_inputs::create_incremental_inputs_data): New method. + (Incremental_inputs::sized_create_incremental_inputs_data): New method. + * incremental.h: New file. + * layout.cc (Layout::Layout): Handle new incremental_inputs_. + (Layout::finalize): Create incremental inputs section in + incremental builds. + (Layout::create_incremental_info_sections): New method. + * layout.h (Layout::incremental_inputs): New method. + (Layout::create_incremental_info_sections): New method. + (Layout::incremental_inputs_): New field. + * main.cc (main): Notify Incremental_input of the command line. + 2009-04-01 Ian Lance Taylor Mikolaj Zalewski diff --git a/gold/incremental.cc b/gold/incremental.cc index 665822df5e..7e99e1ef28 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -22,6 +22,8 @@ #include "gold.h" #include "elfcpp.h" +#include "output.h" +#include "incremental.h" using elfcpp::Convert; @@ -34,7 +36,7 @@ const int INCREMENTAL_LINK_VERSION = 1; namespace internal { // Header of the .gnu_incremental_input section. -struct Incremental_input_header_data +struct Incremental_inputs_header_data { // Incremental linker version. elfcpp::Elf_Word version; @@ -51,7 +53,7 @@ struct Incremental_input_header_data // Data stored in .gnu_incremental_input after the header for each of the // Incremental_input_header_data::input_file_count input entries. -struct Incremental_input_entry_data +struct Incremental_inputs_entry_data { // Offset of file name in .gnu_incremental_strtab section. elfcpp::Elf_Word filename_offset; @@ -78,42 +80,46 @@ struct Incremental_input_entry_data // See internal::Incremental_input_header for fields descriptions. template -class Incremental_input_header_write +class Incremental_inputs_header_write { public: - Incremental_input_header_write(unsigned char *p) - : p_(reinterpret_cast(p)) + Incremental_inputs_header_write(unsigned char *p) + : p_(reinterpret_cast(p)) { } + + static const int data_size = sizeof(internal::Incremental_inputs_header_data); void put_version(elfcpp::Elf_Word v) { this->p_->version = Convert<32, big_endian>::convert_host(v); } void - input_file_count(elfcpp::Elf_Word v) + put_input_file_count(elfcpp::Elf_Word v) { this->p_->input_file_count = Convert<32, big_endian>::convert_host(v); } void - command_line_offset(elfcpp::Elf_Word v) + put_command_line_offset(elfcpp::Elf_Word v) { this->p_->command_line_offset = Convert<32, big_endian>::convert_host(v); } void - reserved(elfcpp::Elf_Word v) + put_reserved(elfcpp::Elf_Word v) { this->p_->reserved = Convert<32, big_endian>::convert_host(v); } private: - internal::Incremental_input_header_data* p_; + internal::Incremental_inputs_header_data* p_; }; // See internal::Incremental_input_entry for fields descriptions. template -class Incremental_input_entry_write +class Incremental_inputs_entry_write { public: - Incremental_input_entry_write(unsigned char *p) - : p_(reinterpret_cast(p)) + Incremental_inputs_entry_write(unsigned char *p) + : p_(reinterpret_cast(p)) { } + static const int data_size = sizeof(internal::Incremental_inputs_entry_data); + void put_filename_offset(elfcpp::Elf_Word v) { this->p_->filename_offset = Convert<32, big_endian>::convert_host(v); } @@ -139,7 +145,98 @@ class Incremental_input_entry_write { this->p_->reserved = Convert<32, big_endian>::convert_host(v); } private: - internal::Incremental_input_entry_data* p_; + internal::Incremental_inputs_entry_data* p_; }; +// 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 +// check if the command line options didn't change. + +void +Incremental_inputs::report_command_line(int argc, const char* const* argv) +{ + // Always store 'gold' as argv[0] to avoid a full relink if the user used a + // different path to the linker. + std::string args("gold"); + // Copied from collect_argv in main.cc. + for (int i = 1; i < argc; ++i) + { + args.append(" '"); + // Now append argv[i], but with all single-quotes escaped + const char* argpos = argv[i]; + while (1) + { + const int len = strcspn(argpos, "'"); + args.append(argpos, len); + if (argpos[len] == '\0') + break; + args.append("'\"'\"'"); + argpos += len + 1; + } + args.append("'"); + } + this->strtab_->add(args.c_str(), true, &this->command_line_key_); +} + +// Finalize the incremental link information. Called from +// Layout::finalize. + +void +Incremental_inputs::finalize() +{ + this->strtab_->set_string_offsets(); +} + +// Create the content of the .gnu_incremental_inputs section. + +Output_section_data* +Incremental_inputs::create_incremental_inputs_section_data() +{ + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + return this->sized_create_inputs_section_data<32, false>(); +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + return this->sized_create_inputs_section_data<32, true>(); +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + return this->sized_create_inputs_section_data<64, false>(); +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + return this->sized_create_inputs_section_data<64, true>(); +#endif + default: + gold_unreachable(); + } +} + +// Sized creation of .gnu_incremental_inputs section. + +template +Output_section_data* +Incremental_inputs::sized_create_inputs_section_data() +{ + unsigned int sz = + Incremental_inputs_header_write::data_size; + unsigned char* buffer = new unsigned char[sz]; + Incremental_inputs_header_write 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(0); // TODO: store input files data. + header_writer.put_command_line_offset(cmd_offset); + header_writer.put_reserved(0); + + return new Output_data_const_buffer(buffer, sz, 8, + "** incremental link inputs list"); +} + } // End namespace gold. diff --git a/gold/incremental.h b/gold/incremental.h new file mode 100644 index 0000000000..dd9ebc5ac7 --- /dev/null +++ b/gold/incremental.h @@ -0,0 +1,82 @@ +// inremental.h -- incremental linking support for gold -*- C++ -*- + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Mikolaj Zalewski . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#ifndef GOLD_INCREMENTAL_H +#define GOLD_INCREMENTAL_H + +#include + +#include "stringpool.h" +#include "workqueue.h" + +namespace gold +{ + +class Archive; +class Input_argument; +class Incremental_inputs_checker; +class Object; +class Output_section_data; + +// This class contains the information needed during an incremental +// build about the inputs necessary to build the .gnu_incremental_inputs. +class Incremental_inputs +{ + public: + Incremental_inputs() + : command_line_key_(0), strtab_(new Stringpool()) + { } + ~Incremental_inputs() { delete this->strtab_; } + + // Record the command line. + void + report_command_line(int argc, const char* const* argv); + + // Prepare for layout. Called from Layout::finalize. + void + finalize(); + + // Create the content of the .gnu_incremental_inputs section. + Output_section_data* + create_incremental_inputs_section_data(); + + // Return the .gnu_incremental_strtab stringpool. + Stringpool* + get_stringpool() + { return this->strtab_; } + + private: + // Code for each of the four possible variants of create_inputs_section_data. + template + Output_section_data* + sized_create_inputs_section_data(); + + // 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_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_INCREMENTAL_H) diff --git a/gold/layout.cc b/gold/layout.cc index c70e11c557..a651d0650d 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -46,8 +46,9 @@ #include "reduced_debug_output.h" #include "reloc.h" #include "descriptors.h" -#include "layout.h" #include "plugin.h" +#include "incremental.h" +#include "layout.h" namespace gold { @@ -122,7 +123,8 @@ Layout::Layout(int number_of_input_files, Script_options* script_options) input_without_gnu_stack_note_(false), has_static_tls_(false), any_postprocessing_sections_(false), - resized_signatures_(false) + resized_signatures_(false), + incremental_inputs_(NULL) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. @@ -131,6 +133,10 @@ Layout::Layout(int number_of_input_files, Script_options* script_options) // We expect two unattached Output_data objects: the file header and // the segment headers. this->special_output_list_.reserve(2); + + // Initialize structure needed for an incremental build. + if (parameters->options().incremental()) + this->incremental_inputs_ = new Incremental_inputs; } // Hash a key we use to look up an output section mapping. @@ -1215,6 +1221,12 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, this->create_version_sections(&versions, symtab, local_dynamic_count, dynamic_symbols, dynstr); } + + if (this->incremental_inputs_) + { + this->incremental_inputs_->finalize(); + this->create_incremental_info_sections(); + } // If there is a SECTIONS clause, put all the input sections into // the required order. @@ -1593,6 +1605,37 @@ Layout::create_build_id() } } +// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed +// for the next run of incremental linking to check what has changed. + +void +Layout::create_incremental_info_sections() +{ + gold_assert(this->incremental_inputs_ != NULL); + + // Add the .gnu_incremental_inputs section. + const char *incremental_inputs_name = + this->namepool_.add(".gnu_incremental_inputs", false, NULL); + Output_section* inputs_os = + this->make_output_section(incremental_inputs_name, + elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0); + Output_section_data* posd = + this->incremental_inputs_->create_incremental_inputs_section_data(); + inputs_os->add_output_section_data(posd); + + // 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); + 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); +} + // Return whether SEG1 should be before SEG2 in the output file. This // is based entirely on the segment type and flags. When this is // called the segment addresses has normally not yet been set. diff --git a/gold/layout.h b/gold/layout.h index 52be1d462f..0a9146bdf4 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -39,6 +39,7 @@ namespace gold { class General_options; +class Incremental_inputs; class Input_objects; class Mapfile; class Symbol_table; @@ -368,6 +369,12 @@ class Layout script_options() const { return this->script_options_; } + // Return the object managing inputs in incremental build. NULL in + // non-incremental builds. + Incremental_inputs* + incremental_inputs() + { return this->incremental_inputs_; } + // Compute and write out the build ID if needed. void write_build_id(Output_file*) const; @@ -473,6 +480,11 @@ class Layout void create_build_id(); + // 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(); + // Find the first read-only PT_LOAD segment, creating one if // necessary. Output_segment* @@ -717,6 +729,9 @@ class Layout bool any_postprocessing_sections_; // Whether we have resized the signatures_ hash table. bool resized_signatures_; + // In incremental build, holds information check the inputs and build the + // .gnu_incremental_inputs section. + Incremental_inputs* incremental_inputs_; }; // This task handles writing out data in output sections which is not diff --git a/gold/main.cc b/gold/main.cc index 2985a84ff2..c2d3c3062a 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -44,6 +44,7 @@ #include "layout.h" #include "plugin.h" #include "gc.h" +#include "incremental.h" using namespace gold; @@ -219,6 +220,9 @@ main(int argc, char** argv) Layout layout(command_line.number_of_input_files(), &command_line.script_options()); + if (layout.incremental_inputs() != NULL) + layout.incremental_inputs()->report_command_line(argc, argv); + // Get the search path from the -L options. Dirsearch search_path; search_path.initialize(&workqueue, &command_line.options().library_path());