]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Parse a SECTIONS clause in a linker script.
authorIan Lance Taylor <iant@google.com>
Wed, 23 Jan 2008 01:31:13 +0000 (01:31 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 23 Jan 2008 01:31:13 +0000 (01:31 +0000)
16 files changed:
gold/Makefile.am
gold/Makefile.in
gold/configure
gold/configure.ac
gold/debug.h
gold/expression.cc
gold/gold.cc
gold/options.cc
gold/script-c.h
gold/script-sections.cc [new file with mode: 0644]
gold/script-sections.h [new file with mode: 0644]
gold/script.cc
gold/script.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/yyscript.y

index d1c564c3f53b00d1232d0d80c7dac86c42aecebd..199c75a363f31032a9b3f94fe6f44145d742b807 100644 (file)
@@ -8,7 +8,8 @@ tooldir = $(exec_prefix)/$(target_alias)
 
 ACLOCAL_AMFLAGS = -I ../bfd -I ../config
 
-AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS)
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS)
 
 INCLUDES = \
        -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
@@ -50,6 +51,7 @@ CCFILES = \
        readsyms.cc \
        reloc.cc \
        resolve.cc \
+       script-sections.cc \
        script.cc \
        stringpool.cc \
        symtab.cc \
@@ -80,8 +82,9 @@ HFILES = \
        readsyms.h \
        reloc.h \
        reloc-types.h \
-       script.h \
        script-c.h \
+       script-sections.h \
+       script.h \
        stringpool.h \
        symtab.h \
        target.h \
index aa399ba4096247758973905f4736db65a1e8fd3b..512345e469d2d38bf089e85d864ea6f3a31546b3 100644 (file)
@@ -78,8 +78,9 @@ am__objects_1 = archive.$(OBJEXT) common.$(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) \
+       script-sections.$(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)
@@ -181,7 +182,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 INSTOBJEXT = @INSTOBJEXT@
 LDFLAGS = @LDFLAGS@
-LFS_CXXFLAGS = @LFS_CXXFLAGS@
+LFS_CFLAGS = @LFS_CFLAGS@
 LIBINTL = @LIBINTL@
 LIBINTL_DEP = @LIBINTL_DEP@
 LIBOBJS = @LIBOBJS@
@@ -275,7 +276,8 @@ AUTOMAKE_OPTIONS =
 SUBDIRS = po testsuite
 tooldir = $(exec_prefix)/$(target_alias)
 ACLOCAL_AMFLAGS = -I ../bfd -I ../config
-AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS)
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS)
 INCLUDES = \
        -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
@@ -309,6 +311,7 @@ CCFILES = \
        readsyms.cc \
        reloc.cc \
        resolve.cc \
+       script-sections.cc \
        script.cc \
        stringpool.cc \
        symtab.cc \
@@ -339,8 +342,9 @@ HFILES = \
        readsyms.h \
        reloc.h \
        reloc-types.h \
-       script.h \
        script-c.h \
+       script-sections.h \
+       script.h \
        stringpool.h \
        symtab.h \
        target.h \
@@ -495,6 +499,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-sections.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@
index deccea59335ca0804dd9d0f0c4a6fcec04adfc4b..ef56ef5e3b3634a6d4e152ede9f9f282ebeed06c 100755 (executable)
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE OBJDUMP_AND_CPPFILT_TRUE OBJDUMP_AND_CPPFILT_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS LIBOBJS CPP EGREP CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE OBJDUMP_AND_CPPFILT_TRUE OBJDUMP_AND_CPPFILT_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -4654,7 +4654,7 @@ fi
 WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//'`
 
 
-LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
 
 
 
@@ -7068,7 +7068,7 @@ s,@STATIC_TLS_FALSE@,$STATIC_TLS_FALSE,;t t
 s,@WARN_CFLAGS@,$WARN_CFLAGS,;t t
 s,@NO_WERROR@,$NO_WERROR,;t t
 s,@WARN_CXXFLAGS@,$WARN_CXXFLAGS,;t t
-s,@LFS_CXXFLAGS@,$LFS_CXXFLAGS,;t t
+s,@LFS_CFLAGS@,$LFS_CFLAGS,;t t
 s,@LIBOBJS@,$LIBOBJS,;t t
 s,@CPP@,$CPP,;t t
 s,@EGREP@,$EGREP,;t t
index cad5e02a81ca2cda0b57b8d3a16145f95dee09f1..62fdaab4de9e8b02173eff5dc795a2ca3a37064e 100644 (file)
@@ -199,8 +199,8 @@ AC_SUBST(WARN_CXXFLAGS)
 
 dnl Force support for large files by default.  This may need to be
 dnl host dependent.  If build == host, we can check getconf LFS_CFLAGS.
-LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
-AC_SUBST(LFS_CXXFLAGS)
+LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+AC_SUBST(LFS_CFLAGS)
 
 AC_REPLACE_FUNCS(pread)
 
index c6bfb7ae6780738fcad94d4725d8bd22b61c8e03..e37e2f157a34a6461af732f0d2a93e409fc6ba83 100644 (file)
@@ -32,8 +32,9 @@ namespace gold
 // The different types of debugging we support.  These are bitflags.
 
 const int DEBUG_TASK = 1;
+const int DEBUG_SCRIPT = 2;
 
-const int DEBUG_ALL = DEBUG_TASK;
+const int DEBUG_ALL = DEBUG_TASK | DEBUG_SCRIPT;
 
 // Print a debug message if TYPE is enabled.  This is a macro so that
 // we only evaluate the arguments if necessary.
index 393328031f0f35c4282a5aa323e27db2f4414a06..533b0255fc092e97f4bdfad006045349cb36ae45 100644 (file)
@@ -27,6 +27,7 @@
 #include "parameters.h"
 #include "symtab.h"
 #include "layout.h"
+#include "output.h"
 #include "script.h"
 #include "script-c.h"
 
@@ -69,6 +70,10 @@ class Integer_expression : public Expression
   value(const Expression_eval_info*)
   { return this->val_; }
 
+  void
+  print(FILE* f) const
+  { fprintf(f, "0x%llx", static_cast<unsigned long long>(this->val_)); }
+
  private:
   uint64_t val_;
 };
@@ -91,6 +96,10 @@ class Symbol_expression : public Expression
   uint64_t
   value(const Expression_eval_info*);
 
+  void
+  print(FILE* f) const
+  { fprintf(f, "%s", this->name_.c_str()); }
+
  private:
   std::string name_;
 };
@@ -125,6 +134,10 @@ class Dot_expression : public Expression
 
   uint64_t
   value(const Expression_eval_info*);
+
+  void
+  print(FILE* f) const
+  { fprintf(f, "."); }
 };
 
 uint64_t
@@ -162,6 +175,10 @@ class Unary_expression : public Expression
   arg_value(const Expression_eval_info* eei) const
   { return this->arg_->value(eei); }
 
+  void
+  arg_print(FILE* f) const
+  { this->arg_->print(f); }
+
  private:
   Expression* arg_;
 };
@@ -180,6 +197,14 @@ class Unary_expression : public Expression
     uint64_t                                                   \
     value(const Expression_eval_info* eei)                     \
     { return OPERATOR this->arg_value(eei); }                  \
+                                                               \
+    void                                                       \
+    print(FILE* f) const                                       \
+    {                                                          \
+      fprintf(f, "(%s ", #OPERATOR);                           \
+      this->arg_print(f);                                      \
+      fprintf(f, ")");                                         \
+    }                                                          \
   };                                                           \
                                                                \
   extern "C" Expression*                                       \
@@ -216,6 +241,26 @@ class Binary_expression : public Expression
   right_value(const Expression_eval_info* eei) const
   { return this->right_->value(eei); }
 
+  void
+  left_print(FILE* f) const
+  { this->left_->print(f); }
+
+  void
+  right_print(FILE* f) const
+  { this->right_->print(f); }
+
+  // This is a call to function FUNCTION_NAME.  Print it.  This is for
+  // debugging.
+  void
+  print_function(FILE* f, const char *function_name) const
+  {
+    fprintf(f, "%s(", function_name);
+    this->left_print(f);
+    fprintf(f, ", ");
+    this->right_print(f);
+    fprintf(f, ")");
+  }
+
  private:
   Expression* left_;
   Expression* right_;
@@ -237,6 +282,16 @@ class Binary_expression : public Expression
     {                                                                  \
       return (this->left_value(eei)                                    \
              OPERATOR this->right_value(eei));                         \
+    }                                                                  \
+                                                                       \
+    void                                                               \
+    print(FILE* f) const                                               \
+    {                                                                  \
+      fprintf(f, "(");                                                 \
+      this->left_print(f);                                             \
+      fprintf(f, " %s ", #OPERATOR);                                   \
+      this->right_print(f);                                            \
+      fprintf(f, ")");                                                 \
     }                                                                  \
   };                                                                   \
                                                                        \
@@ -294,6 +349,18 @@ class Trinary_expression : public Expression
   arg3_value(const Expression_eval_info* eei) const
   { return this->arg3_->value(eei); }
 
+  void
+  arg1_print(FILE* f) const
+  { this->arg1_->print(f); }
+
+  void
+  arg2_print(FILE* f) const
+  { this->arg2_->print(f); }
+
+  void
+  arg3_print(FILE* f) const
+  { this->arg3_->print(f); }
+
  private:
   Expression* arg1_;
   Expression* arg2_;
@@ -316,6 +383,18 @@ class Trinary_cond : public Trinary_expression
            ? this->arg2_value(eei)
            : this->arg3_value(eei));
   }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "(");
+    this->arg1_print(f);
+    fprintf(f, " ? ");
+    this->arg2_print(f);
+    fprintf(f, " : ");
+    this->arg3_print(f);
+    fprintf(f, ")");
+  }
 };
 
 extern "C" Expression*
@@ -336,6 +415,10 @@ class Max_expression : public Binary_expression
   uint64_t
   value(const Expression_eval_info* eei)
   { return std::max(this->left_value(eei), this->right_value(eei)); }
+
+  void
+  print(FILE* f) const
+  { this->print_function(f, "MAX"); }
 };
 
 extern "C" Expression*
@@ -356,6 +439,10 @@ class Min_expression : public Binary_expression
   uint64_t
   value(const Expression_eval_info* eei)
   { return std::min(this->left_value(eei), this->right_value(eei)); }
+
+  void
+  print(FILE* f) const
+  { this->print_function(f, "MIN"); }
 };
 
 extern "C" Expression*
@@ -382,6 +469,10 @@ class Align_expression : public Binary_expression
       return value;
     return ((value + align - 1) / align) * align;
   }
+
+  void
+  print(FILE* f) const
+  { this->print_function(f, "ALIGN"); }
 };
 
 extern "C" Expression*
@@ -408,6 +499,14 @@ class Assert_expression : public Unary_expression
     return value;
   }
 
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "ASSERT(");
+    this->arg_print(f);
+    fprintf(f, ", %s)", this->message_.c_str());
+  }
+
  private:
   std::string message_;
 };
@@ -419,6 +518,46 @@ script_exp_function_assert(Expression* expr, const char* message,
   return new Assert_expression(expr, message, length);
 }
 
+// Addr function.
+
+class Addr_expression : public Expression
+{
+ public:
+  Addr_expression(const char* section_name, size_t section_name_len)
+    : section_name_(section_name, section_name_len)
+  { }
+
+  uint64_t
+  value(const Expression_eval_info*);
+
+  void
+  print(FILE* f) const
+  { fprintf(f, "ADDR(%s)", this->section_name_.c_str()); }
+
+ private:
+  std::string section_name_;
+};
+
+uint64_t
+Addr_expression::value(const Expression_eval_info* eei)
+{
+  const char* section_name = this->section_name_.c_str();
+  Output_section* os = eei->layout->find_output_section(section_name);
+  if (os == NULL)
+    {
+      gold_error("ADDR called on nonexistent output section '%s'",
+                section_name);
+      return 0;
+    }
+  return os->address();
+}
+
+extern "C" Expression*
+script_exp_function_addr(const char* section_name, size_t section_name_len)
+{
+  return new Addr_expression(section_name, section_name_len);
+}
+
 // Functions.
 
 extern "C" Expression*
@@ -445,12 +584,6 @@ 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)
 {
index d1e544afdf3f194a31dff54e40454a0c9c6c5412..9a4304330a90a0045d3b75fe835a92c58ea61c0c 100644 (file)
@@ -29,6 +29,7 @@
 #include "libiberty.h"
 
 #include "options.h"
+#include "debug.h"
 #include "workqueue.h"
 #include "dirsearch.h"
 #include "readsyms.h"
@@ -182,6 +183,9 @@ queue_middle_tasks(const General_options& options,
                 (*input_objects->dynobj_begin())->name().c_str());
     }
 
+  if (is_debugging_enabled(DEBUG_SCRIPT))
+    layout->script_options()->print(stderr);
+
   // For each dynamic object, record whether we've seen all the
   // dynamic objects that it depends upon.
   input_objects->check_dynamic_dependencies();
index 919813617259ffbb138c09b66d48f919e3e72f5b..b1b428f3b2392d8154a9bfc602fd07f5d9d9698f 100644 (file)
@@ -520,7 +520,7 @@ options::Command_line_options::options[] =
          TWO_DASHES, &help),
   SPECIAL('v', "version", N_("Report version information"), NULL,
          TWO_DASHES, &version),
-  GENERAL_ARG('\0', "debug", N_("Turn on debugging (all,task)"),
+  GENERAL_ARG('\0', "debug", N_("Turn on debugging (all,task,script)"),
              N_("--debug=TYPE"), TWO_DASHES,
              &General_options::handle_debug_option)
 };
@@ -547,6 +547,7 @@ options::Command_line_options::debug_options[] =
 {
   { "all", DEBUG_ALL },
   { "task", DEBUG_TASK },
+  { "script", DEBUG_SCRIPT }
 };
 
 const int options::Command_line_options::debug_options_size =
index da8b558c298a75f0218f1952ca4a619ddf198115..496e18b5f24112c66edc02518d361801f8704f6c 100644 (file)
 #define GOLD_SCRIPT_C_H
 
 #ifdef __cplusplus
-extern "C" {
+#include <vector>
+#include <string>
+#endif
+
+#ifdef __cplusplus
+
+// For the C++ code we declare the various supporting structures in
+// the gold namespace.  For the C code we declare it at the top level.
+// The namespace level should not affect the layout of the structure.
+
+namespace gold
+{
 #endif
 
 /* A string value for the bison parser.  */
@@ -44,15 +55,107 @@ struct Parser_string
    alike.  */
 
 #ifdef __cplusplus
-namespace gold
-{
 class Expression;
-}
-typedef gold::Expression* Expression_ptr;
+typedef Expression* Expression_ptr;
 #else
 typedef void* Expression_ptr;
 #endif
 
+/* The information we store for an output section header in the bison
+   parser.  */
+
+struct Parser_output_section_header
+{
+  /* The address.  This may be NULL.  */
+  Expression_ptr address;
+  /* The load address, from the AT specifier.  This may be NULL.  */
+  Expression_ptr load_address;
+  /* The alignment, from the ALIGN specifier.  This may be NULL.  */
+  Expression_ptr align;
+  /* The input section alignment, from the SUBALIGN specifier.  This
+     may be NULL.  */
+  Expression_ptr subalign;
+};
+
+/* The information we store for an output section trailer in the bison
+   parser.  */
+
+struct Parser_output_section_trailer
+{
+  /* The fill value.  This may be NULL.  */
+  Expression_ptr fill;
+};
+
+/* We keep vectors of strings.  In order to manage this in both C and
+   C++, we use a pointer to a vector.  This assumes that all pointers
+   look the same.  */
+
+#ifdef __cplusplus
+typedef std::vector<std::string> String_list;
+typedef String_list* String_list_ptr;
+#else
+typedef void* String_list_ptr;
+#endif
+
+/* The different sorts we can find in a linker script.  */
+
+enum Sort_wildcard
+{
+  SORT_WILDCARD_NONE,
+  SORT_WILDCARD_BY_NAME,
+  SORT_WILDCARD_BY_ALIGNMENT,
+  SORT_WILDCARD_BY_NAME_BY_ALIGNMENT,
+  SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
+};
+
+/* The information we build for a single wildcard specification.  */
+
+struct Wildcard_section
+{
+  /* The wildcard spec itself.  */
+  struct Parser_string name;
+  /* How the entries should be sorted.  */
+  enum Sort_wildcard sort;
+};
+
+/* A vector of Wildcard_section entries.  */
+
+#ifdef __cplusplus
+typedef std::vector<Wildcard_section> String_sort_list;
+typedef String_sort_list* String_sort_list_ptr;
+#else
+typedef void* String_sort_list_ptr;
+#endif
+
+/* A list of wildcard specifications, which may include EXCLUDE_FILE
+   clauses.  */
+
+struct Wildcard_sections
+{
+  /* Wildcard specs.  */
+  String_sort_list_ptr sections;
+  /* Exclusions.  */
+  String_list_ptr exclude;
+};
+
+/* A complete input section specification.  */
+
+struct Input_section_spec
+{
+  /* The file name.  */
+  struct Wildcard_section file;
+  /* The list of sections.  */
+  struct Wildcard_sections input_sections;
+};
+
+struct Version_dependency_list;
+struct Version_expression_list;
+struct Version_tree;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* The bison parser definitions.  */
 
 #include "yyscript.h"
@@ -127,6 +230,83 @@ extern void
 script_set_symbol(void* closure, const char*, size_t, Expression_ptr,
                  int provide, int hidden);
 
+/* Called by the bison parser to add an assertion.  */
+
+extern void
+script_add_assertion(void* closure, Expression_ptr, const char* message,
+                    size_t messagelen);
+
+/* Called by the bison parser to start a SECTIONS clause.  */
+
+extern void
+script_start_sections(void* closure);
+
+/* Called by the bison parser to finish a SECTIONS clause.  */
+
+extern void
+script_finish_sections(void* closure);
+
+/* Called by the bison parser to start handling input section
+   specifications for an output section.  */
+
+extern void
+script_start_output_section(void* closure, const char* name, size_t namelen,
+                           const struct Parser_output_section_header*);
+
+/* Called by the bison parser when done handling input section
+   specifications for an output section.  */
+
+extern void
+script_finish_output_section(void* closure,
+                            const struct Parser_output_section_trailer*);
+
+/* Called by the bison parser to handle a data statement (LONG, BYTE,
+   etc.) in an output section.  */
+
+extern void
+script_add_data(void* closure, int data_token, Expression_ptr val);
+
+/* Called by the bison parser to set the fill value in an output
+   section.  */
+
+extern void
+script_add_fill(void* closure, Expression_ptr val);
+
+/* Called by the bison parser to add an input section specification to
+   an output section.  The KEEP parameter is non-zero if this is
+   within a KEEP clause, meaning that the garbage collector should not
+   discard it.  */
+
+extern void
+script_add_input_section(void* closure, const struct Input_section_spec*,
+                        int keep);
+
+/* Create a new list of string and sort entries.  */
+
+extern String_sort_list_ptr
+script_new_string_sort_list(const struct Wildcard_section*);
+
+/* Add an entry to a list of string and sort entries.  */
+
+extern String_sort_list_ptr
+script_string_sort_list_add(String_sort_list_ptr,
+                           const struct Wildcard_section*);
+
+/* Create a new list of strings.  */
+
+extern String_list_ptr
+script_new_string_list(const char*, size_t);
+
+/* Add an element to a list of strings.  */
+
+extern String_list_ptr
+script_string_list_push_back(String_list_ptr, const char*, size_t);
+
+/* Concatenate two string lists.  */
+
+extern String_list_ptr
+script_string_list_append(String_list_ptr, String_list_ptr);
+
 /* Called by the bison parser for expressions.  */
 
 extern Expression_ptr
@@ -184,7 +364,7 @@ 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();
+script_exp_function_sizeof_headers(void);
 extern Expression_ptr
 script_exp_function_alignof(const char*, size_t);
 extern Expression_ptr
@@ -214,10 +394,6 @@ script_exp_function_segment_start(const char*, size_t, Expression_ptr);
 extern Expression_ptr
 script_exp_function_assert(Expression_ptr, const char*, size_t);
 
-struct Version_dependency_list;
-struct Version_expression_list;
-struct Version_tree;
-
 extern void
 script_register_vers_node(void* closure,
                          const char* tag,
@@ -251,7 +427,11 @@ extern void
 version_script_pop_lang(void* closure);
 
 #ifdef __cplusplus
-}
+} // End extern "C"
+#endif
+
+#ifdef __cplusplus
+} // End namespace gold.
 #endif
 
 #endif /* !defined(GOLD_SCRIPT_C_H) */
diff --git a/gold/script-sections.cc b/gold/script-sections.cc
new file mode 100644 (file)
index 0000000..de6da30
--- /dev/null
@@ -0,0 +1,738 @@
+// script-sections.cc -- linker script SECTIONS 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.
+
+#include "gold.h"
+
+#include <string>
+#include <vector>
+
+#include "script-c.h"
+#include "script.h"
+#include "script-sections.h"
+
+// Support for the SECTIONS clause in linker scripts.
+
+namespace gold
+{
+
+// An element in a SECTIONS clause.
+
+class Sections_element
+{
+ public:
+  Sections_element()
+  { }
+
+  virtual ~Sections_element()
+  { }
+
+  virtual void
+  print(FILE* f) const = 0;
+};
+
+// An assignment in a SECTIONS clause outside of an output section.
+
+class Sections_element_assignment : public Sections_element
+{
+ public:
+  Sections_element_assignment(const char* name, size_t namelen,
+                             Expression* val, bool provide, bool hidden)
+    : assignment_(name, namelen, val, provide, hidden)
+  { }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "  ");
+    this->assignment_.print(f);
+  }
+
+ private:
+  Symbol_assignment assignment_;
+};
+
+// An assertion in a SECTIONS clause outside of an output section.
+
+class Sections_element_assertion : public Sections_element
+{
+ public:
+  Sections_element_assertion(Expression* check, const char* message,
+                            size_t messagelen)
+    : assertion_(check, message, messagelen)
+  { }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "  ");
+    this->assertion_.print(f);
+  }
+
+ private:
+  Script_assertion assertion_;
+};
+
+// An element in an output section in a SECTIONS clause.
+
+class Output_section_element
+{
+ public:
+  Output_section_element()
+  { }
+
+  virtual ~Output_section_element()
+  { }
+
+  virtual void
+  print(FILE* f) const = 0;
+};
+
+// A symbol assignment in an output section.
+
+class Output_section_element_assignment : public Output_section_element
+{
+ public:
+  Output_section_element_assignment(const char* name, size_t namelen,
+                                   Expression* val, bool provide,
+                                   bool hidden)
+    : assignment_(name, namelen, val, provide, hidden)
+  { }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "    ");
+    this->assignment_.print(f);
+  }
+
+ private:
+  Symbol_assignment assignment_;
+};
+
+// An assertion in an output section.
+
+class Output_section_element_assertion : public Output_section_element
+{
+ public:
+  Output_section_element_assertion(Expression* check, const char* message,
+                                  size_t messagelen)
+    : assertion_(check, message, messagelen)
+  { }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "    ");
+    this->assertion_.print(f);
+  }
+
+ private:
+  Script_assertion assertion_;
+};
+
+// A data item in an output section.
+
+class Output_section_element_data : public Output_section_element
+{
+ public:
+  Output_section_element_data(int size, bool is_signed, Expression* val)
+    : size_(size), is_signed_(is_signed), val_(val)
+  { }
+
+  void
+  print(FILE*) const;
+
+ private:
+  // The size in bytes.
+  int size_;
+  // Whether the value is signed.
+  bool is_signed_;
+  // The value.
+  Expression* val_;
+};
+
+// Print for debugging.
+
+void
+Output_section_element_data::print(FILE* f) const
+{
+  const char* s;
+  switch (this->size_)
+    {
+    case 1:
+      s = "BYTE";
+      break;
+    case 2:
+      s = "SHORT";
+      break;
+    case 4:
+      s = "LONG";
+      break;
+    case 8:
+      if (this->is_signed_)
+       s = "SQUAD";
+      else
+       s = "QUAD";
+      break;
+    default:
+      gold_unreachable();
+    }
+  fprintf(f, "    %s(", s);
+  this->val_->print(f);
+  fprintf(f, ")\n");
+}
+
+// A fill value setting in an output section.
+
+class Output_section_element_fill : public Output_section_element
+{
+ public:
+  Output_section_element_fill(Expression* val)
+    : val_(val)
+  { }
+
+  void
+  print(FILE* f) const
+  {
+    fprintf(f, "    FILL(");
+    this->val_->print(f);
+    fprintf(f, ")\n");
+  }
+
+ private:
+  // The new fill value.
+  Expression* val_;
+};
+
+// An input section specification in an output section
+
+class Output_section_element_input : public Output_section_element
+{
+ public:
+  // Note that an Input_section_spec holds some pointers to vectors.
+  // This constructor takes ownership of them.  The parser is
+  // implemented such that this works.
+  Output_section_element_input(const Input_section_spec* spec, bool keep);
+
+  void
+  print(FILE* f) const;
+
+ private:
+  // An input section pattern.
+  struct Input_section_pattern
+  {
+    std::string pattern;
+    Sort_wildcard sort;
+
+    Input_section_pattern(const char* patterna, size_t patternlena,
+                         Sort_wildcard sorta)
+      : pattern(patterna, patternlena), sort(sorta)
+    { }
+  };
+
+  typedef std::vector<Input_section_pattern> Input_section_patterns;
+
+  typedef std::vector<std::string> Filename_exclusions;
+
+  // The file name pattern.
+  std::string filename_pattern_;
+  // How the file names should be sorted.  This may only be
+  // SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME.
+  Sort_wildcard filename_sort_;
+  // The list of file names to exclude.
+  Filename_exclusions filename_exclusions_;
+  // The list of input section patterns.
+  Input_section_patterns input_section_patterns_;
+  // Whether to keep this section when garbage collecting.
+  bool keep_;
+};
+
+// Construct Output_section_element_input.  The parser records strings
+// as pointers into a copy of the script file, which will go away when
+// parsing is complete.  We make sure they are in std::string objects.
+
+Output_section_element_input::Output_section_element_input(
+    const Input_section_spec* spec,
+    bool keep)
+  : filename_pattern_(spec->file.name.value, spec->file.name.length),
+    filename_sort_(spec->file.sort),
+    filename_exclusions_(),
+    input_section_patterns_(),
+    keep_(keep)
+{
+  if (spec->input_sections.exclude != NULL)
+    {
+      for (String_list::const_iterator p =
+            spec->input_sections.exclude->begin();
+          p != spec->input_sections.exclude->end();
+          ++p)
+       this->filename_exclusions_.push_back(*p);
+    }
+
+  if (spec->input_sections.sections != NULL)
+    {
+      Input_section_patterns& isp(this->input_section_patterns_);
+      for (String_sort_list::const_iterator p =
+            spec->input_sections.sections->begin();
+          p != spec->input_sections.sections->end();
+          ++p)
+       isp.push_back(Input_section_pattern(p->name.value, p->name.length,
+                                           p->sort));
+    }
+}
+
+// Print for debugging.
+
+void
+Output_section_element_input::print(FILE* f) const
+{
+  fprintf(f, "    ");
+
+  if (this->keep_)
+    fprintf(f, "KEEP(");
+
+  if (!this->filename_pattern_.empty())
+    {
+      bool need_close_paren = false;
+      switch (this->filename_sort_)
+       {
+       case SORT_WILDCARD_NONE:
+         break;
+       case SORT_WILDCARD_BY_NAME:
+         fprintf(f, "SORT_BY_NAME(");
+         need_close_paren = true;
+         break;
+       default:
+         gold_unreachable();
+       }
+
+      fprintf(f, "%s", this->filename_pattern_.c_str());
+
+      if (need_close_paren)
+       fprintf(f, ")");
+    }
+
+  if (!this->input_section_patterns_.empty()
+      || !this->filename_exclusions_.empty())
+    {
+      fprintf(f, "(");
+
+      bool need_space = false;
+      if (!this->filename_exclusions_.empty())
+       {
+         fprintf(f, "EXCLUDE_FILE(");
+         bool need_comma = false;
+         for (Filename_exclusions::const_iterator p =
+                this->filename_exclusions_.begin();
+              p != this->filename_exclusions_.end();
+              ++p)
+           {
+             if (need_comma)
+               fprintf(f, ", ");
+             fprintf(f, "%s", p->c_str());
+             need_comma = true;
+           }
+         fprintf(f, ")");
+         need_space = true;
+       }
+
+      for (Input_section_patterns::const_iterator p =
+            this->input_section_patterns_.begin();
+          p != this->input_section_patterns_.end();
+          ++p)
+       {
+         if (need_space)
+           fprintf(f, " ");
+
+         int close_parens = 0;
+         switch (p->sort)
+           {
+           case SORT_WILDCARD_NONE:
+             break;
+           case SORT_WILDCARD_BY_NAME:
+             fprintf(f, "SORT_BY_NAME(");
+             close_parens = 1;
+             break;
+           case SORT_WILDCARD_BY_ALIGNMENT:
+             fprintf(f, "SORT_BY_ALIGNMENT(");
+             close_parens = 1;
+             break;
+           case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+             fprintf(f, "SORT_BY_NAME(SORT_BY_ALIGNMENT(");
+             close_parens = 2;
+             break;
+           case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+             fprintf(f, "SORT_BY_ALIGNMENT(SORT_BY_NAME(");
+             close_parens = 2;
+             break;
+           default:
+             gold_unreachable();
+           }
+
+         fprintf(f, "%s", p->pattern.c_str());
+
+         for (int i = 0; i < close_parens; ++i)
+           fprintf(f, ")");
+
+         need_space = true;
+       }
+
+      fprintf(f, ")");
+    }
+
+  if (this->keep_)
+    fprintf(f, ")");
+
+  fprintf(f, "\n");
+}
+
+// An output section.
+
+class Output_section_definition : public Sections_element
+{
+ public:
+  Output_section_definition(const char* name, size_t namelen,
+                           const Parser_output_section_header* header);
+
+  // Finish the output section with the information in the trailer.
+  void
+  finish(const Parser_output_section_trailer* trailer);
+
+  // Add a symbol to be defined.
+  void
+  add_symbol_assignment(const char* name, size_t length, Expression* value,
+                       bool provide, bool hidden);
+  // Add an assertion.
+  void
+  add_assertion(Expression* check, const char* message, size_t messagelen);
+
+  // Add a data item to the current output section.
+  void
+  add_data(int size, bool is_signed, Expression* val);
+
+  // Add a setting for the fill value.
+  void
+  add_fill(Expression* val);
+
+  // Add an input section specification.
+  void
+  add_input_section(const Input_section_spec* spec, bool keep);
+
+  // Print the contents to the FILE.  This is for debugging.
+  void
+  print(FILE*) const;
+
+ private:
+  typedef std::vector<Output_section_element*> Output_section_elements;
+
+  // The output section name.
+  std::string name_;
+  // The address.  This may be NULL.
+  Expression* address_;
+  // The load address.  This may be NULL.
+  Expression* load_address_;
+  // The alignment.  This may be NULL.
+  Expression* align_;
+  // The input section alignment.  This may be NULL.
+  Expression* subalign_;
+  // The fill value.  This may be NULL.
+  Expression* fill_;
+  // The list of elements defining the section.
+  Output_section_elements elements_;
+};
+
+// Constructor.
+
+Output_section_definition::Output_section_definition(
+    const char* name,
+    size_t namelen,
+    const Parser_output_section_header* header)
+  : name_(name, namelen),
+    address_(header->address),
+    load_address_(header->load_address),
+    align_(header->align),
+    subalign_(header->subalign),
+    fill_(NULL),
+    elements_()
+{
+}
+
+// Finish an output section.
+
+void
+Output_section_definition::finish(const Parser_output_section_trailer* trailer)
+{
+  this->fill_ = trailer->fill;
+}
+
+// Add a symbol to be defined.
+
+void
+Output_section_definition::add_symbol_assignment(const char* name,
+                                                size_t length,
+                                                Expression* value,
+                                                bool provide,
+                                                bool hidden)
+{
+  Output_section_element* p = new Output_section_element_assignment(name,
+                                                                   length,
+                                                                   value,
+                                                                   provide,
+                                                                   hidden);
+  this->elements_.push_back(p);
+}
+
+// Add an assertion.
+
+void
+Output_section_definition::add_assertion(Expression* check,
+                                        const char* message,
+                                        size_t messagelen)
+{
+  Output_section_element* p = new Output_section_element_assertion(check,
+                                                                  message,
+                                                                  messagelen);
+  this->elements_.push_back(p);
+}
+
+// Add a data item to the current output section.
+
+void
+Output_section_definition::add_data(int size, bool is_signed, Expression* val)
+{
+  Output_section_element* p = new Output_section_element_data(size, is_signed,
+                                                             val);
+  this->elements_.push_back(p);
+}
+
+// Add a setting for the fill value.
+
+void
+Output_section_definition::add_fill(Expression* val)
+{
+  Output_section_element* p = new Output_section_element_fill(val);
+  this->elements_.push_back(p);
+}
+
+// Add an input section specification.
+
+void
+Output_section_definition::add_input_section(const Input_section_spec* spec,
+                                            bool keep)
+{
+  Output_section_element* p = new Output_section_element_input(spec, keep);
+  this->elements_.push_back(p);
+}
+
+// Print for debugging.
+
+void
+Output_section_definition::print(FILE* f) const
+{
+  fprintf(f, "  %s ", this->name_.c_str());
+
+  if (this->address_ != NULL)
+    {
+      this->address_->print(f);
+      fprintf(f, " ");
+    }
+
+  fprintf(f, ": ");
+
+  if (this->load_address_ != NULL)
+    {
+      fprintf(f, "AT(");
+      this->load_address_->print(f);
+      fprintf(f, ") ");
+    }
+
+  if (this->align_ != NULL)
+    {
+      fprintf(f, "ALIGN(");
+      this->align_->print(f);
+      fprintf(f, ") ");
+    }
+
+  if (this->subalign_ != NULL)
+    {
+      fprintf(f, "SUBALIGN(");
+      this->subalign_->print(f);
+      fprintf(f, ") ");
+    }
+
+  fprintf(f, "{\n");
+
+  for (Output_section_elements::const_iterator p = this->elements_.begin();
+       p != this->elements_.end();
+       ++p)
+    (*p)->print(f);
+
+  fprintf(f, "  }");
+
+  if (this->fill_ != NULL)
+    {
+      fprintf(f, " = ");
+      this->fill_->print(f);
+    }
+
+  fprintf(f, "\n");
+}
+
+// Class Script_sections.
+
+Script_sections::Script_sections()
+  : saw_sections_clause_(false),
+    in_sections_clause_(false),
+    sections_elements_(NULL),
+    output_section_(NULL)
+{
+}
+
+// Start a SECTIONS clause.
+
+void
+Script_sections::start_sections()
+{
+  gold_assert(!this->in_sections_clause_ && this->output_section_ == NULL);
+  this->saw_sections_clause_ = true;
+  this->in_sections_clause_ = true;
+  if (this->sections_elements_ == NULL)
+    this->sections_elements_ = new Sections_elements;
+}
+
+// Finish a SECTIONS clause.
+
+void
+Script_sections::finish_sections()
+{
+  gold_assert(this->in_sections_clause_ && this->output_section_ == NULL);
+  this->in_sections_clause_ = false;
+}
+
+// Add a symbol to be defined.
+
+void
+Script_sections::add_symbol_assignment(const char* name, size_t length,
+                                      Expression* val, bool provide,
+                                      bool hidden)
+{
+  if (this->output_section_ != NULL)
+    this->output_section_->add_symbol_assignment(name, length, val,
+                                                provide, hidden);
+  else
+    {
+      Sections_element* p = new Sections_element_assignment(name, length,
+                                                           val, provide,
+                                                           hidden);
+      this->sections_elements_->push_back(p);
+    }
+}
+
+// Add an assertion.
+
+void
+Script_sections::add_assertion(Expression* check, const char* message,
+                              size_t messagelen)
+{
+  if (this->output_section_ != NULL)
+    this->output_section_->add_assertion(check, message, messagelen);
+  else
+    {
+      Sections_element* p = new Sections_element_assertion(check, message,
+                                                          messagelen);
+      this->sections_elements_->push_back(p);
+    }
+}
+
+// Start processing entries for an output section.
+
+void
+Script_sections::start_output_section(
+    const char* name,
+    size_t namelen,
+    const Parser_output_section_header *header)
+{
+  Output_section_definition* posd = new Output_section_definition(name,
+                                                                 namelen,
+                                                                 header);
+  this->sections_elements_->push_back(posd);
+  gold_assert(this->output_section_ == NULL);
+  this->output_section_ = posd;
+}
+
+// Stop processing entries for an output section.
+
+void
+Script_sections::finish_output_section(
+    const Parser_output_section_trailer* trailer)
+{
+  gold_assert(this->output_section_ != NULL);
+  this->output_section_->finish(trailer);
+  this->output_section_ = NULL;
+}
+
+// Add a data item to the current output section.
+
+void
+Script_sections::add_data(int size, bool is_signed, Expression* val)
+{
+  gold_assert(this->output_section_ != NULL);
+  this->output_section_->add_data(size, is_signed, val);
+}
+
+// Add a fill value setting to the current output section.
+
+void
+Script_sections::add_fill(Expression* val)
+{
+  gold_assert(this->output_section_ != NULL);
+  this->output_section_->add_fill(val);
+}
+
+// Add an input section specification to the current output section.
+
+void
+Script_sections::add_input_section(const Input_section_spec* spec, bool keep)
+{
+  gold_assert(this->output_section_ != NULL);
+  this->output_section_->add_input_section(spec, keep);
+}
+
+// Print the SECTIONS clause to F for debugging.
+
+void
+Script_sections::print(FILE* f) const
+{
+  if (!this->saw_sections_clause_)
+    return;
+
+  fprintf(f, "SECTIONS {\n");
+
+  for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+       p != this->sections_elements_->end();
+       ++p)
+    (*p)->print(f);
+
+  fprintf(f, "}\n");
+}
+
+} // End namespace gold.
diff --git a/gold/script-sections.h b/gold/script-sections.h
new file mode 100644 (file)
index 0000000..4344325
--- /dev/null
@@ -0,0 +1,113 @@
+// script-sections.h -- linker script SECTIONS 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.
+
+// This is for the support of the SECTIONS clause in linker scripts.
+
+#ifndef GOLD_SCRIPT_SECTIONS_H
+#define GOLD_SCRIPT_SECTIONS_H
+
+#include <cstdio>
+#include <vector>
+
+namespace gold
+{
+
+struct Parser_output_section_header;
+struct Parser_output_section_trailer;
+struct Input_section_spec;
+class Expression;
+class Sections_element;
+class Output_section_definition;
+
+class Script_sections
+{
+ public:
+  Script_sections();
+
+  // Start a SECTIONS clause.
+  void
+  start_sections();
+
+  // Finish a SECTIONS clause.
+  void
+  finish_sections();
+
+  // Return whether we ever saw a SECTIONS clause.  If we did, then
+  // all section layout needs to go through this class.
+  bool
+  saw_sections_clause() const
+  { return this->saw_sections_clause_; }
+
+  // Return whether we are currently processing a SECTIONS clause.
+  bool
+  in_sections_clause() const
+  { return this->in_sections_clause_; }
+
+  // Start processing entries for an output section.
+  void
+  start_output_section(const char* name, size_t namelen,
+                      const Parser_output_section_header*);
+
+  // Finish processing entries for an output section.
+  void
+  finish_output_section(const Parser_output_section_trailer*);
+
+  // Add a data item to the current output section.
+  void
+  add_data(int size, bool is_signed, Expression* val);
+
+  // Add a symbol to be defined.
+  void
+  add_symbol_assignment(const char* name, size_t length, Expression* value,
+                       bool provide, bool hidden);
+  // Add an assertion.
+  void
+  add_assertion(Expression* check, const char* message, size_t messagelen);
+
+  // Add a setting for the fill value.
+  void
+  add_fill(Expression* val);
+
+  // Add an input section specification.
+  void
+  add_input_section(const Input_section_spec* spec, bool keep);
+
+  // Print the contents to the FILE.  This is for debugging.
+  void
+  print(FILE*) const;
+
+ private:
+  typedef std::vector<Sections_element*> Sections_elements;
+
+  // True if we ever saw a SECTIONS clause.
+  bool saw_sections_clause_;
+  // True if we are currently processing a SECTIONS clause.
+  bool in_sections_clause_;
+  // The list of elements in the SECTIONS clause.
+  Sections_elements* sections_elements_;
+  // The current output section, if there is one.
+  Output_section_definition* output_section_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SCRIPT_SECTIONS_H
index 3822c244a5c2d34bb136015b970dcd276ce26eab..1661701246181d98276a2d6464680cb34928fdf9 100644 (file)
@@ -885,26 +885,20 @@ class Script_unblock : public Task
   Task_token* next_blocker_;
 };
 
-// Class Script_options.
-
-Script_options::Script_options()
-  : entry_(), symbol_assignments_()
-{
-}
+// class Symbol_assignment.
 
-// Add any symbols we are defining to the symbol table.
+// Add the symbol to the symbol table.  This makes sure the symbol is
+// there and defined.  The actual value is stored later.  We can't
+// determine the actual value at this point, because we can't
+// necessarily evaluate the expression until all ordinary symbols have
+// been finalized.
 
 void
-Script_options::add_symbols_to_table(Symbol_table* symtab,
-                                    const Target* target)
+Symbol_assignment::add_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(),
+  elfcpp::STV vis = this->hidden_ ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
+  this->sym_ = symtab->define_as_constant(target,
+                                         this->name_.c_str(),
                                          NULL, // version
                                          0, // value
                                          0, // size
@@ -912,19 +906,26 @@ Script_options::add_symbols_to_table(Symbol_table* symtab,
                                          elfcpp::STB_GLOBAL,
                                          vis,
                                          0, // nonvis
-                                         p->provide);
-    }
+                                         this->provide_);
 }
 
-// Finalize symbol values.
+// Finalize a symbol value.
 
 void
-Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
 {
+  // If we were only supposed to provide this symbol, the sym_ field
+  // will be NULL if the symbol was not referenced.
+  if (this->sym_ == NULL)
+    {
+      gold_assert(this->provide_);
+      return;
+    }
+
   if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
-      this->sized_finalize_symbols<32>(symtab, layout);
+      this->sized_finalize<32>(symtab, layout);
 #else
       gold_unreachable();
 #endif
@@ -932,7 +933,7 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
   else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
-      this->sized_finalize_symbols<64>(symtab, layout);
+      this->sized_finalize<64>(symtab, layout);
 #else
       gold_unreachable();
 #endif
@@ -943,19 +944,116 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
 
 template<int size>
 void
-Script_options::sized_finalize_symbols(Symbol_table* symtab,
-                                      const Layout* layout)
+Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout)
+{
+  Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
+  ssym->set_value(this->val_->eval(symtab, layout));
+}
+
+// Print for debugging.
+
+void
+Symbol_assignment::print(FILE* f) const
+{
+  if (this->provide_ && this->hidden_)
+    fprintf(f, "PROVIDE_HIDDEN(");
+  else if (this->provide_)
+    fprintf(f, "PROVIDE(");
+  else if (this->hidden_)
+    gold_unreachable();
+
+  fprintf(f, "%s = ", this->name_.c_str());
+  this->val_->print(f);
+
+  if (this->provide_ || this->hidden_)
+    fprintf(f, ")");
+
+  fprintf(f, "\n");
+}
+
+// Class Script_assertion.
+
+// Check the assertion.
+
+void
+Script_assertion::check(const Symbol_table* symtab, const Layout* layout)
+{
+  if (!this->check_->eval(symtab, layout))
+    gold_error("%s", this->message_.c_str());
+}
+
+// Print for debugging.
+
+void
+Script_assertion::print(FILE* f) const
+{
+  fprintf(f, "ASSERT(");
+  this->check_->print(f);
+  fprintf(f, ", \"%s\")\n", this->message_.c_str());
+}
+
+// Class Script_options.
+
+Script_options::Script_options()
+  : entry_(), symbol_assignments_(), version_script_info_(),
+    script_sections_()
+{
+}
+
+// Add a symbol to be defined.
+
+void
+Script_options::add_symbol_assignment(const char* name, size_t length,
+                                     Expression* value, bool provide,
+                                     bool hidden)
+{
+  if (this->script_sections_.in_sections_clause())
+    this->script_sections_.add_symbol_assignment(name, length, value,
+                                                provide, hidden);
+  else
+    {
+      Symbol_assignment* p = new Symbol_assignment(name, length, value,
+                                                  provide, hidden);
+      this->symbol_assignments_.push_back(p);
+    }
+}
+
+// Add an assertion.
+
+void
+Script_options::add_assertion(Expression* check, const char* message,
+                             size_t messagelen)
+{
+  if (this->script_sections_.in_sections_clause())
+    this->script_sections_.add_assertion(check, message, messagelen);
+  else
+    {
+      Script_assertion* p = new Script_assertion(check, message, messagelen);
+      this->assertions_.push_back(p);
+    }
+}
+
+// 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)
-    {
-      if (p->sym != NULL)
-       {
-         Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(p->sym);
-         ssym->set_value(p->value->eval(symtab, layout));
-       }
-    }
+    (*p)->add_to_table(symtab, target);
+}
+
+// Finalize symbol values.
+
+void
+Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+{
+  for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    (*p)->finalize(symtab, layout);
 }
 
 // This class holds data passed through the parser to the lexer and to
@@ -1283,6 +1381,32 @@ Script_options::define_symbol(const char* definition)
   return true;
 }
 
+// Print the script to F for debugging.
+
+void
+Script_options::print(FILE* f) const
+{
+  fprintf(f, "%s: Dumping linker script\n", program_name);
+
+  if (!this->entry_.empty())
+    fprintf(f, "ENTRY(%s)\n", this->entry_.c_str());
+
+  for (Symbol_assignments::const_iterator p =
+        this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    (*p)->print(f);
+
+  for (Assertions::const_iterator p = this->assertions_.begin();
+       p != this->assertions_.end();
+       ++p)
+    (*p)->print(f);
+
+  this->script_sections_.print(f);
+
+  this->version_script_info_.print(f);
+}
+
 // Manage mapping from keywords to the codes expected by the bison
 // parser.  We construct one global object for each lex mode with
 // keywords.
@@ -1333,13 +1457,11 @@ script_keyword_parsecodes[] =
   { "BYTE", BYTE },
   { "CONSTANT", CONSTANT },
   { "CONSTRUCTORS", CONSTRUCTORS },
-  { "COPY", COPY },
   { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS },
   { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN },
   { "DATA_SEGMENT_END", DATA_SEGMENT_END },
   { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END },
   { "DEFINED", DEFINED },
-  { "DSECT", DSECT },
   { "ENTRY", ENTRY },
   { "EXCLUDE_FILE", EXCLUDE_FILE },
   { "EXTERN", EXTERN },
@@ -1349,7 +1471,6 @@ script_keyword_parsecodes[] =
   { "GROUP", GROUP },
   { "HLL", HLL },
   { "INCLUDE", INCLUDE },
-  { "INFO", INFO },
   { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION },
   { "INPUT", INPUT },
   { "KEEP", KEEP },
@@ -1363,7 +1484,6 @@ script_keyword_parsecodes[] =
   { "NEXT", NEXT },
   { "NOCROSSREFS", NOCROSSREFS },
   { "NOFLOAT", NOFLOAT },
-  { "NOLOAD", NOLOAD },
   { "ONLY_IF_RO", ONLY_IF_RO },
   { "ONLY_IF_RW", ONLY_IF_RW },
   { "OPTION", OPTION },
@@ -1464,119 +1584,354 @@ Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
   return ktt->parsecode;
 }
 
-} // End namespace gold.
+// The following structs are used within the VersionInfo class as well
+// as in the bison helper functions.  They store the information
+// parsed from the version script.
 
-// The remaining functions are extern "C", so it's clearer to not put
-// them in namespace gold.
+// A single version expression.
+// For example, pattern="std::map*" and language="C++".
+// pattern and language should be from the stringpool
+struct Version_expression {
+  Version_expression(const std::string& pattern,
+                     const std::string& language,
+                     bool exact_match)
+      : pattern(pattern), language(language), exact_match(exact_match) {}
 
-using namespace gold;
+  std::string pattern;
+  std::string language;
+  // If false, we use glob() to match pattern.  If true, we use strcmp().
+  bool exact_match;
+};
 
-// This function is called by the bison parser to return the next
-// token.
 
-extern "C" int
-yylex(YYSTYPE* lvalp, void* closurev)
-{
-  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-  const Token* token = closure->next_token();
-  switch (token->classification())
-    {
-    default:
-      gold_unreachable();
+// A list of expressions.
+struct Version_expression_list {
+  std::vector<struct Version_expression> expressions;
+};
 
-    case Token::TOKEN_INVALID:
-      yyerror(closurev, "invalid character");
-      return 0;
 
-    case Token::TOKEN_EOF:
-      return 0;
+// A list of which versions upon which another version depends.
+// Strings should be from the Stringpool.
+struct Version_dependency_list {
+  std::vector<std::string> dependencies;
+};
 
-    case Token::TOKEN_STRING:
-      {
-       // This is either a keyword or a STRING.
-       size_t len;
-       const char* str = token->string_value(&len);
-       int parsecode = 0;
-        switch (closure->lex_mode())
-          {
-          case Lex::LINKER_SCRIPT:
-            parsecode = script_keywords.keyword_to_parsecode(str, len);
-            break;
-          case Lex::VERSION_SCRIPT:
-            parsecode = version_script_keywords.keyword_to_parsecode(str, len);
-            break;
-          default:
-            break;
-          }
-       if (parsecode != 0)
-         return parsecode;
-       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 QUOTED_STRING;
+// The total definition of a version.  It includes the tag for the
+// version, its global and local expressions, and any dependencies.
+struct Version_tree {
+  Version_tree()
+      : tag(), global(NULL), local(NULL), dependencies(NULL) {}
 
-    case Token::TOKEN_OPERATOR:
-      return token->operator_value();
+  std::string tag;
+  const struct Version_expression_list* global;
+  const struct Version_expression_list* local;
+  const struct Version_dependency_list* dependencies;
+};
 
-    case Token::TOKEN_INTEGER:
-      lvalp->integer = token->integer_value();
-      return INTEGER;
-    }
+Version_script_info::~Version_script_info()
+{
+  for (size_t k = 0; k < dependency_lists_.size(); ++k)
+    delete dependency_lists_[k];
+  for (size_t k = 0; k < version_trees_.size(); ++k)
+    delete version_trees_[k];
+  for (size_t k = 0; k < expression_lists_.size(); ++k)
+    delete expression_lists_[k];
 }
 
-// This function is called by the bison parser to report an error.
-
-extern "C" void
-yyerror(void* closurev, const char* message)
+std::vector<std::string>
+Version_script_info::get_versions() const
 {
-  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-  gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
-            closure->charpos(), message);
+  std::vector<std::string> ret;
+  for (size_t j = 0; j < version_trees_.size(); ++j)
+    ret.push_back(version_trees_[j]->tag);
+  return ret;
 }
 
-// Called by the bison parser to add a file to the link.
-
-extern "C" void
-script_add_file(void* closurev, const char* name, size_t length)
+std::vector<std::string>
+Version_script_info::get_dependencies(const char* version) const
 {
-  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-
-  // If this is an absolute path, and we found the script in the
-  // 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(name, length);
-  const char* extra_search_path = ".";
-  std::string script_directory;
-  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_string;
-       }
-    }
-  else
-    {
-      // In addition to checking the normal library search path, we
-      // also want to check in the script-directory.
-      const char *slash = strrchr(closure->filename(), '/');
-      if (slash != NULL)
-       {
-         script_directory.assign(closure->filename(),
-                                 slash - closure->filename() + 1);
-         extra_search_path = script_directory.c_str();
-       }
-    }
-
-  Input_file_argument file(name_string.c_str(), false, extra_search_path,
-                          closure->position_dependent_options());
-  closure->inputs()->add_file(file);
+  std::vector<std::string> ret;
+  for (size_t j = 0; j < version_trees_.size(); ++j)
+    if (version_trees_[j]->tag == version)
+      {
+        const struct Version_dependency_list* deps =
+          version_trees_[j]->dependencies;
+        if (deps != NULL)
+          for (size_t k = 0; k < deps->dependencies.size(); ++k)
+            ret.push_back(deps->dependencies[k]);
+        return ret;
+      }
+  return ret;
+}
+
+const std::string&
+Version_script_info::get_symbol_version_helper(const char* symbol_name,
+                                               bool check_global) const
+{
+  for (size_t j = 0; j < version_trees_.size(); ++j)
+    {
+      // Is it a global symbol for this version?
+      const Version_expression_list* explist =
+          check_global ? version_trees_[j]->global : version_trees_[j]->local;
+      if (explist != NULL)
+        for (size_t k = 0; k < explist->expressions.size(); ++k)
+          {
+            const char* name_to_match = symbol_name;
+            const struct Version_expression& exp = explist->expressions[k];
+            char* demangled_name = NULL;
+            if (exp.language == "C++")
+              {
+                demangled_name = cplus_demangle(symbol_name,
+                                                DMGL_ANSI | DMGL_PARAMS);
+                // This isn't a C++ symbol.
+                if (demangled_name == NULL)
+                  continue;
+                name_to_match = demangled_name;
+              }
+            else if (exp.language == "Java")
+              {
+                demangled_name = cplus_demangle(symbol_name,
+                                                (DMGL_ANSI | DMGL_PARAMS
+                                                | DMGL_JAVA));
+                // This isn't a Java symbol.
+                if (demangled_name == NULL)
+                  continue;
+                name_to_match = demangled_name;
+              }
+            bool matched;
+            if (exp.exact_match)
+              matched = strcmp(exp.pattern.c_str(), name_to_match) == 0;
+            else
+              matched = fnmatch(exp.pattern.c_str(), name_to_match,
+                                FNM_NOESCAPE) == 0;
+            if (demangled_name != NULL)
+              free(demangled_name);
+            if (matched)
+              return version_trees_[j]->tag;
+          }
+    }
+  static const std::string empty = "";
+  return empty;
+}
+
+struct Version_dependency_list*
+Version_script_info::allocate_dependency_list()
+{
+  dependency_lists_.push_back(new Version_dependency_list);
+  return dependency_lists_.back();
+}
+
+struct Version_expression_list*
+Version_script_info::allocate_expression_list()
+{
+  expression_lists_.push_back(new Version_expression_list);
+  return expression_lists_.back();
+}
+
+struct Version_tree*
+Version_script_info::allocate_version_tree()
+{
+  version_trees_.push_back(new Version_tree);
+  return version_trees_.back();
+}
+
+// Print for debugging.
+
+void
+Version_script_info::print(FILE* f) const
+{
+  if (this->empty())
+    return;
+
+  fprintf(f, "VERSION {");
+
+  for (size_t i = 0; i < this->version_trees_.size(); ++i)
+    {
+      const Version_tree* vt = this->version_trees_[i];
+
+      if (vt->tag.empty())
+       fprintf(f, "  {\n");
+      else
+       fprintf(f, "  %s {\n", vt->tag.c_str());
+
+      if (vt->global != NULL)
+       {
+         fprintf(f, "    global :\n");
+         this->print_expression_list(f, vt->global);
+       }
+
+      if (vt->local != NULL)
+       {
+         fprintf(f, "    local :\n");
+         this->print_expression_list(f, vt->local);
+       }
+
+      fprintf(f, "  }");
+      if (vt->dependencies != NULL)
+       {
+         const Version_dependency_list* deps = vt->dependencies;
+         for (size_t j = 0; j < deps->dependencies.size(); ++j)
+           {
+             if (j < deps->dependencies.size() - 1)
+               fprintf(f, "\n");
+             fprintf(f, "    %s", deps->dependencies[j].c_str());
+           }
+       }
+      fprintf(f, ";\n");
+    }
+
+  fprintf(f, "}\n");
+}
+
+void
+Version_script_info::print_expression_list(
+    FILE* f,
+    const Version_expression_list* vel) const
+{
+  std::string current_language;
+  for (size_t i = 0; i < vel->expressions.size(); ++i)
+    {
+      const Version_expression& ve(vel->expressions[i]);
+
+      if (ve.language != current_language)
+       {
+         if (!current_language.empty())
+           fprintf(f, "      }\n");
+         fprintf(f, "      extern \"%s\" {\n", ve.language.c_str());
+         current_language = ve.language;
+       }
+
+      fprintf(f, "      ");
+      if (!current_language.empty())
+       fprintf(f, "  ");
+
+      if (ve.exact_match)
+       fprintf(f, "\"");
+      fprintf(f, "%s", ve.pattern.c_str());
+      if (ve.exact_match)
+       fprintf(f, "\"");
+
+      fprintf(f, "\n");
+    }
+
+  if (!current_language.empty())
+    fprintf(f, "      }\n");
+}
+
+} // End namespace gold.
+
+// The remaining functions are extern "C", so it's clearer to not put
+// them in namespace gold.
+
+using namespace gold;
+
+// This function is called by the bison parser to return the next
+// token.
+
+extern "C" int
+yylex(YYSTYPE* lvalp, void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  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:
+      return 0;
+
+    case Token::TOKEN_STRING:
+      {
+       // This is either a keyword or a STRING.
+       size_t len;
+       const char* str = token->string_value(&len);
+       int parsecode = 0;
+        switch (closure->lex_mode())
+          {
+          case Lex::LINKER_SCRIPT:
+            parsecode = script_keywords.keyword_to_parsecode(str, len);
+            break;
+          case Lex::VERSION_SCRIPT:
+            parsecode = version_script_keywords.keyword_to_parsecode(str, len);
+            break;
+          default:
+            break;
+          }
+       if (parsecode != 0)
+         return parsecode;
+       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 QUOTED_STRING;
+
+    case Token::TOKEN_OPERATOR:
+      return token->operator_value();
+
+    case Token::TOKEN_INTEGER:
+      lvalp->integer = token->integer_value();
+      return INTEGER;
+    }
+}
+
+// This function is called by the bison parser to report an error.
+
+extern "C" void
+yyerror(void* closurev, const char* message)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  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, size_t length)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+
+  // If this is an absolute path, and we found the script in the
+  // 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(name, length);
+  const char* extra_search_path = ".";
+  std::string script_directory;
+  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_string;
+       }
+    }
+  else
+    {
+      // In addition to checking the normal library search path, we
+      // also want to check in the script-directory.
+      const char *slash = strrchr(closure->filename(), '/');
+      if (slash != NULL)
+       {
+         script_directory.assign(closure->filename(),
+                                 slash - closure->filename() + 1);
+         extra_search_path = script_directory.c_str();
+       }
+    }
+
+  Input_file_argument file(name_string.c_str(), false, extra_search_path,
+                          closure->position_dependent_options());
+  closure->inputs()->add_file(file);
 }
 
 // Called by the bison parser to start a group.  If we are already in
@@ -1648,6 +2003,16 @@ script_set_symbol(void* closurev, const char* name, size_t length,
                                                   provide, hidden);
 }
 
+// Called by the bison parser to add an assertion.
+
+extern "C" void
+script_add_assertion(void* closurev, Expression* check, const char* message,
+                    size_t messagelen)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->add_assertion(check, message, messagelen);
+}
+
 // Called by the bison parser to parse an OPTION.
 
 extern "C" void
@@ -1678,7 +2043,7 @@ script_parse_option(void* closurev, const char* option, size_t length)
 /* Called by the bison parser to push the lexer into expression
    mode.  */
 
-extern void
+extern "C" void
 script_push_lex_into_expression_mode(void* closurev)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
@@ -1688,7 +2053,7 @@ script_push_lex_into_expression_mode(void* closurev)
 /* Called by the bison parser to push the lexer into version
    mode.  */
 
-extern void
+extern "C" void
 script_push_lex_into_version_mode(void* closurev)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
@@ -1697,165 +2062,13 @@ script_push_lex_into_version_mode(void* closurev)
 
 /* Called by the bison parser to pop the lexer mode.  */
 
-extern void
+extern "C" void
 script_pop_lex_mode(void* closurev)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
   closure->pop_lex_mode();
 }
 
-// The following structs are used within the VersionInfo class as well
-// as in the bison helper functions.  They store the information
-// parsed from the version script.
-
-// A single version expression.
-// For example, pattern="std::map*" and language="C++".
-// pattern and language should be from the stringpool
-struct Version_expression {
-  Version_expression(const std::string& pattern,
-                     const std::string& language,
-                     bool exact_match)
-      : pattern(pattern), language(language), exact_match(exact_match) {}
-
-  std::string pattern;
-  std::string language;
-  // If false, we use glob() to match pattern.  If true, we use strcmp().
-  bool exact_match;
-};
-
-
-// A list of expressions.
-struct Version_expression_list {
-  std::vector<struct Version_expression> expressions;
-};
-
-
-// A list of which versions upon which another version depends.
-// Strings should be from the Stringpool.
-struct Version_dependency_list {
-  std::vector<std::string> dependencies;
-};
-
-
-// The total definition of a version.  It includes the tag for the
-// version, its global and local expressions, and any dependencies.
-struct Version_tree {
-  Version_tree()
-      : tag(), global(NULL), local(NULL), dependencies(NULL) {}
-
-  std::string tag;
-  const struct Version_expression_list* global;
-  const struct Version_expression_list* local;
-  const struct Version_dependency_list* dependencies;
-};
-
-Version_script_info::~Version_script_info()
-{
-  for (size_t k = 0; k < dependency_lists_.size(); ++k)
-    delete dependency_lists_[k];
-  for (size_t k = 0; k < version_trees_.size(); ++k)
-    delete version_trees_[k];
-  for (size_t k = 0; k < expression_lists_.size(); ++k)
-    delete expression_lists_[k];
-}
-
-std::vector<std::string>
-Version_script_info::get_versions() const
-{
-  std::vector<std::string> ret;
-  for (size_t j = 0; j < version_trees_.size(); ++j)
-    ret.push_back(version_trees_[j]->tag);
-  return ret;
-}
-
-std::vector<std::string>
-Version_script_info::get_dependencies(const char* version) const
-{
-  std::vector<std::string> ret;
-  for (size_t j = 0; j < version_trees_.size(); ++j)
-    if (version_trees_[j]->tag == version)
-      {
-        const struct Version_dependency_list* deps =
-          version_trees_[j]->dependencies;
-        if (deps != NULL)
-          for (size_t k = 0; k < deps->dependencies.size(); ++k)
-            ret.push_back(deps->dependencies[k]);
-        return ret;
-      }
-  return ret;
-}
-
-const std::string&
-Version_script_info::get_symbol_version_helper(const char* symbol_name,
-                                               bool check_global) const
-{
-  for (size_t j = 0; j < version_trees_.size(); ++j)
-    {
-      // Is it a global symbol for this version?
-      const Version_expression_list* explist =
-          check_global ? version_trees_[j]->global : version_trees_[j]->local;
-      if (explist != NULL)
-        for (size_t k = 0; k < explist->expressions.size(); ++k)
-          {
-            const char* name_to_match = symbol_name;
-            const struct Version_expression& exp = explist->expressions[k];
-            char* demangled_name = NULL;
-            if (exp.language == "C++")
-              {
-                demangled_name = cplus_demangle(symbol_name,
-                                                DMGL_ANSI | DMGL_PARAMS);
-                // This isn't a C++ symbol.
-                if (demangled_name == NULL)
-                  continue;
-                name_to_match = demangled_name;
-              }
-            else if (exp.language == "Java")
-              {
-                demangled_name = cplus_demangle(symbol_name,
-                                                (DMGL_ANSI | DMGL_PARAMS
-                                                | DMGL_JAVA));
-                // This isn't a Java symbol.
-                if (demangled_name == NULL)
-                  continue;
-                name_to_match = demangled_name;
-              }
-            bool matched;
-            if (exp.exact_match)
-              matched = strcmp(exp.pattern.c_str(), name_to_match) == 0;
-            else
-              matched = fnmatch(exp.pattern.c_str(), name_to_match,
-                                FNM_NOESCAPE) == 0;
-            if (demangled_name != NULL)
-              free(demangled_name);
-            if (matched)
-              return version_trees_[j]->tag;
-          }
-    }
-  static const std::string empty = "";
-  return empty;
-}
-
-struct Version_dependency_list*
-Version_script_info::allocate_dependency_list()
-{
-  dependency_lists_.push_back(new Version_dependency_list);
-  return dependency_lists_.back();
-}
-
-struct Version_expression_list*
-Version_script_info::allocate_expression_list()
-{
-  expression_lists_.push_back(new Version_expression_list);
-  return expression_lists_.back();
-}
-
-struct Version_tree*
-Version_script_info::allocate_version_tree()
-{
-  version_trees_.push_back(new Version_tree);
-  return version_trees_.back();
-}
-
 // Register an entire version node. For example:
 //
 // GLIBC_2.1 {
@@ -1957,3 +2170,151 @@ version_script_pop_lang(void* closurev)
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
   closure->pop_language();
 }
+
+// Called by the bison parser to start a SECTIONS clause.
+
+extern "C" void
+script_start_sections(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->script_sections()->start_sections();
+}
+
+// Called by the bison parser to finish a SECTIONS clause.
+
+extern "C" void
+script_finish_sections(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->script_sections()->finish_sections();
+}
+
+// Start processing entries for an output section.
+
+extern "C" void
+script_start_output_section(void* closurev, const char* name, size_t namelen,
+                           const struct Parser_output_section_header* header)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->script_sections()->start_output_section(name,
+                                                                    namelen,
+                                                                    header);
+}
+
+// Finish processing entries for an output section.
+
+extern "C" void
+script_finish_output_section(void* closurev, 
+                            const struct Parser_output_section_trailer* trail)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->script_sections()->finish_output_section(trail);
+}
+
+// Add a data item (e.g., "WORD (0)") to the current output section.
+
+extern "C" void
+script_add_data(void* closurev, int data_token, Expression* val)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  int size;
+  bool is_signed = true;
+  switch (data_token)
+    {
+    case QUAD:
+      size = 8;
+      is_signed = false;
+      break;
+    case SQUAD:
+      size = 8;
+      break;
+    case LONG:
+      size = 4;
+      break;
+    case SHORT:
+      size = 2;
+      break;
+    case BYTE:
+      size = 1;
+      break;
+    default:
+      gold_unreachable();
+    }
+  closure->script_options()->script_sections()->add_data(size, is_signed, val);
+}
+
+// Add a clause setting the fill value to the current output section.
+
+extern "C" void
+script_add_fill(void* closurev, Expression* val)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  closure->script_options()->script_sections()->add_fill(val);
+}
+
+// Add a new input section specification to the current output
+// section.
+
+extern "C" void
+script_add_input_section(void* closurev,
+                        const struct Input_section_spec* spec,
+                        int keepi)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  bool keep = keepi != 0;
+  closure->script_options()->script_sections()->add_input_section(spec, keep);
+}
+
+// Create a new list of string/sort pairs.
+
+extern "C" String_sort_list_ptr
+script_new_string_sort_list(const struct Wildcard_section* string_sort)
+{
+  return new String_sort_list(1, *string_sort);
+}
+
+// Add an entry to a list of string/sort pairs.  The way the parser
+// works permits us to simply modify the first parameter, rather than
+// copy the vector.
+
+extern "C" String_sort_list_ptr
+script_string_sort_list_add(String_sort_list_ptr pv,
+                           const struct Wildcard_section* string_sort)
+{
+  pv->push_back(*string_sort);
+  return pv;
+}
+
+// Create a new list of strings.
+
+extern "C" String_list_ptr
+script_new_string_list(const char* str, size_t len)
+{
+  return new String_list(1, std::string(str, len));
+}
+
+// Add an element to a list of strings.  The way the parser works
+// permits us to simply modify the first parameter, rather than copy
+// the vector.
+
+extern "C" String_list_ptr
+script_string_list_push_back(String_list_ptr pv, const char* str, size_t len)
+{
+  pv->push_back(std::string(str, len));
+  return pv;
+}
+
+// Concatenate two string lists.  Either or both may be NULL.  The way
+// the parser works permits us to modify the parameters, rather than
+// copy the vector.
+
+extern "C" String_list_ptr
+script_string_list_append(String_list_ptr pv1, String_list_ptr pv2)
+{
+  if (pv1 == NULL)
+    return pv2;
+  if (pv2 == NULL)
+    return pv1;
+  pv1->insert(pv1->end(), pv2->begin(), pv2->end());
+  return pv1;
+}
index 69906cb66e0d2a6aba0571e6dafbe66e3c799e19..4d8cfab681f2d0de5edc1ac2e0aab0bcc960ef49 100644 (file)
 #ifndef GOLD_SCRIPT_H
 #define GOLD_SCRIPT_H
 
+#include <cstdio>
 #include <vector>
 
-struct Version_dependency_list;
-struct Version_expression_list;
-struct Version_tree;
+#include "script-sections.h"
 
 namespace gold
 {
@@ -50,6 +49,9 @@ class Input_file;
 class Target;
 class Task_token;
 class Workqueue;
+struct Version_dependency_list;
+struct Version_expression_list;
+struct Version_tree;
 
 // This class represents an expression in a linker script.
 
@@ -68,6 +70,10 @@ class Expression
   uint64_t
   eval(const Symbol_table*, const Layout*);
 
+  // Print the expression to the FILE.  This is for debugging.
+  virtual void
+  print(FILE*) const = 0;
+
  protected:
   struct Expression_eval_info;
 
@@ -90,7 +96,8 @@ class Expression
 // script.  A single Version_script_info object per target is owned by
 // Script_options.
 
-class Version_script_info {
+class Version_script_info
+{
  public:
   ~Version_script_info();
 
@@ -138,7 +145,14 @@ class Version_script_info {
   struct Version_tree*
   allocate_version_tree();
 
+  // Print contents to the FILE.  This is for debugging.
+  void
+  print(FILE*) const;
+
  private:
+  void
+  print_expression_list(FILE* f, const Version_expression_list*) const;
+
   const std::string& get_symbol_version_helper(const char* symbol,
                                                bool check_global) const;
 
@@ -147,6 +161,77 @@ class Version_script_info {
   std::vector<struct Version_tree*> version_trees_;
 };
 
+// This class manages assignments to symbols.  These can appear in
+// three different locations in scripts: outside of a SECTIONS clause,
+// within a SECTIONS clause, and within an output section definition
+// within a SECTIONS clause.  This can also appear on the command line
+// via the --defsym command line option.
+
+class Symbol_assignment
+{
+ public:
+  Symbol_assignment(const char* name, size_t namelen, Expression* val,
+                   bool provide, bool hidden)
+    : name_(name, namelen), val_(val), provide_(provide), hidden_(hidden),
+      sym_(NULL)
+  { }
+
+  // Add the symbol to the symbol table.
+  void
+  add_to_table(Symbol_table*, const Target*);
+
+  // Finalize the symbol value.
+  void finalize(Symbol_table*, const Layout*);
+
+  // Print the assignment to the FILE.  This is for debugging.
+  void
+  print(FILE*) const;
+
+ private:
+  // Sized version of finalize.
+  template<int size>
+  void
+  sized_finalize(Symbol_table*, const Layout*);
+
+  // Symbol name.
+  std::string name_;
+  // Expression to assign to symbol.
+  Expression* val_;
+  // 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_;
+};
+
+// This class manages assertions in linker scripts.  These can appear
+// in all the places where a Symbol_assignment can appear.
+
+class Script_assertion
+{
+ public:
+  Script_assertion(Expression* check, const char* message,
+                  size_t messagelen)
+    : check_(check), message_(message, messagelen)
+  { }
+
+  // Check the assertion.
+  void
+  check(const Symbol_table*, const Layout*);
+
+  // Print the assertion to the FILE.  This is for debugging.
+  void
+  print(FILE*) const;
+
+ private:
+  // The expression to check.
+  Expression* check_;
+  // The message to issue if the expression fails.
+  std::string message_;
+};
+
 // 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
@@ -172,15 +257,14 @@ class Script_options
   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.
+  // Add a symbol to be defined.
   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));
-  }
+                       bool provide, bool hidden);
+
+  // Add an assertion.
+  void
+  add_assertion(Expression* check, const char* message, size_t messagelen);
 
   // Define a symbol from the command line.
   bool
@@ -198,43 +282,37 @@ class Script_options
   // else has a pointer to this object.
   Version_script_info*
   version_script_info()
-  { return &version_script_info_; }
+  { return &this->version_script_info_; }
 
- 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;
+  // A SECTIONS clause parsed from a linker script.  Everything else
+  // has a pointer to this object.
+  Script_sections*
+  script_sections()
+  { return &this->script_sections_; }
 
-  template<int size>
+  // Print the script to the FILE.  This is for debugging.
   void
-  sized_finalize_symbols(Symbol_table*, const Layout*);
+  print(FILE*) const;
+
+ private:
+  // We keep a list of symbol assignments which occur outside of a
+  // SECTIONS clause.
+  typedef std::vector<Symbol_assignment*> Symbol_assignments;
+
+  // We keep a list of all assertions whcih occur outside of a
+  // SECTIONS clause.
+  typedef std::vector<Script_assertion*> Assertions;
 
   // The entry address.  This will be empty if not set.
   std::string entry_;
   // Symbols to set.
   Symbol_assignments symbol_assignments_;
+  // Assertions to check.
+  Assertions assertions_;
   // Version information parsed from a version script.
   Version_script_info version_script_info_;
+  // Information from any SECTIONS clauses.
+  Script_sections script_sections_;
 };
 
 // FILE was found as an argument on the command line, but was not
index 5820038b5ea66a29df088a0e925057c05c821125..36c3c003fd6d454cba028286c05546827501b1af 100644 (file)
@@ -9,7 +9,7 @@ AUTOMAKE_OPTIONS =
 # The two_file_test tests -fmerge-constants, so we simply always turn
 # it on.  This may need to be controlled by a configure option
 # eventually.
-AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS) -fmerge-constants
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) -fmerge-constants
 
 INCLUDES = \
        -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \
index 8f51d28105d166570a9a08d832f003d0a3608a75..2879fc027ce75ef5d0778497bcc0b0febcab527a 100644 (file)
@@ -619,7 +619,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 INSTOBJEXT = @INSTOBJEXT@
 LDFLAGS = @LDFLAGS@
-LFS_CXXFLAGS = @LFS_CXXFLAGS@
+LFS_CFLAGS = @LFS_CFLAGS@
 LIBINTL = @LIBINTL@
 LIBINTL_DEP = @LIBINTL_DEP@
 LIBOBJS = @LIBOBJS@
@@ -714,7 +714,7 @@ AUTOMAKE_OPTIONS =
 # The two_file_test tests -fmerge-constants, so we simply always turn
 # it on.  This may need to be controlled by a configure option
 # eventually.
-AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS) -fmerge-constants
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) -fmerge-constants
 INCLUDES = \
        -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \
        -I$(srcdir)/../../elfcpp \
index a1d58d395ce6dbb1087b0ddd970a9ab67e1bc207..dfba25f966e9ffdb81c71325dfe212ddbf371ecb 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #include "script-c.h"
 
   uint64_t integer;
   /* An expression.  */
   Expression_ptr expr;
-  // Used for version scripts and within VERSION {}
+  /* An output section header.  */
+  struct Parser_output_section_header output_section_header;
+  /* An output section trailer.  */
+  struct Parser_output_section_trailer output_section_trailer;
+  /* A complete input section specification.  */
+  struct Input_section_spec input_section_spec;
+  /* A list of wildcard specifications, with exclusions.  */
+  struct Wildcard_sections wildcard_sections;
+  /* A single wildcard specification.  */
+  struct Wildcard_section wildcard_section;
+  /* A list of strings.  */
+  String_list_ptr string_list;
+  /* Used for version scripts and within VERSION {}.  */
   struct Version_dependency_list* deplist;
   struct Version_expression_list* versyms;
   struct Version_tree* versnode;
 %token BYTE
 %token CONSTANT
 %token CONSTRUCTORS
-%token COPY
 %token CREATE_OBJECT_SYMBOLS
 %token DATA_SEGMENT_ALIGN
 %token DATA_SEGMENT_END
 %token DATA_SEGMENT_RELRO_END
 %token DEFINED
-%token DSECT
 %token ENTRY
 %token EXCLUDE_FILE
 %token EXTERN
 %token GROUP
 %token HLL
 %token INCLUDE
-%token INFO
 %token INHIBIT_COMMON_ALLOCATION
 %token INPUT
 %token KEEP
 %token NEXT
 %token NOCROSSREFS
 %token NOFLOAT
-%token NOLOAD
 %token ONLY_IF_RO
 %token ONLY_IF_RW
 %token ORIGIN          /* ORIGIN, o, org */
 
 /* Non-terminal types, where needed.  */
 
-%type <expr> parse_exp exp
+%type <expr> parse_exp exp opt_address_and_section_type
+%type <expr> opt_at opt_align opt_subalign opt_fill
+%type <output_section_header> section_header
+%type <output_section_trailer> section_trailer
+%type <integer> data_length
+%type <input_section_spec> input_section_no_keep
+%type <wildcard_sections> wildcard_sections
+%type <wildcard_section> wildcard_file wildcard_section
+%type <string_list> exclude_names
+%type <string> wildcard_name
 %type <versyms> vers_defns
 %type <versnode> vers_tag
 %type <deplist> verdep
@@ -211,6 +229,10 @@ file_cmd:
            { script_end_group(closure); }
         | OPTION '(' string ')'
            { script_parse_option(closure, $3.value, $3.length); }
+       | SECTIONS '{'
+           { script_start_sections(closure); }
+         sections_block '}'
+           { script_finish_sections(closure); }
         | VERSIONK '{'
             { script_push_lex_into_version_mode(closure); }
           version_script '}'
@@ -245,12 +267,304 @@ input_list_element:
            { script_end_as_needed(closure); }
        ;
 
+/* Commands in a SECTIONS block.  */
+sections_block:
+         sections_block section_block_cmd
+       | /* empty */
+       ;
+
+/* A command which may appear within a SECTIONS block.  */
+section_block_cmd:
+         file_or_sections_cmd
+       | STRING section_header
+           { script_start_output_section(closure, $1.value, $1.length, &$2); }
+         '{' section_cmds '}' section_trailer
+           { script_finish_output_section(closure, &$7); }
+       ;
+
+/* The header of an output section in a SECTIONS block--everything
+   after the name.  */
+section_header:
+           { script_push_lex_into_expression_mode(closure); }
+         opt_address_and_section_type opt_at opt_align opt_subalign
+           {
+             $$.address = $2;
+             $$.load_address = $3;
+             $$.align = $4;
+             $$.subalign = $5;
+             script_pop_lex_mode(closure);
+           }
+       ;
+
+/* The optional address followed by the optional section type.  This
+   is a separate nonterminal to avoid a shift/reduce conflict on
+   '(' in section_header.  */
+
+opt_address_and_section_type:
+         ':'
+           { $$ = NULL; }
+       | '(' ')' ':'
+           { $$ = NULL; }
+       | exp ':'
+           { $$ = $1; }
+       | exp '(' ')' ':'
+           { $$ = $1; }
+       | exp '(' STRING ')' ':'
+           {
+             yyerror(closure, "section types are not supported");
+             $$ = $1;
+           }
+       ;
+
+/* The address at which an output section should be loaded.  */
+opt_at:
+         /* empty */
+           { $$ = NULL; }
+       | AT '(' exp ')'
+           { $$ = $3; }
+       ;
+
+/* The alignment of an output section.  */
+opt_align:
+         /* empty */
+           { $$ = NULL; }
+       | ALIGN_K '(' exp ')'
+           { $$ = $3; }
+       ;
+
+/* The input section alignment within an output section.  */
+opt_subalign:
+         /* empty */
+           { $$ = NULL; }
+       | SUBALIGN '(' exp ')'
+           { $$ = $3; }
+       ;
+
+/* The trailer of an output section in a SECTIONS block.  */
+section_trailer:
+           { script_push_lex_into_expression_mode(closure); }
+         opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
+           {
+             $$.fill = $5;
+             script_pop_lex_mode(closure);
+           }
+       ;
+
+/* A memory specification for an output section.  */
+opt_memspec:
+         '>' STRING
+           { yyerror(closure, "memory regions are not supported"); }
+       | /* empty */
+       ;
+
+/* A memory specification for where to load an output section.  */
+opt_at_memspec:
+         AT '>' STRING
+           { yyerror(closure, "memory regions are not supported"); }
+       | /* empty */
+       ;
+
+/* The program segment an output section should go into.  */
+opt_phdr:
+         opt_phdr ':' STRING
+           { yyerror(closure, "program headers are not supported"); }
+       | /* empty */
+       ;
+
+/* The value to use to fill an output section.  */
+opt_fill:
+         '=' exp
+           { $$ = $2; }
+       | /* empty */
+           { $$ = NULL; }
+       ;
+
+/* Commands which may appear within the description of an output
+   section in a SECTIONS block.  */
+section_cmds:
+         /* empty */
+       | section_cmds section_cmd
+       ;
+
+/* A command which may appear within the description of an output
+   section in a SECTIONS block.  */
+section_cmd:
+         assignment end
+       | input_section_spec
+       | data_length '(' parse_exp ')'
+           { script_add_data(closure, $1, $3); }
+       | ASSERT_K '(' parse_exp ',' STRING ')'
+           { script_add_assertion(closure, $3, $5.value, $5.length); }
+       | FILL '(' parse_exp ')'
+           { script_add_fill(closure, $3); }
+       | CONSTRUCTORS
+           {
+             /* The GNU linker uses CONSTRUCTORS for the a.out object
+                file format.  It does nothing when using ELF.  Since
+                some ELF linker scripts use it although it does
+                nothing, we accept it and ignore it.  */
+           }
+       | ';'
+       ;
+
+/* The length of data which may appear within the description of an
+   output section in a SECTIONS block.  */
+data_length:
+         QUAD
+           { $$ = QUAD; }
+       | SQUAD
+           { $$ = SQUAD; }
+       | LONG
+           { $$ = LONG; }
+       | SHORT
+           { $$ = SHORT; }
+       | BYTE
+           { $$ = BYTE; }
+       ;
+
+/* An input section specification.  This may appear within the
+   description of an output section in a SECTIONS block.  */
+input_section_spec:
+         input_section_no_keep
+           { script_add_input_section(closure, &$1, 0); }
+       | KEEP '(' input_section_no_keep ')'
+           { script_add_input_section(closure, &$3, 1); }
+       ;
+
+/* An input section specification within a KEEP clause.  */
+input_section_no_keep:
+         STRING
+           {
+             $$.file.name = $1;
+             $$.file.sort = SORT_WILDCARD_NONE;
+             $$.input_sections.sections = NULL;
+             $$.input_sections.exclude = NULL;
+           }
+       | wildcard_file '(' wildcard_sections ')'
+           {
+             $$.file = $1;
+             $$.input_sections = $3;
+           }
+       ;
+
+/* A wildcard file specification.  */
+wildcard_file:
+         wildcard_name
+           {
+             $$.name = $1;
+             $$.sort = SORT_WILDCARD_NONE;
+           }
+       | SORT_BY_NAME '(' wildcard_name ')'
+           {
+             $$.name = $3;
+             $$.sort = SORT_WILDCARD_BY_NAME;
+           }
+       ;
+
+/* A list of wild card section specifications.  */
+wildcard_sections:
+         wildcard_sections opt_comma wildcard_section
+           {
+             $$.sections = script_string_sort_list_add($1.sections, &$3);
+             $$.exclude = $1.exclude;
+           }
+       | wildcard_section
+           {
+             $$.sections = script_new_string_sort_list(&$1);
+             $$.exclude = NULL;
+           }
+       | wildcard_sections opt_comma EXCLUDE_FILE '(' exclude_names ')'
+           {
+             $$.sections = $1.sections;
+             $$.exclude = script_string_list_append($1.exclude, $5);
+           }
+       | EXCLUDE_FILE '(' exclude_names ')'
+           {
+             $$.sections = NULL;
+             $$.exclude = $3;
+           }
+       ;
+
+/* A single wild card specification.  */
+wildcard_section:
+         wildcard_name
+           {
+             $$.name = $1;
+             $$.sort = SORT_WILDCARD_NONE;
+           }
+       | SORT_BY_NAME '(' wildcard_section ')'
+           {
+             $$.name = $3.name;
+             switch ($3.sort)
+               {
+               case SORT_WILDCARD_NONE:
+                 $$.sort = SORT_WILDCARD_BY_NAME;
+                 break;
+               case SORT_WILDCARD_BY_NAME:
+               case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+                 break;
+               case SORT_WILDCARD_BY_ALIGNMENT:
+               case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+                 $$.sort = SORT_WILDCARD_BY_NAME_BY_ALIGNMENT;
+                 break;
+               default:
+                 abort();
+               }
+           }
+       | SORT_BY_ALIGNMENT '(' wildcard_section ')'
+           {
+             $$.name = $3.name;
+             switch ($3.sort)
+               {
+               case SORT_WILDCARD_NONE:
+                 $$.sort = SORT_WILDCARD_BY_ALIGNMENT;
+                 break;
+               case SORT_WILDCARD_BY_ALIGNMENT:
+               case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+                 break;
+               case SORT_WILDCARD_BY_NAME:
+               case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+                 $$.sort = SORT_WILDCARD_BY_ALIGNMENT_BY_NAME;
+                 break;
+               default:
+                 abort();
+               }
+           }
+       ;
+
+/* A list of file names to exclude.  */
+exclude_names:
+         exclude_names opt_comma wildcard_name
+           { $$ = script_string_list_push_back($1, $3.value, $3.length); }
+       | wildcard_name
+           { $$ = script_new_string_list($1.value, $1.length); }
+       ;
+
+/* A single wildcard name.  We recognize '*' and '?' specially since
+   they are expression tokens.  */
+wildcard_name:
+         STRING
+           { $$ = $1; }
+       | '*'
+           {
+             $$.value = "*";
+             $$.length = 1;
+           }
+       | '?'
+           {
+             $$.value = "?";
+             $$.length = 1;
+           }
+       ;
+
 /* A command which may appear at the top level of a linker script, or
    within a SECTIONS block.  */
 file_or_sections_cmd:
          ENTRY '(' string ')'
            { script_set_entry(closure, $3.value, $3.length); }
        | assignment end
+       | ASSERT_K '(' parse_exp ',' STRING ')'
+           { script_add_assertion(closure, $3, $5.value, $5.length); }
        ;
 
 /* Set a symbol to a value.  */