#include "output.h"
#include "target-select.h"
-using elfcpp::Convert;
-
namespace gold {
// Version information. Will change frequently during the development, later
// we could think about backward (and forward?) compatibility.
-const int INCREMENTAL_LINK_VERSION = 1;
-
-namespace internal {
-
-// 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;
-};
-
-// 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;
-};
-
-}
-
-// Accessors.
-
-// See internal::Incremental_input_header for fields descriptions.
-template<int size, bool big_endian>
-class Incremental_inputs_header_write
-{
- public:
- 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
- put_input_file_count(elfcpp::Elf_Word v)
- { this->p_->input_file_count = Convert<32, big_endian>::convert_host(v); }
-
- void
- put_command_line_offset(elfcpp::Elf_Word v)
- { this->p_->command_line_offset = Convert<32, big_endian>::convert_host(v); }
-
- void
- put_reserved(elfcpp::Elf_Word v)
- { this->p_->reserved = Convert<32, big_endian>::convert_host(v); }
-
- private:
- internal::Incremental_inputs_header_data* p_;
-};
-
-// See internal::Incremental_input_entry for fields descriptions.
-template<int size, bool big_endian>
-class Incremental_inputs_entry_write
-{
- public:
- 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); }
-
- void
- put_data_offset(elfcpp::Elf_Word v)
- { this->p_->data_offset = Convert<32, big_endian>::convert_host(v); }
-
- void
- put_timestamp_sec(elfcpp::Elf_Xword v)
- { this->p_->timestamp_sec = Convert<64, big_endian>::convert_host(v); }
-
- void
- put_timestamp_nsec(elfcpp::Elf_Word v)
- { this->p_->timestamp_nsec = Convert<32, big_endian>::convert_host(v); }
-
- void
- put_input_type(elfcpp::Elf_Word v)
- { this->p_->input_type = Convert<32, big_endian>::convert_host(v); }
-
- void
- put_reserved(elfcpp::Elf_Word v)
- { this->p_->reserved = Convert<32, big_endian>::convert_host(v); }
-
- private:
- internal::Incremental_inputs_entry_data* p_;
-};
+const unsigned int INCREMENTAL_LINK_VERSION = 1;
// 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?
template<int size, bool big_endian>
bool
Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
- Location* location)
+ Location* location,
+ unsigned int* strtab_shndx)
{
unsigned int shndx = this->elf_file_.find_section_by_type(
elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
if (shndx == elfcpp::SHN_UNDEF) // Not found.
return false;
+ *strtab_shndx = this->elf_file_.section_link(shndx);
*location = this->elf_file_.section_contents(shndx);
return true;
}
+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 strtab_shndx;
+ Location location;
+
+ if (!do_find_incremental_inputs_section(&location, &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 strtab_location(this->elf_file_.section_contents(strtab_shndx));
+ View data_view(view(location));
+ View strtab_view(view(strtab_location));
+ elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
+ Incremental_inputs_header<size, big_endian> header(data_view.data());
+
+ if (header.get_version() != INCREMENTAL_LINK_VERSION)
+ {
+ explain_no_incremental(_("different version of incremental build data"));
+ return false;
+ }
+
+ const char* command_line;
+ // We divide instead of multiplying to make sure there is no integer
+ // overflow.
+ size_t max_input_entries = (location.data_size - header_size) / entry_size;
+ if (header.get_input_file_count() > max_input_entries
+ || !strtab.get_c_string(header.get_command_line_offset(), &command_line))
+ {
+ explain_no_incremental(_("invalid incremental build data"));
+ return false;
+ }
+
+ if (incremental_inputs->command_line() != command_line)
+ {
+ explain_no_incremental(_("command line changed"));
+ return false;
+ }
+
+ // TODO: compare incremental_inputs->inputs() with entries in data_view.
+ return true;
+}
+
namespace
{
return NULL;
}
+ if (!parameters->target_valid())
+ set_parameters_target(target);
+ else if (target != ¶meters->target())
+ gold_error(_("%s: incompatible target"), file->filename());
+
return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
}
return NULL;
}
- int size;
- bool big_endian;
+ int size = 0;
+ bool big_endian = false;
std::string error;
if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
&error))
Incremental_binary* binary = open_incremental_binary(&output);
if (binary == NULL)
return false;
- Incremental_binary::Location inputs_location;
- if (!binary->find_incremental_inputs_section(&inputs_location))
- {
- explain_no_incremental("no incremental data from previous build");
- delete binary;
- return false;
- }
- return true;
+ return binary->check_inputs(this->incremental_inputs_);
}
// Add the command line to the string table, setting
}
args.append("'");
}
- this->strtab_->add(args.c_str(), true, &this->command_line_key_);
+
+ this->command_line_ = args;
+ this->strtab_->add(this->command_line_.c_str(), false,
+ &this->command_line_key_);
}
// Record that the input argument INPUT is an achive ARCHIVE. This is
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();
+ }
// TODO: add per input data and timestamp. Currently we store
// an out-of-bounds offset for future version of gold to reject
// such an incremental_inputs section.