+ if (ibase == NULL)
+ {
+ // Normal link. Queue a Read_symbols task for each input file
+ // on the command line.
+ for (Command_line::const_iterator p = cmdline.begin();
+ p != cmdline.end();
+ ++p)
+ {
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue(new Read_symbols(input_objects, symtab, layout,
+ &search_path, 0, mapfile, &*p, NULL,
+ NULL, this_blocker, next_blocker));
+ this_blocker = next_blocker;
+ }
+ }
+ else
+ {
+ // Incremental update link. Process the list of input files
+ // stored in the base file, and queue a task for each file:
+ // a Read_symbols task for a changed file, and an Add_symbols task
+ // for an unchanged file. We need to mark all the space used by
+ // unchanged files before we can start any tasks running.
+ unsigned int input_file_count = ibase->input_file_count();
+ std::vector<Task*> tasks;
+ tasks.reserve(input_file_count);
+ for (unsigned int i = 0; i < input_file_count; ++i)
+ {
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ Task* t = process_incremental_input(ibase, i, input_objects, symtab,
+ layout, &search_path, mapfile,
+ this_blocker, next_blocker);
+ tasks.push_back(t);
+ this_blocker = next_blocker;
+ }
+ // Now we can queue the tasks.
+ for (unsigned int i = 0; i < tasks.size(); i++)
+ workqueue->queue(tasks[i]);
+ }
+
+ if (options.has_plugins())
+ {
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue(new Plugin_hook(options, input_objects, symtab, layout,
+ &search_path, mapfile, this_blocker,
+ next_blocker));
+ this_blocker = next_blocker;
+ }
+
+ if (options.relocatable()
+ && (options.gc_sections() || options.icf_enabled()))
+ gold_error(_("cannot mix -r with --gc-sections or --icf"));
+
+ if (options.gc_sections() || options.icf_enabled())
+ {
+ workqueue->queue(new Task_function(new Gc_runner(options,
+ input_objects,
+ symtab,
+ layout,
+ mapfile),
+ this_blocker,
+ "Task_function Gc_runner"));
+ }
+ else
+ {
+ workqueue->queue(new Task_function(new Middle_runner(options,
+ input_objects,
+ symtab,
+ layout,
+ mapfile),
+ this_blocker,
+ "Task_function Middle_runner"));
+ }
+}
+
+// Process an incremental input file: if it is unchanged from the previous
+// link, return a task to add its symbols from the base file's incremental
+// info; if it has changed, return a normal Read_symbols task. We create a
+// task for every input file, if only to report the file for rebuilding the
+// incremental info.
+
+static Task*
+process_incremental_input(Incremental_binary* ibase,
+ unsigned int input_file_index,
+ Input_objects* input_objects,
+ Symbol_table* symtab,
+ Layout* layout,
+ Dirsearch* search_path,
+ Mapfile* mapfile,
+ Task_token* this_blocker,
+ Task_token* next_blocker)
+{
+ const Incremental_binary::Input_reader* input_reader =
+ ibase->get_input_reader(input_file_index);
+ Incremental_input_type input_type = input_reader->type();
+
+ // Get the input argument corresponding to this input file, matching on
+ // the argument serial number. If the input file cannot be matched
+ // to an existing input argument, synthesize a new one.
+ const Input_argument* input_argument =
+ ibase->get_input_argument(input_file_index);
+ if (input_argument == NULL)
+ {
+ Input_file_argument file(input_reader->filename(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, parameters->options());
+ Input_argument* arg = new Input_argument(file);
+ arg->set_script_info(ibase->get_script_info(input_file_index));
+ input_argument = arg;
+ }
+
+ gold_debug(DEBUG_INCREMENTAL, "Incremental object: %s, type %d",
+ input_reader->filename(), input_type);
+
+ if (input_type == INCREMENTAL_INPUT_SCRIPT)
+ {
+ // Incremental_binary::check_inputs should have cancelled the
+ // incremental update if the script has changed.
+ gold_assert(!ibase->file_has_changed(input_file_index));
+ return new Check_script(layout, ibase, input_file_index, input_reader,
+ this_blocker, next_blocker);
+ }
+
+ if (input_type == INCREMENTAL_INPUT_ARCHIVE)
+ {
+ Incremental_library* lib = ibase->get_library(input_file_index);
+ gold_assert(lib != NULL);
+ if (lib->filename() == "/group/"
+ || !ibase->file_has_changed(input_file_index))
+ {
+ // Queue a task to check that no references have been added to any
+ // of the library's unused symbols.
+ return new Check_library(symtab, layout, ibase, input_file_index,
+ input_reader, this_blocker, next_blocker);
+ }
+ else
+ {
+ // Queue a Read_symbols task to process the archive normally.
+ return new Read_symbols(input_objects, symtab, layout, search_path,
+ 0, mapfile, input_argument, NULL, NULL,
+ this_blocker, next_blocker);
+ }
+ }
+
+ if (input_type == INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+ {
+ // For archive members, check the timestamp of the containing archive.
+ Incremental_library* lib = ibase->get_library(input_file_index);
+ gold_assert(lib != NULL);
+ // Process members of a --start-lib/--end-lib group as normal objects.
+ if (lib->filename() != "/group/")
+ {
+ if (ibase->file_has_changed(lib->input_file_index()))
+ {
+ return new Read_member(input_objects, symtab, layout, mapfile,
+ input_reader, this_blocker, next_blocker);
+ }
+ else
+ {
+ // The previous contributions from this file will be kept.
+ // Mark the pieces of output sections contributed by this
+ // object.
+ ibase->reserve_layout(input_file_index);
+ Object* obj = make_sized_incremental_object(ibase,
+ input_file_index,
+ input_type,
+ input_reader);
+ return new Add_symbols(input_objects, symtab, layout,
+ search_path, 0, mapfile, input_argument,
+ obj, lib, NULL, this_blocker,
+ next_blocker);
+ }
+ }
+ }
+
+ // Normal object file or shared library. Check if the file has changed
+ // since the last incremental link.
+ if (ibase->file_has_changed(input_file_index))
+ {
+ return new Read_symbols(input_objects, symtab, layout, search_path, 0,
+ mapfile, input_argument, NULL, NULL,
+ this_blocker, next_blocker);
+ }
+ else
+ {
+ // The previous contributions from this file will be kept.
+ // Mark the pieces of output sections contributed by this object.
+ ibase->reserve_layout(input_file_index);
+ Object* obj = make_sized_incremental_object(ibase,
+ input_file_index,
+ input_type,
+ input_reader);
+ return new Add_symbols(input_objects, symtab, layout, search_path, 0,
+ mapfile, input_argument, obj, NULL, NULL,
+ this_blocker, next_blocker);
+ }
+}
+
+// Queue up a set of tasks to be done before queueing the middle set
+// of tasks. This is only necessary when garbage collection
+// (--gc-sections) of unused sections is desired. The relocs are read
+// and processed here early to determine the garbage sections before the
+// relocs can be scanned in later tasks.
+
+void
+queue_middle_gc_tasks(const General_options& options,
+ const Task* ,
+ const Input_objects* input_objects,
+ Symbol_table* symtab,
+ Layout* layout,
+ Workqueue* workqueue,
+ Mapfile* mapfile)
+{
+ // Read_relocs for all the objects must be done and processed to find
+ // unused sections before any scanning of the relocs can take place.
+ Task_token* this_blocker = NULL;
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();