mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-10 01:42:21 +08:00
Add support for -e and for ENTRY in linker scripts.
This commit is contained in:
@ -64,7 +64,8 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
|
|||||||
// Layout methods.
|
// Layout methods.
|
||||||
|
|
||||||
Layout::Layout(const General_options& options)
|
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_(),
|
section_name_map_(), segment_list_(), section_list_(),
|
||||||
unattached_section_list_(), special_output_list_(),
|
unattached_section_list_(), special_output_list_(),
|
||||||
section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
|
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.
|
// Lay out the file header.
|
||||||
Output_file_header* 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);
|
load_seg->add_initial_output_data(file_header);
|
||||||
this->special_output_list_.push_back(file_header);
|
this->special_output_list_.push_back(file_header);
|
||||||
|
|
||||||
|
@ -241,6 +241,12 @@ class Layout
|
|||||||
has_static_tls() const
|
has_static_tls() const
|
||||||
{ return this->has_static_tls_; }
|
{ 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.
|
// Dump statistical information to stderr.
|
||||||
void
|
void
|
||||||
print_stats() const;
|
print_stats() const;
|
||||||
@ -426,6 +432,9 @@ class Layout
|
|||||||
|
|
||||||
// A reference to the options on the command line.
|
// A reference to the options on the command line.
|
||||||
const General_options& options_;
|
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.
|
// The output section names.
|
||||||
Stringpool namepool_;
|
Stringpool namepool_;
|
||||||
// The output symbol names.
|
// The output symbol names.
|
||||||
|
@ -395,12 +395,15 @@ options::Command_line_options::options[] =
|
|||||||
GENERAL_NOARG('\0', "detect-odr-violations",
|
GENERAL_NOARG('\0', "detect-odr-violations",
|
||||||
N_("Try to detect violations of the One Definition Rule"),
|
N_("Try to detect violations of the One Definition Rule"),
|
||||||
NULL, TWO_DASHES, &General_options::set_detect_odr_violations),
|
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"),
|
GENERAL_NOARG('E', "export-dynamic", N_("Export all dynamic symbols"),
|
||||||
NULL, TWO_DASHES, &General_options::set_export_dynamic),
|
NULL, TWO_DASHES, &General_options::set_export_dynamic),
|
||||||
GENERAL_NOARG('\0', "eh-frame-hdr", N_("Create exception frame header"),
|
GENERAL_NOARG('\0', "eh-frame-hdr", N_("Create exception frame header"),
|
||||||
NULL, TWO_DASHES, &General_options::set_create_eh_frame_hdr),
|
NULL, TWO_DASHES, &General_options::set_create_eh_frame_hdr),
|
||||||
GENERAL_ARG('h', "soname", N_("Set shared library name"),
|
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_options::set_soname),
|
||||||
GENERAL_ARG('I', "dynamic-linker", N_("Set dynamic linker path"),
|
GENERAL_ARG('I', "dynamic-linker", N_("Set dynamic linker path"),
|
||||||
N_("-I PROGRAM, --dynamic-linker PROGRAM"), TWO_DASHES,
|
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.
|
// The default values for the general options.
|
||||||
|
|
||||||
General_options::General_options()
|
General_options::General_options()
|
||||||
: export_dynamic_(false),
|
: entry_(NULL),
|
||||||
|
export_dynamic_(false),
|
||||||
soname_(NULL),
|
soname_(NULL),
|
||||||
dynamic_linker_(NULL),
|
dynamic_linker_(NULL),
|
||||||
search_path_(),
|
search_path_(),
|
||||||
|
@ -108,6 +108,11 @@ class General_options
|
|||||||
public:
|
public:
|
||||||
General_options();
|
General_options();
|
||||||
|
|
||||||
|
// -e: set entry address.
|
||||||
|
const char*
|
||||||
|
entry() const
|
||||||
|
{ return this->entry_; }
|
||||||
|
|
||||||
// -E: export dynamic symbols.
|
// -E: export dynamic symbols.
|
||||||
bool
|
bool
|
||||||
export_dynamic() const
|
export_dynamic() const
|
||||||
@ -311,6 +316,10 @@ class General_options
|
|||||||
ZLIB_COMPRESSION,
|
ZLIB_COMPRESSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
set_entry(const char* arg)
|
||||||
|
{ this->entry_ = arg; }
|
||||||
|
|
||||||
void
|
void
|
||||||
set_export_dynamic()
|
set_export_dynamic()
|
||||||
{ this->export_dynamic_ = true; }
|
{ this->export_dynamic_ = true; }
|
||||||
@ -509,6 +518,7 @@ class General_options
|
|||||||
void
|
void
|
||||||
add_sysroot();
|
add_sysroot();
|
||||||
|
|
||||||
|
const char* entry_;
|
||||||
bool export_dynamic_;
|
bool export_dynamic_;
|
||||||
const char* soname_;
|
const char* soname_;
|
||||||
const char* dynamic_linker_;
|
const char* dynamic_linker_;
|
||||||
@ -824,6 +834,11 @@ class Command_line
|
|||||||
void
|
void
|
||||||
end_group(const char* arg);
|
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.
|
// Get an option argument--a helper function for special processing.
|
||||||
const char*
|
const char*
|
||||||
get_special_argument(const char* longname, int argc, char** argv,
|
get_special_argument(const char* longname, int argc, char** argv,
|
||||||
|
@ -294,12 +294,14 @@ Output_segment_headers::do_sized_write(Output_file* of)
|
|||||||
|
|
||||||
Output_file_header::Output_file_header(const Target* target,
|
Output_file_header::Output_file_header(const Target* target,
|
||||||
const Symbol_table* symtab,
|
const Symbol_table* symtab,
|
||||||
const Output_segment_headers* osh)
|
const Output_segment_headers* osh,
|
||||||
|
const char* entry)
|
||||||
: target_(target),
|
: target_(target),
|
||||||
symtab_(symtab),
|
symtab_(symtab),
|
||||||
segment_header_(osh),
|
segment_header_(osh),
|
||||||
section_header_(NULL),
|
section_header_(NULL),
|
||||||
shstrtab_(NULL)
|
shstrtab_(NULL),
|
||||||
|
entry_(entry)
|
||||||
{
|
{
|
||||||
const int size = parameters->get_size();
|
const int size = parameters->get_size();
|
||||||
int ehdr_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_machine(this->target_->machine_code());
|
||||||
oehdr.put_e_version(elfcpp::EV_CURRENT);
|
oehdr.put_e_version(elfcpp::EV_CURRENT);
|
||||||
|
|
||||||
// FIXME: Need to support -e, and target specific entry symbol.
|
oehdr.put_e_entry(this->entry<size>());
|
||||||
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_phoff(this->segment_header_->offset());
|
oehdr.put_e_phoff(this->segment_header_->offset());
|
||||||
oehdr.put_e_shoff(this->section_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);
|
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.
|
// Output_data_const methods.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -393,7 +393,8 @@ class Output_file_header : public Output_data
|
|||||||
public:
|
public:
|
||||||
Output_file_header(const Target*,
|
Output_file_header(const Target*,
|
||||||
const Symbol_table*,
|
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
|
// Add information about the section headers. We lay out the ELF
|
||||||
// file header before we create the section headers.
|
// file header before we create the section headers.
|
||||||
@ -416,11 +417,17 @@ class Output_file_header : public Output_data
|
|||||||
void
|
void
|
||||||
do_sized_write(Output_file*);
|
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 Target* target_;
|
||||||
const Symbol_table* symtab_;
|
const Symbol_table* symtab_;
|
||||||
const Output_segment_headers* segment_header_;
|
const Output_segment_headers* segment_header_;
|
||||||
const Output_section_headers* section_header_;
|
const Output_section_headers* section_header_;
|
||||||
const Output_section* shstrtab_;
|
const Output_section* shstrtab_;
|
||||||
|
const char* entry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Output sections are mainly comprised of input sections. However,
|
// Output sections are mainly comprised of input sections. However,
|
||||||
|
@ -66,6 +66,11 @@ script_start_as_needed(void* closure);
|
|||||||
extern void
|
extern void
|
||||||
script_end_as_needed(void* closure);
|
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. */
|
/* Called by the bison parser to parse an OPTION. */
|
||||||
extern void
|
extern void
|
||||||
script_parse_option(void* closure, const char*);
|
script_parse_option(void* closure, const char*);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "workqueue.h"
|
#include "workqueue.h"
|
||||||
#include "readsyms.h"
|
#include "readsyms.h"
|
||||||
#include "parameters.h"
|
#include "parameters.h"
|
||||||
|
#include "layout.h"
|
||||||
#include "yyscript.h"
|
#include "yyscript.h"
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
#include "script-c.h"
|
#include "script-c.h"
|
||||||
@ -834,10 +835,11 @@ class Parser_closure
|
|||||||
const Position_dependent_options& posdep_options,
|
const Position_dependent_options& posdep_options,
|
||||||
bool in_group, bool is_in_sysroot,
|
bool in_group, bool is_in_sysroot,
|
||||||
Command_line* command_line,
|
Command_line* command_line,
|
||||||
|
Layout* layout,
|
||||||
const Lex::Token_sequence* tokens)
|
const Lex::Token_sequence* tokens)
|
||||||
: filename_(filename), posdep_options_(posdep_options),
|
: filename_(filename), posdep_options_(posdep_options),
|
||||||
in_group_(in_group), is_in_sysroot_(is_in_sysroot),
|
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)
|
next_token_index_(0), inputs_(NULL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -869,6 +871,11 @@ class Parser_closure
|
|||||||
Command_line* command_line()
|
Command_line* command_line()
|
||||||
{ return this->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.
|
// Whether we are at the end of the token list.
|
||||||
bool
|
bool
|
||||||
at_eof() const
|
at_eof() const
|
||||||
@ -909,6 +916,8 @@ class Parser_closure
|
|||||||
bool is_in_sysroot_;
|
bool is_in_sysroot_;
|
||||||
// May be NULL if the user chooses not to pass one in.
|
// May be NULL if the user chooses not to pass one in.
|
||||||
Command_line* command_line_;
|
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.
|
// The tokens to be returned by the lexer.
|
||||||
const Lex::Token_sequence* tokens_;
|
const Lex::Token_sequence* tokens_;
|
||||||
@ -940,6 +949,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
|
|||||||
input_group != NULL,
|
input_group != NULL,
|
||||||
input_file->is_in_sysroot(),
|
input_file->is_in_sysroot(),
|
||||||
NULL,
|
NULL,
|
||||||
|
layout,
|
||||||
&lex.tokens());
|
&lex.tokens());
|
||||||
|
|
||||||
if (yyparse(&closure) != 0)
|
if (yyparse(&closure) != 0)
|
||||||
@ -1014,6 +1024,7 @@ read_commandline_script(const char* filename, Command_line* cmdline)
|
|||||||
false,
|
false,
|
||||||
input_file.is_in_sysroot(),
|
input_file.is_in_sysroot(),
|
||||||
cmdline,
|
cmdline,
|
||||||
|
NULL,
|
||||||
&lex.tokens());
|
&lex.tokens());
|
||||||
if (yyparse(&closure) != 0)
|
if (yyparse(&closure) != 0)
|
||||||
{
|
{
|
||||||
@ -1022,6 +1033,9 @@ read_commandline_script(const char* filename, Command_line* cmdline)
|
|||||||
}
|
}
|
||||||
|
|
||||||
input_file.file().unlock(task);
|
input_file.file().unlock(task);
|
||||||
|
|
||||||
|
gold_assert(!closure.saw_inputs());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1318,6 +1332,18 @@ script_end_as_needed(void* closurev)
|
|||||||
closure->position_dependent_options().clear_as_needed();
|
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.
|
// Called by the bison parser to parse an OPTION.
|
||||||
|
|
||||||
extern "C" void
|
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.,
|
// There are some options that we could handle here--e.g.,
|
||||||
// -lLIBRARY. Should we bother?
|
// -lLIBRARY. Should we bother?
|
||||||
gold_warning(_("%s: Ignoring command OPTION; OPTION is only valid"
|
gold_warning(_("%s: ignoring command OPTION; OPTION is only valid"
|
||||||
" for scripts specified via -T"),
|
" for scripts specified via -T/--script"),
|
||||||
closure->filename());
|
closure->filename());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -160,11 +160,13 @@
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
/* A file contains a list of commands. */
|
||||||
file_list:
|
file_list:
|
||||||
file_list file_cmd
|
file_list file_cmd
|
||||||
| /* empty */
|
| /* empty */
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* A command which may appear at top level of a linker script. */
|
||||||
file_cmd:
|
file_cmd:
|
||||||
OUTPUT_FORMAT '(' STRING ')'
|
OUTPUT_FORMAT '(' STRING ')'
|
||||||
| GROUP
|
| GROUP
|
||||||
@ -173,13 +175,16 @@ file_cmd:
|
|||||||
{ script_end_group(closure); }
|
{ script_end_group(closure); }
|
||||||
| OPTION '(' STRING ')'
|
| OPTION '(' STRING ')'
|
||||||
{ script_parse_option(closure, $3); }
|
{ script_parse_option(closure, $3); }
|
||||||
|
| file_or_sections_cmd
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* A list of input file names. */
|
||||||
input_list:
|
input_list:
|
||||||
input_list_element
|
input_list_element
|
||||||
| input_list opt_comma input_list_element
|
| input_list opt_comma input_list_element
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* An input file name. */
|
||||||
input_list_element:
|
input_list_element:
|
||||||
STRING
|
STRING
|
||||||
{ script_add_file(closure, $1); }
|
{ script_add_file(closure, $1); }
|
||||||
@ -189,6 +194,14 @@ input_list_element:
|
|||||||
{ script_end_as_needed(closure); }
|
{ 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:
|
opt_comma:
|
||||||
','
|
','
|
||||||
| /* empty */
|
| /* empty */
|
||||||
|
Reference in New Issue
Block a user