aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-01-23 01:31:13 +0000
committerIan Lance Taylor <iant@google.com>2008-01-23 01:31:13 +0000
commit494e05f4405228561f0af4d424136128ff8830d2 (patch)
treeef8756394ecd755f133be5dc2dfc9b086f6c0cb4 /gold
parent64f926997fdf212014e331a695a25b8144182320 (diff)
downloadgdb-494e05f4405228561f0af4d424136128ff8830d2.zip
gdb-494e05f4405228561f0af4d424136128ff8830d2.tar.gz
gdb-494e05f4405228561f0af4d424136128ff8830d2.tar.bz2
Parse a SECTIONS clause in a linker script.
Diffstat (limited to 'gold')
-rw-r--r--gold/Makefile.am7
-rw-r--r--gold/Makefile.in15
-rwxr-xr-xgold/configure6
-rw-r--r--gold/configure.ac4
-rw-r--r--gold/debug.h3
-rw-r--r--gold/expression.cc145
-rw-r--r--gold/gold.cc4
-rw-r--r--gold/options.cc3
-rw-r--r--gold/script-c.h202
-rw-r--r--gold/script-sections.cc738
-rw-r--r--gold/script-sections.h113
-rw-r--r--gold/script.cc741
-rw-r--r--gold/script.h154
-rw-r--r--gold/testsuite/Makefile.am2
-rw-r--r--gold/testsuite/Makefile.in4
-rw-r--r--gold/yyscript.y326
16 files changed, 2199 insertions, 268 deletions
diff --git a/gold/Makefile.am b/gold/Makefile.am
index d1c564c..199c75a 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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 \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index aa399ba..512345e 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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@
diff --git a/gold/configure b/gold/configure
index deccea5..ef56ef5 100755
--- a/gold/configure
+++ b/gold/configure
@@ -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
diff --git a/gold/configure.ac b/gold/configure.ac
index cad5e02..62fdaab 100644
--- a/gold/configure.ac
+++ b/gold/configure.ac
@@ -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)
diff --git a/gold/debug.h b/gold/debug.h
index c6bfb7a..e37e2f1 100644
--- a/gold/debug.h
+++ b/gold/debug.h
@@ -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.
diff --git a/gold/expression.cc b/gold/expression.cc
index 3933280..533b025 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -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_;
@@ -238,6 +283,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, ")"); \
+ } \
}; \
\
extern "C" Expression* \
@@ -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*
@@ -446,12 +585,6 @@ script_exp_function_sizeof(const char*, size_t)
}
extern "C" Expression*
-script_exp_function_addr(const char*, size_t)
-{
- gold_fatal(_("ADDR not implemented"));
-}
-
-extern "C" Expression*
script_exp_function_loadaddr(const char*, size_t)
{
gold_fatal(_("LOADADDR not implemented"));
diff --git a/gold/gold.cc b/gold/gold.cc
index d1e544a..9a43043 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -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();
diff --git a/gold/options.cc b/gold/options.cc
index 9198136..b1b428f 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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 =
diff --git a/gold/script-c.h b/gold/script-c.h
index da8b558..496e18b 100644
--- a/gold/script-c.h
+++ b/gold/script-c.h
@@ -27,7 +27,18 @@
#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
index 0000000..de6da30
--- /dev/null
+++ b/gold/script-sections.cc
@@ -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
index 0000000..4344325
--- /dev/null
+++ b/gold/script-sections.h
@@ -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
diff --git a/gold/script.cc b/gold/script.cc
index 3822c24..1661701 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -885,26 +885,20 @@ class Script_unblock : public Task
Task_token* next_blocker_;
};
-// Class Script_options.
+// class Symbol_assignment.
-Script_options::Script_options()
- : entry_(), symbol_assignments_()
-{
-}
-
-// 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,6 +1584,241 @@ Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
return ktt->parsecode;
}
+// 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();
+}
+
+// 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
@@ -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;
+}
diff --git a/gold/script.h b/gold/script.h
index 69906cb..4d8cfab 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -30,11 +30,10 @@
#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
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 5820038..36c3c00 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -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 \
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 8f51d28..2879fc0 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -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 \
diff --git a/gold/yyscript.y b/gold/yyscript.y
index a1d58d3..dfba25f 100644
--- a/gold/yyscript.y
+++ b/gold/yyscript.y
@@ -29,6 +29,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <stdlib.h>
#include "script-c.h"
@@ -55,7 +56,19 @@
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;
@@ -103,13 +116,11 @@
%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
@@ -120,7 +131,6 @@
%token GROUP
%token HLL
%token INCLUDE
-%token INFO
%token INHIBIT_COMMON_ALLOCATION
%token INPUT
%token KEEP
@@ -135,7 +145,6 @@
%token NEXT
%token NOCROSSREFS
%token NOFLOAT
-%token NOLOAD
%token ONLY_IF_RO
%token ONLY_IF_RW
%token ORIGIN /* ORIGIN, o, org */
@@ -182,7 +191,16 @@
/* 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. */