Support assignments and expressions in linker scripts.
authorIan Lance Taylor <iant@google.com>
Wed, 9 Jan 2008 19:57:45 +0000 (19:57 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 9 Jan 2008 19:57:45 +0000 (19:57 +0000)
21 files changed:
gold/Makefile.am
gold/Makefile.in
gold/expression.cc [new file with mode: 0644]
gold/gold.cc
gold/layout.cc
gold/layout.h
gold/main.cc
gold/options.cc
gold/options.h
gold/po/POTFILES.in
gold/po/gold.pot
gold/resolve.cc
gold/script-c.h
gold/script.cc
gold/script.h
gold/symtab.cc
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/script_test_1.cc [new file with mode: 0644]
gold/testsuite/script_test_1.t [new file with mode: 0644]
gold/yyscript.y

index ce17e96ed71c98c40713bc690d14189f6a7643a3..d1c564c3f53b00d1232d0d80c7dac86c42aecebd 100644 (file)
@@ -37,6 +37,7 @@ CCFILES = \
        dwarf_reader.cc \
        ehframe.cc \
        errors.cc \
+       expression.cc \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
index bfeaf86e9596e7ab6e824acd6ee746c8de6c6964..8e02a9c81188cddd2c5941a1533fd7162f98723c 100644 (file)
@@ -73,13 +73,13 @@ libgold_a_LIBADD =
 am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) \
        compressed_output.$(OBJEXT) defstd.$(OBJEXT) \
        dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
-       ehframe.$(OBJEXT) errors.$(OBJEXT) fileread.$(OBJEXT) \
-       gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
-       merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
-       output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \
-       reloc.$(OBJEXT) resolve.$(OBJEXT) script.$(OBJEXT) \
-       stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
-       version.$(OBJEXT) workqueue.$(OBJEXT) \
+       ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
+       fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
+       layout.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
+       options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
+       readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \
+       script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
+       target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \
        workqueue-threads.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = yyscript.$(OBJEXT)
@@ -294,6 +294,7 @@ CCFILES = \
        dwarf_reader.cc \
        ehframe.cc \
        errors.cc \
+       expression.cc \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
@@ -477,6 +478,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ehframe.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expression.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
diff --git a/gold/expression.cc b/gold/expression.cc
new file mode 100644 (file)
index 0000000..3933280
--- /dev/null
@@ -0,0 +1,508 @@
+// expression.cc -- expressions in linker scripts for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <string>
+
+#include "parameters.h"
+#include "symtab.h"
+#include "layout.h"
+#include "script.h"
+#include "script-c.h"
+
+namespace gold
+{
+
+// This file holds the code which handles linker expressions.
+
+// When evaluating the value of an expression, we pass in a pointer to
+// this struct, so that the expression evaluation can find the
+// information it needs.
+
+struct Expression::Expression_eval_info
+{
+  const Symbol_table* symtab;
+  const Layout* layout;
+};
+
+// Evaluate an expression.
+
+uint64_t
+Expression::eval(const Symbol_table* symtab, const Layout* layout)
+{
+  Expression_eval_info eei;
+  eei.symtab = symtab;
+  eei.layout = layout;
+  return this->value(&eei);
+}
+
+// A number.
+
+class Integer_expression : public Expression
+{
+ public:
+  Integer_expression(uint64_t val)
+    : val_(val)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info*)
+  { return this->val_; }
+
+ private:
+  uint64_t val_;
+};
+
+extern "C" Expression*
+script_exp_integer(uint64_t val)
+{
+  return new Integer_expression(val);
+}
+
+// An expression whose value is the value of a symbol.
+
+class Symbol_expression : public Expression
+{
+ public:
+  Symbol_expression(const char* name, size_t length)
+    : name_(name, length)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info*);
+
+ private:
+  std::string name_;
+};
+
+uint64_t
+Symbol_expression::value(const Expression_eval_info* eei)
+{
+  Symbol* sym = eei->symtab->lookup(this->name_.c_str());
+  if (sym == NULL || !sym->is_defined())
+    {
+      gold_error(_("undefined symbol '%s' referenced in expression"),
+                this->name_.c_str());
+      return 0;
+    }
+
+  if (parameters->get_size() == 32)
+    return eei->symtab->get_sized_symbol<32>(sym)->value();
+  else if (parameters->get_size() == 64)
+    return eei->symtab->get_sized_symbol<64>(sym)->value();
+  else
+    gold_unreachable();
+}
+
+// An expression whose value is the value of the special symbol ".".
+// This is only valid within a SECTIONS clause.
+
+class Dot_expression : public Expression
+{
+ public:
+  Dot_expression()
+  { }
+
+  uint64_t
+  value(const Expression_eval_info*);
+};
+
+uint64_t
+Dot_expression::value(const Expression_eval_info*)
+{
+  gold_error("dot symbol unimplemented");
+  return 0;
+}
+
+// A string.  This is either the name of a symbol, or ".".
+
+extern "C" Expression*
+script_exp_string(const char* name, size_t length)
+{
+  if (length == 1 && name[0] == '.')
+    return new Dot_expression();
+  else
+    return new Symbol_expression(name, length);
+}
+
+// A unary expression.
+
+class Unary_expression : public Expression
+{
+ public:
+  Unary_expression(Expression* arg)
+    : arg_(arg)
+  { }
+
+  ~Unary_expression()
+  { delete this->arg_; }
+
+ protected:
+  uint64_t
+  arg_value(const Expression_eval_info* eei) const
+  { return this->arg_->value(eei); }
+
+ private:
+  Expression* arg_;
+};
+
+// Handle unary operators.  We use a preprocessor macro as a hack to
+// capture the C operator.
+
+#define UNARY_EXPRESSION(NAME, OPERATOR)                       \
+  class Unary_ ## NAME : public Unary_expression               \
+  {                                                            \
+   public:                                                     \
+    Unary_ ## NAME(Expression* arg)                            \
+      : Unary_expression(arg)                                  \
+    { }                                                                \
+                                                               \
+    uint64_t                                                   \
+    value(const Expression_eval_info* eei)                     \
+    { return OPERATOR this->arg_value(eei); }                  \
+  };                                                           \
+                                                               \
+  extern "C" Expression*                                       \
+  script_exp_unary_ ## NAME(Expression* arg)                   \
+  {                                                            \
+    return new Unary_ ## NAME(arg);                            \
+  }
+
+UNARY_EXPRESSION(minus, -)
+UNARY_EXPRESSION(logical_not, !)
+UNARY_EXPRESSION(bitwise_not, ~)
+
+// A binary expression.
+
+class Binary_expression : public Expression
+{
+ public:
+  Binary_expression(Expression* left, Expression* right)
+    : left_(left), right_(right)
+  { }
+
+  ~Binary_expression()
+  {
+    delete this->left_;
+    delete this->right_;
+  }
+
+ protected:
+  uint64_t
+  left_value(const Expression_eval_info* eei) const
+  { return this->left_->value(eei); }
+
+  uint64_t
+  right_value(const Expression_eval_info* eei) const
+  { return this->right_->value(eei); }
+
+ private:
+  Expression* left_;
+  Expression* right_;
+};
+
+// Handle binary operators.  We use a preprocessor macro as a hack to
+// capture the C operator.
+
+#define BINARY_EXPRESSION(NAME, OPERATOR)                              \
+  class Binary_ ## NAME : public Binary_expression                     \
+  {                                                                    \
+  public:                                                              \
+    Binary_ ## NAME(Expression* left, Expression* right)               \
+      : Binary_expression(left, right)                                 \
+    { }                                                                        \
+                                                                       \
+    uint64_t                                                           \
+    value(const Expression_eval_info* eei)                             \
+    {                                                                  \
+      return (this->left_value(eei)                                    \
+             OPERATOR this->right_value(eei));                         \
+    }                                                                  \
+  };                                                                   \
+                                                                       \
+  extern "C" Expression*                                               \
+  script_exp_binary_ ## NAME(Expression* left, Expression* right)      \
+  {                                                                    \
+    return new Binary_ ## NAME(left, right);                           \
+  }
+
+BINARY_EXPRESSION(mult, *)
+BINARY_EXPRESSION(div, /)
+BINARY_EXPRESSION(mod, %)
+BINARY_EXPRESSION(add, +)
+BINARY_EXPRESSION(sub, -)
+BINARY_EXPRESSION(lshift, <<)
+BINARY_EXPRESSION(rshift, >>)
+BINARY_EXPRESSION(eq, ==)
+BINARY_EXPRESSION(ne, !=)
+BINARY_EXPRESSION(le, <=)
+BINARY_EXPRESSION(ge, >=)
+BINARY_EXPRESSION(lt, <)
+BINARY_EXPRESSION(gt, >)
+BINARY_EXPRESSION(bitwise_and, &)
+BINARY_EXPRESSION(bitwise_xor, ^)
+BINARY_EXPRESSION(bitwise_or, |)
+BINARY_EXPRESSION(logical_and, &&)
+BINARY_EXPRESSION(logical_or, ||)
+
+// A trinary expression.
+
+class Trinary_expression : public Expression
+{
+ public:
+  Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3)
+    : arg1_(arg1), arg2_(arg2), arg3_(arg3)
+  { }
+
+  ~Trinary_expression()
+  {
+    delete this->arg1_;
+    delete this->arg2_;
+    delete this->arg3_;
+  }
+
+ protected:
+  uint64_t
+  arg1_value(const Expression_eval_info* eei) const
+  { return this->arg1_->value(eei); }
+
+  uint64_t
+  arg2_value(const Expression_eval_info* eei) const
+  { return this->arg2_->value(eei); }
+
+  uint64_t
+  arg3_value(const Expression_eval_info* eei) const
+  { return this->arg3_->value(eei); }
+
+ private:
+  Expression* arg1_;
+  Expression* arg2_;
+  Expression* arg3_;
+};
+
+// The conditional operator.
+
+class Trinary_cond : public Trinary_expression
+{
+ public:
+  Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3)
+    : Trinary_expression(arg1, arg2, arg3)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info* eei)
+  {
+    return (this->arg1_value(eei)
+           ? this->arg2_value(eei)
+           : this->arg3_value(eei));
+  }
+};
+
+extern "C" Expression*
+script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3)
+{
+  return new Trinary_cond(arg1, arg2, arg3);
+}
+
+// Max function.
+
+class Max_expression : public Binary_expression
+{
+ public:
+  Max_expression(Expression* left, Expression* right)
+    : Binary_expression(left, right)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info* eei)
+  { return std::max(this->left_value(eei), this->right_value(eei)); }
+};
+
+extern "C" Expression*
+script_exp_function_max(Expression* left, Expression* right)
+{
+  return new Max_expression(left, right);
+}
+
+// Min function.
+
+class Min_expression : public Binary_expression
+{
+ public:
+  Min_expression(Expression* left, Expression* right)
+    : Binary_expression(left, right)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info* eei)
+  { return std::min(this->left_value(eei), this->right_value(eei)); }
+};
+
+extern "C" Expression*
+script_exp_function_min(Expression* left, Expression* right)
+{
+  return new Min_expression(left, right);
+}
+
+// Align function.
+
+class Align_expression : public Binary_expression
+{
+ public:
+  Align_expression(Expression* left, Expression* right)
+    : Binary_expression(left, right)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info* eei)
+  {
+    uint64_t align = this->right_value(eei);
+    uint64_t value = this->left_value(eei);
+    if (align <= 1)
+      return value;
+    return ((value + align - 1) / align) * align;
+  }
+};
+
+extern "C" Expression*
+script_exp_function_align(Expression* left, Expression* right)
+{
+  return new Align_expression(left, right);
+}
+
+// Assert function.
+
+class Assert_expression : public Unary_expression
+{
+ public:
+  Assert_expression(Expression* arg, const char* message, size_t length)
+    : Unary_expression(arg), message_(message, length)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info* eei)
+  {
+    uint64_t value = this->arg_value(eei);
+    if (!value)
+      gold_error("%s", this->message_.c_str());
+    return value;
+  }
+
+ private:
+  std::string message_;
+};
+
+extern "C" Expression*
+script_exp_function_assert(Expression* expr, const char* message,
+                          size_t length)
+{
+  return new Assert_expression(expr, message, length);
+}
+
+// Functions.
+
+extern "C" Expression*
+script_exp_function_defined(const char*, size_t)
+{
+  gold_fatal(_("DEFINED not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_sizeof_headers()
+{
+  gold_fatal(_("SIZEOF_HEADERS not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_alignof(const char*, size_t)
+{
+  gold_fatal(_("ALIGNOF not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_sizeof(const char*, size_t)
+{
+  gold_fatal(_("SIZEOF not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_addr(const char*, size_t)
+{
+  gold_fatal(_("ADDR not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_loadaddr(const char*, size_t)
+{
+  gold_fatal(_("LOADADDR not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_origin(const char*, size_t)
+{
+  gold_fatal(_("ORIGIN not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_length(const char*, size_t)
+{
+  gold_fatal(_("LENGTH not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_constant(const char*, size_t)
+{
+  gold_fatal(_("CONSTANT not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_absolute(Expression*)
+{
+  gold_fatal(_("ABSOLUTE not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_data_segment_align(Expression*, Expression*)
+{
+  gold_fatal(_("DATA_SEGMENT_ALIGN not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_data_segment_relro_end(Expression*, Expression*)
+{
+  gold_fatal(_("DATA_SEGMENT_RELRO_END not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_data_segment_end(Expression*)
+{
+  gold_fatal(_("DATA_SEGMENT_END not implemented"));
+}
+
+extern "C" Expression*
+script_exp_function_segment_start(const char*, size_t, Expression*)
+{
+  gold_fatal(_("SEGMENT_START not implemented"));
+}
+
+} // End namespace gold.
index b30087173a18e6a47a2c6a1920a3b8b69e98a309..d1e544afdf3f194a31dff54e40454a0c9c6c5412 100644 (file)
@@ -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 <iant@google.com>.
 
 // This file is part of gold.
@@ -202,6 +202,9 @@ queue_middle_tasks(const General_options& options,
   // appropriate.
   layout->define_section_symbols(symtab, input_objects->target());
 
+  // Define symbols from any linker scripts.
+  layout->define_script_symbols(symtab, input_objects->target());
+
   // Read the relocations of the input files.  We do this to find
   // which symbols are used by relocations which require a GOT and/or
   // a PLT entry, or a COPY reloc.  When we implement garbage
index a717ed241e12fd228d2102040949f2cf12b5b68a..7db2e81f32668fb96385a2cd5317b8a1a33aa7e8 100644 (file)
@@ -1,6 +1,6 @@
 // layout.cc -- lay out output file sections for gold
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -63,9 +63,9 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
 
 // Layout methods.
 
-Layout::Layout(const General_options& options)
-  : options_(options), entry_(options.entry()), namepool_(), sympool_(),
-    dynpool_(), signatures_(),
+Layout::Layout(const General_options& options, Script_options* script_options)
+  : options_(options), script_options_(script_options), 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),
@@ -722,7 +722,7 @@ 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,
-                                      this->entry_);
+                                      this->script_options_->entry());
   load_seg->add_initial_output_data(file_header);
   this->special_output_list_.push_back(file_header);
 
@@ -745,6 +745,10 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   if (!parameters->doing_static_link())
     this->assign_local_dynsym_offsets(input_objects);
 
+  // Process any symbol assignments from a linker script.  This must
+  // be called after the symbol table has been finalized.
+  this->script_options_->finalize_symbols(symtab, this);
+
   // Create the .shstrtab section.
   Output_section* shstrtab_section = this->create_shstrtab();
 
index a106cccd78a34ca9d7a678681ae6d0c9206bd6fa..b40a7ab461d6abfadfc4b773a9147bd03898d3e9 100644 (file)
@@ -1,6 +1,6 @@
 // layout.h -- lay out output file sections for gold  -*- C++ -*-
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -28,6 +28,7 @@
 #include <utility>
 #include <vector>
 
+#include "script.h"
 #include "workqueue.h"
 #include "object.h"
 #include "dynobj.h"
@@ -84,7 +85,7 @@ class Layout_task_runner : public Task_function_runner
 class Layout
 {
  public:
-  Layout(const General_options& options);
+  Layout(const General_options& options, Script_options*);
 
   // Given an input section SHNDX, named NAME, with data in SHDR, from
   // the object file OBJECT, return the output section where this
@@ -142,6 +143,11 @@ class Layout
   void
   define_section_symbols(Symbol_table*, const Target*);
 
+  // Define symbols from any linker script.
+  void
+  define_script_symbols(Symbol_table* symtab, const Target* target)
+  { this->script_options_->add_symbols_to_table(symtab, target); }
+
   // Return the Stringpool used for symbol names.
   const Stringpool*
   sympool() const
@@ -241,11 +247,14 @@ 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; }
+  // Return the options which may be set by a linker script.
+  Script_options*
+  script_options()
+  { return this->script_options_; }
+
+  const Script_options*
+  script_options() const
+  { return this->script_options_; }
 
   // Dump statistical information to stderr.
   void
@@ -432,9 +441,8 @@ 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_;
+  // Information set by scripts or by command line options.
+  Script_options* script_options_;
   // The output section names.
   Stringpool namepool_;
   // The output symbol names.
index 2874a2d4bd6c59374467b529e304361e08e0a4a6..fb201d7fb02f63ab6eb9407aeef75cec503b262e 100644 (file)
@@ -1,6 +1,6 @@
 // main.cc -- gold main function.
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -27,6 +27,7 @@
 #endif
 #include "libiberty.h"
 
+#include "script.h"
 #include "options.h"
 #include "parameters.h"
 #include "errors.h"
@@ -58,8 +59,12 @@ main(int argc, char** argv)
   // errors object.
   initialize_parameters(&errors);
 
+  // Options which may be set by the command line or by linker
+  // scripts.
+  Script_options script_options;
+
   // Handle the command line options.
-  Command_line command_line;
+  Command_line command_line(&script_options);
   command_line.process(argc - 1, argv + 1);
 
   long start_time = 0;
@@ -82,7 +87,7 @@ main(int argc, char** argv)
   Symbol_table symtab(command_line.number_of_input_files() * 1024);
 
   // The layout object.
-  Layout layout(command_line.options());
+  Layout layout(command_line.options(), &script_options);
 
   // Get the search path from the -L options.
   Dirsearch search_path;
index 2ba5414a43ce9e4378ae9845bbaf1451bd68e295..9b5103cb2e618e0096ec1e4132f31d618e7b631a 100644 (file)
@@ -1,6 +1,6 @@
 // options.c -- handle command line options for gold
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -29,6 +29,7 @@
 #include "libiberty.h"
 
 #include "debug.h"
+#include "script.h"
 #include "options.h"
 
 namespace gold
@@ -154,7 +155,7 @@ invoke_script(int argc, char** argv, char* arg, bool long_option,
                                                          arg, long_option,
                                                          &ret);
   if (!read_commandline_script(script_name, cmdline))
-    gold::gold_error(_("unable to parse script file %s\n"), script_name);
+    gold::gold_error(_("unable to parse script file %s"), script_name);
   return ret;
 }
 
@@ -386,6 +387,9 @@ options::Command_line_options::options[] =
               N_("--compress-debug-sections=[none" ZLIB_STR "]"),
               TWO_DASHES,
               &General_options::set_compress_debug_sections),
+  GENERAL_ARG('\0', "defsym", N_("Define a symbol"),
+             N_("--defsym SYMBOL=EXPRESSION"), TWO_DASHES,
+             &General_options::define_symbol),
   GENERAL_NOARG('\0', "demangle", N_("Demangle C++ symbols in log messages"),
                 NULL, TWO_DASHES, &General_options::set_demangle),
   GENERAL_NOARG('\0', "no-demangle",
@@ -531,9 +535,8 @@ const int options::Command_line_options::debug_options_size =
 
 // The default values for the general options.
 
-General_options::General_options()
-  : entry_(NULL),
-    export_dynamic_(false),
+General_options::General_options(Script_options* script_options)
+  : export_dynamic_(false),
     soname_(NULL),
     dynamic_linker_(NULL),
     search_path_(),
@@ -558,7 +561,8 @@ General_options::General_options()
     thread_count_middle_(0),
     thread_count_final_(0),
     execstack_(EXECSTACK_FROM_INPUT),
-    debug_(0)
+    debug_(0),
+    script_options_(script_options)
 {
   // We initialize demangle_ based on the environment variable
   // COLLECT_NO_DEMANGLE.  The gcc collect2 program will demangle the
@@ -568,13 +572,12 @@ General_options::General_options()
   this->demangle_ = getenv("COLLECT_NO_DEMANGLE") == NULL;
 }
 
-// The default values for the position dependent options.
+// Handle the --defsym option.
 
-Position_dependent_options::Position_dependent_options()
-  : do_static_search_(false),
-    as_needed_(false),
-    include_whole_archive_(false)
+void
+General_options::define_symbol(const char* arg)
 {
+  this->script_options_->define_symbol(arg);
 }
 
 // Handle the -z option.
@@ -645,6 +648,15 @@ General_options::add_sysroot()
   free(canonical_sysroot);
 }
 
+// The default values for the position dependent options.
+
+Position_dependent_options::Position_dependent_options()
+  : do_static_search_(false),
+    as_needed_(false),
+    include_whole_archive_(false)
+{
+}
+
 // Search_directory methods.
 
 // This is called if we have a sysroot.  Apply the sysroot if
@@ -721,8 +733,8 @@ Input_arguments::end_group()
 
 // Command_line options.
 
-Command_line::Command_line()
-  : options_(), position_options_(), inputs_()
+Command_line::Command_line(Script_options* script_options)
+  : options_(script_options), position_options_(), inputs_()
 {
 }
 
index 4cb760809ca32a66820ff7bc42eaa636d12be53c..e81856c1908ae09e9744d02c93f05febf72063b7 100644 (file)
@@ -1,6 +1,6 @@
 // options.h -- handle command line options for gold  -*- C++ -*-
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -106,12 +106,12 @@ class Search_directory
 class General_options
 {
  public:
-  General_options();
+  General_options(Script_options*);
 
   // -e: set entry address.
   const char*
   entry() const
-  { return this->entry_; }
+  { return this->script_options_->entry(); }
 
   // -E: export dynamic symbols.
   bool
@@ -277,6 +277,15 @@ class General_options
   debug() const
   { return this->debug_; }
 
+  // Return the options which may be set from a linker script.
+  Script_options*
+  script_options()
+  { return this->script_options_; }
+
+  const Script_options*
+  script_options() const
+  { return this->script_options_; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -318,7 +327,7 @@ class General_options
 
   void
   set_entry(const char* arg)
-  { this->entry_ = arg; }
+  { this->script_options_->set_entry(arg, strlen(arg)); }
 
   void
   set_export_dynamic()
@@ -396,6 +405,9 @@ class General_options
                  arg);
   }
 
+  void
+  define_symbol(const char* arg);
+
   void
   set_demangle()
   { this->demangle_ = true; }
@@ -518,7 +530,6 @@ class General_options
   void
   add_sysroot();
 
-  const char* entry_;
   bool export_dynamic_;
   const char* soname_;
   const char* dynamic_linker_;
@@ -546,6 +557,9 @@ class General_options
   int thread_count_final_;
   Execstack execstack_;
   unsigned int debug_;
+  // Some options can also be set from linker scripts.  Those are
+  // stored here.
+  Script_options* script_options_;
 };
 
 // The current state of the position dependent options.
@@ -810,7 +824,7 @@ class Command_line
  public:
   typedef Input_arguments::const_iterator const_iterator;
 
-  Command_line();
+  Command_line(Script_options*);
 
   // Process the command line options.  This will exit with an
   // appropriate error message if an unrecognized option is seen.
@@ -834,11 +848,6 @@ 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,
@@ -855,6 +864,15 @@ class Command_line
   position_dependent_options() const
   { return this->position_options_; }
 
+  // Get the options which may be set from a linker script.
+  Script_options*
+  script_options()
+  { return this->options_.script_options(); }
+
+  const Script_options*
+  script_options() const
+  { return this->options_.script_options(); }
+
   // The number of input files.
   int
   number_of_input_files() const
index 6335c9ed97522749fe6fa4cf9521f57b3d73b0c1..b1cfa5a057d112da2051b986c836411c831ccd94 100644 (file)
@@ -16,6 +16,7 @@ ehframe.cc
 ehframe.h
 errors.cc
 errors.h
+expression.cc
 fileread.cc
 fileread.h
 gold.cc
index ff4e2c8f2c67ac237052b6edabe0111e10203b1d..8efe501f2bf07b86d3acc9cb5392b8dd8bcde361 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-12-21 15:26-0800\n"
+"POT-Creation-Date: 2008-01-09 11:37-0800\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,47 +16,47 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: archive.cc:96
+#: archive.cc:97
 #, c-format
 msgid "%s: no archive symbol table (run ranlib)"
 msgstr ""
 
-#: archive.cc:147
+#: archive.cc:151
 #, c-format
 msgid "%s: bad archive symbol table names"
 msgstr ""
 
-#: archive.cc:177
+#: archive.cc:181
 #, c-format
 msgid "%s: malformed archive header at %zu"
 msgstr ""
 
-#: archive.cc:197
+#: archive.cc:201
 #, c-format
 msgid "%s: malformed archive header size at %zu"
 msgstr ""
 
-#: archive.cc:208
+#: archive.cc:212
 #, c-format
 msgid "%s: malformed archive header name at %zu"
 msgstr ""
 
-#: archive.cc:233
+#: archive.cc:237
 #, c-format
 msgid "%s: bad extended name index at %zu"
 msgstr ""
 
-#: archive.cc:243
+#: archive.cc:247
 #, c-format
 msgid "%s: bad extended name entry at header %zu"
 msgstr ""
 
-#: archive.cc:336
+#: archive.cc:340
 #, c-format
 msgid "%s: short archive header at %zu"
 msgstr ""
 
-#: archive.cc:387 archive.cc:401
+#: archive.cc:391 archive.cc:405
 #, c-format
 msgid "%s: member at %zu is not an ELF object"
 msgstr ""
@@ -114,7 +114,7 @@ msgstr ""
 msgid "dynamic symbol table name section has wrong type: %u"
 msgstr ""
 
-#: dynobj.cc:404 object.cc:241 object.cc:579
+#: dynobj.cc:404 object.cc:251 object.cc:589
 #, c-format
 msgid "bad section name offset for section %u: %lu"
 msgstr ""
@@ -178,82 +178,158 @@ msgstr ""
 msgid "size of dynamic symbols is not multiple of symbol size"
 msgstr ""
 
-#: dynobj.cc:1312
+#: dynobj.cc:1316
 #, c-format
 msgid "symbol %s has undefined version %s"
 msgstr ""
 
-#: errors.cc:88
+#: errors.cc:106
 #, c-format
 msgid "%s: warning: "
 msgstr ""
 
-#: errors.cc:127
+#: errors.cc:137
 #, c-format
 msgid "%s: %s: warning: "
 msgstr ""
 
-#: errors.cc:154
+#: errors.cc:161
 #, c-format
 msgid "%s: %s: undefined reference to '%s'\n"
 msgstr ""
 
-#: errors.cc:164
+#: errors.cc:171
 #, c-format
 msgid "%s: "
 msgstr ""
 
-#: fileread.cc:49
+#: expression.cc:104
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr ""
+
+#: expression.cc:427
+msgid "DEFINED not implemented"
+msgstr ""
+
+#: expression.cc:433
+msgid "SIZEOF_HEADERS not implemented"
+msgstr ""
+
+#: expression.cc:439
+msgid "ALIGNOF not implemented"
+msgstr ""
+
+#: expression.cc:445
+msgid "SIZEOF not implemented"
+msgstr ""
+
+#: expression.cc:451
+msgid "ADDR not implemented"
+msgstr ""
+
+#: expression.cc:457
+msgid "LOADADDR not implemented"
+msgstr ""
+
+#: expression.cc:463
+msgid "ORIGIN not implemented"
+msgstr ""
+
+#: expression.cc:469
+msgid "LENGTH not implemented"
+msgstr ""
+
+#: expression.cc:475
+msgid "CONSTANT not implemented"
+msgstr ""
+
+#: expression.cc:481
+msgid "ABSOLUTE not implemented"
+msgstr ""
+
+#: expression.cc:487
+msgid "DATA_SEGMENT_ALIGN not implemented"
+msgstr ""
+
+#: expression.cc:493
+msgid "DATA_SEGMENT_RELRO_END not implemented"
+msgstr ""
+
+#: expression.cc:499
+msgid "DATA_SEGMENT_END not implemented"
+msgstr ""
+
+#: expression.cc:505
+msgid "SEGMENT_START not implemented"
+msgstr ""
+
+#: fileread.cc:50
 #, c-format
 msgid "munmap failed: %s"
 msgstr ""
 
-#: fileread.cc:90
+#: fileread.cc:91
 #, c-format
 msgid "close of %s failed: %s"
 msgstr ""
 
-#: fileread.cc:114
+#: fileread.cc:115
 #, c-format
 msgid "%s: fstat failed: %s"
 msgstr ""
 
-#: fileread.cc:229
+#: fileread.cc:240
 #, c-format
 msgid "%s: pread failed: %s"
 msgstr ""
 
-#: fileread.cc:235
+#: fileread.cc:246
 #, c-format
 msgid "%s: file too short: read only %lld of %lld bytes at %lld"
 msgstr ""
 
-#: fileread.cc:310
+#: fileread.cc:325
 #, c-format
 msgid "%s: mmap offset %lld size %lld failed: %s"
 msgstr ""
 
-#: fileread.cc:391
+#: fileread.cc:400
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr ""
+
+#: fileread.cc:406
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr ""
+
+#: fileread.cc:409
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr ""
+
+#: fileread.cc:556
 #, c-format
 msgid "%s: total bytes mapped for read: %llu\n"
 msgstr ""
 
-#: fileread.cc:393
+#: fileread.cc:558
 #, c-format
 msgid "%s: maximum bytes mapped for read at one time: %llu\n"
 msgstr ""
 
-#: fileread.cc:463
+#: fileread.cc:628
 #, c-format
 msgid "cannot find -l%s"
 msgstr ""
 
-#: fileread.cc:490
+#: fileread.cc:655
 #, c-format
 msgid "cannot find %s"
 msgstr ""
 
-#: fileread.cc:501
+#: fileread.cc:666
 #, c-format
 msgid "cannot open %s: %s"
 msgstr ""
@@ -398,7 +474,7 @@ msgstr ""
 msgid "%s: unsupported ELF machine number %d"
 msgstr ""
 
-#: object.cc:71 script.cc:1229
+#: object.cc:71
 #, c-format
 msgid "%s: %s"
 msgstr ""
@@ -408,124 +484,124 @@ msgstr ""
 msgid "section name section has wrong type: %u"
 msgstr ""
 
-#: object.cc:315
+#: object.cc:325
 #, c-format
 msgid "invalid symbol table name index: %u"
 msgstr ""
 
-#: object.cc:321
+#: object.cc:331
 #, c-format
 msgid "symbol table name section has wrong type: %u"
 msgstr ""
 
-#: object.cc:402
+#: object.cc:412
 #, c-format
 msgid "section group %u info %u out of range"
 msgstr ""
 
-#: object.cc:420
+#: object.cc:430
 #, c-format
 msgid "symbol %u name offset %u out of range"
 msgstr ""
 
-#: object.cc:452
+#: object.cc:462
 #, c-format
 msgid "section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:542 reloc.cc:206 reloc.cc:530
+#: object.cc:552 reloc.cc:213 reloc.cc:570
 #, c-format
 msgid "relocation section %u has bad info %u"
 msgstr ""
 
-#: object.cc:713
+#: object.cc:723
 msgid "size of symbols is not multiple of symbol size"
 msgstr ""
 
-#: object.cc:812
+#: object.cc:823
 #, c-format
 msgid "local symbol %u section name out of range: %u >= %u"
 msgstr ""
 
 #. FIXME: Handle SHN_XINDEX.
-#: object.cc:869
+#: object.cc:880
 #, c-format
 msgid "unknown section index %u for local symbol %u"
 msgstr ""
 
-#: object.cc:878
+#: object.cc:889
 #, c-format
 msgid "local symbol %u section index %u out of range"
 msgstr ""
 
-#: object.cc:1181
+#: object.cc:1192
 #, c-format
 msgid "%s: incompatible target"
 msgstr ""
 
-#: object.cc:1336
+#: object.cc:1347
 #, c-format
 msgid "%s: unsupported ELF file type %d"
 msgstr ""
 
-#: object.cc:1355 object.cc:1401 object.cc:1435
+#: object.cc:1366 object.cc:1412 object.cc:1446
 #, c-format
 msgid "%s: ELF file too short"
 msgstr ""
 
-#: object.cc:1363
+#: object.cc:1374
 #, c-format
 msgid "%s: invalid ELF version 0"
 msgstr ""
 
-#: object.cc:1365
+#: object.cc:1376
 #, c-format
 msgid "%s: unsupported ELF version %d"
 msgstr ""
 
-#: object.cc:1372
+#: object.cc:1383
 #, c-format
 msgid "%s: invalid ELF class 0"
 msgstr ""
 
-#: object.cc:1378
+#: object.cc:1389
 #, c-format
 msgid "%s: unsupported ELF class %d"
 msgstr ""
 
-#: object.cc:1385
+#: object.cc:1396
 #, c-format
 msgid "%s: invalid ELF data encoding"
 msgstr ""
 
-#: object.cc:1391
+#: object.cc:1402
 #, c-format
 msgid "%s: unsupported ELF data encoding %d"
 msgstr ""
 
-#: object.cc:1411
+#: object.cc:1422
 #, c-format
 msgid "%s: not configured to support 32-bit big-endian object"
 msgstr ""
 
-#: object.cc:1424
+#: object.cc:1435
 #, c-format
 msgid "%s: not configured to support 32-bit little-endian object"
 msgstr ""
 
-#: object.cc:1445
+#: object.cc:1456
 #, c-format
 msgid "%s: not configured to support 64-bit big-endian object"
 msgstr ""
 
-#: object.cc:1458
+#: object.cc:1469
 #, c-format
 msgid "%s: not configured to support 64-bit little-endian object"
 msgstr ""
 
-#: options.cc:157
+#: options.cc:158
 #, c-format
-msgid "%s: unable to parse script file %s\n"
+msgid "unable to parse script file %s"
 msgstr ""
 
 #: options.cc:185
@@ -576,337 +652,361 @@ msgid "]"
 msgstr ""
 
 #: options.cc:390
-msgid "Demangle C++ symbols in log messages"
+msgid "Define a symbol"
+msgstr ""
+
+#: options.cc:391
+msgid "--defsym SYMBOL=EXPRESSION"
 msgstr ""
 
 #: options.cc:393
-msgid "Do not demangle C++ symbols in log messages"
+msgid "Demangle C++ symbols in log messages"
 msgstr ""
 
 #: options.cc:396
+msgid "Do not demangle C++ symbols in log messages"
+msgstr ""
+
+#: options.cc:399
 msgid "Try to detect violations of the One Definition Rule"
 msgstr ""
 
-#: options.cc:398
+#: options.cc:401
+msgid "Set program start address"
+msgstr ""
+
+#: options.cc:402
+msgid "-e ADDRESS, --entry ADDRESS"
+msgstr ""
+
+#: options.cc:404
 msgid "Export all dynamic symbols"
 msgstr ""
 
-#: options.cc:400
+#: options.cc:406
 msgid "Create exception frame header"
 msgstr ""
 
-#: options.cc:402
+#: options.cc:408
+msgid "Set shared library name"
+msgstr ""
+
+#: options.cc:409
+msgid "-h FILENAME, -soname FILENAME"
+msgstr ""
+
+#: options.cc:411
 msgid "Set dynamic linker path"
 msgstr ""
 
-#: options.cc:403
+#: options.cc:412
 msgid "-I PROGRAM, --dynamic-linker PROGRAM"
 msgstr ""
 
-#: options.cc:405
+#: options.cc:414
 msgid "Search for library LIBNAME"
 msgstr ""
 
-#: options.cc:406
+#: options.cc:415
 msgid "-lLIBNAME, --library LIBNAME"
 msgstr ""
 
-#: options.cc:408
+#: options.cc:417
 msgid "Add directory to search path"
 msgstr ""
 
-#: options.cc:409
+#: options.cc:418
 msgid "-L DIR, --library-path DIR"
 msgstr ""
 
-#: options.cc:411
+#: options.cc:420
 msgid "Ignored for compatibility"
 msgstr ""
 
-#: options.cc:413
+#: options.cc:422
 msgid "Set output file name"
 msgstr ""
 
-#: options.cc:414
+#: options.cc:423
 msgid "-o FILE, --output FILE"
 msgstr ""
 
-#: options.cc:416
+#: options.cc:425
 msgid "Optimize output file size"
 msgstr ""
 
-#: options.cc:417
+#: options.cc:426
 msgid "-O level"
 msgstr ""
 
-#: options.cc:419
+#: options.cc:428
 msgid "Generate relocatable output"
 msgstr ""
 
-#: options.cc:421
+#: options.cc:430
 msgid "Add DIR to runtime search path"
 msgstr ""
 
-#: options.cc:422
+#: options.cc:431
 msgid "-R DIR, -rpath DIR"
 msgstr ""
 
-#: options.cc:425
+#: options.cc:434
 msgid "Add DIR to link time shared library search path"
 msgstr ""
 
-#: options.cc:426
+#: options.cc:435
 msgid "--rpath-link DIR"
 msgstr ""
 
-#: options.cc:428
+#: options.cc:437
 msgid "Strip all symbols"
 msgstr ""
 
-#: options.cc:431
+#: options.cc:440
 msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
 msgstr ""
 
 #. This must come after -Sdebug since it's a prefix of it.
-#: options.cc:435
+#: options.cc:444
 msgid "Strip debugging information"
 msgstr ""
 
-#: options.cc:437
+#: options.cc:446
 msgid "Generate shared library"
 msgstr ""
 
-#: options.cc:439
+#: options.cc:448
 msgid "Do not link against shared libraries"
 msgstr ""
 
-#: options.cc:441
+#: options.cc:450
 msgid "Print resource usage statistics"
 msgstr ""
 
-#: options.cc:443
+#: options.cc:452
 msgid "Set target system root directory"
 msgstr ""
 
-#: options.cc:444
+#: options.cc:453
 msgid "--sysroot DIR"
 msgstr ""
 
-#: options.cc:445
+#: options.cc:454
 msgid "Set the address of the .text section"
 msgstr ""
 
-#: options.cc:446
+#: options.cc:455
 msgid "-Ttext ADDRESS"
 msgstr ""
 
 #. This must come after -Ttext since it's a prefix of it.
-#: options.cc:449
+#: options.cc:458
 msgid "Read linker script"
 msgstr ""
 
-#: options.cc:450
+#: options.cc:459
 msgid "-T FILE, --script FILE"
 msgstr ""
 
-#: options.cc:452
+#: options.cc:461
 msgid "Run the linker multi-threaded"
 msgstr ""
 
-#: options.cc:454
+#: options.cc:463
 msgid "Do not run the linker multi-threaded"
 msgstr ""
 
-#: options.cc:456
+#: options.cc:465
 msgid "Number of threads to use"
 msgstr ""
 
-#: options.cc:457
+#: options.cc:466
 msgid "--thread-count COUNT"
 msgstr ""
 
-#: options.cc:460
+#: options.cc:469
 msgid "Number of threads to use in initial pass"
 msgstr ""
 
-#: options.cc:461
+#: options.cc:470
 msgid "--thread-count-initial COUNT"
 msgstr ""
 
-#: options.cc:464
+#: options.cc:473
 msgid "Number of threads to use in middle pass"
 msgstr ""
 
-#: options.cc:465
+#: options.cc:474
 msgid "--thread-count-middle COUNT"
 msgstr ""
 
-#: options.cc:468
+#: options.cc:477
 msgid "Number of threads to use in final pass"
 msgstr ""
 
-#: options.cc:469
+#: options.cc:478
 msgid "--thread-count-final COUNT"
 msgstr ""
 
-#: options.cc:472
+#: options.cc:481
 msgid "Include all archive contents"
 msgstr ""
 
-#: options.cc:476
+#: options.cc:485
 msgid "Include only needed archive contents"
 msgstr ""
 
-#: options.cc:481
+#: options.cc:490
 msgid ""
 "Subcommands as follows:\n"
 "    -z execstack              Mark output as requiring executable stack\n"
 "    -z noexecstack            Mark output as not requiring executable stack"
 msgstr ""
 
-#: options.cc:484
+#: options.cc:493
 msgid "-z SUBCOMMAND"
 msgstr ""
 
-#: options.cc:487
+#: options.cc:496
 msgid "Start a library search group"
 msgstr ""
 
-#: options.cc:489
+#: options.cc:498
 msgid "End a library search group"
 msgstr ""
 
-#: options.cc:491
+#: options.cc:500
 msgid "Report usage information"
 msgstr ""
 
-#: options.cc:493
+#: options.cc:502
 msgid "Report version information"
 msgstr ""
 
-#: options.cc:495
+#: options.cc:504
 msgid "Turn on debugging (all,task)"
 msgstr ""
 
-#: options.cc:496
+#: options.cc:505
 msgid "--debug=TYPE"
 msgstr ""
 
-#: options.cc:590
+#: options.cc:600
 #, c-format
 msgid "%s: unrecognized -z subcommand: %s\n"
 msgstr ""
 
-#: options.cc:613
+#: options.cc:623
 #, c-format
 msgid "%s: unrecognized --debug subcommand: %s\n"
 msgstr ""
 
-#: options.cc:793
+#: options.cc:812
 msgid "unexpected argument"
 msgstr ""
 
-#: options.cc:800 options.cc:852 options.cc:933
+#: options.cc:819 options.cc:871 options.cc:952
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:813 options.cc:861
+#: options.cc:832 options.cc:880
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:879
+#: options.cc:898
 #, c-format
 msgid "%s: missing group end\n"
 msgstr ""
 
-#: options.cc:1007
+#: options.cc:1026
 msgid "may not nest groups"
 msgstr ""
 
-#: options.cc:1017
+#: options.cc:1036
 msgid "group end without group start"
 msgstr ""
 
-#: options.cc:1027
+#: options.cc:1046
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:1036
+#: options.cc:1055
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:1045
+#: options.cc:1064
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: options.h:331
+#: options.h:358
 #, c-format
 msgid "invalid optimization level: %s"
 msgstr ""
 
-#: options.h:377
+#: options.h:404
 #, c-format
 msgid "unsupported argument to --compress-debug-sections: %s"
 msgstr ""
 
-#: options.h:428
+#: options.h:458
 #, c-format
 msgid "invalid argument to -Ttext: %s"
 msgstr ""
 
-#: options.h:437
+#: options.h:467
 #, c-format
 msgid "invalid thread count: %s"
 msgstr ""
 
-#: options.h:445
+#: options.h:475
 msgid "--threads not supported"
 msgstr ""
 
-#: output.cc:1478
+#: output.cc:1511
 #, c-format
 msgid "invalid alignment %lu for section \"%s\""
 msgstr ""
 
-#: output.cc:2383
+#: output.cc:2418
 #, c-format
 msgid "%s: open: %s"
 msgstr ""
 
-#: output.cc:2403
+#: output.cc:2438
 #, c-format
 msgid "%s: mremap: %s"
 msgstr ""
 
-#: output.cc:2439
+#: output.cc:2474
 #, c-format
 msgid "%s: lseek: %s"
 msgstr ""
 
-#: output.cc:2442 output.cc:2479
+#: output.cc:2477 output.cc:2514
 #, c-format
 msgid "%s: write: %s"
 msgstr ""
 
-#: output.cc:2450
+#: output.cc:2485
 #, c-format
 msgid "%s: mmap: %s"
 msgstr ""
 
-#: output.cc:2460
+#: output.cc:2495
 #, c-format
 msgid "%s: munmap: %s"
 msgstr ""
 
-#: output.cc:2477
+#: output.cc:2512
 #, c-format
 msgid "%s: write: unexpected 0 return-value"
 msgstr ""
 
-#: output.cc:2489
+#: output.cc:2524
 #, c-format
 msgid "%s: close: %s"
 msgstr ""
@@ -927,22 +1027,22 @@ msgstr ""
 msgid "%s: not an object or archive"
 msgstr ""
 
-#: reloc.cc:225 reloc.cc:548
+#: reloc.cc:232 reloc.cc:588
 #, c-format
 msgid "relocation section %u uses unexpected symbol table %u"
 msgstr ""
 
-#: reloc.cc:240 reloc.cc:566
+#: reloc.cc:247 reloc.cc:606
 #, c-format
 msgid "unexpected entsize for reloc section %u: %lu != %u"
 msgstr ""
 
-#: reloc.cc:249 reloc.cc:575
+#: reloc.cc:256 reloc.cc:615
 #, c-format
 msgid "reloc section %u size %lu uneven"
 msgstr ""
 
-#: reloc.cc:839
+#: reloc.cc:879
 #, c-format
 msgid "reloc section size %zu is not a multiple of reloc size %d\n"
 msgstr ""
@@ -961,40 +1061,45 @@ msgstr ""
 
 #. Two definitions of the same symbol.
 #. FIXME: Do a better job of reporting locations.
-#: resolve.cc:318
+#: resolve.cc:322
 #, c-format
 msgid "%s: multiple definition of %s"
 msgstr ""
 
-#: resolve.cc:319 resolve.cc:324
+#: resolve.cc:323 resolve.cc:328
 msgid "command line"
 msgstr ""
 
-#: resolve.cc:321
+#: resolve.cc:325
 #, c-format
 msgid "%s: previous definition here"
 msgstr ""
 
+#: script.cc:1413
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr ""
+
 #. There are some options that we could handle here--e.g.,
 #. -lLIBRARY.  Should we bother?
-#: script.cc:1333
+#: script.cc:1539
 #, c-format
 msgid ""
-"%s: Ignoring command OPTION; OPTION is only valid for scripts specified via -"
-"T"
+"%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts "
+"specified via -T/--script"
 msgstr ""
 
-#: stringpool.cc:537
+#: stringpool.cc:525
 #, c-format
 msgid "%s: %s entries: %zu; buckets: %zu\n"
 msgstr ""
 
-#: stringpool.cc:541
+#: stringpool.cc:529
 #, c-format
 msgid "%s: %s entries: %zu\n"
 msgstr ""
 
-#: stringpool.cc:544
+#: stringpool.cc:532
 #, c-format
 msgid "%s: %s Stringdata structures: %zu\n"
 msgstr ""
@@ -1023,27 +1128,27 @@ msgstr ""
 msgid "versym for symbol %zu has no name: %u"
 msgstr ""
 
-#: symtab.cc:1493 symtab.cc:1709
+#: symtab.cc:1499 symtab.cc:1715
 #, c-format
 msgid "%s: unsupported symbol section 0x%x"
 msgstr ""
 
-#: symtab.cc:1833
+#: symtab.cc:1839
 #, c-format
 msgid "%s: undefined reference to '%s'"
 msgstr ""
 
-#: symtab.cc:1918
+#: symtab.cc:1924
 #, c-format
 msgid "%s: symbol table entries: %zu; buckets: %zu\n"
 msgstr ""
 
-#: symtab.cc:1921
+#: symtab.cc:1927
 #, c-format
 msgid "%s: symbol table entries: %zu\n"
 msgstr ""
 
-#: symtab.cc:1990
+#: symtab.cc:1996
 #, c-format
 msgid ""
 "while linking %s: symbol '%s' defined in multiple places (possible ODR "
index 6e3d3acce37ff0d2625b77640f4846f57ca93a6b..7062ccc57fe0aa607a21e48717da140f646513f0 100644 (file)
@@ -1,6 +1,6 @@
 // resolve.cc -- symbol resolution for gold
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -277,11 +277,15 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits,
 {
   *adjust_common_sizes = false;
 
-  unsigned int tobits = symbol_to_bits(to->binding(),
-                                       (to->source() == Symbol::FROM_OBJECT
-                                        && to->object()->is_dynamic()),
-                                       to->shndx(),
-                                       to->type());
+  unsigned int tobits;
+  if (to->source() == Symbol::FROM_OBJECT)
+    tobits = symbol_to_bits(to->binding(),
+                           to->object()->is_dynamic(),
+                           to->shndx(),
+                           to->type());
+  else
+    tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS,
+                           to->type());
 
   // FIXME: Warn if either but not both of TO and SYM are STT_TLS.
 
index 4b103f89d8bdc3976ede338b8620abe97aa7a56b..95816b76dd85f28f73cba7f1f6081dfc0402a5d9 100644 (file)
@@ -1,6 +1,6 @@
 /* script-c.h -- C interface for linker scripts in gold.  */
 
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <iant@google.com>.
 
    This file is part of gold.
 extern "C" {
 #endif
 
+/* A string value for the bison parser.  */
+
+struct Parser_string
+{
+  const char* value;
+  size_t length;
+};
+
+/* The expression functions deal with pointers to Expression objects.
+   Since the bison parser generates C code, this is a hack to keep the
+   C++ code type safe.  This hacks assumes that all pointers look
+   alike.  */
+
+#ifdef __cplusplus
+namespace gold
+{
+class Expression;
+}
+typedef gold::Expression* Expression_ptr;
+#else
+typedef void* Expression_ptr;
+#endif
+
+/* The bison parser definitions.  */
+
 #include "yyscript.h"
 
 /* The bison parser function.  */
@@ -50,7 +75,7 @@ yyerror(void* closure, const char*);
 /* Called by the bison parser to add a file to the link.  */
 
 extern void
-script_add_file(void* closure, const char*);
+script_add_file(void* closure, const char*, size_t);
 
 /* Called by the bison parser to start and stop a group.  */
 
@@ -69,11 +94,119 @@ 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*);
+script_set_entry(void* closure, const char*, size_t);
 
 /* Called by the bison parser to parse an OPTION.  */
+
+extern void
+script_parse_option(void* closure, const char*, size_t);
+
+/* Called by the bison parser to push the lexer into expression
+   mode.  */
+
+extern void
+script_push_lex_into_expression_mode(void* closure);
+
+/* Called by the bison parser to pop the lexer mode.  */
+
+extern void
+script_pop_lex_mode(void* closure);
+
+/* Called by the bison parser to set a symbol to a value.  PROVIDE is
+   non-zero if the symbol should be provided--only defined if there is
+   an undefined reference.  HIDDEN is non-zero if the symbol should be
+   hidden.  */
+
 extern void
-script_parse_option(void* closure, const char*);
+script_set_symbol(void* closure, const char*, size_t, Expression_ptr,
+                 int provide, int hidden);
+
+/* Called by the bison parser for expressions.  */
+
+extern Expression_ptr
+script_exp_unary_minus(Expression_ptr);
+extern Expression_ptr
+script_exp_unary_logical_not(Expression_ptr);
+extern Expression_ptr
+script_exp_unary_bitwise_not(Expression_ptr);
+extern Expression_ptr
+script_exp_binary_mult(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_div(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_mod(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_add(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_sub(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_lshift(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_rshift(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_eq(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_ne(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_le(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_ge(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_lt(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_gt(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_and(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_xor(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_or(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_logical_and(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_logical_or(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_trinary_cond(Expression_ptr, Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_integer(uint64_t);
+extern Expression_ptr
+script_exp_string(const char*, size_t);
+extern Expression_ptr
+script_exp_function_max(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_min(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_defined(const char*, size_t);
+extern Expression_ptr
+script_exp_function_sizeof_headers();
+extern Expression_ptr
+script_exp_function_alignof(const char*, size_t);
+extern Expression_ptr
+script_exp_function_sizeof(const char*, size_t);
+extern Expression_ptr
+script_exp_function_addr(const char*, size_t);
+extern Expression_ptr
+script_exp_function_loadaddr(const char*, size_t);
+extern Expression_ptr
+script_exp_function_origin(const char*, size_t);
+extern Expression_ptr
+script_exp_function_length(const char*, size_t);
+extern Expression_ptr
+script_exp_function_constant(const char*, size_t);
+extern Expression_ptr
+script_exp_function_absolute(Expression_ptr);
+extern Expression_ptr
+script_exp_function_align(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_align(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_relro_end(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_end(Expression_ptr);
+extern Expression_ptr
+script_exp_function_segment_start(const char*, size_t, Expression_ptr);
+extern Expression_ptr
+script_exp_function_assert(Expression_ptr, const char*, size_t);
 
 #ifdef __cplusplus
 }
index 2b14e3f15bcad88ad92215e09d5b181d513ad607..ae9cb86251188ca19ed402b32838ddedb381e27e 100644 (file)
@@ -1,6 +1,6 @@
 // script.cc -- handle linker scripts for gold.
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -28,6 +28,7 @@
 #include <cstdlib>
 #include "filenames.h"
 
+#include "elfcpp.h"
 #include "dirsearch.h"
 #include "options.h"
 #include "fileread.h"
@@ -35,7 +36,7 @@
 #include "readsyms.h"
 #include "parameters.h"
 #include "layout.h"
-#include "yyscript.h"
+#include "symtab.h"
 #include "script.h"
 #include "script-c.h"
 
@@ -57,6 +58,8 @@ class Token
     TOKEN_EOF,
     // Token is a string of characters.
     TOKEN_STRING,
+    // Token is a quoted string of characters.
+    TOKEN_QUOTED_STRING,
     // Token is an operator.
     TOKEN_OPERATOR,
     // Token is a number (an integer).
@@ -65,39 +68,33 @@ class Token
 
   // We need an empty constructor so that we can put this STL objects.
   Token()
-    : classification_(TOKEN_INVALID), value_(), opcode_(0),
-      lineno_(0), charpos_(0)
+    : classification_(TOKEN_INVALID), value_(NULL), value_length_(0),
+      opcode_(0), lineno_(0), charpos_(0)
   { }
 
   // A general token with no value.
   Token(Classification classification, int lineno, int charpos)
-    : classification_(classification), value_(), opcode_(0),
-      lineno_(lineno), charpos_(charpos)
+    : classification_(classification), value_(NULL), value_length_(0),
+      opcode_(0), lineno_(lineno), charpos_(charpos)
   {
     gold_assert(classification == TOKEN_INVALID
                || classification == TOKEN_EOF);
   }
 
   // A general token with a value.
-  Token(Classification classification, const std::string& value,
+  Token(Classification classification, const char* value, size_t length,
        int lineno, int charpos)
-    : classification_(classification), value_(value), opcode_(0),
-      lineno_(lineno), charpos_(charpos)
+    : classification_(classification), value_(value), value_length_(length),
+      opcode_(0), lineno_(lineno), charpos_(charpos)
   {
     gold_assert(classification != TOKEN_INVALID
                && classification != TOKEN_EOF);
   }
 
-  // A token representing a string of characters.
-  Token(const std::string& s, int lineno, int charpos)
-    : classification_(TOKEN_STRING), value_(s), opcode_(0),
-      lineno_(lineno), charpos_(charpos)
-  { }
-
   // A token representing an operator.
   Token(int opcode, int lineno, int charpos)
-    : classification_(TOKEN_OPERATOR), value_(), opcode_(opcode),
-      lineno_(lineno), charpos_(charpos)
+    : classification_(TOKEN_OPERATOR), value_(NULL), value_length_(0),
+      opcode_(opcode), lineno_(lineno), charpos_(charpos)
   { }
 
   // Return whether the token is invalid.
@@ -127,10 +124,12 @@ class Token
 
   // Get the value of a token.
 
-  const std::string&
-  string_value() const
+  const char*
+  string_value(size_t* length) const
   {
-    gold_assert(this->classification_ == TOKEN_STRING);
+    gold_assert(this->classification_ == TOKEN_STRING
+               || this->classification_ == TOKEN_QUOTED_STRING);
+    *length = this->value_length_;
     return this->value_;
   }
 
@@ -141,18 +140,23 @@ class Token
     return this->opcode_;
   }
 
-  int64_t
+  uint64_t
   integer_value() const
   {
     gold_assert(this->classification_ == TOKEN_INTEGER);
-    return strtoll(this->value_.c_str(), NULL, 0);
+    // Null terminate.
+    std::string s(this->value_, this->value_length_);
+    return strtoull(s.c_str(), NULL, 0);
   }
 
  private:
   // The token classification.
   Classification classification_;
-  // The token value, for TOKEN_STRING or TOKEN_INTEGER.
-  std::string value_;
+  // The token value, for TOKEN_STRING or TOKEN_QUOTED_STRING or
+  // TOKEN_INTEGER.
+  const char* value_;
+  // The length of the token value.
+  size_t value_length_;
   // The token value, for TOKEN_OPERATOR.
   int opcode_;
   // The line number where this token started (one based).
@@ -162,80 +166,95 @@ class Token
   int charpos_;
 };
 
-// This class handles lexing a file into a sequence of tokens.  We
-// don't expect linker scripts to be large, so we just read them and
-// tokenize them all at once.
+// This class handles lexing a file into a sequence of tokens.
 
 class Lex
 {
  public:
-  Lex(Input_file* input_file)
-    : input_file_(input_file), tokens_()
+  // We unfortunately have to support different lexing modes, because
+  // when reading different parts of a linker script we need to parse
+  // things differently.
+  enum Mode
+  {
+    // Reading an ordinary linker script.
+    LINKER_SCRIPT,
+    // Reading an expression in a linker script.
+    EXPRESSION,
+    // Reading a version script.
+    VERSION_SCRIPT
+  };
+
+  Lex(const char* input_string, size_t input_length, int parsing_token)
+    : input_string_(input_string), input_length_(input_length),
+      current_(input_string), mode_(LINKER_SCRIPT),
+      first_token_(parsing_token), token_(),
+      lineno_(1), linestart_(input_string)
   { }
 
-  // Tokenize the file.  Return the final token, which will be either
-  // an invalid token or an EOF token.  An invalid token indicates
-  // that tokenization failed.
-  Token
-  tokenize();
+  // Read a file into a string.
+  static void
+  read_file(Input_file*, std::string*);
+
+  // Return the next token.
+  const Token*
+  next_token();
 
-  // A token sequence.
-  typedef std::vector<Token> Token_sequence;
+  // Return the current lexing mode.
+  Lex::Mode
+  mode() const
+  { return this->mode_; }
 
-  // Return the tokens.
-  const Token_sequence&
-  tokens() const
-  { return this->tokens_; }
+  // Set the lexing mode.
+  void
+  set_mode(Mode mode)
+  { this->mode_ = mode; }
 
  private:
   Lex(const Lex&);
   Lex& operator=(const Lex&);
 
-  // Read the file into a string buffer.
-  void
-  read_file(std::string*);
-
   // Make a general token with no value at the current location.
   Token
-  make_token(Token::Classification c, const char* p) const
-  { return Token(c, this->lineno_, p - this->linestart_ + 1); }
+  make_token(Token::Classification c, const char* start) const
+  { return Token(c, this->lineno_, start - this->linestart_ + 1); }
 
   // Make a general token with a value at the current location.
   Token
-  make_token(Token::Classification c, const std::string& v, const char* p)
+  make_token(Token::Classification c, const char* v, size_t len,
+            const char* start)
     const
-  { return Token(c, v, this->lineno_, p - this->linestart_ + 1); }
+  { return Token(c, v, len, this->lineno_, start - this->linestart_ + 1); }
 
   // Make an operator token at the current location.
   Token
-  make_token(int opcode, const char* p) const
-  { return Token(opcode, this->lineno_, p - this->linestart_ + 1); }
+  make_token(int opcode, const char* start) const
+  { return Token(opcode, this->lineno_, start - this->linestart_ + 1); }
 
   // Make an invalid token at the current location.
   Token
-  make_invalid_token(const char* p)
-  { return this->make_token(Token::TOKEN_INVALID, p); }
+  make_invalid_token(const char* start)
+  { return this->make_token(Token::TOKEN_INVALID, start); }
 
   // Make an EOF token at the current location.
   Token
-  make_eof_token(const char* p)
-  { return this->make_token(Token::TOKEN_EOF, p); }
+  make_eof_token(const char* start)
+  { return this->make_token(Token::TOKEN_EOF, start); }
 
   // Return whether C can be the first character in a name.  C2 is the
   // next character, since we sometimes need that.
-  static inline bool
+  inline bool
   can_start_name(char c, char c2);
 
   // Return whether C can appear in a name which has already started.
-  static inline bool
+  inline bool
   can_continue_name(char c);
 
   // Return whether C, C2, C3 can start a hex number.
-  static inline bool
+  inline bool
   can_start_hex(char c, char c2, char c3);
 
   // Return whether C can appear in a hex number.
-  static inline bool
+  inline bool
   can_continue_hex(char c);
 
   // Return whether C can start a non-hex number.
@@ -243,7 +262,7 @@ class Lex
   can_start_number(char c);
 
   // Return whether C can appear in a non-hex number.
-  static inline bool
+  inline bool
   can_continue_number(char c)
   { return Lex::can_start_number(c); }
 
@@ -279,20 +298,30 @@ class Lex
   // CAN_CONTINUE_FN.  The token starts at START.  Start matching from
   // MATCH.  Set *PP to the character following the token.
   inline Token
-  gather_token(Token::Classification, bool (*can_continue_fn)(char),
+  gather_token(Token::Classification,
+              bool (Lex::*can_continue_fn)(char),
               const char* start, const char* match, const char** pp);
 
   // Build a token from a quoted string.
   Token
   gather_quoted_string(const char** pp);
 
-  // The file we are reading.
-  Input_file* input_file_;
-  // The token sequence we create.
-  Token_sequence tokens_;
+  // The string we are tokenizing.
+  const char* input_string_;
+  // The length of the string.
+  size_t input_length_;
+  // The current offset into the string.
+  const char* current_;
+  // The current lexing mode.
+  Mode mode_;
+  // The code to use for the first token.  This is set to 0 after it
+  // is used.
+  int first_token_;
+  // The current token.
+  Token token_;
   // The current line number.
   int lineno_;
-  // The start of the current line in the buffer.
+  // The start of the current line in the string.
   const char* linestart_;
 };
 
@@ -301,9 +330,9 @@ class Lex
 // data we've already read, so that we read aligned buffers.
 
 void
-Lex::read_file(std::string* contents)
+Lex::read_file(Input_file* input_file, std::string* contents)
 {
-  off_t filesize = this->input_file_->file().filesize();
+  off_t filesize = input_file->file().filesize();
   contents->clear();
   contents->reserve(filesize);
 
@@ -314,7 +343,7 @@ Lex::read_file(std::string* contents)
       off_t get = BUFSIZ;
       if (get > filesize - off)
        get = filesize - off;
-      this->input_file_->file().read(off, get, buf);
+      input_file->file().read(off, get, buf);
       contents->append(reinterpret_cast<char*>(&buf[0]), get);
       off += get;
     }
@@ -326,8 +355,9 @@ Lex::read_file(std::string* contents)
 // forward slash, backslash, and tilde.  Tilde is the tricky case
 // here; GNU ld also uses it as a bitwise not operator.  It is only
 // recognized as the operator if it is not immediately followed by
-// some character which can appear in a symbol.  That is, "~0" is a
-// symbol name, and "~ 0" is an expression using bitwise not.  We are
+// some character which can appear in a symbol.  That is, when we
+// don't know that we are looking at an expression, "~0" is a file
+// name, and "~ 0" is an expression using bitwise not.  We are
 // compatible.
 
 inline bool
@@ -345,11 +375,14 @@ Lex::can_start_name(char c, char c2)
     case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
     case 'y': case 'z':
-    case '_': case '.': case '$': case '/': case '\\':
+    case '_': case '.': case '$':
       return true;
 
+    case '/': case '\\':
+      return this->mode_ == LINKER_SCRIPT;
+
     case '~':
-      return can_continue_name(c2);
+      return this->mode_ == LINKER_SCRIPT && can_continue_name(c2);
 
     default:
       return false;
@@ -359,7 +392,8 @@ Lex::can_start_name(char c, char c2)
 // Return whether C can continue a name which has already started.
 // Subsequent characters in a name are the same as the leading
 // characters, plus digits and "=+-:[],?*".  So in general the linker
-// script language requires spaces around operators.
+// script language requires spaces around operators, unless we know
+// that we are parsing an expression.
 
 inline bool
 Lex::can_continue_name(char c)
@@ -376,14 +410,17 @@ Lex::can_continue_name(char c)
     case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
     case 'y': case 'z':
-    case '_': case '.': case '$': case '/': case '\\':
-    case '~':
+    case '_': case '.': case '$':
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
-    case '=': case '+': case '-': case ':': case '[': case ']':
-    case ',': case '?': case '*':
       return true;
 
+    case '/': case '\\': case '~':
+    case '=': case '+': case '-':
+    case ':': case '[': case ']':
+    case ',': case '?': case '*':
+      return this->mode_ == LINKER_SCRIPT;
+
     default:
       return false;
     }
@@ -393,8 +430,8 @@ Lex::can_continue_name(char c)
 // of digits.  The old linker accepts leading '$' for hex, and
 // trailing HXBOD.  Those are for MRI compatibility and we don't
 // accept them.  The old linker also accepts trailing MK for mega or
-// kilo.  Those are mentioned in the documentation, and we accept
-// them.
+// kilo.  FIXME: Those are mentioned in the documentation, and we
+// should accept them.
 
 // Return whether C1 C2 C3 can start a hex number.
 
@@ -402,7 +439,7 @@ inline bool
 Lex::can_start_hex(char c1, char c2, char c3)
 {
   if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
-    return Lex::can_continue_hex(c3);
+    return this->can_continue_hex(c3);
   return false;
 }
 
@@ -615,17 +652,15 @@ Lex::skip_line_comment(const char** pp)
 
 inline Token
 Lex::gather_token(Token::Classification classification,
-                 bool (*can_continue_fn)(char),
+                 bool (Lex::*can_continue_fn)(char),
                  const char* start,
                  const char* match,
                  const char **pp)
 {
-  while ((*can_continue_fn)(*match))
+  while ((this->*can_continue_fn)(*match))
     ++match;
   *pp = match;
-  return this->make_token(classification,
-                         std::string(start, match - start),
-                         start);
+  return this->make_token(classification, start, match - start, start);
 }
 
 // Build a token from a quoted string.
@@ -640,9 +675,7 @@ Lex::gather_quoted_string(const char** pp)
   if (p[skip] != '"')
     return this->make_invalid_token(start);
   *pp = p + skip + 1;
-  return this->make_token(Token::TOKEN_STRING,
-                         std::string(p, skip),
-                         start);
+  return this->make_token(Token::TOKEN_QUOTED_STRING, p, skip, start);
 }
 
 // Return the next token at *PP.  Update *PP.  General guideline: we
@@ -700,10 +733,10 @@ Lex::get_token(const char** pp)
        }
 
       // Check for a name.
-      if (Lex::can_start_name(p[0], p[1]))
+      if (this->can_start_name(p[0], p[1]))
        return this->gather_token(Token::TOKEN_STRING,
-                                 Lex::can_continue_name,
-                                 p, p + 2, pp);
+                                 &Lex::can_continue_name,
+                                 p, p + 1, pp);
 
       // We accept any arbitrary name in double quotes, as long as it
       // does not cross a line boundary.
@@ -715,14 +748,14 @@ Lex::get_token(const char** pp)
 
       // Check for a number.
 
-      if (Lex::can_start_hex(p[0], p[1], p[2]))
+      if (this->can_start_hex(p[0], p[1], p[2]))
        return this->gather_token(Token::TOKEN_INTEGER,
-                                 Lex::can_continue_hex,
+                                 &Lex::can_continue_hex,
                                  p, p + 3, pp);
 
       if (Lex::can_start_number(p[0]))
        return this->gather_token(Token::TOKEN_INTEGER,
-                                 Lex::can_continue_number,
+                                 &Lex::can_continue_number,
                                  p, p + 1, pp);
 
       // Check for operators.
@@ -752,34 +785,29 @@ Lex::get_token(const char** pp)
     }
 }
 
-// Tokenize the file.  Return the final token.
+// Return the next token.
 
-Token
-Lex::tokenize()
+const Token*
+Lex::next_token()
 {
-  std::string contents;
-  this->read_file(&contents);
-
-  const char* p = contents.c_str();
-
-  this->lineno_ = 1;
-  this->linestart_ = p;
-
-  while (true)
+  // The first token is special.
+  if (this->first_token_ != 0)
     {
-      Token t(this->get_token(&p));
+      this->token_ = Token(this->first_token_, 0, 0);
+      this->first_token_ = 0;
+      return &this->token_;
+    }
 
-      // Don't let an early null byte fool us into thinking that we've
-      // reached the end of the file.
-      if (t.is_eof()
-         && static_cast<size_t>(p - contents.c_str()) < contents.length())
-       t = this->make_invalid_token(p);
+  this->token_ = this->get_token(&this->current_);
 
-      if (t.is_invalid() || t.is_eof())
-       return t;
+  // Don't let an early null byte fool us into thinking that we've
+  // reached the end of the file.
+  if (this->token_.is_eof()
+      && (static_cast<size_t>(this->current_ - this->input_string_)
+         < this->input_length_))
+    this->token_ = this->make_invalid_token(this->current_);
 
-      this->tokens_.push_back(t);
-    }
+  return &this->token_;
 }
 
 // A trivial task which waits for THIS_BLOCKER to be clear and then
@@ -823,6 +851,79 @@ class Script_unblock : public Task
   Task_token* next_blocker_;
 };
 
+// Class Script_options.
+
+Script_options::Script_options()
+  : entry_(), symbol_assignments_()
+{
+}
+
+// Add any symbols we are defining to the symbol table.
+
+void
+Script_options::add_symbols_to_table(Symbol_table* symtab,
+                                    const Target* target)
+{
+  for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    {
+      elfcpp::STV vis = p->hidden ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
+      p->sym = symtab->define_as_constant(target,
+                                         p->name.c_str(),
+                                         NULL, // version
+                                         0, // value
+                                         0, // size
+                                         elfcpp::STT_NOTYPE,
+                                         elfcpp::STB_GLOBAL,
+                                         vis,
+                                         0, // nonvis
+                                         p->provide);
+    }
+}
+
+// Finalize symbol values.
+
+void
+Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+{
+  if (parameters->get_size() == 32)
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+      this->sized_finalize_symbols<32>(symtab, layout);
+#else
+      gold_unreachable();
+#endif
+    }
+  else if (parameters->get_size() == 64)
+    {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+      this->sized_finalize_symbols<64>(symtab, layout);
+#else
+      gold_unreachable();
+#endif
+    }
+  else
+    gold_unreachable();
+}
+
+template<int size>
+void
+Script_options::sized_finalize_symbols(Symbol_table* symtab,
+                                      const Layout* layout)
+{
+  for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    {
+      if (p->sym != NULL)
+       {
+         Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(p->sym);
+         ssym->set_value(p->value->eval(symtab, layout));
+       }
+    }
+}
+
 // This class holds data passed through the parser to the lexer and to
 // the parser support functions.  This avoids global variables.  We
 // can't use global variables because we need not be called by a
@@ -835,12 +936,12 @@ 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)
+                Script_options* script_options,
+                Lex* lex)
     : filename_(filename), posdep_options_(posdep_options),
       in_group_(in_group), is_in_sysroot_(is_in_sysroot),
-      command_line_(command_line), layout_(layout), tokens_(tokens),
-      next_token_index_(0), inputs_(NULL)
+      command_line_(command_line), script_options_(script_options),
+      lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL)
   { }
 
   // Return the file name.
@@ -868,36 +969,52 @@ class Parser_closure
   // Returns the Command_line structure passed in at constructor time.
   // This value may be NULL.  The caller may modify this, which modifies
   // the passed-in Command_line object (not a copy).
-  Command_line* command_line()
+  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
-  { return this->next_token_index_ >= this->tokens_->size(); }
+  // Return the options which may be set by a script.
+  Script_options*
+  script_options()
+  { return this->script_options_; }
 
   // Return the next token, and advance.
   const Token*
   next_token()
   {
-    const Token* ret = &(*this->tokens_)[this->next_token_index_];
-    ++this->next_token_index_;
-    return ret;
+    const Token* token = this->lex_->next_token();
+    this->lineno_ = token->lineno();
+    this->charpos_ = token->charpos();
+    return token;
   }
 
-  // Return the previous token.
-  const Token*
-  last_token() const
+  // Set a new lexer mode, pushing the current one.
+  void
+  push_lex_mode(Lex::Mode mode)
+  {
+    this->lex_mode_stack_.push_back(this->lex_->mode());
+    this->lex_->set_mode(mode);
+  }
+
+  // Pop the lexer mode.
+  void
+  pop_lex_mode()
   {
-    gold_assert(this->next_token_index_ > 0);
-    return &(*this->tokens_)[this->next_token_index_ - 1];
+    gold_assert(!this->lex_mode_stack_.empty());
+    this->lex_->set_mode(this->lex_mode_stack_.back());
+    this->lex_mode_stack_.pop_back();
   }
 
+  // Return the line number of the last token.
+  int
+  lineno() const
+  { return this->lineno_; }
+
+  // Return the character position in the line of the last token.
+  int
+  charpos() const
+  { return this->charpos_; }
+
   // Return the list of input files, creating it if necessary.  This
   // is a space leak--we never free the INPUTS_ pointer.
   Input_arguments*
@@ -924,13 +1041,16 @@ 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_;
-  // The index of the next token to return.
-  unsigned int next_token_index_;
+  // Options which may be set from any linker script.
+  Script_options* script_options_;
+  // The lexer.
+  Lex* lex_;
+  // The line number of the last token returned by next_token.
+  int lineno_;
+  // The column number of the last token returned by next_token.
+  int charpos_;
+  // A stack of lexer modes.
+  std::vector<Lex::Mode> lex_mode_stack_;
   // New input files found to add to the link.
   Input_arguments* inputs_;
 };
@@ -948,17 +1068,18 @@ read_input_script(Workqueue* workqueue, const General_options& options,
                  Input_file* input_file, const unsigned char*, off_t,
                  Task_token* this_blocker, Task_token* next_blocker)
 {
-  Lex lex(input_file);
-  if (lex.tokenize().is_invalid())
-    return false;
+  std::string input_string;
+  Lex::read_file(input_file, &input_string);
+
+  Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
 
   Parser_closure closure(input_file->filename().c_str(),
                         input_argument->file().options(),
                         input_group != NULL,
                         input_file->is_in_sysroot(),
                          NULL,
-                        layout,
-                        &lex.tokens());
+                        layout->script_options(),
+                        &lex);
 
   if (yyparse(&closure) != 0)
     return false;
@@ -1019,21 +1140,18 @@ read_commandline_script(const char* filename, Command_line* cmdline)
   if (!input_file.open(cmdline->options(), dirsearch, task))
     return false;
 
-  Lex lex(&input_file);
-  if (lex.tokenize().is_invalid())
-    {
-      // Opening the file locked it, so now we need to unlock it.
-      input_file.file().unlock(task);
-      return false;
-    }
+  std::string input_string;
+  Lex::read_file(&input_file, &input_string);
+
+  Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
 
   Parser_closure closure(filename,
                         cmdline->position_dependent_options(),
                         false,
                         input_file.is_in_sysroot(),
                          cmdline,
-                        NULL,
-                        &lex.tokens());
+                        cmdline->script_options(),
+                        &lex);
   if (yyparse(&closure) != 0)
     {
       input_file.file().unlock(task);
@@ -1047,6 +1165,29 @@ read_commandline_script(const char* filename, Command_line* cmdline)
   return true;
 }
 
+// Implement the --defsym option on the command line.  Return true if
+// all is well.
+
+bool
+Script_options::define_symbol(const char* definition)
+{
+  Lex lex(definition, strlen(definition), PARSING_DEFSYM);
+  lex.set_mode(Lex::EXPRESSION);
+
+  // Dummy value.
+  Position_dependent_options posdep_options;
+
+  Parser_closure closure("command line", posdep_options, false, false, NULL,
+                        this, &lex);
+
+  if (yyparse(&closure) != 0)
+    return false;
+
+  gold_assert(!closure.saw_inputs());
+
+  return true;
+}
+
 // Manage mapping from keywords to the codes expected by the bison
 // parser.
 
@@ -1065,7 +1206,7 @@ class Keyword_to_parsecode
   // Return the parsecode corresponding KEYWORD, or 0 if it is not a
   // keyword.
   static int
-  keyword_to_parsecode(const char* keyword);
+  keyword_to_parsecode(const char* keyword, size_t len);
 
  private:
   // The array of all keywords.
@@ -1085,6 +1226,7 @@ Keyword_to_parsecode::keyword_parsecodes_[] =
   { "ABSOLUTE", ABSOLUTE },
   { "ADDR", ADDR },
   { "ALIGN", ALIGN_K },
+  { "ALIGNOF", ALIGNOF },
   { "ASSERT", ASSERT_K },
   { "AS_NEEDED", AS_NEEDED },
   { "AT", AT },
@@ -1170,21 +1312,35 @@ const int Keyword_to_parsecode::keyword_count =
 extern "C"
 {
 
+struct Ktt_key
+{
+  const char* str;
+  size_t len;
+};
+
 static int
 ktt_compare(const void* keyv, const void* kttv)
 {
-  const char* key = static_cast<const char*>(keyv);
+  const Ktt_key* key = static_cast<const Ktt_key*>(keyv);
   const Keyword_to_parsecode::Keyword_parsecode* ktt =
     static_cast<const Keyword_to_parsecode::Keyword_parsecode*>(kttv);
-  return strcmp(key, ktt->keyword);
+  int i = strncmp(key->str, ktt->keyword, key->len);
+  if (i != 0)
+    return i;
+  if (ktt->keyword[key->len] != '\0')
+    return -1;
+  return 0;
 }
 
 } // End extern "C".
 
 int
-Keyword_to_parsecode::keyword_to_parsecode(const char* keyword)
+Keyword_to_parsecode::keyword_to_parsecode(const char* keyword, size_t len)
 {
-  void* kttv = bsearch(keyword,
+  Ktt_key key;
+  key.str = keyword;
+  key.len = len;
+  void* kttv = bsearch(&key,
                       Keyword_to_parsecode::keyword_parsecodes_,
                       Keyword_to_parsecode::keyword_count,
                       sizeof(Keyword_to_parsecode::keyword_parsecodes_[0]),
@@ -1209,29 +1365,36 @@ extern "C" int
 yylex(YYSTYPE* lvalp, void* closurev)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-
-  if (closure->at_eof())
-    return 0;
-
   const Token* token = closure->next_token();
-
   switch (token->classification())
     {
     default:
+      gold_unreachable();
+
     case Token::TOKEN_INVALID:
+      yyerror(closurev, "invalid character");
+      return 0;
+
     case Token::TOKEN_EOF:
-      gold_unreachable();
+      return 0;
 
     case Token::TOKEN_STRING:
       {
-       const char* str = token->string_value().c_str();
-       int parsecode = Keyword_to_parsecode::keyword_to_parsecode(str);
+       // This is either a keyword or a STRING.
+       size_t len;
+       const char* str = token->string_value(&len);
+       int parsecode = Keyword_to_parsecode::keyword_to_parsecode(str, len);
        if (parsecode != 0)
          return parsecode;
-       lvalp->string = str;
+       lvalp->string.value = str;
+       lvalp->string.length = len;
        return STRING;
       }
 
+    case Token::TOKEN_QUOTED_STRING:
+      lvalp->string.value = token->string_value(&lvalp->string.length);
+      return STRING;
+
     case Token::TOKEN_OPERATOR:
       return token->operator_value();
 
@@ -1247,16 +1410,14 @@ extern "C" void
 yyerror(void* closurev, const char* message)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-
-  const Token* token = closure->last_token();
-  gold_error(_("%s:%d:%d: %s"), closure->filename(), token->lineno(),
-            token->charpos(), message);
+  gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
+            closure->charpos(), message);
 }
 
 // Called by the bison parser to add a file to the link.
 
 extern "C" void
-script_add_file(void* closurev, const char* name)
+script_add_file(void* closurev, const char* name, size_t length)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
 
@@ -1264,17 +1425,16 @@ script_add_file(void* closurev, const char* name)
   // sysroot, then we want to prepend the sysroot to the file name.
   // For example, this is how we handle a cross link to the x86_64
   // libc.so, which refers to /lib/libc.so.6.
-  std::string name_string;
+  std::string name_string(name, length);
   const char* extra_search_path = ".";
   std::string script_directory;
-  if (IS_ABSOLUTE_PATH (name))
+  if (IS_ABSOLUTE_PATH(name_string.c_str()))
     {
       if (closure->is_in_sysroot())
        {
          const std::string& sysroot(parameters->sysroot());
          gold_assert(!sysroot.empty());
-         name_string = sysroot + name;
-         name = name_string.c_str();
+         name_string = sysroot + name_string;
        }
     }
   else
@@ -1290,7 +1450,7 @@ script_add_file(void* closurev, const char* name)
        }
     }
 
-  Input_file_argument file(name, false, extra_search_path,
+  Input_file_argument file(name_string.c_str(), false, extra_search_path,
                           closure->position_dependent_options());
   closure->inputs()->add_file(file);
 }
@@ -1345,19 +1505,29 @@ script_end_as_needed(void* closurev)
 // Called by the bison parser to set the entry symbol.
 
 extern "C" void
-script_set_entry(void* closurev, const char* entry)
+script_set_entry(void* closurev, const char* entry, size_t length)
 {
   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);
+  closure->script_options()->set_entry(entry, length);
+}
+
+// Called by the bison parser to define a symbol.
+
+extern "C" void
+script_set_symbol(void* closurev, const char* name, size_t length,
+                 Expression* value, int providei, int hiddeni)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  const bool provide = providei != 0;
+  const bool hidden = hiddeni != 0;
+  closure->script_options()->add_symbol_assignment(name, length, value,
+                                                  provide, hidden);
 }
 
 // Called by the bison parser to parse an OPTION.
 
 extern "C" void
-script_parse_option(void* closurev, const char* option)
+script_parse_option(void* closurev, const char* option, size_t length)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
   // We treat the option as a single command-line option, even if
@@ -1366,16 +1536,36 @@ 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"
+      gold_warning(_("%s:%d:%d: ignoring command OPTION; OPTION is only valid"
                     " for scripts specified via -T/--script"),
-                  closure->filename());
+                  closure->filename(), closure->lineno(), closure->charpos());
     }
   else
     {
       bool past_a_double_dash_option = false;
-      char* mutable_option = strdup(option);
+      char* mutable_option = strndup(option, length);
+      gold_assert(mutable_option != NULL);
       closure->command_line()->process_one_option(1, &mutable_option, 0,
                                                   &past_a_double_dash_option);
       free(mutable_option);
     }
 }
+
+/* Called by the bison parser to push the lexer into expression
+   mode.  */
+
+extern void
+script_push_lex_into_expression_mode(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->push_lex_mode(Lex::EXPRESSION);
+}
+
+/* Called by the bison parser to pop the lexer mode.  */
+
+extern void
+script_pop_lex_mode(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->pop_lex_mode();
+}
index 16caf03dcfc0da74450f3e4139197e9a21ba99ac..0dfa4bb4ace39ed2ab4bc80b4eea3456ff6dd851 100644 (file)
@@ -1,6 +1,6 @@
 // script.h -- handle linker scripts for gold   -*- C++ -*-
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -30,6 +30,8 @@
 #ifndef GOLD_SCRIPT_H
 #define GOLD_SCRIPT_H
 
+#include <vector>
+
 namespace gold
 {
 
@@ -41,9 +43,125 @@ class Input_argument;
 class Input_objects;
 class Input_group;
 class Input_file;
+class Target;
 class Task_token;
 class Workqueue;
 
+// This class represents an expression in a linker script.
+
+class Expression
+{
+ protected:
+  // These should only be created by child classes.
+  Expression()
+  { }
+
+ public:
+  virtual ~Expression()
+  { }
+
+  // Return the value of the expression.
+  uint64_t
+  eval(const Symbol_table*, const Layout*);
+
+ protected:
+  struct Expression_eval_info;
+
+ public:
+  // Compute the value of the expression (implemented by child class).
+  // This is public rather than protected because it is called
+  // directly by children of Expression on other Expression objects.
+  virtual uint64_t
+  value(const Expression_eval_info*) = 0;
+
+ private:
+  // May not be copied.
+  Expression(const Expression&);
+  Expression& operator=(const Expression&);
+};
+
+// We can read a linker script in two different contexts: when
+// initially parsing the command line, and when we find an input file
+// which is actually a linker script.  Also some of the data which can
+// be set by a linker script can also be set via command line options
+// like -e and --defsym.  This means that we have a type of data which
+// can be set both during command line option parsing and while
+// reading input files.  We store that data in an instance of this
+// object.  We will keep pointers to that instance in both the
+// Command_line and Layout objects.
+
+class Script_options
+{
+ public:
+  Script_options();
+
+  // The entry address.
+  const char*
+  entry() const
+  { return this->entry_.empty() ? NULL : this->entry_.c_str(); }
+
+  // Set the entry address.
+  void
+  set_entry(const char* entry, size_t length)
+  { this->entry_.assign(entry, length); }
+
+  // Add a symbol to be defined.  These are for symbol definitions
+  // which appear outside of a SECTIONS clause.
+  void
+  add_symbol_assignment(const char* name, size_t length, Expression* value,
+                       bool provided, bool hidden)
+  {
+    this->symbol_assignments_.push_back(Symbol_assignment(name, length, value,
+                                                         provided, hidden));
+  }
+
+  // Define a symbol from the command line.
+  bool
+  define_symbol(const char* definition);
+
+  // Add all symbol definitions to the symbol table.
+  void
+  add_symbols_to_table(Symbol_table*, const Target*);
+
+  // Finalize the symbol values.
+  void
+  finalize_symbols(Symbol_table*, const Layout*);
+
+ private:
+  // We keep a list of symbol assignments.
+  struct Symbol_assignment
+  {
+    // Symbol name.
+    std::string name;
+    // Expression to assign to symbol.
+    Expression* value;
+    // Whether the assignment should be provided (only set if there is
+    // an undefined reference to the symbol.
+    bool provide;
+    // Whether the assignment should be hidden.
+    bool hidden;
+    // The entry in the symbol table.
+    Symbol* sym;
+
+    Symbol_assignment(const char* namea, size_t lengtha, Expression* valuea,
+                     bool providea, bool hiddena)
+      : name(namea, lengtha), value(valuea), provide(providea),
+       hidden(hiddena), sym(NULL)
+    { }
+  };
+
+  typedef std::vector<Symbol_assignment> Symbol_assignments;
+
+  template<int size>
+  void
+  sized_finalize_symbols(Symbol_table*, const Layout*);
+
+  // The entry address.  This will be empty if not set.
+  std::string entry_;
+  // Symbols to set.
+  Symbol_assignments symbol_assignments_;
+};
+
 // FILE was found as an argument on the command line, but was not
 // recognized as an ELF file.  Try to read it as a script.  We've
 // already read BYTES of data into P.  Return true if the file was
index a9f51386d475268b59e4b4a45387c50f663bb936..ae8e75100b271957e12c615d256ad68cafec47bb 100644 (file)
@@ -1,6 +1,6 @@
 // symtab.cc -- the gold symbol table
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -1056,11 +1056,13 @@ Symbol_table::do_define_in_output_data(
   sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
            offset_is_from_end);
 
-  if (oldsym != NULL
-      && Symbol_table::should_override_with_special(oldsym))
-    this->override_with_special(oldsym, sym);
+  if (oldsym == NULL)
+    return sym;
 
-  return sym;
+  if (Symbol_table::should_override_with_special(oldsym))
+    this->override_with_special(oldsym, sym);
+  delete sym;
+  return oldsym;
 }
 
 // Define a symbol based on an Output_segment.
@@ -1150,11 +1152,13 @@ Symbol_table::do_define_in_output_segment(
   sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
            offset_base);
 
-  if (oldsym != NULL
-      && Symbol_table::should_override_with_special(oldsym))
-    this->override_with_special(oldsym, sym);
+  if (oldsym == NULL)
+    return sym;
 
-  return sym;
+  if (Symbol_table::should_override_with_special(oldsym))
+    this->override_with_special(oldsym, sym);
+  delete sym;
+  return oldsym;
 }
 
 // Define a special symbol with a constant value.  It is a multiple
@@ -1237,11 +1241,13 @@ Symbol_table::do_define_as_constant(
   gold_assert(version == NULL || oldsym != NULL);
   sym->init(name, value, symsize, type, binding, visibility, nonvis);
 
-  if (oldsym != NULL
-      && Symbol_table::should_override_with_special(oldsym))
-    this->override_with_special(oldsym, sym);
+  if (oldsym == NULL)
+    return sym;
 
-  return sym;
+  if (Symbol_table::should_override_with_special(oldsym))
+    this->override_with_special(oldsym, sym);
+  delete sym;
+  return oldsym;
 }
 
 // Define a set of symbols in output sections.
index 8083ff08d3c75965a622ad49b25701ee77700c71..46e949c235220910ded8825203e97cb57a24877c 100644 (file)
@@ -503,5 +503,10 @@ ver_test_3.o: ver_test_3.cc
 ver_test_4.o: ver_test_4.cc
        $(CXXCOMPILE) -c -fpic -o $@ $<
 
+check_PROGRAMS += script_test_1
+script_test_1_SOURCES = script_test_1.cc
+script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
+script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
+
 endif GCC
 endif NATIVE_LINKER
index 316cf00836c6cf1a2cbf9ff9d46d49f2f7fa042a..f61e4e5f397934e03fa87fa351d8035fbcf7462a 100644 (file)
@@ -171,7 +171,14 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_10 = flagstest_compress_debug_sections \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test script_test_1
+@GCC_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+@GCC_FALSE@    $(am__DEPENDENCIES_1)
+@NATIVE_LINKER_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a \
+@NATIVE_LINKER_FALSE@  ../libgold.a ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -233,7 +240,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_7 = flagstest_compress_debug_sections$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT) \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT)
 basic_pic_test_SOURCES = basic_pic_test.c
 basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
 basic_pic_test_LDADD = $(LDADD)
@@ -349,6 +357,11 @@ object_unittest_LDADD = $(LDADD)
 object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
        ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
+am__script_test_1_SOURCES_DIST = script_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_script_test_1_OBJECTS =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1.$(OBJEXT)
+script_test_1_OBJECTS = $(am_script_test_1_OBJECTS)
+script_test_1_LDADD = $(LDADD)
 am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
 tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
@@ -503,8 +516,8 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(exception_static_test_SOURCES) $(exception_test_SOURCES) \
        flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
        flagstest_o_specialfile_and_compress_debug_sections.c \
-       $(object_unittest_SOURCES) $(tls_pic_test_SOURCES) \
-       $(tls_shared_ie_test_SOURCES) \
+       $(object_unittest_SOURCES) $(script_test_1_SOURCES) \
+       $(tls_pic_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
        $(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
        $(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
        $(tls_test_SOURCES) $(two_file_pic_test_SOURCES) \
@@ -535,7 +548,8 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(am__exception_test_SOURCES_DIST) \
        flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
        flagstest_o_specialfile_and_compress_debug_sections.c \
-       $(object_unittest_SOURCES) $(am__tls_pic_test_SOURCES_DIST) \
+       $(object_unittest_SOURCES) $(am__script_test_1_SOURCES_DIST) \
+       $(am__tls_pic_test_SOURCES_DIST) \
        $(am__tls_shared_ie_test_SOURCES_DIST) \
        $(am__tls_shared_nonpic_test_SOURCES_DIST) \
        $(am__tls_shared_test_SOURCES_DIST) \
@@ -905,6 +919,9 @@ object_unittest_SOURCES = object_unittest.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_DEPENDENCIES = gcctestdir/ld ver_test_1.so ver_test_2.so ver_test_4.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDADD = ver_test_1.so ver_test_2.so ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_SOURCES = script_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
 all: all-am
 
 .SUFFIXES:
@@ -1020,6 +1037,9 @@ exception_test$(EXEEXT): $(exception_test_OBJECTS) $(exception_test_DEPENDENCIES
 object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES) 
        @rm -f object_unittest$(EXEEXT)
        $(CXXLINK) $(object_unittest_LDFLAGS) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
+script_test_1$(EXEEXT): $(script_test_1_OBJECTS) $(script_test_1_DEPENDENCIES) 
+       @rm -f script_test_1$(EXEEXT)
+       $(CXXLINK) $(script_test_1_LDFLAGS) $(script_test_1_OBJECTS) $(script_test_1_LDADD) $(LIBS)
 tls_pic_test$(EXEEXT): $(tls_pic_test_OBJECTS) $(tls_pic_test_DEPENDENCIES) 
        @rm -f tls_pic_test$(EXEEXT)
        $(CXXLINK) $(tls_pic_test_LDFLAGS) $(tls_pic_test_OBJECTS) $(tls_pic_test_LDADD) $(LIBS)
@@ -1111,6 +1131,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile_and_compress_debug_sections.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@
diff --git a/gold/testsuite/script_test_1.cc b/gold/testsuite/script_test_1.cc
new file mode 100644 (file)
index 0000000..1bdf770
--- /dev/null
@@ -0,0 +1,47 @@
+// script_test_1.cc -- linker script test 1 for gold  -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// A test for a linker script which sets symbols to values.
+
+#include <cassert>
+#include <cstddef>
+#include <stdint.h>
+
+extern char a, b, c, d, e, f, g;
+int sym = 3;
+int common_sym;
+
+int
+main(int, char**)
+{
+  assert(reinterpret_cast<intptr_t>(&a) == 123);
+  assert(reinterpret_cast<intptr_t>(&b) == reinterpret_cast<intptr_t>(&a) * 2);
+  assert(reinterpret_cast<intptr_t>(&c)
+        == reinterpret_cast<intptr_t>(&b) + 3 * 6);
+  assert(reinterpret_cast<intptr_t>(&d)
+        == (reinterpret_cast<intptr_t>(&b) + 3) * 6);
+  assert(reinterpret_cast<int*>(&e) == &sym);
+  assert(reinterpret_cast<intptr_t>(&f)
+        == reinterpret_cast<intptr_t>(&sym) + 10);
+  assert(reinterpret_cast<int*>(&g) == &common_sym);
+  return 0;
+}
diff --git a/gold/testsuite/script_test_1.t b/gold/testsuite/script_test_1.t
new file mode 100644 (file)
index 0000000..af971c6
--- /dev/null
@@ -0,0 +1,29 @@
+/* script_test_1.t -- linker script test 1 for gold
+
+   Copyright 2008 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor <iant@google.com>.
+
+   This file is part of gold.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+a = 123;
+b = a * 2;
+c = b + 3 * 6;
+d = (b + 3) * 6;
+e = sym;
+f = sym + 10;
+g = common_sym;
index 513241b48578d23026956f36afef7d891ca4340e..a1f954cbfc575279017ee1622669c1d89711a39b 100644 (file)
@@ -1,6 +1,6 @@
 /* yyscript.y -- linker script grammer for gold.  */
 
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <iant@google.com>.
 
    This file is part of gold.
 /* The values associated with tokens.  */
 
 %union {
-  const char* string;
-  int64_t integer;
+  /* A string.  */
+  struct Parser_string string;
+  /* A number.  */
+  uint64_t integer;
+  /* An expression.  */
+  Expression_ptr expr;
 }
 
 /* Operators, including a precedence table for expressions.  */
@@ -68,6 +72,9 @@
 %left '+' '-'
 %left '*' '/' '%'
 
+/* A fake operator used to indicate unary operator precedence.  */
+%right UNARY
+
 /* Constants.  */
 
 %token <string> STRING
@@ -82,6 +89,7 @@
 %token ABSOLUTE
 %token ADDR
 %token ALIGN_K         /* ALIGN */
+%token ALIGNOF
 %token ASSERT_K                /* ASSERT */
 %token AS_NEEDED
 %token AT
 
 %token OPTION
 
+/* Special tokens used to tell the grammar what type of tokens we are
+   parsing.  The token stream always begins with one of these tokens.
+   We do this because version scripts can appear embedded within
+   linker scripts, and because --defsym uses the expression
+   parser.  */
+%token PARSING_LINKER_SCRIPT
+%token PARSING_VERSION_SCRIPT
+%token PARSING_DEFSYM
+
+/* Non-terminal types, where needed.  */
+
+%type <expr> parse_exp exp
+
 %%
 
+/* Read the special token to see what to read next.  */
+top:
+         PARSING_LINKER_SCRIPT linker_script
+       | PARSING_VERSION_SCRIPT version_script
+       | PARSING_DEFSYM defsym_expr
+       ;
+
 /* A file contains a list of commands.  */
-file_list:
-         file_list file_cmd
+linker_script:
+         linker_script file_cmd
        | /* empty */
        ;
 
@@ -173,7 +201,7 @@ file_cmd:
          '(' input_list ')'
            { script_end_group(closure); }
         | OPTION '(' STRING ')'
-            { script_parse_option(closure, $3); }
+           { script_parse_option(closure, $3.value, $3.length); }
        | file_or_sections_cmd
        | ignore_cmd
        ;
@@ -197,7 +225,7 @@ input_list:
 /* An input file name.  */
 input_list_element:
          STRING
-           { script_add_file(closure, $1); }
+           { script_add_file(closure, $1.value, $1.length); }
        | AS_NEEDED
            { script_start_as_needed(closure); }
          '(' input_list ')'
@@ -208,7 +236,191 @@ input_list_element:
    within a SECTIONS block.  */
 file_or_sections_cmd:
          ENTRY '(' STRING ')'
-           { script_set_entry(closure, $3); }
+           { script_set_entry(closure, $3.value, $3.length); }
+       | assignment end
+       ;
+
+/* Set a symbol to a value.  */
+assignment:
+         STRING '=' parse_exp
+           { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+       | STRING PLUSEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_add(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING MINUSEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_sub(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING MULTEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_mult(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING DIVEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_div(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING LSHIFTEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_lshift(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING RSHIFTEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_rshift(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING ANDEQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | STRING OREQ parse_exp
+           {
+             Expression_ptr s = script_exp_string($1.value, $1.length);
+             Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
+             script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+           }
+       | PROVIDE '(' STRING '=' parse_exp ')'
+           { script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
+       | PROVIDE_HIDDEN '(' STRING '=' parse_exp ')'
+           { script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
+       ;
+
+/* Parse an expression, putting the lexer into the right mode.  */
+parse_exp:
+           { script_push_lex_into_expression_mode(closure); }
+         exp
+           {
+             script_pop_lex_mode(closure);
+             $$ = $2;
+           }
+       ;
+
+/* An expression.  */
+exp:
+         '(' exp ')'
+           { $$ = $2; }
+       | '-' exp %prec UNARY
+           { $$ = script_exp_unary_minus($2); }
+       | '!' exp %prec UNARY
+           { $$ = script_exp_unary_logical_not($2); }
+       | '~' exp %prec UNARY
+           { $$ = script_exp_unary_bitwise_not($2); }
+       | '+' exp %prec UNARY
+           { $$ = $2; }
+       | exp '*' exp
+           { $$ = script_exp_binary_mult($1, $3); }
+       | exp '/' exp
+           { $$ = script_exp_binary_div($1, $3); }
+       | exp '%' exp
+           { $$ = script_exp_binary_mod($1, $3); }
+       | exp '+' exp
+           { $$ = script_exp_binary_add($1, $3); }
+       | exp '-' exp
+           { $$ = script_exp_binary_sub($1, $3); }
+       | exp LSHIFT exp
+           { $$ = script_exp_binary_lshift($1, $3); }
+       | exp RSHIFT exp
+           { $$ = script_exp_binary_rshift($1, $3); }
+       | exp EQ exp
+           { $$ = script_exp_binary_eq($1, $3); }
+       | exp NE exp
+           { $$ = script_exp_binary_ne($1, $3); }
+       | exp LE exp
+           { $$ = script_exp_binary_le($1, $3); }
+       | exp GE exp
+           { $$ = script_exp_binary_ge($1, $3); }
+       | exp '<' exp
+           { $$ = script_exp_binary_lt($1, $3); }
+       | exp '>' exp
+           { $$ = script_exp_binary_gt($1, $3); }
+       | exp '&' exp
+           { $$ = script_exp_binary_bitwise_and($1, $3); }
+       | exp '^' exp
+           { $$ = script_exp_binary_bitwise_xor($1, $3); }
+       | exp '|' exp
+           { $$ = script_exp_binary_bitwise_or($1, $3); }
+       | exp ANDAND exp
+           { $$ = script_exp_binary_logical_and($1, $3); }
+       | exp OROR exp
+           { $$ = script_exp_binary_logical_or($1, $3); }
+       | exp '?' exp ':' exp
+           { $$ = script_exp_trinary_cond($1, $3, $5); }
+       | INTEGER
+           { $$ = script_exp_integer($1); }
+       | STRING
+           { $$ = script_exp_string($1.value, $1.length); }
+       | MAX_K '(' exp ',' exp ')'
+           { $$ = script_exp_function_max($3, $5); }
+       | MIN_K '(' exp ',' exp ')'
+           { $$ = script_exp_function_min($3, $5); }
+       | DEFINED '(' STRING ')'
+           { $$ = script_exp_function_defined($3.value, $3.length); }
+       | SIZEOF_HEADERS
+           { $$ = script_exp_function_sizeof_headers(); }
+       | ALIGNOF '(' STRING ')'
+           { $$ = script_exp_function_alignof($3.value, $3.length); }
+       | SIZEOF '(' STRING ')'
+           { $$ = script_exp_function_sizeof($3.value, $3.length); }
+       | ADDR '(' STRING ')'
+           { $$ = script_exp_function_addr($3.value, $3.length); }
+       | LOADADDR '(' STRING ')'
+           { $$ = script_exp_function_loadaddr($3.value, $3.length); }
+       | ORIGIN '(' STRING ')'
+           { $$ = script_exp_function_origin($3.value, $3.length); }
+       | LENGTH '(' STRING ')'
+           { $$ = script_exp_function_length($3.value, $3.length); }
+       | CONSTANT '(' STRING ')'
+           { $$ = script_exp_function_constant($3.value, $3.length); }
+       | ABSOLUTE '(' exp ')'
+           { $$ = script_exp_function_absolute($3); }
+       | ALIGN_K '(' exp ')'
+           { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+       | ALIGN_K '(' exp ',' exp ')'
+           { $$ = script_exp_function_align($3, $5); }
+       | BLOCK '(' exp ')'
+           { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+       | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
+           { $$ = script_exp_function_data_segment_align($3, $5); }
+       | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
+           { $$ = script_exp_function_data_segment_relro_end($3, $5); }
+       | DATA_SEGMENT_END '(' exp ')'
+           { $$ = script_exp_function_data_segment_end($3); }
+       | SEGMENT_START '(' STRING ',' exp ')'
+           {
+             $$ = script_exp_function_segment_start($3.value, $3.length, $5);
+           }
+       | ASSERT_K '(' exp ',' STRING ')'
+           { $$ = script_exp_function_assert($3, $5.value, $5.length); }
+       ;
+
+/* Handle the --defsym option.  */
+defsym_expr:
+         STRING '=' parse_exp
+           { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+       ;
+
+/* A version script.  Not yet implemented.  */
+version_script:
+       ;
+
+/* Some statements require a terminator, which may be a semicolon or a
+   comma.  */
+end:
+         ';'
+       | ','
        ;
 
 /* An optional comma.  */