Parse a SECTIONS clause in a linker script.

This commit is contained in:
Ian Lance Taylor 2008-01-23 01:31:13 +00:00
parent 64f926997f
commit 494e05f440
16 changed files with 2214 additions and 283 deletions

View 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 \

View 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@

6
gold/configure vendored
View File

@ -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

View 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)

View 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.

View 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)
{

View 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();

View 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 =

View File

@ -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) */

738
gold/script-sections.cc Normal file
View File

@ -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.

113
gold/script-sections.h Normal file
View File

@ -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

View File

@ -885,13 +885,154 @@ class Script_unblock : public Task
Task_token* next_blocker_;
};
// class Symbol_assignment.
// 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
Symbol_assignment::add_to_table(Symbol_table* symtab, const Target* target)
{
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
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
vis,
0, // nonvis
this->provide_);
}
// Finalize a symbol value.
void
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<32>(symtab, layout);
#else
gold_unreachable();
#endif
}
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
this->sized_finalize<64>(symtab, layout);
#else
gold_unreachable();
#endif
}
else
gold_unreachable();
}
template<int size>
void
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_()
: 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
@ -901,61 +1042,18 @@ Script_options::add_symbols_to_table(Symbol_table* symtab,
for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
p != this->symbol_assignments_.end();
++p)
{
elfcpp::STV vis = p->hidden ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
p->sym = symtab->define_as_constant(target,
p->name.c_str(),
NULL, // version
0, // value
0, // size
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
vis,
0, // nonvis
p->provide);
}
(*p)->add_to_table(symtab, target);
}
// Finalize symbol values.
void
Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
{
if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
this->sized_finalize_symbols<32>(symtab, layout);
#else
gold_unreachable();
#endif
}
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
this->sized_finalize_symbols<64>(symtab, layout);
#else
gold_unreachable();
#endif
}
else
gold_unreachable();
}
template<int size>
void
Script_options::sized_finalize_symbols(Symbol_table* symtab,
const Layout* layout)
{
for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
p != this->symbol_assignments_.end();
++p)
{
if (p->sym != NULL)
{
Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(p->sym);
ssym->set_value(p->value->eval(symtab, layout));
}
}
(*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;
}

View File

@ -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_; }
// A SECTIONS clause parsed from a linker script. Everything else
// has a pointer to this object.
Script_sections*
script_sections()
{ return &this->script_sections_; }
// Print the script to the FILE. This is for debugging.
void
print(FILE*) const;
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;
// We keep a list of symbol assignments which occur outside of a
// SECTIONS clause.
typedef std::vector<Symbol_assignment*> Symbol_assignments;
Symbol_assignment(const char* namea, size_t lengtha, Expression* valuea,
bool providea, bool hiddena)
: name(namea, lengtha), value(valuea), provide(providea),
hidden(hiddena), sym(NULL)
{ }
};
typedef std::vector<Symbol_assignment> Symbol_assignments;
template<int size>
void
sized_finalize_symbols(Symbol_table*, const Layout*);
// 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

View 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 \

View 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 \

View File

@ -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. */