diff options
Diffstat (limited to 'gold/script-sections.cc')
-rw-r--r-- | gold/script-sections.cc | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/gold/script-sections.cc b/gold/script-sections.cc new file mode 100644 index 0000000..de6da30 --- /dev/null +++ b/gold/script-sections.cc @@ -0,0 +1,738 @@ +// script-sections.cc -- linker script SECTIONS for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor <iant@google.com>. + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "gold.h" + +#include <string> +#include <vector> + +#include "script-c.h" +#include "script.h" +#include "script-sections.h" + +// Support for the SECTIONS clause in linker scripts. + +namespace gold +{ + +// An element in a SECTIONS clause. + +class Sections_element +{ + public: + Sections_element() + { } + + virtual ~Sections_element() + { } + + virtual void + print(FILE* f) const = 0; +}; + +// An assignment in a SECTIONS clause outside of an output section. + +class Sections_element_assignment : public Sections_element +{ + public: + Sections_element_assignment(const char* name, size_t namelen, + Expression* val, bool provide, bool hidden) + : assignment_(name, namelen, val, provide, hidden) + { } + + void + print(FILE* f) const + { + fprintf(f, " "); + this->assignment_.print(f); + } + + private: + Symbol_assignment assignment_; +}; + +// An assertion in a SECTIONS clause outside of an output section. + +class Sections_element_assertion : public Sections_element +{ + public: + Sections_element_assertion(Expression* check, const char* message, + size_t messagelen) + : assertion_(check, message, messagelen) + { } + + void + print(FILE* f) const + { + fprintf(f, " "); + this->assertion_.print(f); + } + + private: + Script_assertion assertion_; +}; + +// An element in an output section in a SECTIONS clause. + +class Output_section_element +{ + public: + Output_section_element() + { } + + virtual ~Output_section_element() + { } + + virtual void + print(FILE* f) const = 0; +}; + +// A symbol assignment in an output section. + +class Output_section_element_assignment : public Output_section_element +{ + public: + Output_section_element_assignment(const char* name, size_t namelen, + Expression* val, bool provide, + bool hidden) + : assignment_(name, namelen, val, provide, hidden) + { } + + void + print(FILE* f) const + { + fprintf(f, " "); + this->assignment_.print(f); + } + + private: + Symbol_assignment assignment_; +}; + +// An assertion in an output section. + +class Output_section_element_assertion : public Output_section_element +{ + public: + Output_section_element_assertion(Expression* check, const char* message, + size_t messagelen) + : assertion_(check, message, messagelen) + { } + + void + print(FILE* f) const + { + fprintf(f, " "); + this->assertion_.print(f); + } + + private: + Script_assertion assertion_; +}; + +// A data item in an output section. + +class Output_section_element_data : public Output_section_element +{ + public: + Output_section_element_data(int size, bool is_signed, Expression* val) + : size_(size), is_signed_(is_signed), val_(val) + { } + + void + print(FILE*) const; + + private: + // The size in bytes. + int size_; + // Whether the value is signed. + bool is_signed_; + // The value. + Expression* val_; +}; + +// Print for debugging. + +void +Output_section_element_data::print(FILE* f) const +{ + const char* s; + switch (this->size_) + { + case 1: + s = "BYTE"; + break; + case 2: + s = "SHORT"; + break; + case 4: + s = "LONG"; + break; + case 8: + if (this->is_signed_) + s = "SQUAD"; + else + s = "QUAD"; + break; + default: + gold_unreachable(); + } + fprintf(f, " %s(", s); + this->val_->print(f); + fprintf(f, ")\n"); +} + +// A fill value setting in an output section. + +class Output_section_element_fill : public Output_section_element +{ + public: + Output_section_element_fill(Expression* val) + : val_(val) + { } + + void + print(FILE* f) const + { + fprintf(f, " FILL("); + this->val_->print(f); + fprintf(f, ")\n"); + } + + private: + // The new fill value. + Expression* val_; +}; + +// An input section specification in an output section + +class Output_section_element_input : public Output_section_element +{ + public: + // Note that an Input_section_spec holds some pointers to vectors. + // This constructor takes ownership of them. The parser is + // implemented such that this works. + Output_section_element_input(const Input_section_spec* spec, bool keep); + + void + print(FILE* f) const; + + private: + // An input section pattern. + struct Input_section_pattern + { + std::string pattern; + Sort_wildcard sort; + + Input_section_pattern(const char* patterna, size_t patternlena, + Sort_wildcard sorta) + : pattern(patterna, patternlena), sort(sorta) + { } + }; + + typedef std::vector<Input_section_pattern> Input_section_patterns; + + typedef std::vector<std::string> Filename_exclusions; + + // The file name pattern. + std::string filename_pattern_; + // How the file names should be sorted. This may only be + // SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME. + Sort_wildcard filename_sort_; + // The list of file names to exclude. + Filename_exclusions filename_exclusions_; + // The list of input section patterns. + Input_section_patterns input_section_patterns_; + // Whether to keep this section when garbage collecting. + bool keep_; +}; + +// Construct Output_section_element_input. The parser records strings +// as pointers into a copy of the script file, which will go away when +// parsing is complete. We make sure they are in std::string objects. + +Output_section_element_input::Output_section_element_input( + const Input_section_spec* spec, + bool keep) + : filename_pattern_(spec->file.name.value, spec->file.name.length), + filename_sort_(spec->file.sort), + filename_exclusions_(), + input_section_patterns_(), + keep_(keep) +{ + if (spec->input_sections.exclude != NULL) + { + for (String_list::const_iterator p = + spec->input_sections.exclude->begin(); + p != spec->input_sections.exclude->end(); + ++p) + this->filename_exclusions_.push_back(*p); + } + + if (spec->input_sections.sections != NULL) + { + Input_section_patterns& isp(this->input_section_patterns_); + for (String_sort_list::const_iterator p = + spec->input_sections.sections->begin(); + p != spec->input_sections.sections->end(); + ++p) + isp.push_back(Input_section_pattern(p->name.value, p->name.length, + p->sort)); + } +} + +// Print for debugging. + +void +Output_section_element_input::print(FILE* f) const +{ + fprintf(f, " "); + + if (this->keep_) + fprintf(f, "KEEP("); + + if (!this->filename_pattern_.empty()) + { + bool need_close_paren = false; + switch (this->filename_sort_) + { + case SORT_WILDCARD_NONE: + break; + case SORT_WILDCARD_BY_NAME: + fprintf(f, "SORT_BY_NAME("); + need_close_paren = true; + break; + default: + gold_unreachable(); + } + + fprintf(f, "%s", this->filename_pattern_.c_str()); + + if (need_close_paren) + fprintf(f, ")"); + } + + if (!this->input_section_patterns_.empty() + || !this->filename_exclusions_.empty()) + { + fprintf(f, "("); + + bool need_space = false; + if (!this->filename_exclusions_.empty()) + { + fprintf(f, "EXCLUDE_FILE("); + bool need_comma = false; + for (Filename_exclusions::const_iterator p = + this->filename_exclusions_.begin(); + p != this->filename_exclusions_.end(); + ++p) + { + if (need_comma) + fprintf(f, ", "); + fprintf(f, "%s", p->c_str()); + need_comma = true; + } + fprintf(f, ")"); + need_space = true; + } + + for (Input_section_patterns::const_iterator p = + this->input_section_patterns_.begin(); + p != this->input_section_patterns_.end(); + ++p) + { + if (need_space) + fprintf(f, " "); + + int close_parens = 0; + switch (p->sort) + { + case SORT_WILDCARD_NONE: + break; + case SORT_WILDCARD_BY_NAME: + fprintf(f, "SORT_BY_NAME("); + close_parens = 1; + break; + case SORT_WILDCARD_BY_ALIGNMENT: + fprintf(f, "SORT_BY_ALIGNMENT("); + close_parens = 1; + break; + case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT: + fprintf(f, "SORT_BY_NAME(SORT_BY_ALIGNMENT("); + close_parens = 2; + break; + case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME: + fprintf(f, "SORT_BY_ALIGNMENT(SORT_BY_NAME("); + close_parens = 2; + break; + default: + gold_unreachable(); + } + + fprintf(f, "%s", p->pattern.c_str()); + + for (int i = 0; i < close_parens; ++i) + fprintf(f, ")"); + + need_space = true; + } + + fprintf(f, ")"); + } + + if (this->keep_) + fprintf(f, ")"); + + fprintf(f, "\n"); +} + +// An output section. + +class Output_section_definition : public Sections_element +{ + public: + Output_section_definition(const char* name, size_t namelen, + const Parser_output_section_header* header); + + // Finish the output section with the information in the trailer. + void + finish(const Parser_output_section_trailer* trailer); + + // Add a symbol to be defined. + void + add_symbol_assignment(const char* name, size_t length, Expression* value, + bool provide, bool hidden); + // Add an assertion. + void + add_assertion(Expression* check, const char* message, size_t messagelen); + + // Add a data item to the current output section. + void + add_data(int size, bool is_signed, Expression* val); + + // Add a setting for the fill value. + void + add_fill(Expression* val); + + // Add an input section specification. + void + add_input_section(const Input_section_spec* spec, bool keep); + + // Print the contents to the FILE. This is for debugging. + void + print(FILE*) const; + + private: + typedef std::vector<Output_section_element*> Output_section_elements; + + // The output section name. + std::string name_; + // The address. This may be NULL. + Expression* address_; + // The load address. This may be NULL. + Expression* load_address_; + // The alignment. This may be NULL. + Expression* align_; + // The input section alignment. This may be NULL. + Expression* subalign_; + // The fill value. This may be NULL. + Expression* fill_; + // The list of elements defining the section. + Output_section_elements elements_; +}; + +// Constructor. + +Output_section_definition::Output_section_definition( + const char* name, + size_t namelen, + const Parser_output_section_header* header) + : name_(name, namelen), + address_(header->address), + load_address_(header->load_address), + align_(header->align), + subalign_(header->subalign), + fill_(NULL), + elements_() +{ +} + +// Finish an output section. + +void +Output_section_definition::finish(const Parser_output_section_trailer* trailer) +{ + this->fill_ = trailer->fill; +} + +// Add a symbol to be defined. + +void +Output_section_definition::add_symbol_assignment(const char* name, + size_t length, + Expression* value, + bool provide, + bool hidden) +{ + Output_section_element* p = new Output_section_element_assignment(name, + length, + value, + provide, + hidden); + this->elements_.push_back(p); +} + +// Add an assertion. + +void +Output_section_definition::add_assertion(Expression* check, + const char* message, + size_t messagelen) +{ + Output_section_element* p = new Output_section_element_assertion(check, + message, + messagelen); + this->elements_.push_back(p); +} + +// Add a data item to the current output section. + +void +Output_section_definition::add_data(int size, bool is_signed, Expression* val) +{ + Output_section_element* p = new Output_section_element_data(size, is_signed, + val); + this->elements_.push_back(p); +} + +// Add a setting for the fill value. + +void +Output_section_definition::add_fill(Expression* val) +{ + Output_section_element* p = new Output_section_element_fill(val); + this->elements_.push_back(p); +} + +// Add an input section specification. + +void +Output_section_definition::add_input_section(const Input_section_spec* spec, + bool keep) +{ + Output_section_element* p = new Output_section_element_input(spec, keep); + this->elements_.push_back(p); +} + +// Print for debugging. + +void +Output_section_definition::print(FILE* f) const +{ + fprintf(f, " %s ", this->name_.c_str()); + + if (this->address_ != NULL) + { + this->address_->print(f); + fprintf(f, " "); + } + + fprintf(f, ": "); + + if (this->load_address_ != NULL) + { + fprintf(f, "AT("); + this->load_address_->print(f); + fprintf(f, ") "); + } + + if (this->align_ != NULL) + { + fprintf(f, "ALIGN("); + this->align_->print(f); + fprintf(f, ") "); + } + + if (this->subalign_ != NULL) + { + fprintf(f, "SUBALIGN("); + this->subalign_->print(f); + fprintf(f, ") "); + } + + fprintf(f, "{\n"); + + for (Output_section_elements::const_iterator p = this->elements_.begin(); + p != this->elements_.end(); + ++p) + (*p)->print(f); + + fprintf(f, " }"); + + if (this->fill_ != NULL) + { + fprintf(f, " = "); + this->fill_->print(f); + } + + fprintf(f, "\n"); +} + +// Class Script_sections. + +Script_sections::Script_sections() + : saw_sections_clause_(false), + in_sections_clause_(false), + sections_elements_(NULL), + output_section_(NULL) +{ +} + +// Start a SECTIONS clause. + +void +Script_sections::start_sections() +{ + gold_assert(!this->in_sections_clause_ && this->output_section_ == NULL); + this->saw_sections_clause_ = true; + this->in_sections_clause_ = true; + if (this->sections_elements_ == NULL) + this->sections_elements_ = new Sections_elements; +} + +// Finish a SECTIONS clause. + +void +Script_sections::finish_sections() +{ + gold_assert(this->in_sections_clause_ && this->output_section_ == NULL); + this->in_sections_clause_ = false; +} + +// Add a symbol to be defined. + +void +Script_sections::add_symbol_assignment(const char* name, size_t length, + Expression* val, bool provide, + bool hidden) +{ + if (this->output_section_ != NULL) + this->output_section_->add_symbol_assignment(name, length, val, + provide, hidden); + else + { + Sections_element* p = new Sections_element_assignment(name, length, + val, provide, + hidden); + this->sections_elements_->push_back(p); + } +} + +// Add an assertion. + +void +Script_sections::add_assertion(Expression* check, const char* message, + size_t messagelen) +{ + if (this->output_section_ != NULL) + this->output_section_->add_assertion(check, message, messagelen); + else + { + Sections_element* p = new Sections_element_assertion(check, message, + messagelen); + this->sections_elements_->push_back(p); + } +} + +// Start processing entries for an output section. + +void +Script_sections::start_output_section( + const char* name, + size_t namelen, + const Parser_output_section_header *header) +{ + Output_section_definition* posd = new Output_section_definition(name, + namelen, + header); + this->sections_elements_->push_back(posd); + gold_assert(this->output_section_ == NULL); + this->output_section_ = posd; +} + +// Stop processing entries for an output section. + +void +Script_sections::finish_output_section( + const Parser_output_section_trailer* trailer) +{ + gold_assert(this->output_section_ != NULL); + this->output_section_->finish(trailer); + this->output_section_ = NULL; +} + +// Add a data item to the current output section. + +void +Script_sections::add_data(int size, bool is_signed, Expression* val) +{ + gold_assert(this->output_section_ != NULL); + this->output_section_->add_data(size, is_signed, val); +} + +// Add a fill value setting to the current output section. + +void +Script_sections::add_fill(Expression* val) +{ + gold_assert(this->output_section_ != NULL); + this->output_section_->add_fill(val); +} + +// Add an input section specification to the current output section. + +void +Script_sections::add_input_section(const Input_section_spec* spec, bool keep) +{ + gold_assert(this->output_section_ != NULL); + this->output_section_->add_input_section(spec, keep); +} + +// Print the SECTIONS clause to F for debugging. + +void +Script_sections::print(FILE* f) const +{ + if (!this->saw_sections_clause_) + return; + + fprintf(f, "SECTIONS {\n"); + + for (Sections_elements::const_iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + (*p)->print(f); + + fprintf(f, "}\n"); +} + +} // End namespace gold. |