From d391083d3c938e56a0d0f3e03867d91369198d35 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 6 Jan 2008 00:47:10 +0000 Subject: [PATCH] Add support for -e and for ENTRY in linker scripts. --- gold/layout.cc | 6 +++-- gold/layout.h | 9 +++++++ gold/options.cc | 8 +++++-- gold/options.h | 15 ++++++++++++ gold/output.cc | 63 +++++++++++++++++++++++++++++++++++++------------ gold/output.h | 9 ++++++- gold/script-c.h | 5 ++++ gold/script.cc | 32 ++++++++++++++++++++++--- gold/yyscript.y | 13 ++++++++++ 9 files changed, 137 insertions(+), 23 deletions(-) diff --git a/gold/layout.cc b/gold/layout.cc index 75aecfe2b5d..a717ed241e1 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -64,7 +64,8 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) // Layout methods. Layout::Layout(const General_options& options) - : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(), + : options_(options), entry_(options.entry()), 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), @@ -720,7 +721,8 @@ 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); + file_header = new Output_file_header(target, symtab, segment_headers, + this->entry_); load_seg->add_initial_output_data(file_header); this->special_output_list_.push_back(file_header); diff --git a/gold/layout.h b/gold/layout.h index 131d6a6cd38..a106cccd78a 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -241,6 +241,12 @@ 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; } + // Dump statistical information to stderr. void print_stats() const; @@ -426,6 +432,9 @@ 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_; // The output section names. Stringpool namepool_; // The output symbol names. diff --git a/gold/options.cc b/gold/options.cc index c3f174718bb..a26139bf425 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -395,12 +395,15 @@ options::Command_line_options::options[] = GENERAL_NOARG('\0', "detect-odr-violations", N_("Try to detect violations of the One Definition Rule"), NULL, TWO_DASHES, &General_options::set_detect_odr_violations), + GENERAL_ARG('e', "entry", N_("Set program start address"), + N_("-e ADDRESS, --entry ADDRESS"), TWO_DASHES, + &General_options::set_entry), GENERAL_NOARG('E', "export-dynamic", N_("Export all dynamic symbols"), NULL, TWO_DASHES, &General_options::set_export_dynamic), GENERAL_NOARG('\0', "eh-frame-hdr", N_("Create exception frame header"), NULL, TWO_DASHES, &General_options::set_create_eh_frame_hdr), GENERAL_ARG('h', "soname", N_("Set shared library name"), - N_("-h FILENAME, --soname FILENAME"), ONE_DASH, + N_("-h FILENAME, -soname FILENAME"), ONE_DASH, &General_options::set_soname), GENERAL_ARG('I', "dynamic-linker", N_("Set dynamic linker path"), N_("-I PROGRAM, --dynamic-linker PROGRAM"), TWO_DASHES, @@ -530,7 +533,8 @@ const int options::Command_line_options::debug_options_size = // The default values for the general options. General_options::General_options() - : export_dynamic_(false), + : entry_(NULL), + export_dynamic_(false), soname_(NULL), dynamic_linker_(NULL), search_path_(), diff --git a/gold/options.h b/gold/options.h index 86d9bd7b6b2..4cb760809ca 100644 --- a/gold/options.h +++ b/gold/options.h @@ -108,6 +108,11 @@ class General_options public: General_options(); + // -e: set entry address. + const char* + entry() const + { return this->entry_; } + // -E: export dynamic symbols. bool export_dynamic() const @@ -311,6 +316,10 @@ class General_options ZLIB_COMPRESSION, }; + void + set_entry(const char* arg) + { this->entry_ = arg; } + void set_export_dynamic() { this->export_dynamic_ = true; } @@ -509,6 +518,7 @@ class General_options void add_sysroot(); + const char* entry_; bool export_dynamic_; const char* soname_; const char* dynamic_linker_; @@ -824,6 +834,11 @@ 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, diff --git a/gold/output.cc b/gold/output.cc index 0e28629d539..4c6959eabc2 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -294,12 +294,14 @@ Output_segment_headers::do_sized_write(Output_file* of) Output_file_header::Output_file_header(const Target* target, const Symbol_table* symtab, - const Output_segment_headers* osh) + const Output_segment_headers* osh, + const char* entry) : target_(target), symtab_(symtab), segment_header_(osh), section_header_(NULL), - shstrtab_(NULL) + shstrtab_(NULL), + entry_(entry) { const int size = parameters->get_size(); int ehdr_size; @@ -415,19 +417,7 @@ Output_file_header::do_sized_write(Output_file* of) oehdr.put_e_machine(this->target_->machine_code()); oehdr.put_e_version(elfcpp::EV_CURRENT); - // FIXME: Need to support -e, and target specific entry symbol. - Symbol* sym = this->symtab_->lookup("_start"); - typename Sized_symbol::Value_type v; - if (sym == NULL) - v = 0; - else - { - Sized_symbol* ssym; - ssym = this->symtab_->get_sized_symbol SELECT_SIZE_NAME(size) ( - sym SELECT_SIZE(size)); - v = ssym->value(); - } - oehdr.put_e_entry(v); + oehdr.put_e_entry(this->entry()); oehdr.put_e_phoff(this->segment_header_->offset()); oehdr.put_e_shoff(this->section_header_->offset()); @@ -447,6 +437,49 @@ Output_file_header::do_sized_write(Output_file* of) of->write_output_view(0, ehdr_size, view); } +// Return the value to use for the entry address. THIS->ENTRY_ is the +// symbol specified on the command line, if any. + +template +typename elfcpp::Elf_types::Elf_Addr +Output_file_header::entry() +{ + const bool should_issue_warning = (this->entry_ != NULL + && parameters->output_is_executable()); + + // FIXME: Need to support target specific entry symbol. + const char* entry = this->entry_; + if (entry == NULL) + entry = "_start"; + + Symbol* sym = this->symtab_->lookup(entry); + + typename Sized_symbol::Value_type v; + if (sym != NULL) + { + Sized_symbol* ssym; + ssym = this->symtab_->get_sized_symbol(sym); + if (!ssym->is_defined() && should_issue_warning) + gold_warning("entry symbol '%s' exists but is not defined", entry); + v = ssym->value(); + } + else + { + // We couldn't find the entry symbol. See if we can parse it as + // a number. This supports, e.g., -e 0x1000. + char* endptr; + v = strtoull(entry, &endptr, 0); + if (*endptr != '\0') + { + if (should_issue_warning) + gold_warning("cannot find entry symbol '%s'", entry); + v = 0; + } + } + + return v; +} + // Output_data_const methods. void diff --git a/gold/output.h b/gold/output.h index 07a336dcd53..f384c8c8e86 100644 --- a/gold/output.h +++ b/gold/output.h @@ -393,7 +393,8 @@ class Output_file_header : public Output_data public: Output_file_header(const Target*, const Symbol_table*, - const Output_segment_headers*); + const Output_segment_headers*, + const char* entry); // Add information about the section headers. We lay out the ELF // file header before we create the section headers. @@ -416,11 +417,17 @@ class Output_file_header : public Output_data void do_sized_write(Output_file*); + // Return the value to use for the entry address. + template + typename elfcpp::Elf_types::Elf_Addr + entry(); + const Target* target_; const Symbol_table* symtab_; const Output_segment_headers* segment_header_; const Output_section_headers* section_header_; const Output_section* shstrtab_; + const char* entry_; }; // Output sections are mainly comprised of input sections. However, diff --git a/gold/script-c.h b/gold/script-c.h index 1214800dd0a..4b103f89d8b 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -66,6 +66,11 @@ script_start_as_needed(void* closure); extern void 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*); + /* Called by the bison parser to parse an OPTION. */ extern void script_parse_option(void* closure, const char*); diff --git a/gold/script.cc b/gold/script.cc index 1373064d379..775aedf6f21 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -34,6 +34,7 @@ #include "workqueue.h" #include "readsyms.h" #include "parameters.h" +#include "layout.h" #include "yyscript.h" #include "script.h" #include "script-c.h" @@ -834,10 +835,11 @@ 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) : filename_(filename), posdep_options_(posdep_options), in_group_(in_group), is_in_sysroot_(is_in_sysroot), - command_line_(command_line), tokens_(tokens), + command_line_(command_line), layout_(layout), tokens_(tokens), next_token_index_(0), inputs_(NULL) { } @@ -869,6 +871,11 @@ class Parser_closure 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 @@ -909,6 +916,8 @@ 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_; @@ -940,6 +949,7 @@ read_input_script(Workqueue* workqueue, const General_options& options, input_group != NULL, input_file->is_in_sysroot(), NULL, + layout, &lex.tokens()); if (yyparse(&closure) != 0) @@ -1014,6 +1024,7 @@ read_commandline_script(const char* filename, Command_line* cmdline) false, input_file.is_in_sysroot(), cmdline, + NULL, &lex.tokens()); if (yyparse(&closure) != 0) { @@ -1022,6 +1033,9 @@ read_commandline_script(const char* filename, Command_line* cmdline) } input_file.file().unlock(task); + + gold_assert(!closure.saw_inputs()); + return true; } @@ -1318,6 +1332,18 @@ script_end_as_needed(void* closurev) closure->position_dependent_options().clear_as_needed(); } +// Called by the bison parser to set the entry symbol. + +extern "C" void +script_set_entry(void* closurev, const char* entry) +{ + Parser_closure* closure = static_cast(closurev); + if (closure->command_line() != NULL) + closure->command_line()->set_entry(entry); + else + closure->layout()->set_entry(entry); +} + // Called by the bison parser to parse an OPTION. extern "C" void @@ -1330,8 +1356,8 @@ 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" - " for scripts specified via -T"), + gold_warning(_("%s: ignoring command OPTION; OPTION is only valid" + " for scripts specified via -T/--script"), closure->filename()); } else diff --git a/gold/yyscript.y b/gold/yyscript.y index 3250e8ed2d7..7cfe7247e78 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -160,11 +160,13 @@ %% +/* A file contains a list of commands. */ file_list: file_list file_cmd | /* empty */ ; +/* A command which may appear at top level of a linker script. */ file_cmd: OUTPUT_FORMAT '(' STRING ')' | GROUP @@ -173,13 +175,16 @@ file_cmd: { script_end_group(closure); } | OPTION '(' STRING ')' { script_parse_option(closure, $3); } + | file_or_sections_cmd ; +/* A list of input file names. */ input_list: input_list_element | input_list opt_comma input_list_element ; +/* An input file name. */ input_list_element: STRING { script_add_file(closure, $1); } @@ -189,6 +194,14 @@ input_list_element: { script_end_as_needed(closure); } ; +/* A command which may appear at the top level of a linker script, or + within a SECTIONS block. */ +file_or_sections_cmd: + ENTRY '(' STRING ')' + { script_set_entry(closure, $3); } + ; + +/* An optional comma. */ opt_comma: ',' | /* empty */ -- 2.39.2