mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
Implement SIZEOF_HEADERS, section constraints, other minor linker
script items.
This commit is contained in:
parent
ae7d22a6f2
commit
3802b2dd6b
@ -24,6 +24,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "parameters.h"
|
||||
#include "symtab.h"
|
||||
#include "layout.h"
|
||||
@ -632,6 +633,155 @@ script_exp_function_addr(const char* section_name, size_t section_name_len)
|
||||
return new Addr_expression(section_name, section_name_len);
|
||||
}
|
||||
|
||||
// CONSTANT. It would be nice if we could simply evaluate this
|
||||
// immediately and return an Integer_expression, but unfortunately we
|
||||
// don't know the target.
|
||||
|
||||
class Constant_expression : public Expression
|
||||
{
|
||||
public:
|
||||
Constant_expression(const char* name, size_t length);
|
||||
|
||||
uint64_t
|
||||
value(const Expression_eval_info*);
|
||||
|
||||
void
|
||||
print(FILE* f) const;
|
||||
|
||||
private:
|
||||
enum Constant_function
|
||||
{
|
||||
CONSTANT_MAXPAGESIZE,
|
||||
CONSTANT_COMMONPAGESIZE
|
||||
};
|
||||
|
||||
Constant_function function_;
|
||||
};
|
||||
|
||||
Constant_expression::Constant_expression(const char* name, size_t length)
|
||||
{
|
||||
if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0)
|
||||
this->function_ = CONSTANT_MAXPAGESIZE;
|
||||
else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0)
|
||||
this->function_ = CONSTANT_COMMONPAGESIZE;
|
||||
else
|
||||
{
|
||||
std::string s(name, length);
|
||||
gold_error(_("unknown constant %s"), s.c_str());
|
||||
this->function_ = CONSTANT_MAXPAGESIZE;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Constant_expression::value(const Expression_eval_info*)
|
||||
{
|
||||
switch (this->function_)
|
||||
{
|
||||
case CONSTANT_MAXPAGESIZE:
|
||||
return parameters->target()->abi_pagesize();
|
||||
case CONSTANT_COMMONPAGESIZE:
|
||||
return parameters->target()->common_pagesize();
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Constant_expression::print(FILE* f) const
|
||||
{
|
||||
const char* name;
|
||||
switch (this->function_)
|
||||
{
|
||||
case CONSTANT_MAXPAGESIZE:
|
||||
name = "MAXPAGESIZE";
|
||||
break;
|
||||
case CONSTANT_COMMONPAGESIZE:
|
||||
name = "COMMONPAGESIZE";
|
||||
break;
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
fprintf(f, "CONSTANT(%s)", name);
|
||||
}
|
||||
|
||||
extern "C" Expression*
|
||||
script_exp_function_constant(const char* name, size_t length)
|
||||
{
|
||||
return new Constant_expression(name, length);
|
||||
}
|
||||
|
||||
// DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall
|
||||
// back to the general case.
|
||||
|
||||
extern "C" Expression*
|
||||
script_exp_function_data_segment_align(Expression* left, Expression*)
|
||||
{
|
||||
Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left);
|
||||
Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1));
|
||||
Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1),
|
||||
e2);
|
||||
return script_exp_binary_add(e1, e3);
|
||||
}
|
||||
|
||||
// DATA_SEGMENT_RELRO. FIXME: This is not implemented.
|
||||
|
||||
extern "C" Expression*
|
||||
script_exp_function_data_segment_relro_end(Expression*, Expression* right)
|
||||
{
|
||||
return right;
|
||||
}
|
||||
|
||||
// DATA_SEGMENT_END. FIXME: This is not implemented.
|
||||
|
||||
extern "C" Expression*
|
||||
script_exp_function_data_segment_end(Expression* val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// SIZEOF_HEADERS.
|
||||
|
||||
class Sizeof_headers_expression : public Expression
|
||||
{
|
||||
public:
|
||||
Sizeof_headers_expression()
|
||||
{ }
|
||||
|
||||
uint64_t
|
||||
value(const Expression_eval_info*);
|
||||
|
||||
void
|
||||
print(FILE* f) const
|
||||
{ fprintf(f, "SIZEOF_HEADERS"); }
|
||||
};
|
||||
|
||||
uint64_t
|
||||
Sizeof_headers_expression::value(const Expression_eval_info* eei)
|
||||
{
|
||||
unsigned int ehdr_size;
|
||||
unsigned int phdr_size;
|
||||
if (parameters->get_size() == 32)
|
||||
{
|
||||
ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
|
||||
phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
|
||||
}
|
||||
else if (parameters->get_size() == 64)
|
||||
{
|
||||
ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
|
||||
phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
return ehdr_size + phdr_size * eei->layout->expected_segment_count();
|
||||
}
|
||||
|
||||
extern "C" Expression*
|
||||
script_exp_function_sizeof_headers()
|
||||
{
|
||||
return new Sizeof_headers_expression();
|
||||
}
|
||||
|
||||
// Functions.
|
||||
|
||||
extern "C" Expression*
|
||||
@ -640,12 +790,6 @@ 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)
|
||||
{
|
||||
@ -676,36 +820,12 @@ 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*)
|
||||
{
|
||||
|
143
gold/layout.cc
143
gold/layout.cc
@ -397,9 +397,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
|
||||
|
||||
hdr_os->set_after_input_sections();
|
||||
|
||||
Output_segment* hdr_oseg =
|
||||
new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
|
||||
this->segment_list_.push_back(hdr_oseg);
|
||||
Output_segment* hdr_oseg;
|
||||
hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
|
||||
elfcpp::PF_R);
|
||||
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
|
||||
|
||||
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
|
||||
@ -523,9 +523,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
|
||||
seg_flags);
|
||||
oseg->add_output_section(os, seg_flags);
|
||||
}
|
||||
|
||||
@ -549,9 +548,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
|
||||
if (p == this->segment_list_.end())
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
|
||||
seg_flags);
|
||||
oseg->add_output_section(os, seg_flags);
|
||||
}
|
||||
}
|
||||
@ -561,11 +559,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
if ((flags & elfcpp::SHF_TLS) != 0)
|
||||
{
|
||||
if (this->tls_segment_ == NULL)
|
||||
{
|
||||
this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(this->tls_segment_);
|
||||
}
|
||||
this->tls_segment_ = this->make_output_segment(elfcpp::PT_TLS,
|
||||
seg_flags);
|
||||
this->tls_segment_->add_output_section(os, seg_flags);
|
||||
}
|
||||
}
|
||||
@ -573,6 +568,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
return os;
|
||||
}
|
||||
|
||||
// Return the number of segments we expect to see.
|
||||
|
||||
size_t
|
||||
Layout::expected_segment_count() const
|
||||
{
|
||||
size_t ret = this->segment_list_.size();
|
||||
|
||||
// If we didn't see a SECTIONS clause in a linker script, we should
|
||||
// already have the complete list of segments. Otherwise we ask the
|
||||
// SECTIONS clause how many segments it expects, and add in the ones
|
||||
// we already have (PT_GNU_STACK, PT_GNU_EH_FRAME, etc.)
|
||||
|
||||
if (!this->script_options_->saw_sections_clause())
|
||||
return ret;
|
||||
else
|
||||
{
|
||||
const Script_sections* ss = this->script_options_->script_sections();
|
||||
return ret + ss->expected_segment_count(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK
|
||||
// is whether we saw a .note.GNU-stack section in the object file.
|
||||
// GNU_STACK_FLAGS is the section flags. The flags give the
|
||||
@ -603,11 +619,11 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
|
||||
if (parameters->doing_static_link())
|
||||
return;
|
||||
|
||||
const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL);
|
||||
this->dynamic_section_ = this->make_output_section(dynamic_name,
|
||||
elfcpp::SHT_DYNAMIC,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE));
|
||||
this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic",
|
||||
elfcpp::SHT_DYNAMIC,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE),
|
||||
false);
|
||||
|
||||
symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
|
||||
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
|
||||
@ -684,8 +700,8 @@ Layout::find_first_load_seg()
|
||||
return *p;
|
||||
}
|
||||
|
||||
Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
|
||||
this->segment_list_.push_back(load_seg);
|
||||
Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD,
|
||||
elfcpp::PF_R);
|
||||
return load_seg;
|
||||
}
|
||||
|
||||
@ -734,11 +750,16 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
||||
this->create_gold_note();
|
||||
this->create_executable_stack_info(target);
|
||||
|
||||
Output_segment* phdr_seg = NULL;
|
||||
if (!parameters->output_is_object() && !parameters->doing_static_link())
|
||||
{
|
||||
// There was a dynamic object in the link. We need to create
|
||||
// some information for the dynamic linker.
|
||||
|
||||
// Create the PT_PHDR segment which will hold the program
|
||||
// headers.
|
||||
phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
|
||||
|
||||
// Create the dynamic symbol table, including the hash table.
|
||||
Output_section* dynstr;
|
||||
std::vector<Symbol*> dynamic_symbols;
|
||||
@ -775,16 +796,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
||||
else
|
||||
load_seg = this->find_first_load_seg();
|
||||
|
||||
Output_segment* phdr_seg = NULL;
|
||||
if (load_seg != NULL
|
||||
&& !parameters->output_is_object()
|
||||
&& !parameters->doing_static_link())
|
||||
{
|
||||
// Create the PT_PHDR segment which will hold the program
|
||||
// headers.
|
||||
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
|
||||
this->segment_list_.push_back(phdr_seg);
|
||||
}
|
||||
gold_assert(phdr_seg == NULL || load_seg != NULL);
|
||||
|
||||
// Lay out the segment headers.
|
||||
Output_segment_headers* segment_headers;
|
||||
@ -988,8 +1000,7 @@ Layout::create_executable_stack_info(const Target* target)
|
||||
int flags = elfcpp::PF_R | elfcpp::PF_W;
|
||||
if (is_stack_executable)
|
||||
flags |= elfcpp::PF_X;
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_GNU_STACK, flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
this->make_output_segment(elfcpp::PT_GNU_STACK, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1591,10 +1602,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
|
||||
|
||||
// Create the dynamic symbol table section.
|
||||
|
||||
const char* dynsym_name = this->namepool_.add(".dynsym", false, NULL);
|
||||
Output_section* dynsym = this->make_output_section(dynsym_name,
|
||||
elfcpp::SHT_DYNSYM,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
|
||||
elfcpp::SHT_DYNSYM,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
Output_section_data* odata = new Output_data_fixed_space(index * symsize,
|
||||
align);
|
||||
@ -1612,10 +1623,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
|
||||
|
||||
// Create the dynamic string table section.
|
||||
|
||||
const char* dynstr_name = this->namepool_.add(".dynstr", false, NULL);
|
||||
Output_section* dynstr = this->make_output_section(dynstr_name,
|
||||
elfcpp::SHT_STRTAB,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
|
||||
elfcpp::SHT_STRTAB,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
|
||||
dynstr->add_output_section_data(strdata);
|
||||
@ -1637,10 +1648,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
|
||||
Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount,
|
||||
&phash, &hashlen);
|
||||
|
||||
const char* hash_name = this->namepool_.add(".hash", false, NULL);
|
||||
Output_section* hashsec = this->make_output_section(hash_name,
|
||||
elfcpp::SHT_HASH,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* hashsec = this->choose_output_section(NULL, ".hash",
|
||||
elfcpp::SHT_HASH,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
Output_section_data* hashdata = new Output_data_const_buffer(phash,
|
||||
hashlen,
|
||||
@ -1753,10 +1764,10 @@ Layout::sized_create_version_sections(
|
||||
const Output_section* dynstr
|
||||
ACCEPT_SIZE_ENDIAN)
|
||||
{
|
||||
const char* vname = this->namepool_.add(".gnu.version", false, NULL);
|
||||
Output_section* vsec = this->make_output_section(vname,
|
||||
elfcpp::SHT_GNU_versym,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
|
||||
elfcpp::SHT_GNU_versym,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
unsigned char* vbuf;
|
||||
unsigned int vsize;
|
||||
@ -1775,10 +1786,11 @@ Layout::sized_create_version_sections(
|
||||
|
||||
if (versions->any_defs())
|
||||
{
|
||||
const char* vdname = this->namepool_.add(".gnu.version_d", false, NULL);
|
||||
Output_section *vdsec;
|
||||
vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* vdsec;
|
||||
vdsec= this->choose_output_section(NULL, ".gnu.version_d",
|
||||
elfcpp::SHT_GNU_verdef,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
unsigned char* vdbuf;
|
||||
unsigned int vdsize;
|
||||
@ -1801,10 +1813,11 @@ Layout::sized_create_version_sections(
|
||||
|
||||
if (versions->any_needs())
|
||||
{
|
||||
const char* vnname = this->namepool_.add(".gnu.version_r", false, NULL);
|
||||
Output_section* vnsec;
|
||||
vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
|
||||
elfcpp::SHF_ALLOC);
|
||||
vnsec = this->choose_output_section(NULL, ".gnu.version_r",
|
||||
elfcpp::SHT_GNU_verneed,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
unsigned char* vnbuf;
|
||||
unsigned int vnsize;
|
||||
@ -1842,14 +1855,14 @@ Layout::create_interp(const Target* target)
|
||||
|
||||
Output_section_data* odata = new Output_data_const(interp, len, 1);
|
||||
|
||||
const char* interp_name = this->namepool_.add(".interp", false, NULL);
|
||||
Output_section* osec = this->make_output_section(interp_name,
|
||||
elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC);
|
||||
Output_section* osec = this->choose_output_section(NULL, ".interp",
|
||||
elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
osec->add_output_section_data(odata);
|
||||
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_INTERP, elfcpp::PF_R);
|
||||
this->segment_list_.push_back(oseg);
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
|
||||
elfcpp::PF_R);
|
||||
oseg->add_initial_output_section(osec, elfcpp::PF_R);
|
||||
}
|
||||
|
||||
@ -1859,9 +1872,9 @@ void
|
||||
Layout::finish_dynamic_section(const Input_objects* input_objects,
|
||||
const Symbol_table* symtab)
|
||||
{
|
||||
Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
|
||||
elfcpp::PF_R | elfcpp::PF_W);
|
||||
this->segment_list_.push_back(oseg);
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
|
||||
(elfcpp::PF_R
|
||||
| elfcpp::PF_W));
|
||||
oseg->add_initial_output_section(this->dynamic_section_,
|
||||
elfcpp::PF_R | elfcpp::PF_W);
|
||||
|
||||
|
@ -237,6 +237,10 @@ class Layout
|
||||
find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
|
||||
elfcpp::Elf_Word clear) const;
|
||||
|
||||
// Return the number of segments we expect to produce.
|
||||
size_t
|
||||
expected_segment_count() const;
|
||||
|
||||
// Set a flag to indicate that an object file uses the static TLS model.
|
||||
void
|
||||
set_has_static_tls()
|
||||
|
@ -2324,21 +2324,22 @@ Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
off = align_address(off, (*p)->addralign());
|
||||
|
||||
if (reset)
|
||||
(*p)->reset_address_and_file_offset();
|
||||
|
||||
// When using a linker script the section will most likely
|
||||
// already have an address.
|
||||
if (!(*p)->is_address_valid())
|
||||
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
|
||||
{
|
||||
off = align_address(off, (*p)->addralign());
|
||||
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The script may have inserted a skip forward, but it
|
||||
// better not have moved backward.
|
||||
gold_assert((*p)->address() >= addr);
|
||||
off = startoff + ((*p)->address() - addr);
|
||||
gold_assert((*p)->address() >= addr + (off - startoff));
|
||||
off += (*p)->address() - (addr + (off - startoff));
|
||||
(*p)->set_file_offset(off);
|
||||
(*p)->finalize_data_size();
|
||||
}
|
||||
|
@ -61,6 +61,21 @@ typedef Expression* Expression_ptr;
|
||||
typedef void* Expression_ptr;
|
||||
#endif
|
||||
|
||||
/* A constraint for whether to use a particular output section
|
||||
definition. */
|
||||
|
||||
enum Section_constraint
|
||||
{
|
||||
/* No constraint. */
|
||||
CONSTRAINT_NONE,
|
||||
/* Only if all input sections are read-only. */
|
||||
CONSTRAINT_ONLY_IF_RO,
|
||||
/* Only if at least input section is writable. */
|
||||
CONSTRAINT_ONLY_IF_RW,
|
||||
/* Special constraint. */
|
||||
CONSTRAINT_SPECIAL
|
||||
};
|
||||
|
||||
/* The information we store for an output section header in the bison
|
||||
parser. */
|
||||
|
||||
@ -75,6 +90,8 @@ struct Parser_output_section_header
|
||||
/* The input section alignment, from the SUBALIGN specifier. This
|
||||
may be NULL. */
|
||||
Expression_ptr subalign;
|
||||
/* A constraint on this output section. */
|
||||
enum Section_constraint constraint;
|
||||
};
|
||||
|
||||
/* The information we store for an output section trailer in the bison
|
||||
@ -204,6 +221,11 @@ script_set_entry(void* closure, const char*, size_t);
|
||||
extern void
|
||||
script_parse_option(void* closure, const char*, size_t);
|
||||
|
||||
/* Called by the bison parser to handle SEARCH_DIR. */
|
||||
|
||||
extern void
|
||||
script_add_search_dir(void* closure, const char*, size_t);
|
||||
|
||||
/* Called by the bison parser to push the lexer into expression
|
||||
mode. */
|
||||
|
||||
|
@ -82,6 +82,20 @@ class Sections_element
|
||||
set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*)
|
||||
{ }
|
||||
|
||||
// Check a constraint (ONLY_IF_RO, etc.) on an output section. If
|
||||
// this section is constrained, and the input sections do not match,
|
||||
// return the constraint, and set *POSD.
|
||||
virtual Section_constraint
|
||||
check_constraint(Output_section_definition**)
|
||||
{ return CONSTRAINT_NONE; }
|
||||
|
||||
// See if this is the alternate output section for a constrained
|
||||
// output section. If it is, transfer the Output_section and return
|
||||
// true. Otherwise return false.
|
||||
virtual bool
|
||||
alternate_constraint(Output_section_definition*, Section_constraint)
|
||||
{ return false; }
|
||||
|
||||
// Print the element for debugging purposes.
|
||||
virtual void
|
||||
print(FILE* f) const = 0;
|
||||
@ -1146,6 +1160,18 @@ class Output_section_definition : public Sections_element
|
||||
set_section_addresses(Symbol_table* symtab, Layout* layout,
|
||||
bool* dot_has_value, uint64_t* dot_value);
|
||||
|
||||
// Check a constraint (ONLY_IF_RO, etc.) on an output section. If
|
||||
// this section is constrained, and the input sections do not match,
|
||||
// return the constraint, and set *POSD.
|
||||
Section_constraint
|
||||
check_constraint(Output_section_definition** posd);
|
||||
|
||||
// See if this is the alternate output section for a constrained
|
||||
// output section. If it is, transfer the Output_section and return
|
||||
// true. Otherwise return false.
|
||||
bool
|
||||
alternate_constraint(Output_section_definition*, Section_constraint);
|
||||
|
||||
// Print the contents to the FILE. This is for debugging.
|
||||
void
|
||||
print(FILE*) const;
|
||||
@ -1163,6 +1189,8 @@ class Output_section_definition : public Sections_element
|
||||
Expression* align_;
|
||||
// The input section alignment. This may be NULL.
|
||||
Expression* subalign_;
|
||||
// The constraint, if any.
|
||||
Section_constraint constraint_;
|
||||
// The fill value. This may be NULL.
|
||||
Expression* fill_;
|
||||
// The list of elements defining the section.
|
||||
@ -1183,6 +1211,7 @@ Output_section_definition::Output_section_definition(
|
||||
load_address_(header->load_address),
|
||||
align_(header->align),
|
||||
subalign_(header->subalign),
|
||||
constraint_(header->constraint),
|
||||
fill_(NULL),
|
||||
elements_(),
|
||||
output_section_(NULL)
|
||||
@ -1540,6 +1569,88 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
|
||||
gold_assert(input_sections.empty());
|
||||
}
|
||||
|
||||
// Check a constraint (ONLY_IF_RO, etc.) on an output section. If
|
||||
// this section is constrained, and the input sections do not match,
|
||||
// return the constraint, and set *POSD.
|
||||
|
||||
Section_constraint
|
||||
Output_section_definition::check_constraint(Output_section_definition** posd)
|
||||
{
|
||||
switch (this->constraint_)
|
||||
{
|
||||
case CONSTRAINT_NONE:
|
||||
return CONSTRAINT_NONE;
|
||||
|
||||
case CONSTRAINT_ONLY_IF_RO:
|
||||
if (this->output_section_ != NULL
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
|
||||
{
|
||||
*posd = this;
|
||||
return CONSTRAINT_ONLY_IF_RO;
|
||||
}
|
||||
return CONSTRAINT_NONE;
|
||||
|
||||
case CONSTRAINT_ONLY_IF_RW:
|
||||
if (this->output_section_ != NULL
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
|
||||
{
|
||||
*posd = this;
|
||||
return CONSTRAINT_ONLY_IF_RW;
|
||||
}
|
||||
return CONSTRAINT_NONE;
|
||||
|
||||
case CONSTRAINT_SPECIAL:
|
||||
if (this->output_section_ != NULL)
|
||||
gold_error(_("SPECIAL constraints are not implemented"));
|
||||
return CONSTRAINT_NONE;
|
||||
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is the alternate output section for a constrained
|
||||
// output section. If it is, transfer the Output_section and return
|
||||
// true. Otherwise return false.
|
||||
|
||||
bool
|
||||
Output_section_definition::alternate_constraint(
|
||||
Output_section_definition* posd,
|
||||
Section_constraint constraint)
|
||||
{
|
||||
if (this->name_ != posd->name_)
|
||||
return false;
|
||||
|
||||
switch (constraint)
|
||||
{
|
||||
case CONSTRAINT_ONLY_IF_RO:
|
||||
if (this->constraint_ != CONSTRAINT_ONLY_IF_RW)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case CONSTRAINT_ONLY_IF_RW:
|
||||
if (this->constraint_ != CONSTRAINT_ONLY_IF_RO)
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
// We have found the alternate constraint. We just need to move
|
||||
// over the Output_section. When constraints are used properly,
|
||||
// THIS should not have an output_section pointer, as all the input
|
||||
// sections should have matched the other definition.
|
||||
|
||||
if (this->output_section_ != NULL)
|
||||
gold_error(_("mismatched definition for constrained sections"));
|
||||
|
||||
this->output_section_ = posd->output_section_;
|
||||
posd->output_section_ = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Print for debugging.
|
||||
|
||||
void
|
||||
@ -1926,6 +2037,33 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
gold_assert(this->saw_sections_clause_);
|
||||
|
||||
// Implement ONLY_IF_RO/ONLY_IF_RW constraints. These are a pain
|
||||
// for our representation.
|
||||
for (Sections_elements::iterator p = this->sections_elements_->begin();
|
||||
p != this->sections_elements_->end();
|
||||
++p)
|
||||
{
|
||||
Output_section_definition* posd;
|
||||
Section_constraint failed_constraint = (*p)->check_constraint(&posd);
|
||||
if (failed_constraint != CONSTRAINT_NONE)
|
||||
{
|
||||
Sections_elements::iterator q;
|
||||
for (q = this->sections_elements_->begin();
|
||||
q != this->sections_elements_->end();
|
||||
++q)
|
||||
{
|
||||
if (q != p)
|
||||
{
|
||||
if ((*q)->alternate_constraint(posd, failed_constraint))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (q == this->sections_elements_->end())
|
||||
gold_error(_("no matching section constraint"));
|
||||
}
|
||||
}
|
||||
|
||||
bool dot_has_value = false;
|
||||
uint64_t dot_value = 0;
|
||||
for (Sections_elements::iterator p = this->sections_elements_->begin();
|
||||
@ -2118,10 +2256,15 @@ Script_sections::create_segments(Layout* layout)
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
size_t sizeof_headers = file_header_size + segment_headers_size;
|
||||
|
||||
if (first_seg != NULL
|
||||
&& ((first_seg->paddr() & (abi_pagesize - 1))
|
||||
>= file_header_size + segment_headers_size))
|
||||
return first_seg;
|
||||
&& (first_seg->paddr() & (abi_pagesize - 1)) >= sizeof_headers)
|
||||
{
|
||||
first_seg->set_addresses(first_seg->vaddr() - sizeof_headers,
|
||||
first_seg->paddr() - sizeof_headers);
|
||||
return first_seg;
|
||||
}
|
||||
|
||||
Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD,
|
||||
elfcpp::PF_R);
|
||||
@ -2132,16 +2275,13 @@ Script_sections::create_segments(Layout* layout)
|
||||
uint64_t vma = first_seg->vaddr();
|
||||
uint64_t lma = first_seg->paddr();
|
||||
|
||||
if (lma >= file_header_size + segment_headers_size
|
||||
&& lma >= abi_pagesize)
|
||||
{
|
||||
// We want a segment with the same relationship between VMA
|
||||
// and LMA, but with enough room for the headers.
|
||||
uint64_t size_for_page = align_address((file_header_size
|
||||
+ segment_headers_size),
|
||||
abi_pagesize);
|
||||
load_seg->set_addresses(vma - size_for_page, lma - size_for_page);
|
||||
}
|
||||
// We want a segment with the same relationship between VMA and
|
||||
// LMA, but with enough room for the headers, and aligned to
|
||||
// load at the start of a page.
|
||||
uint64_t hdr_lma = lma - sizeof_headers;
|
||||
hdr_lma &= ~(abi_pagesize - 1);
|
||||
if (lma >= hdr_lma && vma >= (lma - hdr_lma))
|
||||
load_seg->set_addresses(vma - (lma - hdr_lma), hdr_lma);
|
||||
else
|
||||
{
|
||||
// We could handle this case by create the file header
|
||||
@ -2216,6 +2356,48 @@ Script_sections::create_note_and_tls_segments(
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of segments we expect to create based on the
|
||||
// SECTIONS clause. This is used to implement SIZEOF_HEADERS.
|
||||
|
||||
size_t
|
||||
Script_sections::expected_segment_count(const Layout* layout) const
|
||||
{
|
||||
Layout::Section_list sections;
|
||||
layout->get_allocated_sections(§ions);
|
||||
|
||||
// We assume that we will need two PT_LOAD segments.
|
||||
size_t ret = 2;
|
||||
|
||||
bool saw_note = false;
|
||||
bool saw_tls = false;
|
||||
for (Layout::Section_list::const_iterator p = sections.begin();
|
||||
p != sections.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
// Assume that all note sections will fit into a single
|
||||
// PT_NOTE segment.
|
||||
if (!saw_note)
|
||||
{
|
||||
++ret;
|
||||
saw_note = true;
|
||||
}
|
||||
}
|
||||
else if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
|
||||
{
|
||||
// There can only be one PT_TLS segment.
|
||||
if (!saw_tls)
|
||||
{
|
||||
++ret;
|
||||
saw_tls = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Print the SECTIONS clause to F for debugging.
|
||||
|
||||
void
|
||||
|
@ -134,6 +134,11 @@ class Script_sections
|
||||
Output_segment*
|
||||
set_section_addresses(Symbol_table*, Layout*);
|
||||
|
||||
// Return the number of segments we expect to create based on the
|
||||
// SECTIONS clause.
|
||||
size_t
|
||||
expected_segment_count(const Layout*) const;
|
||||
|
||||
// Print the contents to the FILE. This is for debugging.
|
||||
void
|
||||
print(FILE*) const;
|
||||
|
@ -393,7 +393,9 @@ Lex::can_start_name(char c, char c2)
|
||||
return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
|
||||
|
||||
case '*': case '[':
|
||||
return this->mode_ == VERSION_SCRIPT;
|
||||
return (this->mode_ == VERSION_SCRIPT
|
||||
|| (this->mode_ == LINKER_SCRIPT
|
||||
&& can_continue_name(&c2)));
|
||||
|
||||
default:
|
||||
return false;
|
||||
@ -1607,6 +1609,7 @@ script_keyword_parsecodes[] =
|
||||
{ "SHORT", SHORT },
|
||||
{ "SIZEOF", SIZEOF },
|
||||
{ "SIZEOF_HEADERS", SIZEOF_HEADERS },
|
||||
{ "SORT", SORT_BY_NAME },
|
||||
{ "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
|
||||
{ "SORT_BY_NAME", SORT_BY_NAME },
|
||||
{ "SPECIAL", SPECIAL },
|
||||
@ -2145,6 +2148,24 @@ script_parse_option(void* closurev, const char* option, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the bison parser to handle SEARCH_DIR. This is handled
|
||||
// exactly like a -L option.
|
||||
|
||||
extern "C" void
|
||||
script_add_search_dir(void* closurev, const char* option, size_t length)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
if (closure->command_line() == NULL)
|
||||
gold_warning(_("%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid"
|
||||
" for scripts specified via -T/--script"),
|
||||
closure->filename(), closure->lineno(), closure->charpos());
|
||||
else
|
||||
{
|
||||
std::string s = "-L" + std::string(option, length);
|
||||
script_parse_option(closurev, s.c_str(), s.size());
|
||||
}
|
||||
}
|
||||
|
||||
/* Called by the bison parser to push the lexer into expression
|
||||
mode. */
|
||||
|
||||
|
@ -60,6 +60,8 @@
|
||||
struct Parser_output_section_header output_section_header;
|
||||
/* An output section trailer. */
|
||||
struct Parser_output_section_trailer output_section_trailer;
|
||||
/* A section constraint. */
|
||||
enum Section_constraint constraint;
|
||||
/* A complete input section specification. */
|
||||
struct Input_section_spec input_section_spec;
|
||||
/* A list of wildcard specifications, with exclusions. */
|
||||
@ -195,6 +197,7 @@
|
||||
%type <expr> opt_at opt_align opt_subalign opt_fill
|
||||
%type <output_section_header> section_header
|
||||
%type <output_section_trailer> section_trailer
|
||||
%type <constraint> opt_constraint
|
||||
%type <integer> data_length
|
||||
%type <input_section_spec> input_section_no_keep
|
||||
%type <wildcard_sections> wildcard_sections
|
||||
@ -229,6 +232,8 @@ file_cmd:
|
||||
{ script_end_group(closure); }
|
||||
| OPTION '(' string ')'
|
||||
{ script_parse_option(closure, $3.value, $3.length); }
|
||||
| SEARCH_DIR '(' string ')'
|
||||
{ script_add_search_dir(closure, $3.value, $3.length); }
|
||||
| SECTIONS '{'
|
||||
{ script_start_sections(closure); }
|
||||
sections_block '}'
|
||||
@ -239,6 +244,7 @@ file_cmd:
|
||||
{ script_pop_lex_mode(closure); }
|
||||
| file_or_sections_cmd
|
||||
| ignore_cmd
|
||||
| ';'
|
||||
;
|
||||
|
||||
/* Top level commands which we ignore. The GNU linker uses these to
|
||||
@ -287,12 +293,14 @@ section_block_cmd:
|
||||
section_header:
|
||||
{ script_push_lex_into_expression_mode(closure); }
|
||||
opt_address_and_section_type opt_at opt_align opt_subalign
|
||||
{ script_pop_lex_mode(closure); }
|
||||
opt_constraint
|
||||
{
|
||||
$$.address = $2;
|
||||
$$.load_address = $3;
|
||||
$$.align = $4;
|
||||
$$.subalign = $5;
|
||||
script_pop_lex_mode(closure);
|
||||
$$.constraint = $7;
|
||||
}
|
||||
;
|
||||
|
||||
@ -340,13 +348,23 @@ opt_subalign:
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
/* A section constraint. */
|
||||
opt_constraint:
|
||||
/* empty */
|
||||
{ $$ = CONSTRAINT_NONE; }
|
||||
| ONLY_IF_RO
|
||||
{ $$ = CONSTRAINT_ONLY_IF_RO; }
|
||||
| ONLY_IF_RW
|
||||
{ $$ = CONSTRAINT_ONLY_IF_RW; }
|
||||
| SPECIAL
|
||||
{ $$ = CONSTRAINT_SPECIAL; }
|
||||
;
|
||||
|
||||
/* The trailer of an output section in a SECTIONS block. */
|
||||
section_trailer:
|
||||
{ script_push_lex_into_expression_mode(closure); }
|
||||
opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
|
||||
{
|
||||
$$.fill = $5;
|
||||
script_pop_lex_mode(closure);
|
||||
$$.fill = $4;
|
||||
}
|
||||
;
|
||||
|
||||
@ -374,7 +392,7 @@ opt_phdr:
|
||||
/* The value to use to fill an output section. FIXME: This does not
|
||||
handle a string of arbitrary length. */
|
||||
opt_fill:
|
||||
'=' exp
|
||||
'=' parse_exp
|
||||
{ $$ = $2; }
|
||||
| /* empty */
|
||||
{ $$ = NULL; }
|
||||
@ -405,6 +423,7 @@ section_cmd:
|
||||
some ELF linker scripts use it although it does
|
||||
nothing, we accept it and ignore it. */
|
||||
}
|
||||
| SORT_BY_NAME '(' CONSTRUCTORS ')'
|
||||
| ';'
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user