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