script items.
#include <string>
+#include "elfcpp.h"
#include "parameters.h"
#include "symtab.h"
#include "layout.h"
return new Addr_expression(section_name, section_name_len);
}
-// Functions.
+// 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_defined(const char*, size_t)
+script_exp_function_constant(const char* name, size_t length)
{
- gold_fatal(_("DEFINED not implemented"));
+ 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_sizeof_headers()
+script_exp_function_data_segment_align(Expression* left, Expression*)
{
- gold_fatal(_("SIZEOF_HEADERS not implemented"));
+ 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_alignof(const char*, size_t)
+script_exp_function_data_segment_relro_end(Expression*, Expression* right)
{
- gold_fatal(_("ALIGNOF not implemented"));
+ return right;
}
+// DATA_SEGMENT_END. FIXME: This is not implemented.
+
extern "C" Expression*
-script_exp_function_sizeof(const char*, size_t)
+script_exp_function_data_segment_end(Expression* val)
{
- gold_fatal(_("SIZEOF not implemented"));
+ 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_loadaddr(const char*, size_t)
+script_exp_function_sizeof_headers()
{
- gold_fatal(_("LOADADDR not implemented"));
+ return new Sizeof_headers_expression();
}
+// Functions.
+
extern "C" Expression*
-script_exp_function_origin(const char*, size_t)
+script_exp_function_defined(const char*, size_t)
{
- gold_fatal(_("ORIGIN not implemented"));
+ gold_fatal(_("DEFINED not implemented"));
}
extern "C" Expression*
-script_exp_function_length(const char*, size_t)
+script_exp_function_alignof(const char*, size_t)
{
- gold_fatal(_("LENGTH not implemented"));
+ gold_fatal(_("ALIGNOF not implemented"));
}
extern "C" Expression*
-script_exp_function_constant(const char*, size_t)
+script_exp_function_sizeof(const char*, size_t)
{
- gold_fatal(_("CONSTANT not implemented"));
+ gold_fatal(_("SIZEOF not implemented"));
}
extern "C" Expression*
-script_exp_function_absolute(Expression*)
+script_exp_function_loadaddr(const char*, size_t)
{
- gold_fatal(_("ABSOLUTE not implemented"));
+ gold_fatal(_("LOADADDR not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_align(Expression*, Expression*)
+script_exp_function_origin(const char*, size_t)
{
- gold_fatal(_("DATA_SEGMENT_ALIGN not implemented"));
+ gold_fatal(_("ORIGIN not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_relro_end(Expression*, Expression*)
+script_exp_function_length(const char*, size_t)
{
- gold_fatal(_("DATA_SEGMENT_RELRO_END not implemented"));
+ gold_fatal(_("LENGTH not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_end(Expression*)
+script_exp_function_absolute(Expression*)
{
- gold_fatal(_("DATA_SEGMENT_END not implemented"));
+ gold_fatal(_("ABSOLUTE not implemented"));
}
extern "C" Expression*
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);
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);
}
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);
}
}
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);
}
}
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
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,
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;
}
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;
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;
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);
}
}
// 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);
// 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);
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,
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;
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;
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;
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);
}
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);
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()
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();
}
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. */
/* 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
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. */
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;
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;
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.
load_address_(header->load_address),
align_(header->align),
subalign_(header->subalign),
+ constraint_(header->constraint),
fill_(NULL),
elements_(),
output_section_(NULL)
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
{
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();
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);
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
}
}
+// 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
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;
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;
{ "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 },
}
}
+// 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. */
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. */
%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
{ 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 '}'
{ script_pop_lex_mode(closure); }
| file_or_sections_cmd
| ignore_cmd
+ | ';'
;
/* Top level commands which we ignore. The GNU linker uses these to
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;
}
;
{ $$ = $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;
}
;
/* 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; }
some ELF linker scripts use it although it does
nothing, we accept it and ignore it. */
}
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
| ';'
;