Implement SIZEOF_HEADERS, section constraints, other minor linker

script items.
This commit is contained in:
Ian Lance Taylor 2008-02-04 06:45:50 +00:00
parent ae7d22a6f2
commit 3802b2dd6b
9 changed files with 506 additions and 119 deletions

View File

@ -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*)
{

View File

@ -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);

View File

@ -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()

View File

@ -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();
}

View File

@ -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. */

View File

@ -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(&sections);
// 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

View File

@ -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;

View File

@ -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. */

View File

@ -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 ')'
| ';'
;