diff options
-rw-r--r-- | gold/layout.cc | 46 | ||||
-rw-r--r-- | gold/layout.h | 3 | ||||
-rw-r--r-- | gold/output.cc | 6 | ||||
-rw-r--r-- | gold/output.h | 12 | ||||
-rw-r--r-- | gold/script-c.h | 14 | ||||
-rw-r--r-- | gold/script-sections.cc | 115 | ||||
-rw-r--r-- | gold/script-sections.h | 20 | ||||
-rw-r--r-- | gold/script.cc | 4 | ||||
-rw-r--r-- | gold/yyscript.y | 72 |
9 files changed, 260 insertions, 32 deletions
diff --git a/gold/layout.cc b/gold/layout.cc index f95813b..2ffbdf4 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -502,13 +502,27 @@ Layout::choose_output_section(const Relobj* relobj, const char* name, Script_sections* ss = this->script_options_->script_sections(); const char* file_name = relobj == NULL ? NULL : relobj->name().c_str(); Output_section** output_section_slot; - name = ss->output_section_name(file_name, name, &output_section_slot); + Script_sections::Section_type script_section_type; + name = ss->output_section_name(file_name, name, &output_section_slot, + &script_section_type); if (name == NULL) { // The SECTIONS clause says to discard this input section. return NULL; } + // We can only handle script section types ST_NONE and ST_NOLOAD. + switch (script_section_type) + { + case Script_sections::ST_NONE: + break; + case Script_sections::ST_NOLOAD: + flags &= elfcpp::SHF_ALLOC; + break; + default: + gold_unreachable(); + } + // If this is an orphan section--one not mentioned in the linker // script--then OUTPUT_SECTION_SLOT will be NULL, and we do the // default processing below. @@ -533,6 +547,25 @@ Layout::choose_output_section(const Relobj* relobj, const char* name, is_dynamic_linker_section, is_relro, is_last_relro, is_first_non_relro); os->set_found_in_sections_clause(); + + // Special handling for NOLOAD sections. + if (script_section_type == Script_sections::ST_NOLOAD) + { + os->set_is_noload(); + + // The constructor of Output_section sets addresses of non-ALLOC + // sections to 0 by default. We don't want that for NOLOAD + // sections even if they have no SHF_ALLOC flag. + if ((os->flags() & elfcpp::SHF_ALLOC) == 0 + && os->is_address_valid()) + { + gold_assert(os->address() == 0 + && !os->is_offset_valid() + && !os->is_data_size_valid()); + os->reset_address_and_file_offset(); + } + } + *output_section_slot = os; return os; } @@ -1157,13 +1190,20 @@ Layout::attach_allocated_section_to_segment(Output_section* os) // Make an output section for a script. Output_section* -Layout::make_output_section_for_script(const char* name) +Layout::make_output_section_for_script( + const char* name, + Script_sections::Section_type section_type) { name = this->namepool_.add(name, false, NULL); + elfcpp::Elf_Xword sh_flags = elfcpp::SHF_ALLOC; + if (section_type == Script_sections::ST_NOLOAD) + sh_flags = 0; Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS, - elfcpp::SHF_ALLOC, false, + sh_flags, false, false, false, false, false); os->set_found_in_sections_clause(); + if (section_type == Script_sections::ST_NOLOAD) + os->set_is_noload(); return os; } diff --git a/gold/layout.h b/gold/layout.h index cd15c98..912be31 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -600,7 +600,8 @@ class Layout // Make a section for a linker script to hold data. Output_section* - make_output_section_for_script(const char* name); + make_output_section_for_script(const char* name, + Script_sections::Section_type section_type); // Make a segment. This is used by the linker script code. Output_segment* diff --git a/gold/output.cc b/gold/output.cc index 37ec8b3..6878034 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1911,6 +1911,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, generate_code_fills_at_write_(false), is_entsize_zero_(false), section_offsets_need_adjustment_(false), + is_noload_(false), tls_offset_(0), checkpoint_(NULL), merge_section_map_(), @@ -2588,8 +2589,9 @@ Output_section::do_reset_address_and_file_offset() { // An unallocated section has no address. Forcing this means that // we don't need special treatment for symbols defined in debug - // sections. We do the same in the constructor. - if ((this->flags_ & elfcpp::SHF_ALLOC) == 0) + // sections. We do the same in the constructor. This does not + // apply to NOLOAD sections though. + if (((this->flags_ & elfcpp::SHF_ALLOC) == 0) && !this->is_noload_) this->set_address(0); for (Input_section_list::iterator p = this->input_sections_.begin(); diff --git a/gold/output.h b/gold/output.h index a63f07c..8088565 100644 --- a/gold/output.h +++ b/gold/output.h @@ -2894,6 +2894,16 @@ class Output_section : public Output_data void adjust_section_offsets(); + // Whether this is a NOLOAD section. + bool + is_noload() const + { return this->is_noload_; } + + // Set NOLOAD flag. + void + set_is_noload() + { this->is_noload_ = true; } + // Print merge statistics to stderr. void print_merge_stats(); @@ -3659,6 +3669,8 @@ class Output_section : public Output_data bool is_entsize_zero_ : 1; // Whether section offsets need adjustment due to relaxation. bool section_offsets_need_adjustment_ : 1; + // Whether this is a NOLOAD section. + bool is_noload_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; diff --git a/gold/script-c.h b/gold/script-c.h index a646bda..77b4aa4 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -61,6 +61,18 @@ typedef Expression* Expression_ptr; typedef void* Expression_ptr; #endif +/* Script_section type. */ +enum Script_section_type +{ + /* No section type. */ + SCRIPT_SECTION_TYPE_NONE, + SCRIPT_SECTION_TYPE_NOLOAD, + SCRIPT_SECTION_TYPE_DSECT, + SCRIPT_SECTION_TYPE_COPY, + SCRIPT_SECTION_TYPE_INFO, + SCRIPT_SECTION_TYPE_OVERLAY +}; + /* A constraint for whether to use a particular output section definition. */ @@ -83,6 +95,8 @@ struct Parser_output_section_header { /* The address. This may be NULL. */ Expression_ptr address; + /* Section type. May be NULL string. */ + enum Script_section_type section_type; /* The load address, from the AT specifier. This may be NULL. */ Expression_ptr load_address; /* The alignment, from the ALIGN specifier. This may be NULL. */ diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 12a934b..24b9103 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -356,7 +356,8 @@ class Sections_element // section name. This only real implementation is in // Output_section_definition. virtual const char* - output_section_name(const char*, const char*, Output_section***) + output_section_name(const char*, const char*, Output_section***, + Script_sections::Section_type*) { return NULL; } // Initialize OSP with an output section. @@ -1617,7 +1618,7 @@ class Output_section_definition : public Sections_element // section name. const char* output_section_name(const char* file_name, const char* section_name, - Output_section***); + Output_section***, Script_sections::Section_type*); // Initialize OSP with an output section. void @@ -1665,7 +1666,14 @@ class Output_section_definition : public Sections_element void print(FILE*) const; + // Return the output section type if specified or Script_sections::ST_NONE. + Script_sections::Section_type + section_type() const; + private: + static const char* + script_section_type_name(Script_section_type); + typedef std::vector<Output_section_element*> Output_section_elements; // The output section name. @@ -1698,6 +1706,8 @@ class Output_section_definition : public Sections_element uint64_t evaluated_addralign_; // The output section is relro. bool is_relro_; + // The output section type if specified. + enum Script_section_type script_section_type_; }; // Constructor. @@ -1719,7 +1729,8 @@ Output_section_definition::Output_section_definition( evaluated_address_(0), evaluated_load_address_(0), evaluated_addralign_(0), - is_relro_(false) + is_relro_(false), + script_section_type_(header->section_type) { } @@ -1815,7 +1826,8 @@ Output_section_definition::create_sections(Layout* layout) if ((*p)->needs_output_section()) { const char* name = this->name_.c_str(); - this->output_section_ = layout->make_output_section_for_script(name); + this->output_section_ = + layout->make_output_section_for_script(name, this->section_type()); return; } } @@ -1873,9 +1885,11 @@ Output_section_definition::finalize_symbols(Symbol_table* symtab, // Return the output section name to use for an input section name. const char* -Output_section_definition::output_section_name(const char* file_name, - const char* section_name, - Output_section*** slot) +Output_section_definition::output_section_name( + const char* file_name, + const char* section_name, + Output_section*** slot, + Script_sections::Section_type *psection_type) { // Ask each element whether it matches NAME. for (Output_section_elements::const_iterator p = this->elements_.begin(); @@ -1887,6 +1901,7 @@ Output_section_definition::output_section_name(const char* file_name, // We found a match for NAME, which means that it should go // into this output section. *slot = &this->output_section_; + *psection_type = this->section_type(); return this->name_.c_str(); } } @@ -1906,6 +1921,9 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, uint64_t* load_address) { uint64_t address; + uint64_t old_dot_value = *dot_value; + uint64_t old_load_address = *load_address; + if (this->address_ == NULL) address = *dot_value; else @@ -1941,10 +1959,11 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, *dot_value = address; - // The address of non-SHF_ALLOC sections is forced to zero, - // regardless of what the linker script wants. + // Except for NOLOAD sections, the address of non-SHF_ALLOC sections is + // forced to zero, regardless of what the linker script wants. if (this->output_section_ != NULL - && (this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0) + && ((this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0 + || this->output_section_->is_noload())) this->output_section_->set_address(address); this->evaluated_address_ = address; @@ -2029,6 +2048,13 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, this->output_section_->set_is_relro(); else this->output_section_->clear_is_relro(); + + // If this is a NOLOAD section, keep dot and load address unchanged. + if (this->output_section_->is_noload()) + { + *dot_value = old_dot_value; + *load_address = old_load_address; + } } } @@ -2186,6 +2212,10 @@ Output_section_definition::print(FILE* f) const fprintf(f, " "); } + if (this->script_section_type_ != SCRIPT_SECTION_TYPE_NONE) + fprintf(f, "(%s) ", + this->script_section_type_name(this->script_section_type_)); + fprintf(f, ": "); if (this->load_address_ != NULL) @@ -2235,6 +2265,52 @@ Output_section_definition::print(FILE* f) const fprintf(f, "\n"); } +Script_sections::Section_type +Output_section_definition::section_type() const +{ + switch (this->script_section_type_) + { + case SCRIPT_SECTION_TYPE_NONE: + return Script_sections::ST_NONE; + case SCRIPT_SECTION_TYPE_NOLOAD: + return Script_sections::ST_NOLOAD; + case SCRIPT_SECTION_TYPE_COPY: + case SCRIPT_SECTION_TYPE_DSECT: + case SCRIPT_SECTION_TYPE_INFO: + case SCRIPT_SECTION_TYPE_OVERLAY: + // There are not really support so we treat them as ST_NONE. The + // parse should have issued errors for them already. + return Script_sections::ST_NONE; + default: + gold_unreachable(); + } +} + +// Return the name of a script section type. + +const char* +Output_section_definition::script_section_type_name ( + Script_section_type script_section_type) +{ + switch (script_section_type) + { + case SCRIPT_SECTION_TYPE_NONE: + return "NONE"; + case SCRIPT_SECTION_TYPE_NOLOAD: + return "NOLOAD"; + case SCRIPT_SECTION_TYPE_DSECT: + return "DSECT"; + case SCRIPT_SECTION_TYPE_COPY: + return "COPY"; + case SCRIPT_SECTION_TYPE_INFO: + return "INFO"; + case SCRIPT_SECTION_TYPE_OVERLAY: + return "OVERLAY"; + default: + gold_unreachable(); + } +} + // An output section created to hold orphaned input sections. These // do not actually appear in linker scripts. However, for convenience // when setting the output section addresses, we put a marker to these @@ -2724,16 +2800,19 @@ Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout) // and section name. const char* -Script_sections::output_section_name(const char* file_name, - const char* section_name, - Output_section*** output_section_slot) +Script_sections::output_section_name( + const char* file_name, + const char* section_name, + Output_section*** output_section_slot, + Script_sections::Section_type *psection_type) { for (Sections_elements::const_iterator p = this->sections_elements_->begin(); p != this->sections_elements_->end(); ++p) { const char* ret = (*p)->output_section_name(file_name, section_name, - output_section_slot); + output_section_slot, + psection_type); if (ret != NULL) { @@ -2742,6 +2821,7 @@ Script_sections::output_section_name(const char* file_name, if (strcmp(ret, "/DISCARD/") == 0) { *output_section_slot = NULL; + *psection_type = Script_sections::ST_NONE; return NULL; } return ret; @@ -2752,6 +2832,7 @@ Script_sections::output_section_name(const char* file_name, // gets the name of the input section. *output_section_slot = NULL; + *psection_type = Script_sections::ST_NONE; return section_name; } @@ -2967,6 +3048,12 @@ Sort_output_sections::operator()(const Output_section* os1, if (os1->type() == elfcpp::SHT_NOBITS && os2->type() == elfcpp::SHT_PROGBITS) return false; + // Sort non-NOLOAD before NOLOAD. + if (os1->is_noload() && !os2->is_noload()) + return true; + if (!os1->is_noload() && os2->is_noload()) + return true; + // Otherwise we don't care. return false; } diff --git a/gold/script-sections.h b/gold/script-sections.h index c0d1d08..725d1a2 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -52,6 +52,20 @@ class Script_sections typedef std::list<Sections_element*> Sections_elements; public: + + // Logical script section types. We map section types returned by the + // parser into these since some section types have the same semantics. + enum Section_type + { + // No section type specified. + ST_NONE, + // Section is NOLOAD. We allocate space in the output but section + // is not loaded in runtime. + ST_NOLOAD, + // No space is allocated to section. + ST_NOALLOC + }; + Script_sections(); // Start a SECTIONS clause. @@ -147,9 +161,13 @@ class Script_sections // 3) If the input section is not mapped by the SECTIONS clause, // this returns SECTION_NAME, and sets *OUTPUT_SECTION_SLOT to // NULL. + // PSCRIPT_SECTION_TYPE points to a location for returning the section + // type specified in script. This can be SCRIPT_SECTION_TYPE_NONE if + // no type is specified. const char* output_section_name(const char* file_name, const char* section_name, - Output_section*** output_section_slot); + Output_section*** output_section_slot, + Section_type* pscript_section_type); // Place a marker for an orphan output section into the SECTIONS // clause. diff --git a/gold/script.cc b/gold/script.cc index bef0cdb..11e4612 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1646,11 +1646,13 @@ script_keyword_parsecodes[] = { "BYTE", BYTE }, { "CONSTANT", CONSTANT }, { "CONSTRUCTORS", CONSTRUCTORS }, + { "COPY", COPY }, { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS }, { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN }, { "DATA_SEGMENT_END", DATA_SEGMENT_END }, { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END }, { "DEFINED", DEFINED }, + { "DSECT", DSECT }, { "ENTRY", ENTRY }, { "EXCLUDE_FILE", EXCLUDE_FILE }, { "EXTERN", EXTERN }, @@ -1660,6 +1662,7 @@ script_keyword_parsecodes[] = { "GROUP", GROUP }, { "HLL", HLL }, { "INCLUDE", INCLUDE }, + { "INFO", INFO }, { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION }, { "INPUT", INPUT }, { "KEEP", KEEP }, @@ -1673,6 +1676,7 @@ script_keyword_parsecodes[] = { "NEXT", NEXT }, { "NOCROSSREFS", NOCROSSREFS }, { "NOFLOAT", NOFLOAT }, + { "NOLOAD", NOLOAD }, { "ONLY_IF_RO", ONLY_IF_RO }, { "ONLY_IF_RW", ONLY_IF_RW }, { "OPTION", OPTION }, diff --git a/gold/yyscript.y b/gold/yyscript.y index 81c136a..f762536 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -77,6 +77,7 @@ struct Version_dependency_list* deplist; struct Version_expression_list* versyms; struct Version_tree* versnode; + enum Script_section_type section_type; } /* Operators, including a precedence table for expressions. */ @@ -121,11 +122,13 @@ %token BYTE %token CONSTANT %token CONSTRUCTORS +%token COPY %token CREATE_OBJECT_SYMBOLS %token DATA_SEGMENT_ALIGN %token DATA_SEGMENT_END %token DATA_SEGMENT_RELRO_END %token DEFINED +%token DSECT %token ENTRY %token EXCLUDE_FILE %token EXTERN @@ -137,6 +140,7 @@ %token HLL %token INCLUDE %token INHIBIT_COMMON_ALLOCATION +%token INFO %token INPUT %token KEEP %token LENGTH /* LENGTH, l, len */ @@ -150,6 +154,7 @@ %token NEXT %token NOCROSSREFS %token NOFLOAT +%token NOLOAD %token ONLY_IF_RO %token ONLY_IF_RW %token ORIGIN /* ORIGIN, o, org */ @@ -197,9 +202,10 @@ /* Non-terminal types, where needed. */ -%type <expr> parse_exp exp opt_address_and_section_type +%type <expr> parse_exp exp %type <expr> opt_at opt_align opt_subalign opt_fill -%type <output_section_header> section_header +%type <output_section_header> section_header opt_address_and_section_type +%type <section_type> section_type %type <output_section_trailer> section_trailer %type <constraint> opt_constraint %type <string_list> opt_phdr @@ -343,7 +349,8 @@ section_header: { script_pop_lex_mode(closure); } opt_constraint { - $$.address = $2; + $$.address = $2.address; + $$.section_type = $2.section_type; $$.load_address = $3; $$.align = $4; $$.subalign = $5; @@ -356,18 +363,61 @@ section_header: '(' in section_header. */ opt_address_and_section_type: - ':' - { $$ = NULL; } + ':' + { + $$.address = NULL; + $$.section_type = SCRIPT_SECTION_TYPE_NONE; + } | '(' ')' ':' - { $$ = NULL; } + { + $$.address = NULL; + $$.section_type = SCRIPT_SECTION_TYPE_NONE; + } | exp ':' - { $$ = $1; } + { + $$.address = $1; + $$.section_type = SCRIPT_SECTION_TYPE_NONE; + } | exp '(' ')' ':' - { $$ = $1; } - | exp '(' string ')' ':' { - yyerror(closure, "section types are not supported"); - $$ = $1; + $$.address = $1; + $$.section_type = SCRIPT_SECTION_TYPE_NONE; + } + | '(' section_type ')' ':' + { + $$.address = NULL; + $$.section_type = $2; + } + | exp '(' section_type ')' ':' + { + $$.address = $1; + $$.section_type = $3; + } + ; + +/* We only support NOLOAD. */ +section_type: + NOLOAD + { $$ = SCRIPT_SECTION_TYPE_NOLOAD; } + | DSECT + { + yyerror(closure, "DSECT section type is unsupported"); + $$ = SCRIPT_SECTION_TYPE_DSECT; + } + | COPY + { + yyerror(closure, "COPY section type is unsupported"); + $$ = SCRIPT_SECTION_TYPE_COPY; + } + | INFO + { + yyerror(closure, "INFO section type is unsupported"); + $$ = SCRIPT_SECTION_TYPE_INFO; + } + | OVERLAY + { + yyerror(closure, "OVERLAY section type is unsupported"); + $$ = SCRIPT_SECTION_TYPE_OVERLAY; } ; |