| // script-sections.h -- linker script SECTIONS for gold -*- C++ -*- | |
| // Copyright (C) 2008-2022 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. | |
| // This is for the support of the SECTIONS clause in linker scripts. | |
| #ifndef GOLD_SCRIPT_SECTIONS_H | |
| #define GOLD_SCRIPT_SECTIONS_H | |
| #include <cstdio> | |
| #include <list> | |
| #include <vector> | |
| namespace gold | |
| { | |
| struct Parser_output_section_header; | |
| struct Parser_output_section_trailer; | |
| struct Input_section_spec; | |
| class Expression; | |
| class Sections_element; | |
| class Memory_region; | |
| class Phdrs_element; | |
| class Output_data; | |
| class Output_section_definition; | |
| class Output_section; | |
| class Output_segment; | |
| class Orphan_section_placement; | |
| class Script_sections | |
| { | |
| public: | |
| // This is a list, not a vector, because we insert orphan sections | |
| // in the middle. | |
| typedef std::list<Sections_element*> Sections_elements; | |
| // 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. | |
| void | |
| start_sections(); | |
| // Finish a SECTIONS clause. | |
| void | |
| finish_sections(); | |
| // Return whether we ever saw a SECTIONS clause. If we did, then | |
| // all section layout needs to go through this class. | |
| bool | |
| saw_sections_clause() const | |
| { return this->saw_sections_clause_; } | |
| // Return whether we are currently processing a SECTIONS clause. | |
| bool | |
| in_sections_clause() const | |
| { return this->in_sections_clause_; } | |
| // Return whether we ever saw a PHDRS clause. We ignore the PHDRS | |
| // clause unless we also saw a SECTIONS clause. | |
| bool | |
| saw_phdrs_clause() const | |
| { return this->saw_sections_clause_ && this->phdrs_elements_ != NULL; } | |
| // Start processing entries for an output section. | |
| void | |
| start_output_section(const char* name, size_t namelen, | |
| const Parser_output_section_header*); | |
| // Finish processing entries for an output section. | |
| void | |
| finish_output_section(const Parser_output_section_trailer*); | |
| // Add a data item to the current output section. | |
| void | |
| add_data(int size, bool is_signed, Expression* val); | |
| // Add a symbol to be defined. | |
| void | |
| add_symbol_assignment(const char* name, size_t length, Expression* value, | |
| bool provide, bool hidden); | |
| // Add an assignment to the special dot symbol. | |
| void | |
| add_dot_assignment(Expression* value); | |
| // Add an assertion. | |
| void | |
| add_assertion(Expression* check, const char* message, size_t messagelen); | |
| // 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); | |
| // Saw DATA_SEGMENT_ALIGN. | |
| void | |
| data_segment_align(); | |
| // Saw DATA_SEGMENT_RELRO_END. | |
| void | |
| data_segment_relro_end(); | |
| // Create any required sections. | |
| void | |
| create_sections(Layout*); | |
| // Add any symbols we are defining to the symbol table. | |
| void | |
| add_symbols_to_table(Symbol_table*); | |
| // Finalize symbol values and check assertions. | |
| void | |
| finalize_symbols(Symbol_table* symtab, const Layout* layout); | |
| // Find the name of the output section to use for an input file name | |
| // and section name. This returns a name, and sets | |
| // *OUTPUT_SECTION_SLOT to point to the address where the actual | |
| // output section may be stored. | |
| // 1) If the input section should be discarded, this returns NULL | |
| // and sets *OUTPUT_SECTION_SLOT to NULL. | |
| // 2) If the input section is mapped by the SECTIONS clause, this | |
| // returns the name to use for the output section (in permanent | |
| // storage), and sets *OUTPUT_SECTION_SLOT to point to where the | |
| // output section should be stored. **OUTPUT_SECTION_SLOT will be | |
| // non-NULL if we have seen this output section already. | |
| // 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. | |
| // *KEEP indicates whether the section should survive garbage collection. | |
| // MATCH_INPUT_SPEC indicates whether the section should be matched | |
| // with input section specs or simply against the output section name | |
| // (i.e., for linker-created sections like .dynamic). | |
| const char* | |
| output_section_name(const char* file_name, const char* section_name, | |
| Output_section*** output_section_slot, | |
| Section_type* pscript_section_type, | |
| bool* keep, bool match_input_spec); | |
| // Place a marker for an orphan output section into the SECTIONS | |
| // clause. | |
| void | |
| place_orphan(Output_section* os); | |
| // Set the addresses of all the output sections. Return the segment | |
| // which holds the file header and segment headers, if any. | |
| Output_segment* | |
| set_section_addresses(Symbol_table*, Layout*); | |
| // Add a program header definition. | |
| void | |
| add_phdr(const char* name, size_t namelen, unsigned int type, | |
| bool filehdr, bool phdrs, bool is_flags_valid, unsigned int flags, | |
| Expression* load_address); | |
| // Return the number of segments we expect to create based on the | |
| // SECTIONS clause. | |
| size_t | |
| expected_segment_count(const Layout*) const; | |
| // Add the file header and segment header to non-load segments as | |
| // specified by the PHDRS clause. | |
| void | |
| put_headers_in_phdrs(Output_data* file_header, Output_data* segment_headers); | |
| // Look for an output section by name and return the address, the | |
| // load address, the alignment, and the size. This is used when an | |
| // expression refers to an output section which was not actually | |
| // created. This returns true if the section was found, false | |
| // otherwise. | |
| bool | |
| get_output_section_info(const char* name, uint64_t* address, | |
| uint64_t* load_address, uint64_t* addralign, | |
| uint64_t* size) const; | |
| // Release all Output_segments. This is used in relaxation. | |
| void | |
| release_segments(); | |
| // Whether we ever saw a SEGMENT_START expression, the presence of which | |
| // changes the behaviour of -Ttext, -Tdata and -Tbss options. | |
| bool | |
| saw_segment_start_expression() const | |
| { return this->saw_segment_start_expression_; } | |
| // Set the flag which indicates whether we saw a SEGMENT_START expression. | |
| void | |
| set_saw_segment_start_expression(bool value) | |
| { this->saw_segment_start_expression_ = value; } | |
| // Add a memory region. | |
| void | |
| add_memory_region(const char*, size_t, unsigned int, | |
| Expression*, Expression*); | |
| // Find a memory region's origin. | |
| Expression* | |
| find_memory_region_origin(const char*, size_t); | |
| // Find a memory region's length. | |
| Expression* | |
| find_memory_region_length(const char*, size_t); | |
| // Find a memory region by name. | |
| Memory_region* | |
| find_memory_region(const char*, size_t); | |
| // Find a memory region that should be used by a given output section. | |
| Memory_region* | |
| find_memory_region(Output_section_definition*, bool, bool, | |
| Output_section_definition**); | |
| // Returns true if the provide block of memory is contained | |
| // within a memory region. | |
| bool | |
| block_in_region(Symbol_table*, Layout*, uint64_t, uint64_t) const; | |
| // Set the memory region of the section. | |
| void | |
| set_memory_region(Memory_region*, bool); | |
| // Print the contents to the FILE. This is for debugging. | |
| void | |
| print(FILE*) const; | |
| // Used for orphan sections. | |
| typedef Sections_elements::iterator Elements_iterator; | |
| private: | |
| typedef std::vector<Memory_region*> Memory_regions; | |
| typedef std::vector<Phdrs_element*> Phdrs_elements; | |
| // Create segments. | |
| Output_segment* | |
| create_segments(Layout*, uint64_t); | |
| // Create PT_NOTE and PT_TLS segments. | |
| void | |
| create_note_and_tls_segments(Layout*, const std::vector<Output_section*>*); | |
| // Return whether the section is a BSS section. | |
| static bool | |
| is_bss_section(const Output_section*); | |
| // Return the total size of the headers. | |
| size_t | |
| total_header_size(Layout* layout) const; | |
| // Return the amount we have to subtract from the LMA to accommodate | |
| // headers of the given size. | |
| uint64_t | |
| header_size_adjustment(uint64_t lma, size_t sizeof_headers) const; | |
| // Create the segments from a PHDRS clause. | |
| Output_segment* | |
| create_segments_from_phdrs_clause(Layout* layout, uint64_t); | |
| // Attach sections to segments from a PHDRS clause. | |
| void | |
| attach_sections_using_phdrs_clause(Layout*); | |
| // Set addresses of segments from a PHDRS clause. | |
| Output_segment* | |
| set_phdrs_clause_addresses(Layout*, uint64_t); | |
| // True if we ever saw a SECTIONS clause. | |
| bool saw_sections_clause_; | |
| // True if we are currently processing a SECTIONS clause. | |
| bool in_sections_clause_; | |
| // The list of elements in the SECTIONS clause. | |
| Sections_elements* sections_elements_; | |
| // The current output section, if there is one. | |
| Output_section_definition* output_section_; | |
| // The list of memory regions in the MEMORY clause. | |
| Memory_regions* memory_regions_; | |
| // The list of program headers in the PHDRS clause. | |
| Phdrs_elements* phdrs_elements_; | |
| // Where to put orphan sections. | |
| Orphan_section_placement* orphan_section_placement_; | |
| // A pointer to the last Sections_element when we see | |
| // DATA_SEGMENT_ALIGN. | |
| Sections_elements::iterator data_segment_align_start_; | |
| // Whether we have seen DATA_SEGMENT_ALIGN. | |
| bool saw_data_segment_align_; | |
| // Whether we have seen DATA_SEGMENT_RELRO_END. | |
| bool saw_relro_end_; | |
| // Whether we have seen SEGMENT_START. | |
| bool saw_segment_start_expression_; | |
| // Whether we have created all necessary segments. | |
| bool segments_created_; | |
| }; | |
| // Attributes for memory regions. | |
| enum | |
| { | |
| MEM_EXECUTABLE = (1 << 0), | |
| MEM_WRITEABLE = (1 << 1), | |
| MEM_READABLE = (1 << 2), | |
| MEM_ALLOCATABLE = (1 << 3), | |
| MEM_INITIALIZED = (1 << 4), | |
| MEM_ATTR_MASK = (1 << 5) - 1 | |
| }; | |
| } // End namespace gold. | |
| #endif // !defined(GOLD_SCRIPT_SECTIONS_H |