diff options
author | Ian Lance Taylor <iant@google.com> | 2008-02-04 06:45:50 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2008-02-04 06:45:50 +0000 |
commit | 3802b2dd6b937e2904b6e2de087e224437eab493 (patch) | |
tree | ac185197a2a44c92c3785020c2ce1e389f2b0287 /gold/script-sections.cc | |
parent | ae7d22a6f2f59251b85ef5655b800f2dfe2dfbee (diff) | |
download | gdb-3802b2dd6b937e2904b6e2de087e224437eab493.zip gdb-3802b2dd6b937e2904b6e2de087e224437eab493.tar.gz gdb-3802b2dd6b937e2904b6e2de087e224437eab493.tar.bz2 |
Implement SIZEOF_HEADERS, section constraints, other minor linker
script items.
Diffstat (limited to 'gold/script-sections.cc')
-rw-r--r-- | gold/script-sections.cc | 208 |
1 files changed, 195 insertions, 13 deletions
diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 2505170..6c8a7f5 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 |