aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/layout.cc6
-rw-r--r--gold/layout.h9
-rw-r--r--gold/options.cc8
-rw-r--r--gold/options.h15
-rw-r--r--gold/output.cc63
-rw-r--r--gold/output.h9
-rw-r--r--gold/script-c.h5
-rw-r--r--gold/script.cc32
-rw-r--r--gold/yyscript.y13
9 files changed, 137 insertions, 23 deletions
diff --git a/gold/layout.cc b/gold/layout.cc
index 75aecfe..a717ed2 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 131d6a6..a106ccc 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 c3f1747..a26139b 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 86d9bd7..4cb7608 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
@@ -312,6 +317,10 @@ class General_options
};
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 0e28629..4c6959e 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<size>::Value_type v;
- if (sym == NULL)
- v = 0;
- else
- {
- Sized_symbol<size>* 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<size>());
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<int size>
+typename elfcpp::Elf_types<size>::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<size>::Value_type v;
+ if (sym != NULL)
+ {
+ Sized_symbol<size>* ssym;
+ ssym = this->symtab_->get_sized_symbol<size>(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 07a336d..f384c8c 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<int size>
+ typename elfcpp::Elf_types<size>::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 1214800..4b103f8 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 1373064..775aedf 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<Parser_closure*>(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 3250e8e..7cfe724 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 */