Add support for -e and for ENTRY in linker scripts.
authorIan Lance Taylor <iant@google.com>
Sun, 6 Jan 2008 00:47:10 +0000 (00:47 +0000)
committerIan Lance Taylor <iant@google.com>
Sun, 6 Jan 2008 00:47:10 +0000 (00:47 +0000)
gold/layout.cc
gold/layout.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/script-c.h
gold/script.cc
gold/yyscript.y

index 75aecfe2b5d7a23f3dd8b44c877cd6816bcbf6a8..a717ed241e12fd228d2102040949f2cf12b5b68a 100644 (file)
@@ -64,7 +64,8 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
 // Layout methods.
 
 Layout::Layout(const General_options& options)
-  : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
+  : options_(options), entry_(options.entry()), namepool_(), sympool_(),
+    dynpool_(), signatures_(),
     section_name_map_(), segment_list_(), section_list_(),
     unattached_section_list_(), special_output_list_(),
     section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
@@ -720,7 +721,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
 
   // Lay out the file header.
   Output_file_header* file_header;
-  file_header = new Output_file_header(target, symtab, segment_headers);
+  file_header = new Output_file_header(target, symtab, segment_headers,
+                                      this->entry_);
   load_seg->add_initial_output_data(file_header);
   this->special_output_list_.push_back(file_header);
 
index 131d6a6cd38f691a1b6d95e24c93dceda8880edc..a106cccd78a34ca9d7a678681ae6d0c9206bd6fa 100644 (file)
@@ -241,6 +241,12 @@ class Layout
   has_static_tls() const
   { return this->has_static_tls_; }
 
+  // Set the name of the entry symbol.  This is used by linker scripts
+  // which look like regular objects.
+  void
+  set_entry(const char* entry)
+  { this->entry_ = entry; }
+
   // Dump statistical information to stderr.
   void
   print_stats() const;
@@ -426,6 +432,9 @@ class Layout
 
   // A reference to the options on the command line.
   const General_options& options_;
+  // The name of the entry symbol.  This is from the command line, or
+  // from a linker script, or is NULL.
+  const char* entry_;
   // The output section names.
   Stringpool namepool_;
   // The output symbol names.
index c3f174718bb91c49fcb786ea5919b03e8a6bb69f..a26139bf425265162eb22b6d8f6c200359daa763 100644 (file)
@@ -395,12 +395,15 @@ options::Command_line_options::options[] =
   GENERAL_NOARG('\0', "detect-odr-violations",
                 N_("Try to detect violations of the One Definition Rule"),
                 NULL, TWO_DASHES, &General_options::set_detect_odr_violations),
+  GENERAL_ARG('e', "entry", N_("Set program start address"),
+             N_("-e ADDRESS, --entry ADDRESS"), TWO_DASHES,
+             &General_options::set_entry),
   GENERAL_NOARG('E', "export-dynamic", N_("Export all dynamic symbols"),
                 NULL, TWO_DASHES, &General_options::set_export_dynamic),
   GENERAL_NOARG('\0', "eh-frame-hdr", N_("Create exception frame header"),
                 NULL, TWO_DASHES, &General_options::set_create_eh_frame_hdr),
   GENERAL_ARG('h', "soname", N_("Set shared library name"),
-             N_("-h FILENAME, --soname FILENAME"), ONE_DASH,
+             N_("-h FILENAME, -soname FILENAME"), ONE_DASH,
              &General_options::set_soname),
   GENERAL_ARG('I', "dynamic-linker", N_("Set dynamic linker path"),
              N_("-I PROGRAM, --dynamic-linker PROGRAM"), TWO_DASHES,
@@ -530,7 +533,8 @@ const int options::Command_line_options::debug_options_size =
 // The default values for the general options.
 
 General_options::General_options()
-  : export_dynamic_(false),
+  : entry_(NULL),
+    export_dynamic_(false),
     soname_(NULL),
     dynamic_linker_(NULL),
     search_path_(),
index 86d9bd7b6b29588d9b44c20b3fd08659f80d2308..4cb760809ca32a66820ff7bc42eaa636d12be53c 100644 (file)
@@ -108,6 +108,11 @@ class General_options
  public:
   General_options();
 
+  // -e: set entry address.
+  const char*
+  entry() const
+  { return this->entry_; }
+
   // -E: export dynamic symbols.
   bool
   export_dynamic() const
@@ -311,6 +316,10 @@ class General_options
     ZLIB_COMPRESSION,
   };
 
+  void
+  set_entry(const char* arg)
+  { this->entry_ = arg; }
+
   void
   set_export_dynamic()
   { this->export_dynamic_ = true; }
@@ -509,6 +518,7 @@ class General_options
   void
   add_sysroot();
 
+  const char* entry_;
   bool export_dynamic_;
   const char* soname_;
   const char* dynamic_linker_;
@@ -824,6 +834,11 @@ class Command_line
   void
   end_group(const char* arg);
 
+  // Set the entry symbol from a linker script.
+  void
+  set_entry(const char* entry)
+  { this->options_.set_entry(entry); }
+
   // Get an option argument--a helper function for special processing.
   const char*
   get_special_argument(const char* longname, int argc, char** argv,
index 0e28629d53953550d749efa74f7fcf2993a345a9..4c6959eabc209c5e128254dc1d5952e140c85539 100644 (file)
@@ -294,12 +294,14 @@ Output_segment_headers::do_sized_write(Output_file* of)
 
 Output_file_header::Output_file_header(const Target* target,
                                       const Symbol_table* symtab,
-                                      const Output_segment_headers* osh)
+                                      const Output_segment_headers* osh,
+                                      const char* entry)
   : target_(target),
     symtab_(symtab),
     segment_header_(osh),
     section_header_(NULL),
-    shstrtab_(NULL)
+    shstrtab_(NULL),
+    entry_(entry)
 {
   const int size = parameters->get_size();
   int ehdr_size;
@@ -415,19 +417,7 @@ Output_file_header::do_sized_write(Output_file* of)
   oehdr.put_e_machine(this->target_->machine_code());
   oehdr.put_e_version(elfcpp::EV_CURRENT);
 
-  // FIXME: Need to support -e, and target specific entry symbol.
-  Symbol* sym = this->symtab_->lookup("_start");
-  typename Sized_symbol<size>::Value_type v;
-  if (sym == NULL)
-    v = 0;
-  else
-    {
-      Sized_symbol<size>* ssym;
-      ssym = this->symtab_->get_sized_symbol SELECT_SIZE_NAME(size) (
-        sym SELECT_SIZE(size));
-      v = ssym->value();
-    }
-  oehdr.put_e_entry(v);
+  oehdr.put_e_entry(this->entry<size>());
 
   oehdr.put_e_phoff(this->segment_header_->offset());
   oehdr.put_e_shoff(this->section_header_->offset());
@@ -447,6 +437,49 @@ Output_file_header::do_sized_write(Output_file* of)
   of->write_output_view(0, ehdr_size, view);
 }
 
+// Return the value to use for the entry address.  THIS->ENTRY_ is the
+// symbol specified on the command line, if any.
+
+template<int size>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Output_file_header::entry()
+{
+  const bool should_issue_warning = (this->entry_ != NULL
+                                    && parameters->output_is_executable());
+
+  // FIXME: Need to support target specific entry symbol.
+  const char* entry = this->entry_;
+  if (entry == NULL)
+    entry = "_start";
+
+  Symbol* sym = this->symtab_->lookup(entry);
+
+  typename Sized_symbol<size>::Value_type v;
+  if (sym != NULL)
+    {
+      Sized_symbol<size>* ssym;
+      ssym = this->symtab_->get_sized_symbol<size>(sym);
+      if (!ssym->is_defined() && should_issue_warning)
+       gold_warning("entry symbol '%s' exists but is not defined", entry);
+      v = ssym->value();
+    }
+  else
+    {
+      // We couldn't find the entry symbol.  See if we can parse it as
+      // a number.  This supports, e.g., -e 0x1000.
+      char* endptr;
+      v = strtoull(entry, &endptr, 0);
+      if (*endptr != '\0')
+       {
+         if (should_issue_warning)
+           gold_warning("cannot find entry symbol '%s'", entry);
+         v = 0;
+       }
+    }
+
+  return v;
+}
+
 // Output_data_const methods.
 
 void
index 07a336dcd53cc7d3ea3d78c189610f2f61735106..f384c8c8e86d6343ea4ec859a32d65dfb090d9bd 100644 (file)
@@ -393,7 +393,8 @@ class Output_file_header : public Output_data
  public:
   Output_file_header(const Target*,
                     const Symbol_table*,
-                    const Output_segment_headers*);
+                    const Output_segment_headers*,
+                    const char* entry);
 
   // Add information about the section headers.  We lay out the ELF
   // file header before we create the section headers.
@@ -416,11 +417,17 @@ class Output_file_header : public Output_data
   void
   do_sized_write(Output_file*);
 
+  // Return the value to use for the entry address.
+  template<int size>
+  typename elfcpp::Elf_types<size>::Elf_Addr
+  entry();
+
   const Target* target_;
   const Symbol_table* symtab_;
   const Output_segment_headers* segment_header_;
   const Output_section_headers* section_header_;
   const Output_section* shstrtab_;
+  const char* entry_;
 };
 
 // Output sections are mainly comprised of input sections.  However,
index 1214800dd0ad26d6e4b4782e8dafb27ff57c720a..4b103f89d8bdc3976ede338b8620abe97aa7a56b 100644 (file)
@@ -66,6 +66,11 @@ script_start_as_needed(void* closure);
 extern void
 script_end_as_needed(void* closure);
 
+/* Called by the bison parser to set the entry symbol.  */
+
+extern void
+script_set_entry(void* closure, const char*);
+
 /* Called by the bison parser to parse an OPTION.  */
 extern void
 script_parse_option(void* closure, const char*);
index 1373064d379f6e38172d9f2c9aa5c9353fe9e8ed..775aedf6f210c31ceacd8e975bc03fec1090d7de 100644 (file)
@@ -34,6 +34,7 @@
 #include "workqueue.h"
 #include "readsyms.h"
 #include "parameters.h"
+#include "layout.h"
 #include "yyscript.h"
 #include "script.h"
 #include "script-c.h"
@@ -834,10 +835,11 @@ class Parser_closure
                 const Position_dependent_options& posdep_options,
                 bool in_group, bool is_in_sysroot,
                  Command_line* command_line,
+                Layout* layout,
                 const Lex::Token_sequence* tokens)
     : filename_(filename), posdep_options_(posdep_options),
       in_group_(in_group), is_in_sysroot_(is_in_sysroot),
-      command_line_(command_line), tokens_(tokens),
+      command_line_(command_line), layout_(layout), tokens_(tokens),
       next_token_index_(0), inputs_(NULL)
   { }
 
@@ -869,6 +871,11 @@ class Parser_closure
   Command_line* command_line()
   { return this->command_line_; }
 
+  // Return the Layout structure passed in at constructor time.  This
+  // value may be NULL.
+  Layout* layout()
+  { return this->layout_; }
+
   // Whether we are at the end of the token list.
   bool
   at_eof() const
@@ -909,6 +916,8 @@ class Parser_closure
   bool is_in_sysroot_;
   // May be NULL if the user chooses not to pass one in.
   Command_line* command_line_;
+  // May be NULL if the user chooses not to pass one in.
+  Layout* layout_;
 
   // The tokens to be returned by the lexer.
   const Lex::Token_sequence* tokens_;
@@ -940,6 +949,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
                         input_group != NULL,
                         input_file->is_in_sysroot(),
                          NULL,
+                        layout,
                         &lex.tokens());
 
   if (yyparse(&closure) != 0)
@@ -1014,6 +1024,7 @@ read_commandline_script(const char* filename, Command_line* cmdline)
                         false,
                         input_file.is_in_sysroot(),
                          cmdline,
+                        NULL,
                         &lex.tokens());
   if (yyparse(&closure) != 0)
     {
@@ -1022,6 +1033,9 @@ read_commandline_script(const char* filename, Command_line* cmdline)
     }
 
   input_file.file().unlock(task);
+
+  gold_assert(!closure.saw_inputs());
+
   return true;
 }
 
@@ -1318,6 +1332,18 @@ script_end_as_needed(void* closurev)
   closure->position_dependent_options().clear_as_needed();
 }
 
+// Called by the bison parser to set the entry symbol.
+
+extern "C" void
+script_set_entry(void* closurev, const char* entry)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  if (closure->command_line() != NULL)
+    closure->command_line()->set_entry(entry);
+  else
+    closure->layout()->set_entry(entry);
+}
+
 // Called by the bison parser to parse an OPTION.
 
 extern "C" void
@@ -1330,8 +1356,8 @@ script_parse_option(void* closurev, const char* option)
     {
       // There are some options that we could handle here--e.g.,
       // -lLIBRARY.  Should we bother?
-      gold_warning(_("%s: Ignoring command OPTION; OPTION is only valid"
-                    " for scripts specified via -T"),
+      gold_warning(_("%s: ignoring command OPTION; OPTION is only valid"
+                    " for scripts specified via -T/--script"),
                   closure->filename());
     }
   else
index 3250e8ed2d715bb6fe430be60e9471ca58a4d6e1..7cfe7247e782db472236bc622b379f04c4f8f8d1 100644 (file)
 
 %%
 
+/* A file contains a list of commands.  */
 file_list:
          file_list file_cmd
        | /* empty */
        ;
 
+/* A command which may appear at top level of a linker script.  */
 file_cmd:
          OUTPUT_FORMAT '(' STRING ')'
        | GROUP
@@ -173,13 +175,16 @@ file_cmd:
            { script_end_group(closure); }
         | OPTION '(' STRING ')'
             { script_parse_option(closure, $3); }
+       | file_or_sections_cmd
        ;
 
+/* A list of input file names.  */
 input_list:
          input_list_element
        | input_list opt_comma input_list_element
        ;
 
+/* An input file name.  */
 input_list_element:
          STRING
            { script_add_file(closure, $1); }
@@ -189,6 +194,14 @@ input_list_element:
            { script_end_as_needed(closure); }
        ;
 
+/* A command which may appear at the top level of a linker script, or
+   within a SECTIONS block.  */
+file_or_sections_cmd:
+         ENTRY '(' STRING ')'
+           { script_set_entry(closure, $3); }
+       ;
+
+/* An optional comma.  */
 opt_comma:
          ','
        | /* empty */