Support selecting target by name.
authorIan Lance Taylor <iant@google.com>
Wed, 13 Feb 2008 02:44:50 +0000 (02:44 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 13 Feb 2008 02:44:50 +0000 (02:44 +0000)
gold/fileread.cc
gold/fileread.h
gold/gold.cc
gold/i386.cc
gold/options.cc
gold/options.h
gold/target-select.cc
gold/target-select.h
gold/testsuite/testfile.cc
gold/x86_64.cc

index 797b878b8adb0bb6040c14d829e4f47584499435..8e111750225b028feb98f6769ff3ab4c406167af 100644 (file)
@@ -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(),
index 33c1f091e1d00369f283535b71af94995272d6ba..6a05928fb72ef4e6ba19928926dd79ae279fb07a 100644 (file)
@@ -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_;
index 1775db66cfbd8fbc3fbc653dbf00708190f376dd..eefcb48abbeed15da268fdd50b6db1bae52e6930 100644 (file)
@@ -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)
index 2d8efdd5ecb2ed3d6b7695fd4a495c359a825530..8bd3f32bb24386751d05308ee34308ba76cbc0b0 100644 (file)
@@ -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.
index e83b78d6e5dfbecc6b0c07ef69b86d0fc31c3918..db655a2e4c6a85d520f0fa5e3315efcaca00a52f 100644 (file)
@@ -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
index d62c2c2650370b5bf4d73e20a00d6576650e0aa6..c484b55e5e4edeba3a681d151a54edc29bd6b618 100644 (file)
@@ -37,6 +37,7 @@
 #include <string>
 #include <vector>
 
+#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_;
index 0cfa02bc6add1996f01ec019c525f9ba3b198108..fdf7b896367d1d8bf255c44539aecfdf1bf74fd9 100644 (file)
@@ -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.
index da27bd4df9cb3c133f66edb753bb196a68465578..5757d5b5d7f077fec784acb1153cf07948c35c28 100644 (file)
@@ -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)
index 3c989375025050418f4a17115333dce7afc44f3d..24c30f52c4a49e20a532c3005b89a782de8280a4 100644 (file)
@@ -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
index d5869dc5f6dd918a32cf547cda0d0af78d6ad61c..c65031e9cdcba07ffda5605608f8938c4b28e922 100644 (file)
@@ -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.