mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
Parse a SECTIONS clause in a linker script.
This commit is contained in:
parent
64f926997f
commit
494e05f440
@ -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 \
|
||||
|
@ -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
6
gold/configure
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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 =
|
||||
|
202
gold/script-c.h
202
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) */
|
||||
|
738
gold/script-sections.cc
Normal file
738
gold/script-sections.cc
Normal 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
113
gold/script-sections.h
Normal 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
|
771
gold/script.cc
771
gold/script.cc
@ -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;
|
||||
}
|
||||
|
154
gold/script.h
154
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_; }
|
||||
|
||||
// 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
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
326
gold/yyscript.y
326
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. */
|
||||
|
Loading…
Reference in New Issue
Block a user