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-21 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <iant@google.com>
Mikolaj Zalewski <mikolajz@google.com>
#include "gold.h"
#include "elfcpp.h"
+#include "output.h"
+#include "incremental.h"
using elfcpp::Convert;
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;
// 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;
// See internal::Incremental_input_header for fields descriptions.
template<int size, bool big_endian>
-class Incremental_input_header_write
+class Incremental_inputs_header_write
{
public:
- Incremental_input_header_write(unsigned char *p)
- : p_(reinterpret_cast<internal::Incremental_input_header_data>(p))
+ Incremental_inputs_header_write(unsigned char *p)
+ : p_(reinterpret_cast<internal::Incremental_inputs_header_data*>(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<int size, bool big_endian>
-class Incremental_input_entry_write
+class Incremental_inputs_entry_write
{
public:
- Incremental_input_entry_write(unsigned char *p)
- : p_(reinterpret_cast<internal::Incremental_input_entry_data>(p))
+ Incremental_inputs_entry_write(unsigned char *p)
+ : p_(reinterpret_cast<internal::Incremental_inputs_entry_data*>(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); }
{ 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<int size, bool big_endian>
+Output_section_data*
+Incremental_inputs::sized_create_inputs_section_data()
+{
+ unsigned int sz =
+ Incremental_inputs_header_write<size, big_endian>::data_size;
+ unsigned char* buffer = new unsigned char[sz];
+ 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(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.
--- /dev/null
+// inremental.h -- incremental linking support for gold -*- C++ -*-
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Mikolaj Zalewski <mikolajz@google.com>.
+
+// 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 <vector>
+
+#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<int size, bool big_endian>
+ 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)
#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
{
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.
// 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.
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.
}
}
+// 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.
{
class General_options;
+class Incremental_inputs;
class Input_objects;
class Mapfile;
class Symbol_table;
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;
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*
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
#include "layout.h"
#include "plugin.h"
#include "gc.h"
+#include "incremental.h"
using namespace gold;
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());