From e5756efb6d46f569d2e99d19f726b32b84f58bd7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 9 Jan 2008 19:57:45 +0000 Subject: [PATCH] Support assignments and expressions in linker scripts. --- gold/Makefile.am | 1 + gold/Makefile.in | 16 +- gold/expression.cc | 508 +++++++++++++++++++++++++++++++++++ gold/gold.cc | 5 +- gold/layout.cc | 14 +- gold/layout.h | 28 +- gold/main.cc | 11 +- gold/options.cc | 38 ++- gold/options.h | 40 ++- gold/po/POTFILES.in | 1 + gold/po/gold.pot | 401 +++++++++++++++++----------- gold/resolve.cc | 16 +- gold/script-c.h | 141 +++++++++- gold/script.cc | 574 ++++++++++++++++++++++++++-------------- gold/script.h | 120 ++++++++- gold/symtab.cc | 32 ++- gold/testsuite/Makefile.am | 5 + gold/testsuite/Makefile.in | 31 ++- gold/testsuite/script_test_1.cc | 47 ++++ gold/testsuite/script_test_1.t | 29 ++ gold/yyscript.y | 228 +++++++++++++++- 21 files changed, 1859 insertions(+), 427 deletions(-) create mode 100644 gold/expression.cc create mode 100644 gold/testsuite/script_test_1.cc create mode 100644 gold/testsuite/script_test_1.t 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 . + +// 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 + +#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 . // 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 . // 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 . // This file is part of gold. @@ -28,6 +28,7 @@ #include #include +#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 . // 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 . // 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 . // 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 \n" "Language-Team: LANGUAGE \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 . // 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 . 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 . // This file is part of gold. @@ -28,6 +28,7 @@ #include #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_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(&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(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(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 +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* ssym = symtab->get_sized_symbol(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_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(keyv); + const Ktt_key* key = static_cast(keyv); const Keyword_to_parsecode::Keyword_parsecode* ktt = static_cast(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(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(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(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(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(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(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(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(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 . // This file is part of gold. @@ -30,6 +30,8 @@ #ifndef GOLD_SCRIPT_H #define GOLD_SCRIPT_H +#include + 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_assignments; + + template + 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 . // 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 . + +// 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 +#include +#include + +extern char a, b, c, d, e, f, g; +int sym = 3; +int common_sym; + +int +main(int, char**) +{ + assert(reinterpret_cast(&a) == 123); + assert(reinterpret_cast(&b) == reinterpret_cast(&a) * 2); + assert(reinterpret_cast(&c) + == reinterpret_cast(&b) + 3 * 6); + assert(reinterpret_cast(&d) + == (reinterpret_cast(&b) + 3) * 6); + assert(reinterpret_cast(&e) == &sym); + assert(reinterpret_cast(&f) + == reinterpret_cast(&sym) + 10); + assert(reinterpret_cast(&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 . + + 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 . 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 @@ -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 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. */ -- 2.7.4