From 0daa6f62c88fe4d1dd680b09e855c4b8b7811403 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 13 Feb 2008 02:44:50 +0000 Subject: [PATCH] Support selecting target by name. --- gold/fileread.cc | 31 ++++++++++++------------------- gold/fileread.h | 3 ++- gold/gold.cc | 11 +---------- gold/i386.cc | 13 +++++++++++++ gold/options.cc | 34 +++++++++++++++++++++++++++++++++- gold/options.h | 8 +++++++- gold/target-select.cc | 17 ++++++++++++++++- gold/target-select.h | 12 +++++++++++- gold/testsuite/testfile.cc | 4 ++++ gold/x86_64.cc | 13 +++++++++++++ 10 files changed, 112 insertions(+), 34 deletions(-) diff --git a/gold/fileread.cc b/gold/fileread.cc index 797b878..8e11175 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -698,7 +698,7 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath, else { gold_assert(format == General_options::OBJECT_FORMAT_BINARY); - ok = this->open_binary(task, name); + ok = this->open_binary(options, task, name); } if (!ok) @@ -714,29 +714,22 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath, // Open a file for --format binary. bool -Input_file::open_binary(const Task* task, const std::string& name) +Input_file::open_binary(const General_options& options, + const Task* task, const std::string& name) { // In order to open a binary file, we need machine code, size, and - // endianness. If we have a target already, use it, otherwise use - // the defaults. - elfcpp::EM machine; - int size; - bool big_endian; + // endianness. We may not have a valid target at this point, in + // which case we use the default target. + Target* target; if (parameters->is_target_valid()) - { - Target* target = parameters->target(); - machine = target->machine_code(); - size = target->get_size(); - big_endian = target->is_big_endian(); - } + target = parameters->target(); else - { - machine = elfcpp::GOLD_DEFAULT_MACHINE; - size = GOLD_DEFAULT_SIZE; - big_endian = GOLD_DEFAULT_BIG_ENDIAN; - } + target = options.default_target(); - Binary_to_elf binary_to_elf(machine, size, big_endian, name); + Binary_to_elf binary_to_elf(target->machine_code(), + target->get_size(), + target->is_big_endian(), + name); if (!binary_to_elf.convert(task)) return false; return this->file_.open(task, name, binary_to_elf.converted_data_leak(), diff --git a/gold/fileread.h b/gold/fileread.h index 33c1f09..6a05928 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -428,7 +428,8 @@ class Input_file // Open a binary file. bool - open_binary(const Task* task, const std::string& name); + open_binary(const General_options&, const Task* task, + const std::string& name); // The argument from the command line. const Input_file_argument* input_argument_; diff --git a/gold/gold.cc b/gold/gold.cc index 1775db6..eefcb48 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -31,7 +31,6 @@ #include "options.h" #include "debug.h" -#include "target-select.h" #include "workqueue.h" #include "dirsearch.h" #include "readsyms.h" @@ -167,15 +166,7 @@ queue_middle_tasks(const General_options& options, // 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) - { - // The GOLD_xx macros are defined by the configure script. - Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE, - GOLD_DEFAULT_SIZE, - GOLD_DEFAULT_BIG_ENDIAN, - 0, 0); - gold_assert(target != NULL); - set_parameters_target(target); - } + set_parameters_target(options.default_target()); int thread_count = options.thread_count_middle(); if (thread_count == 0) diff --git a/gold/i386.cc b/gold/i386.cc index 2d8efdd..8bd3f32 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -2433,6 +2433,9 @@ public: Target* recognize(int machine, int osabi, int abiversion); + Target* + recognize_by_name(const char* name); + private: Target_i386* target_; }; @@ -2448,6 +2451,16 @@ Target_selector_i386::recognize(int, int, int) return this->target_; } +Target* +Target_selector_i386::recognize_by_name(const char* name) +{ + if (strcmp(name, "elf32-i386") != 0) + return NULL; + if (this->target_ == NULL) + this->target_ = new Target_i386(); + return this->target_; +} + Target_selector_i386 target_selector_i386; } // End anonymous namespace. diff --git a/gold/options.cc b/gold/options.cc index e83b78d..db655a2 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -30,6 +30,7 @@ #include "debug.h" #include "script.h" +#include "target-select.h" #include "options.h" namespace gold @@ -140,7 +141,8 @@ namespace // minimally compatible. In practice for an ELF target this would be // the same target as the input files; that name always start with // "elf". Non-ELF targets would be "srec", "symbolsrec", "tekhex", -// "binary", "ihex". +// "binary", "ihex". See also +// General_options::default_target_settings. gold::General_options::Object_format string_to_object_format(const char* arg) @@ -635,6 +637,7 @@ General_options::General_options(Script_options* script_options) optimization_level_(0), output_file_name_("a.out"), output_format_(OBJECT_FORMAT_ELF), + output_format_string_(NULL), is_relocatable_(false), strip_(STRIP_NONE), allow_shlib_undefined_(false), @@ -678,9 +681,38 @@ General_options::define_symbol(const char* arg) void General_options::set_output_format(const char* arg) { + this->output_format_string_ = arg; this->output_format_ = string_to_object_format(arg); } +// The x86_64 kernel build converts a binary file to an object file +// using -r --format binary --oformat elf32-i386 foo.o. In order to +// support that for gold we support determining the default target +// choice from the output format. We recognize names that the GNU +// linker uses. + +Target* +General_options::default_target() const +{ + if (this->output_format_string_ != NULL) + { + Target* target = select_target_by_name(this->output_format_string_); + if (target != NULL) + return target; + + gold_error(_("unrecognized output format %s"), + this->output_format_string_); + } + + // The GOLD_DEFAULT_xx macros are defined by the configure script. + Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE, + GOLD_DEFAULT_SIZE, + GOLD_DEFAULT_BIG_ENDIAN, + 0, 0); + gold_assert(target != NULL); + return target; +} + // Handle the -z option. void diff --git a/gold/options.h b/gold/options.h index d62c2c2..c484b55 100644 --- a/gold/options.h +++ b/gold/options.h @@ -37,6 +37,7 @@ #include #include +#include "elfcpp.h" #include "script.h" namespace gold @@ -45,6 +46,7 @@ namespace gold class Command_line; class Input_file_group; class Position_dependent_options; +class Target; namespace options { @@ -157,11 +159,14 @@ class General_options { return this->output_file_name_; } // --oformat: Output format. - Object_format output_format() const { return this->output_format_; } + // Return the default target. + Target* + default_target() const; + // -r: Whether we are doing a relocatable link. bool is_relocatable() const @@ -562,6 +567,7 @@ class General_options int optimization_level_; const char* output_file_name_; Object_format output_format_; + const char* output_format_string_; bool is_relocatable_; Strip strip_; bool allow_shlib_undefined_; diff --git a/gold/target-select.cc b/gold/target-select.cc index 0cfa02b..fdf7b89 100644 --- a/gold/target-select.cc +++ b/gold/target-select.cc @@ -50,7 +50,7 @@ Target_selector::Target_selector(int machine, int size, bool is_big_endian) // Find the target for an ELF file. -extern Target* +Target* select_target(int machine, int size, bool is_big_endian, int osabi, int abiversion) { @@ -69,4 +69,19 @@ select_target(int machine, int size, bool is_big_endian, int osabi, return NULL; } +// Find a target using a BFD name. This is used to support the +// --oformat option. + +Target* +select_target_by_name(const char* name) +{ + for (Target_selector* p = target_selectors; p != NULL; p = p->next()) + { + Target* ret = p->recognize_by_name(name); + if (ret != NULL) + return ret; + } + return NULL; +} + } // End namespace gold. diff --git a/gold/target-select.h b/gold/target-select.h index da27bd4..5757d5b 100644 --- a/gold/target-select.h +++ b/gold/target-select.h @@ -49,7 +49,13 @@ class Target_selector // If we can handle this target, return a pointer to a target // structure. The size and endianness are known. - virtual Target* recognize(int machine, int osabi, int abiversion) = 0; + virtual Target* + recognize(int machine, int osabi, int abiversion) = 0; + + // If NAME matches the target, return a pointer to a target + // structure. + virtual Target* + recognize_by_name(const char* name) = 0; // Return the next Target_selector in the linked list. Target_selector* @@ -84,6 +90,10 @@ class Target_selector extern Target* select_target(int machine, int size, bool big_endian, int osabi, int abiversion); +// Select a target using a BFD name. + +extern Target* select_target_by_name(const char* name); + } // End namespace gold. #endif // !defined(GOLD_TARGET_SELECT_H) diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc index 3c98937..24c30f5 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -176,6 +176,10 @@ class Target_selector_test : public Target_selector return NULL; } + + Target* + recognize_by_name(const char*) + { return NULL; } }; // Register the test target selectors. These don't need to be diff --git a/gold/x86_64.cc b/gold/x86_64.cc index d5869dc..c65031e 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -2223,6 +2223,9 @@ public: Target* recognize(int machine, int osabi, int abiversion); + Target* + recognize_by_name(const char*); + private: Target_x86_64* target_; }; @@ -2238,6 +2241,16 @@ Target_selector_x86_64::recognize(int, int, int) return this->target_; } +Target* +Target_selector_x86_64::recognize_by_name(const char* name) +{ + if (strcmp(name, "elf64-x86-64") != 0) + return NULL; + if (this->target_ == NULL) + this->target_ = new Target_x86_64(); + return this->target_; +} + Target_selector_x86_64 target_selector_x86_64; } // End anonymous namespace. -- 2.7.4