X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gold%2Fgold.cc;h=8d86a1bbb474bea9c9d3bb0cdf6c1772b219bbea;hb=b302c308cd92656419cddc2672f43a1cbd027961;hp=7d01a81305f192070c08fe227c0e525b3fbe4a0b;hpb=9025d29d14ae287d2bc338ef1b0bfa043799e15c;p=binutils-gdb.git diff --git a/gold/gold.cc b/gold/gold.cc index 7d01a81305f..8d86a1bbb47 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -1,6 +1,6 @@ // gold.cc -- main linker functions -// Copyright 2006, 2007 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -26,8 +26,11 @@ #include #include #include +#include +#include "libiberty.h" #include "options.h" +#include "debug.h" #include "workqueue.h" #include "dirsearch.h" #include "readsyms.h" @@ -37,6 +40,7 @@ #include "layout.h" #include "reloc.h" #include "defstd.h" +#include "plugin.h" namespace gold { @@ -46,29 +50,33 @@ const char* program_name; void gold_exit(bool status) { + if (parameters != NULL + && parameters->options_valid() + && parameters->options().has_plugins()) + parameters->options().plugins()->cleanup(); + if (!status && parameters != NULL && parameters->options_valid()) + unlink_if_ordinary(parameters->options().output_file_name()); exit(status ? EXIT_SUCCESS : EXIT_FAILURE); } -void -gold_fatal(const char* msg, bool perrno) -{ - fprintf(stderr, "%s: ", program_name); - if (perrno) - perror(msg); - else - fprintf(stderr, "%s\n", msg); - gold_exit(false); -} - void gold_nomem() { // We are out of memory, so try hard to print a reasonable message. // Note that we don't try to translate this message, since the // translation process itself will require memory. - write(2, program_name, strlen(program_name)); - const char* const s = ": out of memory\n"; - write(2, s, strlen(s)); + + // LEN only exists to avoid a pointless warning when write is + // declared with warn_use_result, as when compiling with + // -D_USE_FORTIFY on GNU/Linux. Casting to void does not appear to + // work, at least not with gcc 4.3.0. + + ssize_t len = write(2, program_name, strlen(program_name)); + if (len >= 0) + { + const char* const s = ": out of memory\n"; + len = write(2, s, strlen(s)); + } gold_exit(false); } @@ -77,7 +85,7 @@ gold_nomem() void do_gold_unreachable(const char* filename, int lineno, const char* function) { - fprintf(stderr, "%s: internal error in %s, at %s:%d\n", + fprintf(stderr, _("%s: internal error in %s, at %s:%d\n"), program_name, function, filename, lineno); gold_exit(false); } @@ -91,39 +99,45 @@ class Middle_runner : public Task_function_runner Middle_runner(const General_options& options, const Input_objects* input_objects, Symbol_table* symtab, - Layout* layout) + Layout* layout, Mapfile* mapfile) : options_(options), input_objects_(input_objects), symtab_(symtab), - layout_(layout) + layout_(layout), mapfile_(mapfile) { } void - run(Workqueue*); + run(Workqueue*, const Task*); private: const General_options& options_; const Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; + Mapfile* mapfile_; }; void -Middle_runner::run(Workqueue* workqueue) +Middle_runner::run(Workqueue* workqueue, const Task* task) { - queue_middle_tasks(this->options_, this->input_objects_, this->symtab_, - this->layout_, workqueue); + queue_middle_tasks(this->options_, task, this->input_objects_, this->symtab_, + this->layout_, workqueue, this->mapfile_); } // Queue up the initial set of tasks for this link job. void queue_initial_tasks(const General_options& options, - const Dirsearch& search_path, + Dirsearch& search_path, const Command_line& cmdline, Workqueue* workqueue, Input_objects* input_objects, - Symbol_table* symtab, Layout* layout) + Symbol_table* symtab, Layout* layout, Mapfile* mapfile) { if (cmdline.begin() == cmdline.end()) - gold_fatal(_("no input files"), false); + gold_fatal(_("no input files")); + + int thread_count = options.thread_count_initial(); + if (thread_count == 0) + thread_count = cmdline.number_of_input_files(); + workqueue->set_thread_count(thread_count); // Read the input files. We have to add the symbols to the symbol // table in order. We do this by creating a separate blocker for @@ -134,19 +148,31 @@ queue_initial_tasks(const General_options& options, p != cmdline.end(); ++p) { - Task_token* next_blocker = new Task_token(); + Task_token* next_blocker = new Task_token(true); next_blocker->add_blocker(); workqueue->queue(new Read_symbols(options, input_objects, symtab, layout, - search_path, &*p, NULL, this_blocker, - next_blocker)); + &search_path, mapfile, &*p, NULL, + this_blocker, next_blocker)); + this_blocker = next_blocker; + } + + 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; } workqueue->queue(new Task_function(new Middle_runner(options, input_objects, symtab, - layout), - this_blocker)); + layout, + mapfile), + this_blocker, + "Task_function Middle_runner")); } // Queue up the middle set of tasks. These are the tasks which run @@ -155,22 +181,83 @@ queue_initial_tasks(const General_options& options, void queue_middle_tasks(const General_options& options, + const Task* task, const Input_objects* input_objects, Symbol_table* symtab, Layout* layout, - Workqueue* workqueue) + Workqueue* workqueue, + Mapfile* mapfile) { + // We have to support the case of not seeing any input objects, and + // generate an empty file. Existing builds depend on being able to + // pass an empty archive to the linker and get an empty object file + // out. In order to do this we need to use a default target. + if (input_objects->number_of_input_objects() == 0) + set_parameters_target(¶meters->default_target()); + + int thread_count = options.thread_count_middle(); + if (thread_count == 0) + thread_count = std::max(2, input_objects->number_of_input_objects()); + workqueue->set_thread_count(thread_count); + + // Now we have seen all the input files. + const bool doing_static_link = (!input_objects->any_dynamic() + && !parameters->options().shared()); + set_parameters_doing_static_link(doing_static_link); + if (!doing_static_link && options.is_static()) + { + // We print out just the first .so we see; there may be others. + gold_assert(input_objects->dynobj_begin() != input_objects->dynobj_end()); + gold_error(_("cannot mix -static with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + } + if (!doing_static_link && parameters->options().relocatable()) + gold_error(_("cannot mix -r with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + if (!doing_static_link + && options.oformat_enum() != General_options::OBJECT_FORMAT_ELF) + gold_fatal(_("cannot use non-ELF output format with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + + if (is_debugging_enabled(DEBUG_SCRIPT)) + layout->script_options()->print(stderr); + + // For each dynamic object, record whether we've seen all the + // dynamic objects that it depends upon. + input_objects->check_dynamic_dependencies(); + + // See if any of the input definitions violate the One Definition Rule. + // TODO: if this is too slow, do this as a task, rather than inline. + symtab->detect_odr_violations(task, options.output_file_name()); + + // Create any output sections required by any linker script. + layout->create_script_sections(); + // Define some sections and symbols needed for a dynamic link. This // handles some cases we want to see before we read the relocs. - layout->create_initial_dynamic_sections(input_objects, symtab); + layout->create_initial_dynamic_sections(symtab); + + // Define symbols from any linker scripts. + layout->define_script_symbols(symtab); + + // Add any symbols named with -u options to the symbol table. + symtab->add_undefined_symbols_from_command_line(); - // Predefine standard symbols. This should be fast, so we don't - // bother to create a task for it. - define_standard_symbols(symtab, layout, input_objects->target()); + // Attach sections to segments. + layout->attach_sections_to_segments(); - // Define __start and __stop symbols for output sections where - // appropriate. - layout->define_section_symbols(symtab, input_objects->target()); + if (!parameters->options().relocatable()) + { + // Predefine standard symbols. + define_standard_symbols(symtab, layout); + + // Define __start and __stop symbols for output sections where + // appropriate. + layout->define_section_symbols(symtab); + } + + // Make sure we have symbols for any required group signatures. + layout->define_group_signatures(symtab); // Read the relocations of the input files. We do this to find // which symbols are used by relocations which require a GOT and/or @@ -183,8 +270,8 @@ queue_middle_tasks(const General_options& options, // Doing that is more complex, since we may later decide to discard // some of the sections, and thus change our minds about the types // of references made to the symbols. - Task_token* blocker = new Task_token(); - Task_token* symtab_lock = new Task_token(); + Task_token* blocker = new Task_token(true); + Task_token* symtab_lock = new Task_token(false); for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); p != input_objects->relobj_end(); ++p) @@ -201,17 +288,25 @@ queue_middle_tasks(const General_options& options, // Allocate common symbols. This requires write access to the // symbol table, but is independent of the relocation processing. - blocker->add_blocker(); - workqueue->queue(new Allocate_commons_task(options, symtab, layout, - symtab_lock, blocker)); + if (parameters->options().define_common()) + { + blocker->add_blocker(); + workqueue->queue(new Allocate_commons_task(symtab, layout, mapfile, + symtab_lock, blocker)); + } // When all those tasks are complete, we can start laying out the // output file. + // TODO(csilvers): figure out a more principled way to get the target + Target* target = const_cast(¶meters->target()); workqueue->queue(new Task_function(new Layout_task_runner(options, input_objects, symtab, - layout), - blocker)); + target, + layout, + mapfile), + blocker, + "Task_function Layout_task_runner")); } // Queue up the final set of tasks. This is called at the end of @@ -221,12 +316,49 @@ void queue_final_tasks(const General_options& options, const Input_objects* input_objects, const Symbol_table* symtab, - const Layout* layout, + Layout* layout, Workqueue* workqueue, Output_file* of) { + int thread_count = options.thread_count_final(); + if (thread_count == 0) + thread_count = std::max(2, input_objects->number_of_input_objects()); + workqueue->set_thread_count(thread_count); + + bool any_postprocessing_sections = layout->any_postprocessing_sections(); + + // Use a blocker to wait until all the input sections have been + // written out. + Task_token* input_sections_blocker = NULL; + if (!any_postprocessing_sections) + input_sections_blocker = new Task_token(true); + + // Use a blocker to block any objects which have to wait for the + // output sections to complete before they can apply relocations. + Task_token* output_sections_blocker = new Task_token(true); + // Use a blocker to block the final cleanup task. - Task_token* final_blocker = new Task_token(); + Task_token* final_blocker = new Task_token(true); + + // Queue a task to write out the symbol table. + final_blocker->add_blocker(); + workqueue->queue(new Write_symbols_task(layout, + symtab, + input_objects, + layout->sympool(), + layout->dynpool(), + of, + final_blocker)); + + // Queue a task to write out the output sections. + output_sections_blocker->add_blocker(); + final_blocker->add_blocker(); + workqueue->queue(new Write_sections_task(layout, of, output_sections_blocker, + final_blocker)); + + // Queue a task to write out everything else. + final_blocker->add_blocker(); + workqueue->queue(new Write_data_task(layout, symtab, of, final_blocker)); // Queue a task for each input object to relocate the sections and // write out the local symbols. @@ -234,28 +366,44 @@ queue_final_tasks(const General_options& options, p != input_objects->relobj_end(); ++p) { + if (input_sections_blocker != NULL) + input_sections_blocker->add_blocker(); final_blocker->add_blocker(); workqueue->queue(new Relocate_task(options, symtab, layout, *p, of, + input_sections_blocker, + output_sections_blocker, final_blocker)); } - // Queue a task to write out the symbol table. - final_blocker->add_blocker(); - workqueue->queue(new Write_symbols_task(symtab, - input_objects->target(), - layout->sympool(), - layout->dynpool(), - of, - final_blocker)); - - // Queue a task to write out everything else. - final_blocker->add_blocker(); - workqueue->queue(new Write_data_task(layout, symtab, of, final_blocker)); + // Queue a task to write out the output sections which depend on + // input sections. If there are any sections which require + // postprocessing, then we need to do this last, since it may resize + // the output file. + if (!any_postprocessing_sections) + { + final_blocker->add_blocker(); + Task* t = new Write_after_input_sections_task(layout, of, + input_sections_blocker, + final_blocker); + workqueue->queue(t); + } + else + { + Task_token *new_final_blocker = new Task_token(true); + new_final_blocker->add_blocker(); + Task* t = new Write_after_input_sections_task(layout, of, + final_blocker, + new_final_blocker); + workqueue->queue(t); + final_blocker = new_final_blocker; + } // Queue a task to close the output file. This will be blocked by // FINAL_BLOCKER. - workqueue->queue(new Task_function(new Close_task_runner(of), - final_blocker)); + workqueue->queue(new Task_function(new Close_task_runner(&options, layout, + of), + final_blocker, + "Task_function Close_task_runner")); } } // End namespace gold.