aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog37
-rw-r--r--gold/gold.h3
-rw-r--r--gold/incremental.cc147
-rw-r--r--gold/incremental.h90
-rw-r--r--gold/main.cc5
-rw-r--r--gold/options.h8
-rw-r--r--gold/plugin.cc3
-rw-r--r--gold/readsyms.cc18
-rw-r--r--gold/script.cc8
-rw-r--r--gold/script.h21
10 files changed, 317 insertions, 23 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 5df808b..dd8e3c2 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,40 @@
+2009-05-15 Mikolaj Zalewski <mikolajz@google.com>
+
+ * gold.h (Incremental_argument_list): Remove (invalid) forward
+ declaration.
+ * incremental.cc (Incremental_inputs::report_achive): New method.
+ (Incremental_inputs::report_object): New method.
+ (Incremental_inputs::report_script): New method.
+ (Incremental_inputs::finalize_inputs): New method.
+ (Incremental_inputs::finalize): Call finalize_inputs().
+ (Incremental_inputs::sized_create_incremental_inputs_section_data):
+ Create inputs entries.
+ * incremental.h (Incremental_input_type): New enum.
+ (Incremental_inputs::Incremental_input): Initialize new fields.
+ (Incremental_inputs::report_inputs): New method.
+ (Incremental_inputs::report_achive): New method.
+ (Incremental_inputs::report_object): New method.
+ (Incremental_inputs::report_script): New method.
+ (Incremental_inputs::finalize_inputs): New method.
+ (Incremental_inputs::Input_info): New struct.
+ (Incremental_inputs::Input_info_map): New typedef.
+ (Incremental_inputs::lock_): New field.
+ (Incremental_inputs::Inputs_): New field.
+ (Incremental_inputs::Inputs_map): New field.
+ * main.cc (main): Call Incremental_input::report_inputs.
+ * options.h (Input_argument_list): Typedef moved from
+ Input_arguments.
+ (Input_file_group::Files): Remove, use ::Input_argument_list.
+ (Input_file_group::Input_argument_list): Remove, use
+ ::Input_argument_list.
+ * plugin.cc (Plugin_manager::add_input_file): Add error in
+ incremental build.
+ * read_syms.cc (do_read_syms): Call Incremental_input::report_*
+ functions.
+ * script.cc (read_input_script): Call
+ Incremental_input::report_script.
+ * script.h (Script_info): New class.
+
2009-04-27 Ian Lance Taylor <iant@google.com>
* x86_64.cc (do_adjust_output_section): Set entsize to
diff --git a/gold/gold.h b/gold/gold.h
index efebda8..bf014e8 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -148,7 +148,6 @@ namespace gold
class General_options;
class Command_line;
-class Input_argument_list;
class Dirsearch;
class Input_objects;
class Mapfile;
@@ -293,7 +292,7 @@ queue_initial_tasks(const General_options&,
// Queue up the set of tasks to be done before
// the middle set of tasks. Only used when garbage
-// collection is to be done.
+// collection is to be done.
extern void
queue_middle_gc_tasks(const General_options&,
const Task*,
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 7e99e1e..8024551 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -86,7 +86,7 @@ class Incremental_inputs_header_write
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
@@ -179,12 +179,114 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
this->strtab_->add(args.c_str(), true, &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.
+
+void
+Incremental_inputs::report_archive(const Input_argument* input,
+ Archive* archive)
+{
+ Hold_lock hl(*this->lock_);
+
+ Input_info info;
+ info.type = INCREMENTAL_INPUT_ARCHIVE;
+ info.archive = archive;
+ inputs_map_.insert(std::make_pair(input, info));
+}
+
+// Record that the input argument INPUT is an object OBJ. This is
+// called by Read_symbols after finding out the type of the file.
+
+void
+Incremental_inputs::report_object(const Input_argument* input,
+ Object* obj)
+{
+ Hold_lock hl(*this->lock_);
+
+ Input_info info;
+ info.type = (obj->is_dynamic()
+ ? INCREMENTAL_INPUT_SHARED_LIBRARY
+ : INCREMENTAL_INPUT_OBJECT);
+ info.object = obj;
+ inputs_map_.insert(std::make_pair(input, info));
+}
+
+// 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.
+
+void
+Incremental_inputs::report_script(const Input_argument* input,
+ Script_info* script)
+{
+ Hold_lock hl(*this->lock_);
+
+ Input_info info;
+ info.type = INCREMENTAL_INPUT_SCRIPT;
+ info.script = script;
+ inputs_map_.insert(std::make_pair(input, info));
+}
+
+// Compute indexes in the order in which the inputs should appear in
+// .gnu_incremental_inputs. This needs to be done after all the
+// scripts are parsed. The function is first called for the command
+// line inputs arguments and may call itself recursively for e.g. a
+// list of elements of a group or a list of inputs added by a script.
+// The [BEGIN; END) interval to analyze and *INDEX is the current
+// value of the index (that will be updated).
+
+void
+Incremental_inputs::finalize_inputs(
+ Input_argument_list::const_iterator begin,
+ Input_argument_list::const_iterator end,
+ unsigned int* index)
+{
+ for (Input_argument_list::const_iterator p = begin; p != end; ++p)
+ {
+ if (p->is_group())
+ {
+ finalize_inputs(p->group()->begin(), p->group()->end(), index);
+ continue;
+ }
+
+ Inputs_info_map::iterator it = inputs_map_.find(&(*p));
+ // TODO: turn it into an assert when the code will be more stable.
+ if (it == 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);
+ }
+ }
+}
+
// Finalize the incremental link information. Called from
// Layout::finalize.
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 = inputs_map_.begin();
+ p != inputs_map_.end();
+ ++p)
+ {
+ gold_assert(p->second.filename_key != 0);
+ }
+
this->strtab_->set_string_offsets();
}
@@ -213,7 +315,7 @@ Incremental_inputs::create_incremental_inputs_section_data()
#endif
default:
gold_unreachable();
- }
+ }
}
// Sized creation of .gnu_incremental_inputs section.
@@ -221,22 +323,49 @@ Incremental_inputs::create_incremental_inputs_section_data()
template<int size, bool big_endian>
Output_section_data*
Incremental_inputs::sized_create_inputs_section_data()
-{
- unsigned int sz =
+{
+ 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(0); // TODO: store input files data.
+ 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)
+ {
+ 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);
+ // 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.
+ entry.put_data_offset(0xffffffff);
+ entry.put_timestamp_sec(0);
+ entry.put_timestamp_usec(0);
+ entry.put_input_type(it->second.type);
+ entry.put_reserved(0);
+ }
+
return new Output_data_const_buffer(buffer, sz, 8,
- "** incremental link inputs list");
+ "** incremental link inputs list");
}
} // End namespace gold.
diff --git a/gold/incremental.h b/gold/incremental.h
index dd9ebc5..ed074ae 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -23,6 +23,7 @@
#ifndef GOLD_INCREMENTAL_H
#define GOLD_INCREMENTAL_H
+#include <map>
#include <vector>
#include "stringpool.h"
@@ -37,20 +38,49 @@ class Incremental_inputs_checker;
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
+};
+
// 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())
+ : lock_(new Lock()), inputs_(NULL), 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);
-
+
+ // Record the input arguments obtained from parsing the command line.
+ void
+ report_inputs(const Input_arguments& inputs)
+ { this->inputs_ = &inputs; }
+
+ // Record that the input argument INPUT is an archive ARCHIVE.
+ void
+ report_archive(const Input_argument* input, Archive* archive);
+
+ // Record that the input argument INPUT is to an object OBJ.
+ void
+ report_object(const Input_argument* input, Object* obj);
+
+ // Record that the input argument INPUT is to an script SCRIPT.
+ void
+ report_script(const Input_argument* input, Script_info* script);
+
// Prepare for layout. Called from Layout::finalize.
void
finalize();
@@ -58,8 +88,8 @@ class Incremental_inputs
// Create the content of the .gnu_incremental_inputs section.
Output_section_data*
create_incremental_inputs_section_data();
-
- // Return the .gnu_incremental_strtab stringpool.
+
+ // Return the .gnu_incremental_strtab stringpool.
Stringpool*
get_stringpool()
{ return this->strtab_; }
@@ -68,7 +98,57 @@ class Incremental_inputs
// 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();
+ sized_create_inputs_section_data();
+
+ // 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.
+
+ void
+ finalize_inputs(Input_argument_list::const_iterator begin,
+ Input_argument_list::const_iterator end,
+ unsigned int* index);
+
+ // Additional data about an input needed for an incremental link.
+ // None of these pointers is owned by the structure.
+ struct Input_info
+ {
+ Input_info()
+ : type(INCREMENTAL_INPUT_INVALID), archive(NULL), object(NULL),
+ script(NULL), filename_key(0), index(0)
+ { }
+
+ // Type of the file pointed by this argument.
+ Incremental_input_type type;
+
+ // Present if type == INCREMENTAL_INPUT_ARCHIVE.
+ Archive* archive;
+
+ // Present if type == INCREMENTAL_INPUT_OBJECT or
+ // INCREMENTAL_INPUT_SHARED_LIBRARY.
+ Object* object;
+
+ // Present if type == INCREMENTAL_INPUT_SCRIPT.
+ Script_info* script;
+
+ // Key of the filename string in the section stringtable.
+ Stringpool::Key filename_key;
+
+ // Position of the entry information in the output section.
+ unsigned int index;
+ };
+
+ typedef std::map<const Input_argument*, Input_info> Inputs_info_map;
+
+ // A lock guarding access to inputs_ during the first phase of linking, when
+ // report_ function may be called from multiple threads.
+ Lock* lock_;
+
+ // The list of input arguments obtained from parsing the command line.
+ const Input_arguments* inputs_;
+
+ // A map containing additional information about the input elements.
+ Inputs_info_map inputs_map_;
// The key of the command line string in the string pool.
Stringpool::Key command_line_key_;
diff --git a/gold/main.cc b/gold/main.cc
index c2d3c30..84b4ae9 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -221,7 +221,10 @@ 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_command_line(argc, argv);
+ layout.incremental_inputs()->report_inputs(command_line.inputs());
+ }
// Get the search path from the -L options.
Dirsearch search_path;
diff --git a/gold/options.h b/gold/options.h
index 904743e..b811332 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1275,14 +1275,15 @@ class Input_argument
Input_file_group* group_;
};
+typedef std::vector<Input_argument> Input_argument_list;
+
// A group from the command line. This is a set of arguments within
// --start-group ... --end-group.
class Input_file_group
{
public:
- typedef std::vector<Input_argument> Files;
- typedef Files::const_iterator const_iterator;
+ typedef Input_argument_list::const_iterator const_iterator;
Input_file_group()
: files_()
@@ -1304,7 +1305,7 @@ class Input_file_group
{ return this->files_.end(); }
private:
- Files files_;
+ Input_argument_list files_;
};
// A list of files from the command line or a script.
@@ -1312,7 +1313,6 @@ class Input_file_group
class Input_arguments
{
public:
- typedef std::vector<Input_argument> Input_argument_list;
typedef Input_argument_list::const_iterator const_iterator;
Input_arguments()
diff --git a/gold/plugin.cc b/gold/plugin.cc
index 3c4d4ae..b1007a7 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -407,6 +407,9 @@ Plugin_manager::add_input_file(char *pathname)
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())
+ gold_error(_("Input files added by plug-ins in --incremental mode not "
+ "supported yet.\n"));
this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
this->symtab_,
this->layout_,
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index b6da88d..c05d5a3 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -33,6 +33,8 @@
#include "script.h"
#include "readsyms.h"
#include "plugin.h"
+#include "layout.h"
+#include "incremental.h"
namespace gold
{
@@ -199,7 +201,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
{
bool is_thin_archive
= memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0;
- if (is_thin_archive
+ if (is_thin_archive
|| memcmp(ehdr, Archive::armag, Archive::sarmag) == 0)
{
// This is an archive.
@@ -207,7 +209,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
input_file, is_thin_archive,
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);
@@ -280,6 +288,12 @@ 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
diff --git a/gold/script.cc b/gold/script.cc
index 30b4e3c..86ce13b 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -43,6 +43,7 @@
#include "target-select.h"
#include "script.h"
#include "script-c.h"
+#include "incremental.h"
namespace gold
{
@@ -1414,6 +1415,13 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
this_blocker = nb;
}
+ if (layout->incremental_inputs())
+ {
+ // Like new Read_symbols(...) above, we rely on close.inputs()
+ // getting leaked by closure.
+ Script_info* info = new Script_info(closure.inputs());
+ layout->incremental_inputs()->report_script(input_argument, info);
+ }
*used_next_blocker = true;
return true;
diff --git a/gold/script.h b/gold/script.h
index e4554d0..781d24d 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -45,6 +45,7 @@ class Symbol_table;
class Layout;
class Mapfile;
class Input_argument;
+class Input_arguments;
class Input_objects;
class Input_group;
class Input_file;
@@ -382,6 +383,26 @@ class Script_options
Script_sections script_sections_;
};
+// Information about a script input that will persist during the whole linker
+// run. Needed only during an incremental build to retrieve the input files
+// added by this script.
+
+class Script_info
+{
+ public:
+ Script_info(Input_arguments* inputs)
+ : inputs_(inputs)
+ { }
+
+ // Returns the input files included because of this script.
+ Input_arguments*
+ inputs()
+ { return inputs_; }
+
+ private:
+ Input_arguments* inputs_;
+};
+
// FILE was found as an argument on the command line, but was not
// recognized as an ELF file. Try to read it as a script. Return
// true if the file was handled. This has to handle /usr/lib/libc.so