From 3802b2dd6b937e2904b6e2de087e224437eab493 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 4 Feb 2008 06:45:50 +0000 Subject: [PATCH] Implement SIZEOF_HEADERS, section constraints, other minor linker script items. --- gold/expression.cc | 170 +++++++++++++++++++++++++++----- gold/layout.cc | 143 ++++++++++++++------------- gold/layout.h | 4 + gold/output.cc | 11 ++- gold/script-c.h | 22 +++++ gold/script-sections.cc | 208 +++++++++++++++++++++++++++++++++++++--- gold/script-sections.h | 5 + gold/script.cc | 23 ++++- gold/yyscript.y | 29 +++++- 9 files changed, 501 insertions(+), 114 deletions(-) diff --git a/gold/expression.cc b/gold/expression.cc index e8fd9fd8954..d57b45cb396 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -24,6 +24,7 @@ #include +#include "elfcpp.h" #include "parameters.h" #include "symtab.h" #include "layout.h" @@ -632,78 +633,197 @@ script_exp_function_addr(const char* section_name, size_t section_name_len) 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* diff --git a/gold/layout.cc b/gold/layout.cc index a0fcc49d6a7..1e597ac6f25 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -397,9 +397,9 @@ Layout::layout_eh_frame(Sized_relobj* 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 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); diff --git a/gold/layout.h b/gold/layout.h index ceacf5dd419..d7f59650432 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -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() diff --git a/gold/output.cc b/gold/output.cc index c0db1afdc2f..8eb79fa9e1a 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -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(); } diff --git a/gold/script-c.h b/gold/script-c.h index 496e18b5f24..26dc5566042 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -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. */ diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 2505170fb77..6c8a7f5b2b3 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -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 diff --git a/gold/script-sections.h b/gold/script-sections.h index 6ac4303a490..ec708bd50d1 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -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; diff --git a/gold/script.cc b/gold/script.cc index 734349b891d..973c05ce6df 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -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(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. */ diff --git a/gold/yyscript.y b/gold/yyscript.y index a0379063b55..ad7670904f4 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -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 opt_at opt_align opt_subalign opt_fill %type section_header %type section_trailer +%type opt_constraint %type data_length %type input_section_no_keep %type 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 ')' | ';' ; -- 2.30.2