diff options
Diffstat (limited to 'gold')
-rw-r--r-- | gold/defstd.cc | 8 | ||||
-rw-r--r-- | gold/dynobj.h | 10 | ||||
-rw-r--r-- | gold/expression.cc | 80 | ||||
-rw-r--r-- | gold/gold.cc | 9 | ||||
-rw-r--r-- | gold/layout.cc | 388 | ||||
-rw-r--r-- | gold/layout.h | 36 | ||||
-rw-r--r-- | gold/object.h | 31 | ||||
-rw-r--r-- | gold/output.cc | 269 | ||||
-rw-r--r-- | gold/output.h | 243 | ||||
-rw-r--r-- | gold/po/POTFILES.in | 2 | ||||
-rw-r--r-- | gold/po/gold.pot | 350 | ||||
-rw-r--r-- | gold/script-sections.cc | 1521 | ||||
-rw-r--r-- | gold/script-sections.h | 55 | ||||
-rw-r--r-- | gold/script.cc | 140 | ||||
-rw-r--r-- | gold/script.h | 56 | ||||
-rw-r--r-- | gold/symtab.cc | 35 | ||||
-rw-r--r-- | gold/symtab.h | 16 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 5 | ||||
-rw-r--r-- | gold/testsuite/script_test_2.cc | 69 | ||||
-rw-r--r-- | gold/testsuite/script_test_2.t | 63 | ||||
-rw-r--r-- | gold/testsuite/script_test_2a.cc | 24 | ||||
-rw-r--r-- | gold/testsuite/script_test_2b.cc | 24 | ||||
-rw-r--r-- | gold/yyscript.y | 3 |
23 files changed, 3019 insertions, 418 deletions
diff --git a/gold/defstd.cc b/gold/defstd.cc index 944af3e..984f3e1 100644 --- a/gold/defstd.cc +++ b/gold/defstd.cc @@ -23,6 +23,7 @@ #include "gold.h" #include "symtab.h" +#include "layout.h" #include "defstd.h" // This is a simple file which defines the standard symbols like @@ -251,8 +252,11 @@ namespace gold void define_standard_symbols(Symbol_table* symtab, const Layout* layout) { - symtab->define_symbols(layout, in_section_count, in_section); - symtab->define_symbols(layout, in_segment_count, in_segment); + bool saw_sections_clause = layout->script_options()->saw_sections_clause(); + symtab->define_symbols(layout, in_section_count, in_section, + saw_sections_clause); + symtab->define_symbols(layout, in_segment_count, in_segment, + saw_sections_clause); } } // End namespace gold. diff --git a/gold/dynobj.h b/gold/dynobj.h index 0b22362..67b0f51 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -176,6 +176,11 @@ class Sized_dynobj : public Dynobj void do_add_symbols(Symbol_table*, Read_symbols_data*); + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx) + { return this->elf_file_.section_size(shndx); } + // Get the name of a section. std::string do_section_name(unsigned int shndx) @@ -207,6 +212,11 @@ class Sized_dynobj : public Dynobj do_section_info(unsigned int shndx) { return this->elf_file_.section_info(shndx); } + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx) + { return this->elf_file_.section_addralign(shndx); } + private: // For convenience. typedef Sized_dynobj<size, big_endian> This; diff --git a/gold/expression.cc b/gold/expression.cc index 533b025..e8fd9fd 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -36,14 +36,33 @@ namespace gold // This file holds the code which handles linker expressions. +// The dot symbol, which linker scripts refer to simply as ".", +// requires special treatment. The dot symbol is set several times, +// section addresses will refer to it, output sections will change it, +// and it can be set based on the value of other symbols. We simplify +// the handling by prohibiting setting the dot symbol to the value of +// a non-absolute symbol. + // When evaluating the value of an expression, we pass in a pointer to // this struct, so that the expression evaluation can find the // information it needs. struct Expression::Expression_eval_info { + // The symbol table. const Symbol_table* symtab; + // The layout--we use this to get section information. const Layout* layout; + // Whether expressions can refer to the dot symbol. The dot symbol + // is only available within a SECTIONS clause. + bool is_dot_available; + // Whether the dot symbol currently has a value. + bool dot_has_value; + // The current value of the dot symbol. + uint64_t dot_value; + // Points to the IS_ABSOLUTE variable, which is set to false if the + // expression uses a value which is not absolute. + bool* is_absolute; }; // Evaluate an expression. @@ -51,9 +70,41 @@ struct Expression::Expression_eval_info uint64_t Expression::eval(const Symbol_table* symtab, const Layout* layout) { + bool dummy; + return this->eval_maybe_dot(symtab, layout, false, false, 0, &dummy); +} + +// Evaluate an expression which may refer to the dot symbol. + +uint64_t +Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, + bool dot_has_value, uint64_t dot_value, + bool* is_absolute) +{ + return this->eval_maybe_dot(symtab, layout, true, dot_has_value, dot_value, + is_absolute); +} + +// Evaluate an expression which may or may not refer to the dot +// symbol. + +uint64_t +Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, + bool is_dot_available, bool dot_has_value, + uint64_t dot_value, bool* is_absolute) +{ Expression_eval_info eei; eei.symtab = symtab; eei.layout = layout; + eei.is_dot_available = is_dot_available; + eei.dot_has_value = dot_has_value; + eei.dot_value = dot_value; + + // We assume the value is absolute, and only set this to false if we + // find a section relative reference. + *is_absolute = true; + eei.is_absolute = is_absolute; + return this->value(&eei); } @@ -115,6 +166,14 @@ Symbol_expression::value(const Expression_eval_info* eei) return 0; } + // If this symbol does not have an absolute value, then the whole + // expression does not have an absolute value. This is not strictly + // accurate: the subtraction of two symbols in the same section is + // absolute. This is unlikely to matter in practice, as this value + // is only used for error checking. + if (!sym->value_is_absolute()) + *eei->is_absolute = false; + if (parameters->get_size() == 32) return eei->symtab->get_sized_symbol<32>(sym)->value(); else if (parameters->get_size() == 64) @@ -141,10 +200,21 @@ class Dot_expression : public Expression }; uint64_t -Dot_expression::value(const Expression_eval_info*) +Dot_expression::value(const Expression_eval_info* eei) { - gold_error("dot symbol unimplemented"); - return 0; + if (!eei->is_dot_available) + { + gold_error(_("invalid reference to dot symbol outside of " + "SECTIONS clause")); + return 0; + } + else if (!eei->dot_has_value) + { + gold_error(_("invalid reference to dot symbol before " + "it has been given a value")); + return 0; + } + return eei->dot_value; } // A string. This is either the name of a symbol, or ".". @@ -549,6 +619,10 @@ Addr_expression::value(const Expression_eval_info* eei) section_name); return 0; } + + // Note that the address of a section is an absolute address, and we + // should not clear *EEI->IS_ABSOLUTE here. + return os->address(); } diff --git a/gold/gold.cc b/gold/gold.cc index c738e31..aa6f32a 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -198,17 +198,16 @@ queue_middle_tasks(const General_options& options, // handles some cases we want to see before we read the relocs. layout->create_initial_dynamic_sections(symtab); - // Predefine standard symbols. This should be fast, so we don't - // bother to create a task for it. + // Define symbols from any linker scripts. + layout->define_script_symbols(symtab); + + // Predefine standard symbols. define_standard_symbols(symtab, layout); // Define __start and __stop symbols for output sections where // appropriate. layout->define_section_symbols(symtab); - // Define symbols from any linker scripts. - layout->define_script_symbols(symtab); - // Read the relocations of the input files. We do this to find // which symbols are used by relocations which require a GOT and/or // a PLT entry, or a COPY reloc. When we implement garbage diff --git a/gold/layout.cc b/gold/layout.cc index 3969283..a0fcc49 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -29,6 +29,8 @@ #include "parameters.h" #include "options.h" +#include "script.h" +#include "script-sections.h" #include "output.h" #include "symtab.h" #include "dynobj.h" @@ -185,11 +187,11 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name, Output_section* Layout::find_output_section(const char* name) const { - for (Section_name_map::const_iterator p = this->section_name_map_.begin(); - p != this->section_name_map_.end(); + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); ++p) - if (strcmp(p->second->name(), name) == 0) - return p->second; + if (strcmp((*p)->name(), name) == 0) + return *p; return NULL; } @@ -211,19 +213,13 @@ Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set, } // Return the output section to use for section NAME with type TYPE -// and section flags FLAGS. +// and section flags FLAGS. NAME must be canonicalized in the string +// pool, and NAME_KEY is the key. Output_section* Layout::get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) { - // We should ignore some flags. - flags &= ~ (elfcpp::SHF_INFO_LINK - | elfcpp::SHF_LINK_ORDER - | elfcpp::SHF_GROUP - | elfcpp::SHF_MERGE - | elfcpp::SHF_STRINGS); - const Key key(name_key, std::make_pair(type, flags)); const std::pair<Key, Output_section*> v(key, NULL); std::pair<Section_name_map::iterator, bool> ins( @@ -241,6 +237,80 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key, } } +// Pick the output section to use for section NAME, in input file +// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a +// linker created section. ADJUST_NAME is true if we should apply the +// standard name mappings in Layout::output_section_name. This will +// return NULL if the input section should be discarded. + +Output_section* +Layout::choose_output_section(const Relobj* relobj, const char* name, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + bool adjust_name) +{ + // We should ignore some flags. FIXME: This will need some + // adjustment for ld -r. + flags &= ~ (elfcpp::SHF_INFO_LINK + | elfcpp::SHF_LINK_ORDER + | elfcpp::SHF_GROUP + | elfcpp::SHF_MERGE + | elfcpp::SHF_STRINGS); + + if (this->script_options_->saw_sections_clause()) + { + // We are using a SECTIONS clause, so the output section is + // chosen based only on the 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); + if (name == NULL) + { + // The SECTIONS clause says to discard this input section. + return NULL; + } + + // 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. + + if (output_section_slot != NULL) + { + if (*output_section_slot != NULL) + return *output_section_slot; + + // We don't put sections found in the linker script into + // SECTION_NAME_MAP_. That keeps us from getting confused + // if an orphan section is mapped to a section with the same + // name as one in the linker script. + + name = this->namepool_.add(name, false, NULL); + + Output_section* os = this->make_output_section(name, type, flags); + os->set_found_in_sections_clause(); + *output_section_slot = os; + return os; + } + } + + // FIXME: Handle SHF_OS_NONCONFORMING somewhere. + + // Turn NAME from the name of the input section into the name of the + // output section. + + size_t len = strlen(name); + if (adjust_name && !parameters->output_is_object()) + name = Layout::output_section_name(name, &len); + + Stringpool::Key name_key; + name = this->namepool_.add_with_length(name, len, true, &name_key); + + // Find or make the output section. The output section is selected + // based on the section name, type, and flags. + return this->get_output_section(name, name_key, type, flags); +} + // Return the output section to use for input section SHNDX, with name // NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the // index of a relocation section which applies to this section, or 0 @@ -260,27 +330,18 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx, if (!this->include_section(object, name, shdr)) return NULL; - // If we are not doing a relocateable link, choose the name to use - // for the output section. - size_t len = strlen(name); - if (!parameters->output_is_object()) - name = Layout::output_section_name(name, &len); - - // FIXME: Handle SHF_OS_NONCONFORMING here. - - // Canonicalize the section name. - Stringpool::Key name_key; - name = this->namepool_.add_with_length(name, len, true, &name_key); - - // Find the output section. The output section is selected based on - // the section name, type, and flags. - Output_section* os = this->get_output_section(name, name_key, - shdr.get_sh_type(), - shdr.get_sh_flags()); + Output_section* os = this->choose_output_section(object, + name, + shdr.get_sh_type(), + shdr.get_sh_flags(), + true); + if (os == NULL) + return NULL; // FIXME: Handle SHF_LINK_ORDER somewhere. - *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx); + *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx, + this->script_options_->saw_sections_clause()); return os; } @@ -304,12 +365,14 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object, gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS); gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC); - Stringpool::Key name_key; - const char* name = this->namepool_.add(".eh_frame", false, &name_key); - - Output_section* os = this->get_output_section(name, name_key, - elfcpp::SHT_PROGBITS, - elfcpp::SHF_ALLOC); + const char* const name = ".eh_frame"; + Output_section* os = this->choose_output_section(object, + name, + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC, + false); + if (os == NULL) + return NULL; if (this->eh_frame_section_ == NULL) { @@ -319,26 +382,28 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object, if (this->options_.create_eh_frame_hdr()) { - Stringpool::Key hdr_name_key; - const char* hdr_name = this->namepool_.add(".eh_frame_hdr", - false, - &hdr_name_key); Output_section* hdr_os = - this->get_output_section(hdr_name, hdr_name_key, - elfcpp::SHT_PROGBITS, - elfcpp::SHF_ALLOC); + this->choose_output_section(NULL, + ".eh_frame_hdr", + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC, + false); - Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_); - hdr_os->add_output_section_data(hdr_posd); + if (hdr_os != NULL) + { + Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, + this->eh_frame_data_); + hdr_os->add_output_section_data(hdr_posd); - hdr_os->set_after_input_sections(); + 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); - hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R); + Output_segment* hdr_oseg = + new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R); + this->segment_list_.push_back(hdr_oseg); + hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R); - this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); + this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); + } } } @@ -357,7 +422,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object, { // We couldn't handle this .eh_frame section for some reason. // Add it as a normal section. - *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx); + bool saw_sections_clause = this->script_options_->saw_sections_clause(); + *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx, + saw_sections_clause); } return os; @@ -370,12 +437,10 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, Output_section_data* posd) { - // Canonicalize the name. - Stringpool::Key name_key; - name = this->namepool_.add(name, true, &name_key); - - Output_section* os = this->get_output_section(name, name_key, type, flags); - os->add_output_section_data(posd); + Output_section* os = this->choose_output_section(NULL, name, type, flags, + false); + if (os != NULL) + os->add_output_section_data(posd); } // Map section flags to segment flags. @@ -428,6 +493,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, this->unattached_section_list_.push_back(os); else { + // If we have a SECTIONS clause, we can't handle the attachment + // to segments until after we've seen all the sections. + if (this->script_options_->saw_sections_clause()) + return os; + // This output section goes into a PT_LOAD segment. elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags); @@ -581,7 +651,7 @@ Layout::define_section_symbols(Symbol_table* symtab) elfcpp::STV_DEFAULT, 0, // nonvis false, // offset_is_from_end - false); // only_if_ref + true); // only_if_ref symtab->define_in_output_data(stop_name.c_str(), NULL, // version @@ -593,7 +663,7 @@ Layout::define_section_symbols(Symbol_table* symtab) elfcpp::STV_DEFAULT, 0, // nonvis true, // offset_is_from_end - false); // only_if_ref + true); // only_if_ref } } } @@ -664,17 +734,11 @@ 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->doing_static_link()) + 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 = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R); - this->segment_list_.push_back(phdr_seg); - // Create the dynamic symbol table, including the hash table. Output_section* dynstr; std::vector<Symbol*> dynamic_symbols; @@ -703,15 +767,30 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, dynamic_symbols, dynstr); } - // FIXME: Handle PT_GNU_STACK. + // If there is a SECTIONS clause, put all the input sections into + // the required order. + Output_segment* load_seg; + if (this->script_options_->saw_sections_clause()) + load_seg = this->set_section_addresses_from_script(symtab); + else + load_seg = this->find_first_load_seg(); - Output_segment* 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); + } // Lay out the segment headers. Output_segment_headers* segment_headers; segment_headers = new Output_segment_headers(this->segment_list_); - load_seg->add_initial_output_data(segment_headers); - this->special_output_list_.push_back(segment_headers); + if (load_seg != NULL) + load_seg->add_initial_output_data(segment_headers); if (phdr_seg != NULL) phdr_seg->add_initial_output_data(segment_headers); @@ -719,8 +798,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, Output_file_header* file_header; file_header = new Output_file_header(target, symtab, segment_headers, this->script_options_->entry()); - load_seg->add_initial_output_data(file_header); + if (load_seg != NULL) + load_seg->add_initial_output_data(file_header); + this->special_output_list_.push_back(file_header); + this->special_output_list_.push_back(segment_headers); // We set the output section indexes in set_segment_offsets and // set_section_indexes. @@ -970,6 +1052,27 @@ Layout::segment_precedes(const Output_segment* seg1, return flags1 < flags2; } + // If the addresses are set already, sort by load address. + if (seg1->are_addresses_set()) + { + if (!seg2->are_addresses_set()) + return true; + + unsigned int section_count1 = seg1->output_section_count(); + unsigned int section_count2 = seg2->output_section_count(); + if (section_count1 == 0 && section_count2 > 0) + return true; + if (section_count1 > 0 && section_count2 == 0) + return false; + + uint64_t paddr1 = seg1->first_section_load_address(); + uint64_t paddr2 = seg2->first_section_load_address(); + if (paddr1 != paddr2) + return paddr1 < paddr2; + } + else if (seg2->are_addresses_set()) + return false; + // We sort PT_LOAD segments based on the flags. Readonly segments // come before writable segments. Then executable segments come // before non-executable segments. Then the unlikely case of a @@ -984,15 +1087,9 @@ Layout::segment_precedes(const Output_segment* seg1, if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R)) return (flags1 & elfcpp::PF_R) == 0; - uint64_t vaddr1 = seg1->vaddr(); - uint64_t vaddr2 = seg2->vaddr(); - if (vaddr1 != vaddr2) - return vaddr1 < vaddr2; - - uint64_t paddr1 = seg1->paddr(); - uint64_t paddr2 = seg2->paddr(); - gold_assert(paddr1 != paddr2); - return paddr1 < paddr2; + // We shouldn't get here--we shouldn't create segments which we + // can't distinguish. + gold_unreachable(); } // Set the file offsets of all the segments, and all the sections they @@ -1010,13 +1107,29 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // Find the PT_LOAD segments, and set their addresses and offsets // and their section's addresses and offsets. uint64_t addr; - if (parameters->output_is_shared()) - addr = 0; - else if (options_.user_set_text_segment_address()) + if (this->options_.user_set_text_segment_address()) addr = options_.text_segment_address(); + else if (parameters->output_is_shared()) + addr = 0; else addr = target->default_text_segment_address(); off_t off = 0; + + // If LOAD_SEG is NULL, then the file header and segment headers + // will not be loadable. But they still need to be at offset 0 in + // the file. Set their offsets now. + if (load_seg == NULL) + { + for (Data_list::iterator p = this->special_output_list_.begin(); + p != this->special_output_list_.end(); + ++p) + { + off = align_address(off, (*p)->addralign()); + (*p)->set_address_and_file_offset(0, off); + off += (*p)->data_size(); + } + } + bool was_readonly = false; for (Segment_list::iterator p = this->segment_list_.begin(); p != this->segment_list_.end(); @@ -1028,34 +1141,55 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, gold_unreachable(); load_seg = NULL; - // If the last segment was readonly, and this one is not, - // then skip the address forward one page, maintaining the - // same position within the page. This lets us store both - // segments overlapping on a single page in the file, but - // the loader will put them on different pages in memory. - uint64_t orig_addr = addr; uint64_t orig_off = off; - uint64_t aligned_addr = addr; + uint64_t aligned_addr = 0; uint64_t abi_pagesize = target->abi_pagesize(); - // FIXME: This should depend on the -n and -N options. - (*p)->set_minimum_addralign(target->common_pagesize()); + // FIXME: This should depend on the -n and -N options. + (*p)->set_minimum_p_align(target->common_pagesize()); - if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0) + bool are_addresses_set = (*p)->are_addresses_set(); + if (are_addresses_set) { - uint64_t align = (*p)->addralign(); - - addr = align_address(addr, align); + // When it comes to setting file offsets, we care about + // the physical address. + addr = (*p)->paddr(); + + // Adjust the file offset to the same address modulo the + // page size. + uint64_t unsigned_off = off; + uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1)) + | (addr & (abi_pagesize - 1))); + if (aligned_off < unsigned_off) + aligned_off += abi_pagesize; + off = aligned_off; + } + else + { + // If the last segment was readonly, and this one is + // not, then skip the address forward one page, + // maintaining the same position within the page. This + // lets us store both segments overlapping on a single + // page in the file, but the loader will put them on + // different pages in memory. + + addr = align_address(addr, (*p)->maximum_alignment()); aligned_addr = addr; - if ((addr & (abi_pagesize - 1)) != 0) - addr = addr + abi_pagesize; + + if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0) + { + if ((addr & (abi_pagesize - 1)) != 0) + addr = addr + abi_pagesize; + } + + off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); } unsigned int shndx_hold = *pshndx; - off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); - uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx); + uint64_t new_addr = (*p)->set_section_addresses(false, addr, &off, + pshndx); // Now that we know the size of this segment, we may be able // to save a page in memory, at the cost of wasting some @@ -1063,7 +1197,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // page. Here we use the real machine page size rather than // the ABI mandated page size. - if (aligned_addr != addr) + if (!are_addresses_set && aligned_addr != addr) { uint64_t common_pagesize = target->common_pagesize(); uint64_t first_off = (common_pagesize @@ -1078,8 +1212,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, { *pshndx = shndx_hold; addr = align_address(aligned_addr, common_pagesize); + addr = align_address(addr, (*p)->maximum_alignment()); off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); - new_addr = (*p)->set_section_addresses(addr, &off, pshndx); + new_addr = (*p)->set_section_addresses(true, addr, &off, + pshndx); } } @@ -1172,6 +1308,30 @@ Layout::set_section_indexes(unsigned int shndx) return shndx; } +// Set the section addresses according to the linker script. This is +// only called when we see a SECTIONS clause. This returns the +// program segment which should hold the file header and segment +// headers, if any. It will return NULL if they should not be in a +// segment. + +Output_segment* +Layout::set_section_addresses_from_script(Symbol_table* symtab) +{ + Script_sections* ss = this->script_options_->script_sections(); + gold_assert(ss->saw_sections_clause()); + + // Place each orphaned output section in the script. + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if (!(*p)->found_in_sections_clause()) + ss->place_orphan(*p); + } + + return this->script_options_->set_section_addresses(symtab, this); +} + // Count the local symbols in the regular symbol table and the dynamic // symbol table, and build the respective string pools. @@ -1963,6 +2123,28 @@ Layout::add_comdat(const char* signature, bool group) } } +// Store the allocated sections into the section list. + +void +Layout::get_allocated_sections(Section_list* section_list) const +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0) + section_list->push_back(*p); +} + +// Create an output segment. + +Output_segment* +Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) +{ + Output_segment* oseg = new Output_segment(type, flags); + this->segment_list_.push_back(oseg); + return oseg; +} + // Write out the Output_sections. Most won't have anything to write, // since most of the data will come from input sections which are // handled elsewhere. But some Output_sections do have Output_data. diff --git a/gold/layout.h b/gold/layout.h index f070039..ceacf5d 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -260,11 +260,11 @@ class Layout void print_stats() const; - // The list of segments. + // A list of segments. typedef std::vector<Output_segment*> Segment_list; - // The list of sections not attached to a segment. + // A list of sections. typedef std::vector<Output_section*> Section_list; @@ -272,6 +272,24 @@ class Layout // either a section or a segment. typedef std::vector<Output_data*> Data_list; + // Store the allocated sections into the section list. This is used + // by the linker script code. + void + get_allocated_sections(Section_list*) const; + + // Make a segment. This is used by the linker script code. + Output_segment* + make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags); + + // Return the number of segments. + size_t + segment_count() const + { return this->segment_list_.size(); } + + // Map from section flags to segment flags. + static elfcpp::Elf_Word + section_flags_to_segment(elfcpp::Elf_Xword flags); + private: Layout(const Layout&); Layout& operator=(const Layout&); @@ -376,6 +394,12 @@ class Layout get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags); + // Choose the output section for NAME in RELOBJ. + Output_section* + choose_output_section(const Relobj* relobj, const char* name, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + bool adjust_name); + // Create a new Output_section. Output_section* make_output_section(const char* name, elfcpp::Elf_Word type, @@ -405,14 +429,14 @@ class Layout unsigned int set_section_indexes(unsigned int pshndx); + // Set the section addresses when using a script. + Output_segment* + set_section_addresses_from_script(Symbol_table*); + // Return whether SEG1 comes before SEG2 in the output file. static bool segment_precedes(const Output_segment* seg1, const Output_segment* seg2); - // Map from section flags to segment flags. - static elfcpp::Elf_Word - section_flags_to_segment(elfcpp::Elf_Xword flags); - // A mapping used for group signatures. typedef Unordered_map<std::string, bool> Signatures; diff --git a/gold/object.h b/gold/object.h index e4140be..5a62546 100644 --- a/gold/object.h +++ b/gold/object.h @@ -206,8 +206,12 @@ class Object const unsigned char* section_contents(unsigned int shndx, section_size_type* plen, bool cache); - // Return the name of a section given a section index. This is only - // used for error messages. + // Return the size of a section given a section index. + uint64_t + section_size(unsigned int shndx) + { return this->do_section_size(shndx); } + + // Return the name of a section given a section index. std::string section_name(unsigned int shndx) { return this->do_section_name(shndx); } @@ -232,6 +236,11 @@ class Object section_info(unsigned int shndx) { return this->do_section_info(shndx); } + // Return the required section alignment given a section index. + uint64_t + section_addralign(unsigned int shndx) + { return this->do_section_addralign(shndx); } + // Read the symbol information. void read_symbols(Read_symbols_data* sd) @@ -344,6 +353,10 @@ class Object virtual Location do_section_contents(unsigned int shndx) = 0; + // Get the size of a section--implemented by child class. + virtual uint64_t + do_section_size(unsigned int shndx) = 0; + // Get the name of a section--implemented by child class. virtual std::string do_section_name(unsigned int shndx) = 0; @@ -364,6 +377,10 @@ class Object virtual unsigned int do_section_info(unsigned int shndx) = 0; + // Get section alignment--implemented by child class. + virtual uint64_t + do_section_addralign(unsigned int shndx) = 0; + // Get the file. We pass on const-ness. Input_file* input_file() @@ -1136,6 +1153,11 @@ class Sized_relobj : public Relobj do_relocate(const General_options& options, const Symbol_table* symtab, const Layout*, Output_file* of); + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx) + { return this->elf_file_.section_size(shndx); } + // Get the name of a section. std::string do_section_name(unsigned int shndx) @@ -1166,6 +1188,11 @@ class Sized_relobj : public Relobj do_section_info(unsigned int shndx) { return this->elf_file_.section_info(shndx); } + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx) + { return this->elf_file_.section_addralign(shndx); } + private: // For convenience. typedef Sized_relobj<size, big_endian> This; diff --git a/gold/output.cc b/gold/output.cc index 1060de6..c0db1af 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -275,6 +275,7 @@ Output_segment_headers::do_sized_write(Output_file* of) { const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size; off_t all_phdrs_size = this->segment_list_.size() * phdr_size; + gold_assert(all_phdrs_size == this->data_size()); unsigned char* view = of->get_output_view(this->offset(), all_phdrs_size); unsigned char* v = view; @@ -287,6 +288,8 @@ Output_segment_headers::do_sized_write(Output_file* of) v += phdr_size; } + gold_assert(v - view == all_phdrs_size); + of->write_output_view(this->offset(), all_phdrs_size, view); } @@ -1371,6 +1374,15 @@ Output_section::Input_section::set_address_and_file_offset( this->u2_.posd->set_address_and_file_offset(address, file_offset); } +// Reset the address and file offset. + +void +Output_section::Input_section::reset_address_and_file_offset() +{ + if (!this->is_input_section()) + this->u2_.posd->reset_address_and_file_offset(); +} + // Finalize the data size. void @@ -1444,6 +1456,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, : name_(name), addralign_(0), entsize_(0), + load_address_(0), link_section_(NULL), link_(0), info_section_(NULL), @@ -1463,6 +1476,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, should_link_to_dynsym_(false), after_input_sections_(false), requires_postprocessing_(false), + found_in_sections_clause_(false), + has_load_address_(false), tls_offset_(0) { // An unallocated section has no address. Forcing this means that @@ -1495,7 +1510,9 @@ Output_section::set_entsize(uint64_t v) // receive special handling. In the normal case we don't always keep // track of input sections for an Output_section. Instead, each // Object keeps track of the Output_section for each of its input -// sections. +// sections. However, if HAVE_SECTIONS_SCRIPT is true, we do keep +// track of input sections here; this is used when SECTIONS appears in +// a linker script. template<int size, bool big_endian> off_t @@ -1503,7 +1520,8 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx, const char* secname, const elfcpp::Shdr<size, big_endian>& shdr, - unsigned int reloc_shndx) + unsigned int reloc_shndx, + bool have_sections_script) { elfcpp::Elf_Xword addralign = shdr.get_sh_addralign(); if ((addralign & (addralign - 1)) != 0) @@ -1517,6 +1535,11 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, this->addralign_ = addralign; typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags(); + this->flags_ |= (sh_flags + & (elfcpp::SHF_WRITE + | elfcpp::SHF_ALLOC + | elfcpp::SHF_EXECINSTR)); + uint64_t entsize = shdr.get_sh_entsize(); // .debug_str is a mergeable string section, but is not always so @@ -1547,6 +1570,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, addralign); if (aligned_offset_in_section > offset_in_section + && !have_sections_script && (sh_flags & elfcpp::SHF_EXECINSTR) != 0 && object->target()->has_code_fill()) { @@ -1572,7 +1596,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, // We need to keep track of this section if we are already keeping // track of sections, or if we are relaxing. FIXME: Add test for // relaxing. - if (!this->input_sections_.empty()) + if (have_sections_script || !this->input_sections_.empty()) this->input_sections_.push_back(Input_section(object, shndx, shdr.get_sh_size(), addralign)); @@ -1587,6 +1611,15 @@ Output_section::add_output_section_data(Output_section_data* posd) { Input_section inp(posd); this->add_output_section_data(&inp); + + if (posd->is_data_size_valid()) + { + off_t offset_in_section = this->current_data_size_for_child(); + off_t aligned_offset_in_section = align_address(offset_in_section, + posd->addralign()); + this->set_current_data_size_for_child(aligned_offset_in_section + + posd->data_size()); + } } // Add arbitrary data to an output section by Input_section. @@ -1809,6 +1842,17 @@ Output_section::set_final_data_size() this->set_data_size(off - startoff); } +// Reset the address and file offset. + +void +Output_section::do_reset_address_and_file_offset() +{ + for (Input_section_list::iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + p->reset_address_and_file_offset(); +} + // Set the TLS offset. Called only for SHT_TLS sections. void @@ -1863,7 +1907,7 @@ Output_section::do_write(Output_file* of) { std::string fill_data(parameters->target()->code_fill(p->length())); of->write(output_section_file_offset + p->section_offset(), - fill_data.data(), fill_data.size()); + fill_data.data(), fill_data.size()); } for (Input_section_list::iterator p = this->input_sections_.begin(); @@ -1917,7 +1961,8 @@ Output_section::write_to_postprocessing_buffer() ++p) { std::string fill_data(target->code_fill(p->length())); - memcpy(buffer + p->section_offset(), fill_data.data(), fill_data.size()); + memcpy(buffer + p->section_offset(), fill_data.data(), + fill_data.size()); } off_t off = this->first_input_offset_; @@ -1931,6 +1976,89 @@ Output_section::write_to_postprocessing_buffer() } } +// Get the input sections for linker script processing. We leave +// behind the Output_section_data entries. Note that this may be +// slightly incorrect for merge sections. We will leave them behind, +// but it is possible that the script says that they should follow +// some other input sections, as in: +// .rodata { *(.rodata) *(.rodata.cst*) } +// For that matter, we don't handle this correctly: +// .rodata { foo.o(.rodata.cst*) *(.rodata.cst*) } +// With luck this will never matter. + +uint64_t +Output_section::get_input_sections( + uint64_t address, + const std::string& fill, + std::list<std::pair<Relobj*, unsigned int> >* input_sections) +{ + uint64_t orig_address = address; + + address = align_address(address, this->addralign()); + + Input_section_list remaining; + for (Input_section_list::iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + { + if (p->is_input_section()) + input_sections->push_back(std::make_pair(p->relobj(), p->shndx())); + else + { + uint64_t aligned_address = align_address(address, p->addralign()); + if (aligned_address != address && !fill.empty()) + { + section_size_type length = + convert_to_section_size_type(aligned_address - address); + std::string this_fill; + this_fill.reserve(length); + while (this_fill.length() + fill.length() <= length) + this_fill += fill; + if (this_fill.length() < length) + this_fill.append(fill, 0, length - this_fill.length()); + + Output_section_data* posd = new Output_data_const(this_fill, 0); + remaining.push_back(Input_section(posd)); + } + address = aligned_address; + + remaining.push_back(*p); + + p->finalize_data_size(); + address += p->data_size(); + } + } + + this->input_sections_.swap(remaining); + this->first_input_offset_ = 0; + + uint64_t data_size = address - orig_address; + this->set_current_data_size_for_child(data_size); + return data_size; +} + +// Add an input section from a script. + +void +Output_section::add_input_section_for_script(Relobj* object, + unsigned int shndx, + off_t data_size, + uint64_t addralign) +{ + if (addralign > this->addralign_) + this->addralign_ = addralign; + + off_t offset_in_section = this->current_data_size_for_child(); + off_t aligned_offset_in_section = align_address(offset_in_section, + addralign); + + this->set_current_data_size_for_child(aligned_offset_in_section + + data_size); + + this->input_sections_.push_back(Input_section(object, shndx, + data_size, addralign)); +} + // Print stats for merge sections to stderr. void @@ -1951,12 +2079,14 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) vaddr_(0), paddr_(0), memsz_(0), - align_(0), + max_align_(0), + min_p_align_(0), offset_(0), filesz_(0), type_(type), flags_(flags), - is_align_known_(false) + is_max_align_known_(false), + are_addresses_set_(false) { } @@ -1968,7 +2098,7 @@ Output_segment::add_output_section(Output_section* os, bool front) { gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); - gold_assert(!this->is_align_known_); + gold_assert(!this->is_max_align_known_); // Update the segment flags. this->flags_ |= seg_flags; @@ -2069,38 +2199,37 @@ Output_segment::add_output_section(Output_section* os, void Output_segment::add_initial_output_data(Output_data* od) { - gold_assert(!this->is_align_known_); + gold_assert(!this->is_max_align_known_); this->output_data_.push_front(od); } // Return the maximum alignment of the Output_data in Output_segment. -// Once we compute this, we prohibit new sections from being added. uint64_t -Output_segment::addralign() +Output_segment::maximum_alignment() { - if (!this->is_align_known_) + if (!this->is_max_align_known_) { uint64_t addralign; - addralign = Output_segment::maximum_alignment(&this->output_data_); - if (addralign > this->align_) - this->align_ = addralign; + addralign = Output_segment::maximum_alignment_list(&this->output_data_); + if (addralign > this->max_align_) + this->max_align_ = addralign; - addralign = Output_segment::maximum_alignment(&this->output_bss_); - if (addralign > this->align_) - this->align_ = addralign; + addralign = Output_segment::maximum_alignment_list(&this->output_bss_); + if (addralign > this->max_align_) + this->max_align_ = addralign; - this->is_align_known_ = true; + this->is_max_align_known_ = true; } - return this->align_; + return this->max_align_; } // Return the maximum alignment of a list of Output_data. uint64_t -Output_segment::maximum_alignment(const Output_data_list* pdl) +Output_segment::maximum_alignment_list(const Output_data_list* pdl) { uint64_t ret = 0; for (Output_data_list::const_iterator p = pdl->begin(); @@ -2136,33 +2265,41 @@ Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const return count; } -// Set the section addresses for an Output_segment. ADDR is the -// address and *POFF is the file offset. Set the section indexes -// starting with *PSHNDX. Return the address of the immediately -// following segment. Update *POFF and *PSHNDX. +// Set the section addresses for an Output_segment. If RESET is true, +// reset the addresses first. ADDR is the address and *POFF is the +// file offset. Set the section indexes starting with *PSHNDX. +// Return the address of the immediately following segment. Update +// *POFF and *PSHNDX. uint64_t -Output_segment::set_section_addresses(uint64_t addr, off_t* poff, +Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff, unsigned int* pshndx) { gold_assert(this->type_ == elfcpp::PT_LOAD); - this->vaddr_ = addr; - this->paddr_ = addr; + if (!reset && this->are_addresses_set_) + { + gold_assert(this->paddr_ == addr); + addr = this->vaddr_; + } + else + { + this->vaddr_ = addr; + this->paddr_ = addr; + this->are_addresses_set_ = true; + } off_t orig_off = *poff; this->offset_ = orig_off; - *poff = align_address(*poff, this->addralign()); - - addr = this->set_section_list_addresses(&this->output_data_, addr, poff, - pshndx); + addr = this->set_section_list_addresses(reset, &this->output_data_, + addr, poff, pshndx); this->filesz_ = *poff - orig_off; off_t off = *poff; - uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr, - poff, pshndx); + uint64_t ret = this->set_section_list_addresses(reset, &this->output_bss_, + addr, poff, pshndx); this->memsz_ = *poff - orig_off; // Ignore the file offset adjustments made by the BSS Output_data @@ -2176,7 +2313,7 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff, // structures. uint64_t -Output_segment::set_section_list_addresses(Output_data_list* pdl, +Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl, uint64_t addr, off_t* poff, unsigned int* pshndx) { @@ -2188,7 +2325,23 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl, ++p) { off = align_address(off, (*p)->addralign()); - (*p)->set_address_and_file_offset(addr + (off - startoff), off); + + 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); + 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); + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); + } // Unless this is a PT_TLS segment, we want to ignore the size // of a SHF_TLS/SHT_NOBITS section. Such a section does not @@ -2217,12 +2370,15 @@ Output_segment::set_offset() { gold_assert(this->type_ != elfcpp::PT_LOAD); + gold_assert(!this->are_addresses_set_); + if (this->output_data_.empty() && this->output_bss_.empty()) { this->vaddr_ = 0; this->paddr_ = 0; + this->are_addresses_set_ = true; this->memsz_ = 0; - this->align_ = 0; + this->min_p_align_ = 0; this->offset_ = 0; this->filesz_ = 0; return; @@ -2234,7 +2390,10 @@ Output_segment::set_offset() else first = this->output_data_.front(); this->vaddr_ = first->address(); - this->paddr_ = this->vaddr_; + this->paddr_ = (first->has_load_address() + ? first->load_address() + : this->vaddr_); + this->are_addresses_set_ = true; this->offset_ = first->offset(); if (this->output_data_.empty()) @@ -2275,6 +2434,26 @@ Output_segment::set_tls_offsets() (*p)->set_tls_offset(this->vaddr_); } +// Return the address of the first section. + +uint64_t +Output_segment::first_section_load_address() const +{ + for (Output_data_list::const_iterator p = this->output_data_.begin(); + p != this->output_data_.end(); + ++p) + if ((*p)->is_section()) + return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address(); + + for (Output_data_list::const_iterator p = this->output_bss_.begin(); + p != this->output_bss_.end(); + ++p) + if ((*p)->is_section()) + return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address(); + + gold_unreachable(); +} + // Return the number of Output_sections in an Output_segment. unsigned int @@ -2313,7 +2492,7 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) ophdr->put_p_filesz(this->filesz_); ophdr->put_p_memsz(this->memsz_); ophdr->put_p_flags(this->flags_); - ophdr->put_p_align(this->addralign()); + ophdr->put_p_align(std::max(this->min_p_align_, this->maximum_alignment())); } // Write the section headers into V. @@ -2534,7 +2713,8 @@ Output_section::add_input_section<32, false>( unsigned int shndx, const char* secname, const elfcpp::Shdr<32, false>& shdr, - unsigned int reloc_shndx); + unsigned int reloc_shndx, + bool have_sections_script); #endif #ifdef HAVE_TARGET_32_BIG @@ -2545,7 +2725,8 @@ Output_section::add_input_section<32, true>( unsigned int shndx, const char* secname, const elfcpp::Shdr<32, true>& shdr, - unsigned int reloc_shndx); + unsigned int reloc_shndx, + bool have_sections_script); #endif #ifdef HAVE_TARGET_64_LITTLE @@ -2556,7 +2737,8 @@ Output_section::add_input_section<64, false>( unsigned int shndx, const char* secname, const elfcpp::Shdr<64, false>& shdr, - unsigned int reloc_shndx); + unsigned int reloc_shndx, + bool have_sections_script); #endif #ifdef HAVE_TARGET_64_BIG @@ -2567,7 +2749,8 @@ Output_section::add_input_section<64, true>( unsigned int shndx, const char* secname, const elfcpp::Shdr<64, true>& shdr, - unsigned int reloc_shndx); + unsigned int reloc_shndx, + bool have_sections_script); #endif #ifdef HAVE_TARGET_32_LITTLE diff --git a/gold/output.h b/gold/output.h index 96c0247..1354551 100644 --- a/gold/output.h +++ b/gold/output.h @@ -88,11 +88,32 @@ class Output_data return this->offset_; } + // Reset the address and file offset. This essentially disables the + // sanity testing about duplicate and unknown settings. + void + reset_address_and_file_offset() + { + this->is_address_valid_ = false; + this->is_offset_valid_ = false; + this->is_data_size_valid_ = false; + this->do_reset_address_and_file_offset(); + } + // Return the required alignment. uint64_t addralign() const { return this->do_addralign(); } + // Return whether this has a load address. + bool + has_load_address() const + { return this->do_has_load_address(); } + + // Return the load address. + uint64_t + load_address() const + { return this->do_load_address(); } + // Return whether this is an Output_section. bool is_section() const @@ -224,6 +245,16 @@ class Output_data virtual uint64_t do_addralign() const = 0; + // Return whether this has a load address. + virtual bool + do_has_load_address() const + { return false; } + + // Return the load address. + virtual uint64_t + do_load_address() const + { gold_unreachable(); } + // Return whether this is an Output_section. virtual bool do_is_section() const @@ -258,6 +289,11 @@ class Output_data set_final_data_size() { gold_unreachable(); } + // A hook for resetting the address and file offset. + virtual void + do_reset_address_and_file_offset() + { } + // Set the TLS offset. Called only for SHT_TLS sections. virtual void do_set_tls_offset(uint64_t) @@ -1491,13 +1527,16 @@ class Output_section : public Output_data // Add a new input section SHNDX, named NAME, with header SHDR, from // object OBJECT. RELOC_SHNDX is the index of a relocation section // which applies to this section, or 0 if none, or -1U if more than - // one. Return the offset within the output section. + // one. HAVE_SECTIONS_SCRIPT is true if we have a SECTIONS clause + // in a linker script; in that case we need to keep track of input + // sections associated with an output section. Return the offset + // within the output section. template<int size, bool big_endian> off_t add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx, const char *name, const elfcpp::Shdr<size, big_endian>& shdr, - unsigned int reloc_shndx); + unsigned int reloc_shndx, bool have_sections_script); // Add generated data POSD to this output section. void @@ -1527,6 +1566,14 @@ class Output_section : public Output_data void set_entsize(uint64_t v); + // Set the load address. + void + set_load_address(uint64_t load_address) + { + this->load_address_ = load_address; + this->has_load_address_ = true; + } + // Set the link field to the output section index of a section. void set_link_section(const Output_data* od) @@ -1709,12 +1756,53 @@ class Output_section : public Output_data uint64_t starting_output_address(const Relobj* object, unsigned int shndx) const; + // Record that this output section was found in the SECTIONS clause + // of a linker script. + void + set_found_in_sections_clause() + { this->found_in_sections_clause_ = true; } + + // Return whether this output section was found in the SECTIONS + // clause of a linker script. + bool + found_in_sections_clause() const + { return this->found_in_sections_clause_; } + // Write the section header into *OPHDR. template<int size, bool big_endian> void write_header(const Layout*, const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const; + // The next few calls are for linker script support. + + // Store the list of input sections for this Output_section into the + // list passed in. This removes the input sections, leaving only + // any Output_section_data elements. This returns the size of those + // Output_section_data elements. ADDRESS is the address of this + // output section. FILL is the fill value to use, in case there are + // any spaces between the remaining Output_section_data elements. + uint64_t + get_input_sections(uint64_t address, const std::string& fill, + std::list<std::pair<Relobj*, unsigned int > >*); + + // Add an input section from a script. + void + add_input_section_for_script(Relobj* object, unsigned int shndx, + off_t data_size, uint64_t addralign); + + // Set the current size of the output section. + void + set_current_data_size(off_t size) + { this->set_current_data_size_for_child(size); } + + // Get the current size of the output section. + off_t + current_data_size() const + { return this->current_data_size_for_child(); } + + // End of linker script support. + // Print merge statistics to stderr. void print_merge_stats(); @@ -1732,7 +1820,7 @@ class Output_section : public Output_data void do_set_out_shndx(unsigned int shndx) { - gold_assert(this->out_shndx_ == -1U); + gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx); this->out_shndx_ = shndx; } @@ -1743,6 +1831,10 @@ class Output_section : public Output_data virtual void set_final_data_size(); + // Reset the address and file offset. + void + do_reset_address_and_file_offset(); + // Write the data to the file. For a typical Output_section, this // does nothing: the data is written out by calling Object::Relocate // on each input object. But if there are any Output_section_data @@ -1755,6 +1847,19 @@ class Output_section : public Output_data do_addralign() const { return this->addralign_; } + // Return whether there is a load address. + bool + do_has_load_address() const + { return this->has_load_address_; } + + // Return the load address. + uint64_t + do_load_address() const + { + gold_assert(this->has_load_address_); + return this->load_address_; + } + // Return whether this is an Output_section. bool do_is_section() const @@ -1877,6 +1982,15 @@ class Output_section : public Output_data off_t data_size() const; + // Whether this is an input section. + bool + is_input_section() const + { + return (this->shndx_ != OUTPUT_SECTION_CODE + && this->shndx_ != MERGE_DATA_SECTION_CODE + && this->shndx_ != MERGE_STRING_SECTION_CODE); + } + // Return whether this is a merge section which matches the // parameters. bool @@ -1890,6 +2004,22 @@ class Output_section : public Output_data && this->addralign() == addralign); } + // Return the object for an input section. + Relobj* + relobj() const + { + gold_assert(this->is_input_section()); + return this->u2_.object; + } + + // Return the input section index for an input section. + unsigned int + shndx() const + { + gold_assert(this->is_input_section()); + return this->shndx_; + } + // Set the output section. void set_output_section(Output_section* os) @@ -1905,6 +2035,10 @@ class Output_section : public Output_data set_address_and_file_offset(uint64_t address, off_t file_offset, off_t section_file_offset); + // Reset the address and file offset. + void + reset_address_and_file_offset(); + // Finalize the data size. void finalize_data_size(); @@ -1968,15 +2102,6 @@ class Output_section : public Output_data MERGE_STRING_SECTION_CODE = -3U }; - // Whether this is an input section. - bool - is_input_section() const - { - return (this->shndx_ != OUTPUT_SECTION_CODE - && this->shndx_ != MERGE_DATA_SECTION_CODE - && this->shndx_ != MERGE_STRING_SECTION_CODE); - } - // For an ordinary input section, this is the section index in the // input file. For an Output_section_data, this is // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or @@ -2007,15 +2132,16 @@ class Output_section : public Output_data typedef std::vector<Input_section> Input_section_list; // Fill data. This is used to fill in data between input sections. - // When we have to keep track of the input sections, we can use an - // Output_data_const, but we don't want to have to keep track of - // input sections just to implement fills. For a fill we record the - // offset, and the actual data to be written out. + // It is also used for data statements (BYTE, WORD, etc.) in linker + // scripts. When we have to keep track of the input sections, we + // can use an Output_data_const, but we don't want to have to keep + // track of input sections just to implement fills. class Fill { public: Fill(off_t section_offset, off_t length) - : section_offset_(section_offset), length_(length) + : section_offset_(section_offset), + length_(convert_to_section_size_type(length)) { } // Return section offset. @@ -2024,7 +2150,7 @@ class Output_section : public Output_data { return this->section_offset_; } // Return fill length. - off_t + section_size_type length() const { return this->length_; } @@ -2032,7 +2158,7 @@ class Output_section : public Output_data // The offset within the output section. off_t section_offset_; // The length of the space to fill. - off_t length_; + section_size_type length_; }; typedef std::vector<Fill> Fill_list; @@ -2064,6 +2190,10 @@ class Output_section : public Output_data uint64_t addralign_; // The section entry size. uint64_t entsize_; + // The load address. This is only used when using a linker script + // with a SECTIONS clause. The has_load_address_ field indicates + // whether this field is valid. + uint64_t load_address_; // The file offset is in the parent class. // Set the section link field to the index of this section. const Output_data* link_section_; @@ -2076,7 +2206,7 @@ class Output_section : public Output_data // The section type. const elfcpp::Elf_Word type_; // The section flags. - const elfcpp::Elf_Xword flags_; + elfcpp::Elf_Xword flags_; // The section index. unsigned int out_shndx_; // If there is a STT_SECTION for this output section in the normal @@ -2121,6 +2251,11 @@ class Output_section : public Output_data // Whether this section requires post processing after all // relocations have been applied. bool requires_postprocessing_ : 1; + // Whether an input section was mapped to this output section + // because of a SECTIONS clause in a linker script. + bool found_in_sections_clause_ : 1; + // Whether this section has an explicitly specified load address. + bool has_load_address_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; @@ -2168,7 +2303,7 @@ class Output_segment // Return the maximum alignment of the Output_data. uint64_t - addralign(); + maximum_alignment(); // Add an Output_section to this segment. void @@ -2189,23 +2324,40 @@ class Output_segment unsigned int dynamic_reloc_count() const; + // Return the address of the first section. + uint64_t + first_section_load_address() const; + + // Return whether the addresses have been set already. + bool + are_addresses_set() const + { return this->are_addresses_set_; } + + // Set the addresses. + void + set_addresses(uint64_t vaddr, uint64_t paddr) + { + this->vaddr_ = vaddr; + this->paddr_ = paddr; + this->are_addresses_set_ = true; + } + // Set the address of the segment to ADDR and the offset to *POFF - // (aligned if necessary), and set the addresses and offsets of all - // contained output sections accordingly. Set the section indexes - // of all contained output sections starting with *PSHNDX. Return - // the address of the immediately following segment. Update *POFF - // and *PSHNDX. This should only be called for a PT_LOAD segment. + // and set the addresses and offsets of all contained output + // sections accordingly. Set the section indexes of all contained + // output sections starting with *PSHNDX. If RESET is true, first + // reset the addresses of the contained sections. Return the + // address of the immediately following segment. Update *POFF and + // *PSHNDX. This should only be called for a PT_LOAD segment. uint64_t - set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx); + set_section_addresses(bool reset, uint64_t addr, off_t* poff, + unsigned int* pshndx); // Set the minimum alignment of this segment. This may be adjusted // upward based on the section alignments. void - set_minimum_addralign(uint64_t align) - { - gold_assert(!this->is_align_known_); - this->align_ = align; - } + set_minimum_p_align(uint64_t align) + { this->min_p_align_ = align; } // Set the offset of this segment based on the section. This should // only be called for a non-PT_LOAD segment. @@ -2244,12 +2396,12 @@ class Output_segment // Find the maximum alignment in an Output_data_list. static uint64_t - maximum_alignment(const Output_data_list*); + maximum_alignment_list(const Output_data_list*); // Set the section addresses in an Output_data_list. uint64_t - set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff, - unsigned int* pshndx); + set_section_list_addresses(bool reset, Output_data_list*, uint64_t addr, + off_t* poff, unsigned int* pshndx); // Return the number of Output_sections in an Output_data_list. unsigned int @@ -2276,10 +2428,17 @@ class Output_segment uint64_t paddr_; // The size of the segment in memory. uint64_t memsz_; - // The segment alignment. The is_align_known_ field indicates - // whether this has been finalized. It can be set to a minimum - // value before it is finalized. - uint64_t align_; + // The maximum section alignment. The is_max_align_known_ field + // indicates whether this has been finalized. + uint64_t max_align_; + // The required minimum value for the p_align field. This is used + // for PT_LOAD segments. Note that this does not mean that + // addresses should be aligned to this value; it means the p_paddr + // and p_vaddr fields must be congruent modulo this value. For + // non-PT_LOAD segments, the dynamic linker works more efficiently + // if the p_align field has the more conventional value, although it + // can align as needed. + uint64_t min_p_align_; // The offset of the segment data within the file. off_t offset_; // The size of the segment data in the file. @@ -2288,8 +2447,10 @@ class Output_segment elfcpp::Elf_Word type_; // The segment flags. elfcpp::Elf_Word flags_; - // Whether we have finalized align_. - bool is_align_known_; + // Whether we have finalized max_align_. + bool is_max_align_known_ : 1; + // Whether vaddr and paddr were set by a linker script. + bool are_addresses_set_ : 1; }; // This class represents the output file. diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in index b1cfa5a..e4411e2 100644 --- a/gold/po/POTFILES.in +++ b/gold/po/POTFILES.in @@ -45,6 +45,8 @@ resolve.cc script.cc script-c.h script.h +script-sections.cc +script-sections.h stringpool.cc stringpool.h symtab.cc diff --git a/gold/po/gold.pot b/gold/po/gold.pot index 8efe501..392b1c0 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-01-09 11:37-0800\n" +"POT-Creation-Date: 2008-02-01 22:48-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -61,7 +61,7 @@ msgstr "" msgid "%s: member at %zu is not an ELF object" msgstr "" -#: compressed_output.cc:126 +#: compressed_output.cc:127 msgid "not compressing section data: zlib error" msgstr "" @@ -70,115 +70,115 @@ msgstr "" msgid "%s: can not read directory: %s" msgstr "" -#: dynobj.cc:145 +#: dynobj.cc:147 #, c-format msgid "unexpected duplicate type %u section: %u, %u" msgstr "" -#: dynobj.cc:181 +#: dynobj.cc:183 #, c-format msgid "unexpected link in section %u header: %u != %u" msgstr "" -#: dynobj.cc:217 +#: dynobj.cc:219 #, c-format msgid "DYNAMIC section %u link out of range: %u" msgstr "" -#: dynobj.cc:225 +#: dynobj.cc:227 #, c-format msgid "DYNAMIC section %u link %u is not a strtab" msgstr "" -#: dynobj.cc:253 +#: dynobj.cc:255 #, c-format msgid "DT_SONAME value out of range: %lld >= %lld" msgstr "" -#: dynobj.cc:265 +#: dynobj.cc:267 #, c-format msgid "DT_NEEDED value out of range: %lld >= %lld" msgstr "" -#: dynobj.cc:278 +#: dynobj.cc:280 msgid "missing DT_NULL in dynamic segment" msgstr "" -#: dynobj.cc:323 +#: dynobj.cc:325 #, c-format msgid "invalid dynamic symbol table name index: %u" msgstr "" -#: dynobj.cc:330 +#: dynobj.cc:332 #, c-format msgid "dynamic symbol table name section has wrong type: %u" msgstr "" -#: dynobj.cc:404 object.cc:251 object.cc:589 +#: dynobj.cc:406 object.cc:251 object.cc:589 #, c-format msgid "bad section name offset for section %u: %lu" msgstr "" -#: dynobj.cc:433 +#: dynobj.cc:435 #, c-format msgid "duplicate definition for version %u" msgstr "" -#: dynobj.cc:462 +#: dynobj.cc:464 #, c-format msgid "unexpected verdef version %u" msgstr "" -#: dynobj.cc:478 +#: dynobj.cc:480 #, c-format msgid "verdef vd_cnt field too small: %u" msgstr "" -#: dynobj.cc:486 +#: dynobj.cc:488 #, c-format msgid "verdef vd_aux field out of range: %u" msgstr "" -#: dynobj.cc:497 +#: dynobj.cc:499 #, c-format msgid "verdaux vda_name field out of range: %u" msgstr "" -#: dynobj.cc:507 +#: dynobj.cc:509 #, c-format msgid "verdef vd_next field out of range: %u" msgstr "" -#: dynobj.cc:541 +#: dynobj.cc:543 #, c-format msgid "unexpected verneed version %u" msgstr "" -#: dynobj.cc:550 +#: dynobj.cc:552 #, c-format msgid "verneed vn_aux field out of range: %u" msgstr "" -#: dynobj.cc:564 +#: dynobj.cc:566 #, c-format msgid "vernaux vna_name field out of range: %u" msgstr "" -#: dynobj.cc:575 +#: dynobj.cc:577 #, c-format msgid "verneed vna_next field out of range: %u" msgstr "" -#: dynobj.cc:586 +#: dynobj.cc:588 #, c-format msgid "verneed vn_next field out of range: %u" msgstr "" -#: dynobj.cc:634 +#: dynobj.cc:636 msgid "size of dynamic symbols is not multiple of symbol size" msgstr "" -#: dynobj.cc:1316 +#: dynobj.cc:1355 #, c-format msgid "symbol %s has undefined version %s" msgstr "" @@ -203,64 +203,60 @@ msgstr "" msgid "%s: " msgstr "" -#: expression.cc:104 +#: expression.cc:113 #, c-format msgid "undefined symbol '%s' referenced in expression" msgstr "" -#: expression.cc:427 +#: expression.cc:566 msgid "DEFINED not implemented" msgstr "" -#: expression.cc:433 +#: expression.cc:572 msgid "SIZEOF_HEADERS not implemented" msgstr "" -#: expression.cc:439 +#: expression.cc:578 msgid "ALIGNOF not implemented" msgstr "" -#: expression.cc:445 +#: expression.cc:584 msgid "SIZEOF not implemented" msgstr "" -#: expression.cc:451 -msgid "ADDR not implemented" -msgstr "" - -#: expression.cc:457 +#: expression.cc:590 msgid "LOADADDR not implemented" msgstr "" -#: expression.cc:463 +#: expression.cc:596 msgid "ORIGIN not implemented" msgstr "" -#: expression.cc:469 +#: expression.cc:602 msgid "LENGTH not implemented" msgstr "" -#: expression.cc:475 +#: expression.cc:608 msgid "CONSTANT not implemented" msgstr "" -#: expression.cc:481 +#: expression.cc:614 msgid "ABSOLUTE not implemented" msgstr "" -#: expression.cc:487 +#: expression.cc:620 msgid "DATA_SEGMENT_ALIGN not implemented" msgstr "" -#: expression.cc:493 +#: expression.cc:626 msgid "DATA_SEGMENT_RELRO_END not implemented" msgstr "" -#: expression.cc:499 +#: expression.cc:632 msgid "DATA_SEGMENT_END not implemented" msgstr "" -#: expression.cc:505 +#: expression.cc:638 msgid "SEGMENT_START not implemented" msgstr "" @@ -319,34 +315,34 @@ msgstr "" msgid "%s: maximum bytes mapped for read at one time: %llu\n" msgstr "" -#: fileread.cc:628 +#: fileread.cc:642 #, c-format msgid "cannot find -l%s" msgstr "" -#: fileread.cc:655 +#: fileread.cc:669 #, c-format msgid "cannot find %s" msgstr "" -#: fileread.cc:666 +#: fileread.cc:680 #, c-format msgid "cannot open %s: %s" msgstr "" -#: gold.cc:72 +#: gold.cc:73 #, c-format msgid "%s: internal error in %s, at %s:%d\n" msgstr "" #. We had some input files, but we weren't able to open any of #. them. -#: gold.cc:118 gold.cc:166 +#: gold.cc:119 gold.cc:167 msgid "no input files" msgstr "" #. We print out just the first .so we see; there may be others. -#: gold.cc:181 +#: gold.cc:182 #, c-format msgid "cannot mix -static with dynamic object %s" msgstr "" @@ -412,42 +408,42 @@ msgid "pthread_cond_broadcast failed: %s" msgstr "" #. FIXME: This needs to specify the location somehow. -#: i386.cc:160 i386.cc:1484 x86_64.cc:172 x86_64.cc:1373 +#: i386.cc:160 i386.cc:1490 x86_64.cc:172 x86_64.cc:1375 msgid "missing expected TLS relocation" msgstr "" -#: i386.cc:810 x86_64.cc:764 x86_64.cc:978 +#: i386.cc:809 x86_64.cc:764 x86_64.cc:978 #, c-format msgid "%s: unsupported reloc %u against local symbol" msgstr "" -#: i386.cc:917 i386.cc:1213 x86_64.cc:889 x86_64.cc:1160 +#: i386.cc:916 i386.cc:1214 x86_64.cc:889 x86_64.cc:1162 #, c-format msgid "%s: unexpected reloc %u in object file" msgstr "" -#: i386.cc:1056 x86_64.cc:992 x86_64.cc:1256 +#: i386.cc:1055 x86_64.cc:992 x86_64.cc:1258 #, c-format msgid "%s: unsupported reloc %u against global symbol %s" msgstr "" -#: i386.cc:1367 +#: i386.cc:1368 #, c-format msgid "%s: unsupported RELA reloc section" msgstr "" -#: i386.cc:1627 x86_64.cc:1575 +#: i386.cc:1640 x86_64.cc:1577 #, c-format msgid "unexpected reloc %u in object file" msgstr "" -#: i386.cc:1659 i386.cc:1734 i386.cc:1741 i386.cc:1772 i386.cc:1825 -#: x86_64.cc:1596 x86_64.cc:1676 x86_64.cc:1700 +#: i386.cc:1672 i386.cc:1747 i386.cc:1754 i386.cc:1785 i386.cc:1838 +#: x86_64.cc:1598 x86_64.cc:1678 x86_64.cc:1702 #, c-format msgid "unsupported reloc %u" msgstr "" -#: i386.cc:1749 +#: i386.cc:1762 msgid "both SUN and GNU model TLS relocations" msgstr "" @@ -604,365 +600,378 @@ msgstr "" msgid "unable to parse script file %s" msgstr "" -#: options.cc:185 +#: options.cc:174 +#, c-format +msgid "unable to parse version script file %s" +msgstr "" + +#: options.cc:201 #, c-format msgid "" "Usage: %s [options] file...\n" "Options:\n" msgstr "" -#: options.cc:356 +#: options.cc:372 msgid "Allow unresolved references in shared libraries" msgstr "" -#: options.cc:360 +#: options.cc:376 msgid "Do not allow unresolved references in shared libraries" msgstr "" -#: options.cc:364 +#: options.cc:380 msgid "Only set DT_NEEDED for dynamic libs if used" msgstr "" -#: options.cc:367 +#: options.cc:383 msgid "Always DT_NEEDED for dynamic libs (default)" msgstr "" -#: options.cc:370 +#: options.cc:386 msgid "-l searches for shared libraries" msgstr "" -#: options.cc:374 +#: options.cc:390 msgid "-l does not search for shared libraries" msgstr "" -#: options.cc:377 +#: options.cc:393 msgid "Bind defined symbols locally" msgstr "" -#: options.cc:385 +#: options.cc:401 msgid "Compress .debug_* sections in the output file (default is none)" msgstr "" -#: options.cc:387 +#: options.cc:403 msgid "--compress-debug-sections=[none" msgstr "" -#: options.cc:387 +#: options.cc:403 msgid "]" msgstr "" -#: options.cc:390 +#: options.cc:406 msgid "Define a symbol" msgstr "" -#: options.cc:391 +#: options.cc:407 msgid "--defsym SYMBOL=EXPRESSION" msgstr "" -#: options.cc:393 +#: options.cc:409 msgid "Demangle C++ symbols in log messages" msgstr "" -#: options.cc:396 +#: options.cc:412 msgid "Do not demangle C++ symbols in log messages" msgstr "" -#: options.cc:399 +#: options.cc:415 msgid "Try to detect violations of the One Definition Rule" msgstr "" -#: options.cc:401 +#: options.cc:417 msgid "Set program start address" msgstr "" -#: options.cc:402 +#: options.cc:418 msgid "-e ADDRESS, --entry ADDRESS" msgstr "" -#: options.cc:404 +#: options.cc:420 msgid "Export all dynamic symbols" msgstr "" -#: options.cc:406 +#: options.cc:422 msgid "Create exception frame header" msgstr "" -#: options.cc:408 +#: options.cc:424 msgid "Set shared library name" msgstr "" -#: options.cc:409 +#: options.cc:425 msgid "-h FILENAME, -soname FILENAME" msgstr "" -#: options.cc:411 +#: options.cc:427 msgid "Set dynamic linker path" msgstr "" -#: options.cc:412 +#: options.cc:428 msgid "-I PROGRAM, --dynamic-linker PROGRAM" msgstr "" -#: options.cc:414 +#: options.cc:430 msgid "Search for library LIBNAME" msgstr "" -#: options.cc:415 +#: options.cc:431 msgid "-lLIBNAME, --library LIBNAME" msgstr "" -#: options.cc:417 +#: options.cc:433 msgid "Add directory to search path" msgstr "" -#: options.cc:418 +#: options.cc:434 msgid "-L DIR, --library-path DIR" msgstr "" -#: options.cc:420 +#: options.cc:436 msgid "Ignored for compatibility" msgstr "" -#: options.cc:422 +#: options.cc:438 msgid "Set output file name" msgstr "" -#: options.cc:423 +#: options.cc:439 msgid "-o FILE, --output FILE" msgstr "" -#: options.cc:425 +#: options.cc:441 msgid "Optimize output file size" msgstr "" -#: options.cc:426 +#: options.cc:442 msgid "-O level" msgstr "" -#: options.cc:428 +#: options.cc:444 msgid "Generate relocatable output" msgstr "" -#: options.cc:430 +#: options.cc:446 msgid "Add DIR to runtime search path" msgstr "" -#: options.cc:431 +#: options.cc:447 msgid "-R DIR, -rpath DIR" msgstr "" -#: options.cc:434 +#: options.cc:450 msgid "Add DIR to link time shared library search path" msgstr "" -#: options.cc:435 +#: options.cc:451 msgid "--rpath-link DIR" msgstr "" -#: options.cc:437 +#: options.cc:453 msgid "Strip all symbols" msgstr "" -#: options.cc:440 +#: options.cc:456 msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)" msgstr "" #. This must come after -Sdebug since it's a prefix of it. -#: options.cc:444 +#: options.cc:460 msgid "Strip debugging information" msgstr "" -#: options.cc:446 +#: options.cc:462 msgid "Generate shared library" msgstr "" -#: options.cc:448 +#: options.cc:464 msgid "Do not link against shared libraries" msgstr "" -#: options.cc:450 +#: options.cc:466 msgid "Print resource usage statistics" msgstr "" -#: options.cc:452 +#: options.cc:468 msgid "Set target system root directory" msgstr "" -#: options.cc:453 +#: options.cc:469 msgid "--sysroot DIR" msgstr "" -#: options.cc:454 +#: options.cc:470 msgid "Set the address of the .text section" msgstr "" -#: options.cc:455 +#: options.cc:471 msgid "-Ttext ADDRESS" msgstr "" #. This must come after -Ttext since it's a prefix of it. -#: options.cc:458 +#: options.cc:474 msgid "Read linker script" msgstr "" -#: options.cc:459 +#: options.cc:475 msgid "-T FILE, --script FILE" msgstr "" -#: options.cc:461 +#: options.cc:477 +msgid "Read version script" +msgstr "" + +#: options.cc:478 +msgid "--version-script FILE" +msgstr "" + +#: options.cc:480 msgid "Run the linker multi-threaded" msgstr "" -#: options.cc:463 +#: options.cc:482 msgid "Do not run the linker multi-threaded" msgstr "" -#: options.cc:465 +#: options.cc:484 msgid "Number of threads to use" msgstr "" -#: options.cc:466 +#: options.cc:485 msgid "--thread-count COUNT" msgstr "" -#: options.cc:469 +#: options.cc:488 msgid "Number of threads to use in initial pass" msgstr "" -#: options.cc:470 +#: options.cc:489 msgid "--thread-count-initial COUNT" msgstr "" -#: options.cc:473 +#: options.cc:492 msgid "Number of threads to use in middle pass" msgstr "" -#: options.cc:474 +#: options.cc:493 msgid "--thread-count-middle COUNT" msgstr "" -#: options.cc:477 +#: options.cc:496 msgid "Number of threads to use in final pass" msgstr "" -#: options.cc:478 +#: options.cc:497 msgid "--thread-count-final COUNT" msgstr "" -#: options.cc:481 +#: options.cc:500 msgid "Include all archive contents" msgstr "" -#: options.cc:485 +#: options.cc:504 msgid "Include only needed archive contents" msgstr "" -#: options.cc:490 +#: options.cc:509 msgid "" "Subcommands as follows:\n" " -z execstack Mark output as requiring executable stack\n" " -z noexecstack Mark output as not requiring executable stack" msgstr "" -#: options.cc:493 +#: options.cc:512 msgid "-z SUBCOMMAND" msgstr "" -#: options.cc:496 +#: options.cc:515 msgid "Start a library search group" msgstr "" -#: options.cc:498 +#: options.cc:517 msgid "End a library search group" msgstr "" -#: options.cc:500 +#: options.cc:519 msgid "Report usage information" msgstr "" -#: options.cc:502 +#: options.cc:521 msgid "Report version information" msgstr "" -#: options.cc:504 -msgid "Turn on debugging (all,task)" +#: options.cc:523 +msgid "Turn on debugging (all,task,script)" msgstr "" -#: options.cc:505 +#: options.cc:524 msgid "--debug=TYPE" msgstr "" -#: options.cc:600 +#: options.cc:620 #, c-format msgid "%s: unrecognized -z subcommand: %s\n" msgstr "" -#: options.cc:623 +#: options.cc:643 #, c-format msgid "%s: unrecognized --debug subcommand: %s\n" msgstr "" -#: options.cc:812 +#: options.cc:832 msgid "unexpected argument" msgstr "" -#: options.cc:819 options.cc:871 options.cc:952 +#: options.cc:839 options.cc:891 options.cc:972 msgid "missing argument" msgstr "" -#: options.cc:832 options.cc:880 +#: options.cc:852 options.cc:900 msgid "unknown option" msgstr "" -#: options.cc:898 +#: options.cc:918 #, c-format msgid "%s: missing group end\n" msgstr "" -#: options.cc:1026 +#: options.cc:1046 msgid "may not nest groups" msgstr "" -#: options.cc:1036 +#: options.cc:1056 msgid "group end without group start" msgstr "" -#: options.cc:1046 +#: options.cc:1066 #, c-format msgid "%s: use the --help option for usage information\n" msgstr "" -#: options.cc:1055 +#: options.cc:1075 #, c-format msgid "%s: %s: %s\n" msgstr "" -#: options.cc:1064 +#: options.cc:1084 #, c-format msgid "%s: -%c: %s\n" msgstr "" -#: options.h:358 +#: options.h:363 #, c-format msgid "invalid optimization level: %s" msgstr "" -#: options.h:404 +#: options.h:409 #, c-format msgid "unsupported argument to --compress-debug-sections: %s" msgstr "" -#: options.h:458 +#: options.h:463 #, c-format msgid "invalid argument to -Ttext: %s" msgstr "" -#: options.h:467 +#: options.h:472 #, c-format msgid "invalid thread count: %s" msgstr "" -#: options.h:475 +#: options.h:480 msgid "--threads not supported" msgstr "" @@ -971,42 +980,42 @@ msgstr "" msgid "invalid alignment %lu for section \"%s\"" msgstr "" -#: output.cc:2418 +#: output.cc:2416 #, c-format msgid "%s: open: %s" msgstr "" -#: output.cc:2438 +#: output.cc:2436 #, c-format msgid "%s: mremap: %s" msgstr "" -#: output.cc:2474 +#: output.cc:2472 #, c-format msgid "%s: lseek: %s" msgstr "" -#: output.cc:2477 output.cc:2514 +#: output.cc:2475 output.cc:2512 #, c-format msgid "%s: write: %s" msgstr "" -#: output.cc:2485 +#: output.cc:2483 #, c-format msgid "%s: mmap: %s" msgstr "" -#: output.cc:2495 +#: output.cc:2493 #, c-format msgid "%s: munmap: %s" msgstr "" -#: output.cc:2512 +#: output.cc:2510 #, c-format msgid "%s: write: unexpected 0 return-value" msgstr "" -#: output.cc:2524 +#: output.cc:2522 #, c-format msgid "%s: close: %s" msgstr "" @@ -1016,13 +1025,8 @@ msgstr "" msgid "%s: file is empty" msgstr "" -#: readsyms.cc:185 -#, c-format -msgid "%s: ordinary object found in input group" -msgstr "" - #. Here we have to handle any other input file types we need. -#: readsyms.cc:242 +#: readsyms.cc:231 #, c-format msgid "%s: not an object or archive" msgstr "" @@ -1075,14 +1079,14 @@ msgstr "" msgid "%s: previous definition here" msgstr "" -#: script.cc:1413 +#: script.cc:1890 #, c-format msgid "%s:%d:%d: %s" msgstr "" #. There are some options that we could handle here--e.g., #. -lLIBRARY. Should we bother? -#: script.cc:1539 +#: script.cc:2026 #, c-format msgid "" "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts " @@ -1104,51 +1108,51 @@ msgstr "" msgid "%s: %s Stringdata structures: %zu\n" msgstr "" -#: symtab.cc:603 +#: symtab.cc:627 #, c-format msgid "bad global symbol name offset %u at %zu" msgstr "" -#: symtab.cc:682 +#: symtab.cc:730 msgid "too few symbol versions" msgstr "" -#: symtab.cc:711 +#: symtab.cc:762 #, c-format msgid "bad symbol name offset %u at %zu" msgstr "" -#: symtab.cc:765 +#: symtab.cc:816 #, c-format msgid "versym for symbol %zu out of range: %u" msgstr "" -#: symtab.cc:773 +#: symtab.cc:824 #, c-format msgid "versym for symbol %zu has no name: %u" msgstr "" -#: symtab.cc:1499 symtab.cc:1715 +#: symtab.cc:1625 symtab.cc:1824 #, c-format msgid "%s: unsupported symbol section 0x%x" msgstr "" -#: symtab.cc:1839 +#: symtab.cc:1952 #, c-format msgid "%s: undefined reference to '%s'" msgstr "" -#: symtab.cc:1924 +#: symtab.cc:2037 #, c-format msgid "%s: symbol table entries: %zu; buckets: %zu\n" msgstr "" -#: symtab.cc:1927 +#: symtab.cc:2040 #, c-format msgid "%s: symbol table entries: %zu\n" msgstr "" -#: symtab.cc:1996 +#: symtab.cc:2109 #, c-format msgid "" "while linking %s: symbol '%s' defined in multiple places (possible ODR " @@ -1188,12 +1192,12 @@ msgstr "" msgid "%s failed: %s" msgstr "" -#: x86_64.cc:1281 +#: x86_64.cc:1283 #, c-format msgid "%s: unsupported REL reloc section" msgstr "" -#: x86_64.cc:1748 +#: x86_64.cc:1750 #, c-format msgid "unsupported reloc type %u" msgstr "" diff --git a/gold/script-sections.cc b/gold/script-sections.cc index de6da30..2505170 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -22,9 +22,17 @@ #include "gold.h" +#include <cstring> +#include <algorithm> +#include <list> #include <string> #include <vector> +#include <fnmatch.h> +#include "parameters.h" +#include "object.h" +#include "layout.h" +#include "output.h" #include "script-c.h" #include "script.h" #include "script-sections.h" @@ -45,6 +53,36 @@ class Sections_element virtual ~Sections_element() { } + // Add any symbol being defined to the symbol table. + virtual void + add_symbols_to_table(Symbol_table*) + { } + + // Finalize symbols and check assertions. + virtual void + finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*) + { } + + // Return the output section name to use for an input file name and + // section name. This only real implementation is in + // Output_section_definition. + virtual const char* + output_section_name(const char*, const char*, Output_section***) + { return NULL; } + + // Return whether to place an orphan output section after this + // element. + virtual bool + place_orphan_here(const Output_section *, bool*) const + { return false; } + + // Set section addresses. This includes applying assignments if the + // the expression is an absolute value. + virtual void + set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*) + { } + + // Print the element for debugging purposes. virtual void print(FILE* f) const = 0; }; @@ -59,6 +97,32 @@ class Sections_element_assignment : public Sections_element : assignment_(name, namelen, val, provide, hidden) { } + // Add the symbol to the symbol table. + void + add_symbols_to_table(Symbol_table* symtab) + { this->assignment_.add_to_table(symtab); } + + // Finalize the symbol. + void + finalize_symbols(Symbol_table* symtab, const Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value, + *dot_value); + } + + // Set the section address. There is no section here, but if the + // value is absolute, we set the symbol. This permits us to use + // absolute symbols when setting dot. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + this->assignment_.set_if_absolute(symtab, layout, true, *dot_has_value, + *dot_value); + } + + // Print for debugging. void print(FILE* f) const { @@ -70,6 +134,53 @@ class Sections_element_assignment : public Sections_element Symbol_assignment assignment_; }; +// An assignment to the dot symbol in a SECTIONS clause outside of an +// output section. + +class Sections_element_dot_assignment : public Sections_element +{ + public: + Sections_element_dot_assignment(Expression* val) + : val_(val) + { } + + // Finalize the symbol. + void + finalize_symbols(Symbol_table* symtab, const Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + bool dummy; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &dummy); + *dot_has_value = true; + } + + // Update the dot symbol while setting section addresses. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + bool is_absolute; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("dot set to non-absolute value")); + *dot_has_value = true; + } + + // Print for debugging. + void + print(FILE* f) const + { + fprintf(f, " . = "); + this->val_->print(f); + fprintf(f, "\n"); + } + + private: + Expression* val_; +}; + // An assertion in a SECTIONS clause outside of an output section. class Sections_element_assertion : public Sections_element @@ -80,6 +191,13 @@ class Sections_element_assertion : public Sections_element : assertion_(check, message, messagelen) { } + // Check the assertion. + void + finalize_symbols(Symbol_table* symtab, const Layout* layout, bool*, + uint64_t*) + { this->assertion_.check(symtab, layout); } + + // Print for debugging. void print(FILE* f) const { @@ -96,16 +214,62 @@ class Sections_element_assertion : public Sections_element class Output_section_element { public: + // A list of input sections. + typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list; + Output_section_element() { } virtual ~Output_section_element() { } + // Add any symbol being defined to the symbol table. + virtual void + add_symbols_to_table(Symbol_table*) + { } + + // Finalize symbols and check assertions. + virtual void + finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*) + { } + + // Return whether this element matches FILE_NAME and SECTION_NAME. + // The only real implementation is in Output_section_element_input. + virtual bool + match_name(const char*, const char*) const + { return false; } + + // Set section addresses. This includes applying assignments if the + // the expression is an absolute value. + virtual void + set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t, + uint64_t*, std::string*, Input_section_list*) + { } + + // Print the element for debugging purposes. virtual void print(FILE* f) const = 0; + + protected: + // Return a fill string that is LENGTH bytes long, filling it with + // FILL. + std::string + get_fill_string(const std::string* fill, section_size_type length) const; }; +std::string +Output_section_element::get_fill_string(const std::string* fill, + section_size_type length) const +{ + std::string this_fill; + this_fill.reserve(length); + while (this_fill.length() + fill->length() <= length) + this_fill += *fill; + if (this_fill.length() < length) + this_fill.append(*fill, 0, length - this_fill.length()); + return this_fill; +} + // A symbol assignment in an output section. class Output_section_element_assignment : public Output_section_element @@ -117,6 +281,32 @@ class Output_section_element_assignment : public Output_section_element : assignment_(name, namelen, val, provide, hidden) { } + // Add the symbol to the symbol table. + void + add_symbols_to_table(Symbol_table* symtab) + { this->assignment_.add_to_table(symtab); } + + // Finalize the symbol. + void + finalize_symbols(Symbol_table* symtab, const Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value, + *dot_value); + } + + // Set the section address. There is no section here, but if the + // value is absolute, we set the symbol. This permits us to use + // absolute symbols when setting dot. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, + uint64_t, uint64_t* dot_value, std::string*, + Input_section_list*) + { + this->assignment_.set_if_absolute(symtab, layout, true, true, *dot_value); + } + + // Print for debugging. void print(FILE* f) const { @@ -128,6 +318,81 @@ class Output_section_element_assignment : public Output_section_element Symbol_assignment assignment_; }; +// An assignment to the dot symbol in an output section. + +class Output_section_element_dot_assignment : public Output_section_element +{ + public: + Output_section_element_dot_assignment(Expression* val) + : val_(val) + { } + + // Finalize the symbol. + void + finalize_symbols(Symbol_table* symtab, const Layout* layout, + bool* dot_has_value, uint64_t* dot_value) + { + bool dummy; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &dummy); + *dot_has_value = true; + } + + // Update the dot symbol while setting section addresses. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, + uint64_t, uint64_t* dot_value, std::string*, + Input_section_list*); + + // Print for debugging. + void + print(FILE* f) const + { + fprintf(f, " . = "); + this->val_->print(f); + fprintf(f, "\n"); + } + + private: + Expression* val_; +}; + +// Update the dot symbol while setting section addresses. + +void +Output_section_element_dot_assignment::set_section_addresses( + Symbol_table* symtab, + Layout* layout, + Output_section* output_section, + uint64_t, + uint64_t* dot_value, + std::string* fill, + Input_section_list*) +{ + bool is_absolute; + uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, true, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("dot set to non-absolute value")); + if (next_dot < *dot_value) + gold_error(_("dot may not move backward")); + if (next_dot > *dot_value && output_section != NULL) + { + section_size_type length = convert_to_section_size_type(next_dot + - *dot_value); + Output_section_data* posd; + if (fill->empty()) + posd = new Output_data_fixed_space(length, 0); + else + { + std::string this_fill = this->get_fill_string(fill, length); + posd = new Output_data_const(this_fill, 0); + } + output_section->add_output_section_data(posd); + } + *dot_value = next_dot; +} + // An assertion in an output section. class Output_section_element_assertion : public Output_section_element @@ -158,10 +423,26 @@ class Output_section_element_data : public Output_section_element : size_(size), is_signed_(is_signed), val_(val) { } + // Finalize symbols--we just need to update dot. + void + finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t* dot_value) + { *dot_value += this->size_; } + + // Store the value in the section. + void + set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t, + uint64_t* dot_value, std::string*, + Input_section_list*); + + // Print for debugging. void print(FILE*) const; private: + template<bool big_endian> + std::string + set_fill_string(uint64_t); + // The size in bytes. int size_; // Whether the value is signed. @@ -170,6 +451,74 @@ class Output_section_element_data : public Output_section_element Expression* val_; }; +// Store the value in the section. + +void +Output_section_element_data::set_section_addresses(Symbol_table* symtab, + Layout* layout, + Output_section* os, + uint64_t, + uint64_t* dot_value, + std::string*, + Input_section_list*) +{ + gold_assert(os != NULL); + + bool is_absolute; + uint64_t val = this->val_->eval_with_dot(symtab, layout, true, *dot_value, + &is_absolute); + if (!is_absolute) + gold_error(_("data directive with non-absolute value")); + + std::string fill; + if (parameters->is_big_endian()) + fill = this->set_fill_string<true>(val); + else + fill = this->set_fill_string<false>(val); + + os->add_output_section_data(new Output_data_const(fill, 0)); + + *dot_value += this->size_; +} + +// Get the value to store in a std::string. + +template<bool big_endian> +std::string + Output_section_element_data::set_fill_string(uint64_t val) +{ + std::string ret; + unsigned char buf[8]; + switch (this->size_) + { + case 1: + elfcpp::Swap_unaligned<8, big_endian>::writeval(buf, val); + ret.assign(reinterpret_cast<char*>(buf), 1); + break; + case 2: + elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val); + ret.assign(reinterpret_cast<char*>(buf), 2); + break; + case 4: + elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val); + ret.assign(reinterpret_cast<char*>(buf), 4); + break; + case 8: + if (parameters->get_size() == 32) + { + val &= 0xffffffff; + if (this->is_signed_ && (val & 0x80000000) != 0) + val |= 0xffffffff00000000LL; + } + elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val); + ret.assign(reinterpret_cast<char*>(buf), 8); + break; + default: + gold_unreachable(); + } + return ret; +} + // Print for debugging. void @@ -210,6 +559,25 @@ class Output_section_element_fill : public Output_section_element : val_(val) { } + // Update the fill value while setting section addresses. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, + uint64_t, uint64_t* dot_value, std::string* fill, + Input_section_list*) + { + bool is_absolute; + uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, true, + *dot_value, + &is_absolute); + if (!is_absolute) + gold_error(_("fill set to non-absolute value")); + // FIXME: The GNU linker supports fill values of arbitrary length. + unsigned char fill_buff[4]; + elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val); + fill->assign(reinterpret_cast<char*>(fill_buff), 4); + } + + // Print for debugging. void print(FILE* f) const { @@ -223,16 +591,43 @@ class Output_section_element_fill : public Output_section_element Expression* val_; }; +// Return whether STRING contains a wildcard character. This is used +// to speed up matching. + +static inline bool +is_wildcard_string(const std::string& s) +{ + return strpbrk(s.c_str(), "?*[") != NULL; +} + // 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); + // Finalize symbols--just update the value of the dot symbol. + void + finalize_symbols(Symbol_table*, const Layout*, bool* dot_has_value, + uint64_t* dot_value) + { + *dot_value = this->final_dot_value_; + *dot_has_value = true; + } + + // See whether we match FILE_NAME and SECTION_NAME as an input + // section. + bool + match_name(const char* file_name, const char* section_name) const; + + // Set the section address. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, + uint64_t subalign, uint64_t* dot_value, + std::string* fill, Input_section_list*); + + // Print for debugging. void print(FILE* f) const; @@ -241,20 +636,42 @@ class Output_section_element_input : public Output_section_element struct Input_section_pattern { std::string pattern; + bool pattern_is_wildcard; Sort_wildcard sort; Input_section_pattern(const char* patterna, size_t patternlena, Sort_wildcard sorta) - : pattern(patterna, patternlena), sort(sorta) + : pattern(patterna, patternlena), + pattern_is_wildcard(is_wildcard_string(this->pattern)), + sort(sorta) { } }; typedef std::vector<Input_section_pattern> Input_section_patterns; - typedef std::vector<std::string> Filename_exclusions; + // Filename_exclusions is a pair of filename pattern and a bool + // indicating whether the filename is a wildcard. + typedef std::vector<std::pair<std::string, bool> > Filename_exclusions; + + // Return whether STRING matches PATTERN, where IS_WILDCARD_PATTERN + // indicates whether this is a wildcard pattern. + static inline bool + match(const char* string, const char* pattern, bool is_wildcard_pattern) + { + return (is_wildcard_pattern + ? fnmatch(pattern, string, 0) == 0 + : strcmp(string, pattern) == 0); + } + + // See if we match a file name. + bool + match_file_name(const char* file_name) const; - // The file name pattern. + // The file name pattern. If this is the empty string, we match all + // files. std::string filename_pattern_; + // Whether the file name pattern is a wildcard. + bool filename_is_wildcard_; // How the file names should be sorted. This may only be // SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME. Sort_wildcard filename_sort_; @@ -264,6 +681,8 @@ class Output_section_element_input : public Output_section_element Input_section_patterns input_section_patterns_; // Whether to keep this section when garbage collecting. bool keep_; + // The value of dot after including all matching sections. + uint64_t final_dot_value_; }; // Construct Output_section_element_input. The parser records strings @@ -273,19 +692,32 @@ class Output_section_element_input : public Output_section_element 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_pattern_(), + filename_is_wildcard_(false), filename_sort_(spec->file.sort), filename_exclusions_(), input_section_patterns_(), - keep_(keep) + keep_(keep), + final_dot_value_(0) { + // The filename pattern "*" is common, and matches all files. Turn + // it into the empty string. + if (spec->file.name.length != 1 || spec->file.name.value[0] != '*') + this->filename_pattern_.assign(spec->file.name.value, + spec->file.name.length); + this->filename_is_wildcard_ = is_wildcard_string(this->filename_pattern_); + 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); + { + bool is_wildcard = is_wildcard_string(*p); + this->filename_exclusions_.push_back(std::make_pair(*p, + is_wildcard)); + } } if (spec->input_sections.sections != NULL) @@ -300,6 +732,253 @@ Output_section_element_input::Output_section_element_input( } } +// See whether we match FILE_NAME. + +bool +Output_section_element_input::match_file_name(const char* file_name) const +{ + if (!this->filename_pattern_.empty()) + { + // If we were called with no filename, we refuse to match a + // pattern which requires a file name. + if (file_name == NULL) + return false; + + if (!match(file_name, this->filename_pattern_.c_str(), + this->filename_is_wildcard_)) + return false; + } + + if (file_name != NULL) + { + // Now we have to see whether FILE_NAME matches one of the + // exclusion patterns, if any. + for (Filename_exclusions::const_iterator p = + this->filename_exclusions_.begin(); + p != this->filename_exclusions_.end(); + ++p) + { + if (match(file_name, p->first.c_str(), p->second)) + return false; + } + } + + return true; +} + +// See whether we match FILE_NAME and SECTION_NAME. + +bool +Output_section_element_input::match_name(const char* file_name, + const char* section_name) const +{ + if (!this->match_file_name(file_name)) + return false; + + // If there are no section name patterns, then we match. + if (this->input_section_patterns_.empty()) + return true; + + // See whether we match the section name patterns. + for (Input_section_patterns::const_iterator p = + this->input_section_patterns_.begin(); + p != this->input_section_patterns_.end(); + ++p) + { + if (match(section_name, p->pattern.c_str(), p->pattern_is_wildcard)) + return true; + } + + // We didn't match any section names, so we didn't match. + return false; +} + +// Information we use to sort the input sections. + +struct Input_section_info +{ + Relobj* relobj; + unsigned int shndx; + std::string section_name; + uint64_t size; + uint64_t addralign; +}; + +// A class to sort the input sections. + +class Input_section_sorter +{ + public: + Input_section_sorter(Sort_wildcard filename_sort, Sort_wildcard section_sort) + : filename_sort_(filename_sort), section_sort_(section_sort) + { } + + bool + operator()(const Input_section_info&, const Input_section_info&) const; + + private: + Sort_wildcard filename_sort_; + Sort_wildcard section_sort_; +}; + +bool +Input_section_sorter::operator()(const Input_section_info& isi1, + const Input_section_info& isi2) const +{ + if (this->section_sort_ == SORT_WILDCARD_BY_NAME + || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT + || (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME + && isi1.addralign == isi2.addralign)) + { + if (isi1.section_name != isi2.section_name) + return isi1.section_name < isi2.section_name; + } + if (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT + || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT + || this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME) + { + if (isi1.addralign != isi2.addralign) + return isi1.addralign < isi2.addralign; + } + if (this->filename_sort_ == SORT_WILDCARD_BY_NAME) + { + if (isi1.relobj->name() != isi2.relobj->name()) + return isi1.relobj->name() < isi2.relobj->name(); + } + + // Otherwise we leave them in the same order. + return false; +} + +// Set the section address. Look in INPUT_SECTIONS for sections which +// match this spec, sort them as specified, and add them to the output +// section. + +void +Output_section_element_input::set_section_addresses( + Symbol_table*, + Layout*, + Output_section* output_section, + uint64_t subalign, + uint64_t* dot_value, + std::string* fill, + Input_section_list* input_sections) +{ + // We build a list of sections which match each + // Input_section_pattern. + + typedef std::vector<std::vector<Input_section_info> > Matching_sections; + size_t input_pattern_count = this->input_section_patterns_.size(); + if (input_pattern_count == 0) + input_pattern_count = 1; + Matching_sections matching_sections(input_pattern_count); + + // Look through the list of sections for this output section. Add + // each one which matches to one of the elements of + // MATCHING_SECTIONS. + + Input_section_list::iterator p = input_sections->begin(); + while (p != input_sections->end()) + { + // Calling section_name and section_addralign is not very + // efficient. + Input_section_info isi; + isi.relobj = p->first; + isi.shndx = p->second; + + // Lock the object so that we can get information about the + // section. This is OK since we know we are single-threaded + // here. + { + const Task* task = reinterpret_cast<const Task*>(-1); + Task_lock_obj<Object> tl(task, p->first); + + isi.section_name = p->first->section_name(p->second); + isi.size = p->first->section_size(p->second); + isi.addralign = p->first->section_addralign(p->second); + } + + if (!this->match_file_name(isi.relobj->name().c_str())) + ++p; + else if (this->input_section_patterns_.empty()) + { + matching_sections[0].push_back(isi); + p = input_sections->erase(p); + } + else + { + size_t i; + for (i = 0; i < input_pattern_count; ++i) + { + const Input_section_pattern& + isp(this->input_section_patterns_[i]); + if (match(isi.section_name.c_str(), isp.pattern.c_str(), + isp.pattern_is_wildcard)) + break; + } + + if (i >= this->input_section_patterns_.size()) + ++p; + else + { + matching_sections[i].push_back(isi); + p = input_sections->erase(p); + } + } + } + + // Look through MATCHING_SECTIONS. Sort each one as specified, + // using a stable sort so that we get the default order when + // sections are otherwise equal. Add each input section to the + // output section. + + for (size_t i = 0; i < input_pattern_count; ++i) + { + if (matching_sections[i].empty()) + continue; + + gold_assert(output_section != NULL); + + const Input_section_pattern& isp(this->input_section_patterns_[i]); + if (isp.sort != SORT_WILDCARD_NONE + || this->filename_sort_ != SORT_WILDCARD_NONE) + std::stable_sort(matching_sections[i].begin(), + matching_sections[i].end(), + Input_section_sorter(this->filename_sort_, + isp.sort)); + + for (std::vector<Input_section_info>::const_iterator p = + matching_sections[i].begin(); + p != matching_sections[i].end(); + ++p) + { + uint64_t this_subalign = p->addralign; + if (this_subalign < subalign) + this_subalign = subalign; + + uint64_t address = align_address(*dot_value, this_subalign); + + if (address > *dot_value && !fill->empty()) + { + section_size_type length = + convert_to_section_size_type(address - *dot_value); + std::string this_fill = this->get_fill_string(fill, length); + Output_section_data* posd = new Output_data_const(this_fill, 0); + output_section->add_output_section_data(posd); + } + + output_section->add_input_section_for_script(p->relobj, + p->shndx, + p->size, + this_subalign); + + *dot_value = address + p->size; + } + } + + this->final_dot_value_ = *dot_value; +} + // Print for debugging. void @@ -348,7 +1027,7 @@ Output_section_element_input::print(FILE* f) const { if (need_comma) fprintf(f, ", "); - fprintf(f, "%s", p->c_str()); + fprintf(f, "%s", p->first.c_str()); need_comma = true; } fprintf(f, ")"); @@ -410,6 +1089,8 @@ Output_section_element_input::print(FILE* f) const class Output_section_definition : public Sections_element { public: + typedef Output_section_element::Input_section_list Input_section_list; + Output_section_definition(const char* name, size_t namelen, const Parser_output_section_header* header); @@ -421,6 +1102,11 @@ class Output_section_definition : public Sections_element 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); @@ -437,6 +1123,29 @@ class Output_section_definition : public Sections_element void add_input_section(const Input_section_spec* spec, bool keep); + // Add any symbols being defined to the symbol table. + void + add_symbols_to_table(Symbol_table* symtab); + + // Finalize symbols and check assertions. + void + finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*); + + // Return the output section name to use for an input file name and + // section name. + const char* + output_section_name(const char* file_name, const char* section_name, + Output_section***); + + // Return whether to place an orphan section after this one. + bool + place_orphan_here(const Output_section *os, bool* exact) const; + + // Set the section address. + void + set_section_addresses(Symbol_table* symtab, Layout* layout, + bool* dot_has_value, uint64_t* dot_value); + // Print the contents to the FILE. This is for debugging. void print(FILE*) const; @@ -458,6 +1167,9 @@ class Output_section_definition : public Sections_element Expression* fill_; // The list of elements defining the section. Output_section_elements elements_; + // The Output_section created for this definition. This will be + // NULL if none was created. + Output_section* output_section_; }; // Constructor. @@ -472,7 +1184,8 @@ Output_section_definition::Output_section_definition( align_(header->align), subalign_(header->subalign), fill_(NULL), - elements_() + elements_(), + output_section_(NULL) { } @@ -501,6 +1214,15 @@ Output_section_definition::add_symbol_assignment(const char* name, this->elements_.push_back(p); } +// Add an assignment to the special dot symbol. + +void +Output_section_definition::add_dot_assignment(Expression* value) +{ + Output_section_element* p = new Output_section_element_dot_assignment(value); + this->elements_.push_back(p); +} + // Add an assertion. void @@ -543,6 +1265,281 @@ Output_section_definition::add_input_section(const Input_section_spec* spec, this->elements_.push_back(p); } +// Add any symbols being defined to the symbol table. + +void +Output_section_definition::add_symbols_to_table(Symbol_table* symtab) +{ + for (Output_section_elements::iterator p = this->elements_.begin(); + p != this->elements_.end(); + ++p) + (*p)->add_symbols_to_table(symtab); +} + +// Finalize symbols and check assertions. + +void +Output_section_definition::finalize_symbols(Symbol_table* symtab, + const Layout* layout, + bool* dot_has_value, + uint64_t* dot_value) +{ + if (this->output_section_ != NULL) + *dot_value = this->output_section_->address(); + else + { + uint64_t address = *dot_value; + if (this->address_ != NULL) + { + bool dummy; + address = this->address_->eval_with_dot(symtab, layout, + *dot_has_value, *dot_value, + &dummy); + } + if (this->align_ != NULL) + { + bool dummy; + uint64_t align = this->align_->eval_with_dot(symtab, layout, + *dot_has_value, + *dot_value, + &dummy); + address = align_address(address, align); + } + *dot_value = address; + } + *dot_has_value = true; + + for (Output_section_elements::iterator p = this->elements_.begin(); + p != this->elements_.end(); + ++p) + (*p)->finalize_symbols(symtab, layout, dot_has_value, dot_value); +} + +// 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) +{ + // Ask each element whether it matches NAME. + for (Output_section_elements::const_iterator p = this->elements_.begin(); + p != this->elements_.end(); + ++p) + { + if ((*p)->match_name(file_name, section_name)) + { + // We found a match for NAME, which means that it should go + // into this output section. + *slot = &this->output_section_; + return this->name_.c_str(); + } + } + + // We don't know about this section name. + return NULL; +} + +// Return whether to place an orphan output section after this +// section. + +bool +Output_section_definition::place_orphan_here(const Output_section *os, + bool* exact) const +{ + // Check for the simple case first. + if (this->output_section_ != NULL + && this->output_section_->type() == os->type() + && this->output_section_->flags() == os->flags()) + { + *exact = true; + return true; + } + + // Otherwise use some heuristics. + + if ((os->flags() & elfcpp::SHF_ALLOC) == 0) + return false; + + if (os->type() == elfcpp::SHT_NOBITS) + { + if (this->output_section_ != NULL + && this->output_section_->type() == elfcpp::SHT_NOBITS) + return true; + if (this->name_ == ".bss") + return true; + } + else if (os->type() == elfcpp::SHT_NOTE) + { + if (this->output_section_ != NULL + && this->output_section_->type() == elfcpp::SHT_NOTE) + return true; + if (this->name_ == ".interp" + || this->name_.compare(0, 5, ".note") == 0) + return true; + } + else if (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA) + { + if (this->output_section_ != NULL + && (this->output_section_->type() == elfcpp::SHT_REL + || this->output_section_->type() == elfcpp::SHT_RELA)) + return true; + if (this->name_.compare(0, 4, ".rel") == 0) + return true; + } + else if (os->type() == elfcpp::SHT_PROGBITS + && (os->flags() & elfcpp::SHF_WRITE) != 0) + { + if (this->output_section_ != NULL + && this->output_section_->type() == elfcpp::SHT_PROGBITS + && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0) + return true; + if (this->name_ == ".data") + return true; + } + else if (os->type() == elfcpp::SHT_PROGBITS + && (os->flags() & elfcpp::SHF_EXECINSTR) != 0) + { + if (this->output_section_ != NULL + && this->output_section_->type() == elfcpp::SHT_PROGBITS + && (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) != 0) + return true; + if (this->name_ == ".text") + return true; + } + else if (os->type() == elfcpp::SHT_PROGBITS) + { + if (this->output_section_ != NULL + && this->output_section_->type() == elfcpp::SHT_PROGBITS + && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0 + && (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) == 0) + return true; + if (this->name_ == ".rodata") + return true; + } + + return false; +} + +// Set the section address. Note that the OUTPUT_SECTION_ field will +// be NULL if no input sections were mapped to this output section. +// We still have to adjust dot and process symbol assignments. + +void +Output_section_definition::set_section_addresses(Symbol_table* symtab, + Layout* layout, + bool* dot_has_value, + uint64_t* dot_value) +{ + bool is_absolute; + uint64_t address; + if (this->address_ != NULL) + { + address = this->address_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("address of section %s is not absolute"), + this->name_.c_str()); + } + else + { + if (!*dot_has_value) + gold_error(_("no address given for section %s"), + this->name_.c_str()); + address = *dot_value; + } + + uint64_t align; + if (this->align_ == NULL) + { + if (this->output_section_ == NULL) + align = 0; + else + align = this->output_section_->addralign(); + } + else + { + align = this->align_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("alignment of section %s is not absolute"), + this->name_.c_str()); + if (this->output_section_ != NULL) + this->output_section_->set_addralign(align); + } + + address = align_address(address, align); + + *dot_value = address; + *dot_has_value = true; + + // 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_->set_address(address); + + if (this->load_address_ != NULL && this->output_section_ != NULL) + { + uint64_t load_address = + this->load_address_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("load address of section %s is not absolute"), + this->name_.c_str()); + this->output_section_->set_load_address(load_address); + } + + uint64_t subalign; + if (this->subalign_ == NULL) + subalign = 0; + else + { + subalign = this->subalign_->eval_with_dot(symtab, layout, *dot_has_value, + *dot_value, &is_absolute); + if (!is_absolute) + gold_error(_("subalign of section %s is not absolute"), + this->name_.c_str()); + } + + std::string fill; + if (this->fill_ != NULL) + { + // FIXME: The GNU linker supports fill values of arbitrary + // length. + uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout, + *dot_has_value, + *dot_value, + &is_absolute); + if (!is_absolute) + gold_error(_("fill of section %s is not absolute"), + this->name_.c_str()); + unsigned char fill_buff[4]; + elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val); + fill.assign(reinterpret_cast<char*>(fill_buff), 4); + } + + Input_section_list input_sections; + if (this->output_section_ != NULL) + { + // Get the list of input sections attached to this output + // section. This will leave the output section with only + // Output_section_data entries. + address += this->output_section_->get_input_sections(address, + fill, + &input_sections); + *dot_value = address; + } + + for (Output_section_elements::iterator p = this->elements_.begin(); + p != this->elements_.end(); + ++p) + (*p)->set_section_addresses(symtab, layout, this->output_section_, + subalign, dot_value, &fill, &input_sections); + + gold_assert(input_sections.empty()); +} + // Print for debugging. void @@ -597,6 +1594,98 @@ Output_section_definition::print(FILE* f) const fprintf(f, "\n"); } +// 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 +// sections in the appropriate place in the list of SECTIONS elements. + +class Orphan_output_section : public Sections_element +{ + public: + Orphan_output_section(Output_section* os) + : os_(os) + { } + + // Return whether to place an orphan section after this one. + bool + place_orphan_here(const Output_section *os, bool* exact) const; + + // Set section addresses. + void + set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*); + + // Print for debugging. + void + print(FILE* f) const + { + fprintf(f, " marker for orphaned output section %s\n", + this->os_->name()); + } + + private: + Output_section* os_; +}; + +// Whether to place another orphan section after this one. + +bool +Orphan_output_section::place_orphan_here(const Output_section* os, + bool* exact) const +{ + if (this->os_->type() == os->type() + && this->os_->flags() == os->flags()) + { + *exact = true; + return true; + } + return false; +} + +// Set section addresses. + +void +Orphan_output_section::set_section_addresses(Symbol_table*, Layout*, + bool* dot_has_value, + uint64_t* dot_value) +{ + typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list; + + if (!*dot_has_value) + gold_error(_("no address for orphan section %s"), this->os_->name()); + + uint64_t address = *dot_value; + address = align_address(address, this->os_->addralign()); + + if ((this->os_->flags() & elfcpp::SHF_ALLOC) != 0) + this->os_->set_address(address); + + Input_section_list input_sections; + address += this->os_->get_input_sections(address, "", &input_sections); + + for (Input_section_list::iterator p = input_sections.begin(); + p != input_sections.end(); + ++p) + { + uint64_t addralign; + uint64_t size; + + // We know what are single-threaded, so it is OK to lock the + // object. + { + const Task* task = reinterpret_cast<const Task*>(-1); + Task_lock_obj<Object> tl(task, p->first); + addralign = p->first->section_addralign(p->second); + size = p->first->section_size(p->second); + } + + address = align_address(address, addralign); + this->os_->add_input_section_for_script(p->first, p->second, size, 0); + address += size; + } + + *dot_value = address; +} + // Class Script_sections. Script_sections::Script_sections() @@ -647,6 +1736,20 @@ Script_sections::add_symbol_assignment(const char* name, size_t length, } } +// Add an assignment to the special dot symbol. + +void +Script_sections::add_dot_assignment(Expression* val) +{ + if (this->output_section_ != NULL) + this->output_section_->add_dot_assignment(val); + else + { + Sections_element* p = new Sections_element_dot_assignment(val); + this->sections_elements_->push_back(p); + } +} + // Add an assertion. void @@ -717,6 +1820,402 @@ Script_sections::add_input_section(const Input_section_spec* spec, bool keep) this->output_section_->add_input_section(spec, keep); } +// Add any symbols we are defining to the symbol table. + +void +Script_sections::add_symbols_to_table(Symbol_table* symtab) +{ + if (!this->saw_sections_clause_) + return; + for (Sections_elements::iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + (*p)->add_symbols_to_table(symtab); +} + +// Finalize symbols and check assertions. + +void +Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout) +{ + if (!this->saw_sections_clause_) + return; + bool dot_has_value = false; + uint64_t dot_value = 0; + for (Sections_elements::iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + (*p)->finalize_symbols(symtab, layout, &dot_has_value, &dot_value); +} + +// Return the name of the output section to use for an input file name +// and section name. + +const char* +Script_sections::output_section_name(const char* file_name, + const char* section_name, + Output_section*** output_section_slot) +{ + 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); + + if (ret != NULL) + { + // The special name /DISCARD/ means that the input section + // should be discarded. + if (strcmp(ret, "/DISCARD/") == 0) + { + *output_section_slot = NULL; + return NULL; + } + return ret; + } + } + + // If we couldn't find a mapping for the name, the output section + // gets the name of the input section. + + *output_section_slot = NULL; + + return section_name; +} + +// Place a marker for an orphan output section into the SECTIONS +// clause. + +void +Script_sections::place_orphan(Output_section* os) +{ + // Look for an output section definition which matches the output + // section. Put a marker after that section. + Sections_elements::iterator place = this->sections_elements_->end(); + for (Sections_elements::iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + { + bool exact; + if ((*p)->place_orphan_here(os, &exact)) + { + place = p; + if (exact) + break; + } + } + + // The insert function puts the new element before the iterator. + if (place != this->sections_elements_->end()) + ++place; + + this->sections_elements_->insert(place, new Orphan_output_section(os)); +} + +// Set the addresses of all the output sections. Walk through all the +// elements, tracking the dot symbol. Apply assignments which set +// absolute symbol values, in case they are used when setting dot. +// Fill in data statement values. As we find output sections, set the +// address, set the address of all associated input sections, and +// update dot. Return the segment which should hold the file header +// and segment headers, if any. + +Output_segment* +Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout) +{ + gold_assert(this->saw_sections_clause_); + + bool dot_has_value = false; + uint64_t dot_value = 0; + for (Sections_elements::iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + (*p)->set_section_addresses(symtab, layout, &dot_has_value, &dot_value); + + return this->create_segments(layout); +} + +// Sort the sections in order to put them into segments. + +class Sort_output_sections +{ + public: + bool + operator()(const Output_section* os1, const Output_section* os2) const; +}; + +bool +Sort_output_sections::operator()(const Output_section* os1, + const Output_section* os2) const +{ + // Sort first by the load address. + uint64_t lma1 = (os1->has_load_address() + ? os1->load_address() + : os1->address()); + uint64_t lma2 = (os2->has_load_address() + ? os2->load_address() + : os2->address()); + if (lma1 != lma2) + return lma1 < lma2; + + // Then sort by the virtual address. + if (os1->address() != os2->address()) + return os1->address() < os2->address(); + + // Sort TLS sections to the end. + bool tls1 = (os1->flags() & elfcpp::SHF_TLS) != 0; + bool tls2 = (os2->flags() & elfcpp::SHF_TLS) != 0; + if (tls1 != tls2) + return tls2; + + // Sort PROGBITS before NOBITS. + if (os1->type() == elfcpp::SHT_PROGBITS && os2->type() == elfcpp::SHT_NOBITS) + return true; + if (os1->type() == elfcpp::SHT_NOBITS && os2->type() == elfcpp::SHT_PROGBITS) + return false; + + // Otherwise we don't care. + return false; +} + +// Return whether OS is a BSS section. This is a SHT_NOBITS section. +// We treat a section with the SHF_TLS flag set as taking up space +// even if it is SHT_NOBITS (this is true of .tbss), as we allocate +// space for them in the file. + +bool +Script_sections::is_bss_section(const Output_section* os) +{ + return (os->type() == elfcpp::SHT_NOBITS + && (os->flags() & elfcpp::SHF_TLS) == 0); +} + +// Create the PT_LOAD segments when using a SECTIONS clause. Returns +// the segment which should hold the file header and segment headers, +// if any. + +Output_segment* +Script_sections::create_segments(Layout* layout) +{ + gold_assert(this->saw_sections_clause_); + + if (parameters->output_is_object()) + return NULL; + + Layout::Section_list sections; + layout->get_allocated_sections(§ions); + + // Sort the sections by address. + std::stable_sort(sections.begin(), sections.end(), Sort_output_sections()); + + this->create_note_and_tls_segments(layout, §ions); + + // Walk through the sections adding them to PT_LOAD segments. + const uint64_t abi_pagesize = parameters->target()->abi_pagesize(); + Output_segment* first_seg = NULL; + Output_segment* current_seg = NULL; + bool is_current_seg_readonly = true; + Layout::Section_list::iterator plast = sections.end(); + uint64_t last_vma = 0; + uint64_t last_lma = 0; + uint64_t last_size = 0; + for (Layout::Section_list::iterator p = sections.begin(); + p != sections.end(); + ++p) + { + const uint64_t vma = (*p)->address(); + const uint64_t lma = ((*p)->has_load_address() + ? (*p)->load_address() + : vma); + const uint64_t size = (*p)->current_data_size(); + + bool need_new_segment; + if (current_seg == NULL) + need_new_segment = true; + else if (lma - vma != last_lma - last_vma) + { + // This section has a different LMA relationship than the + // last one; we need a new segment. + need_new_segment = true; + } + else if (align_address(last_lma + last_size, abi_pagesize) + < align_address(lma, abi_pagesize)) + { + // Putting this section in the segment would require + // skipping a page. + need_new_segment = true; + } + else if (is_bss_section(*plast) && !is_bss_section(*p)) + { + // A non-BSS section can not follow a BSS section in the + // same segment. + need_new_segment = true; + } + else if (is_current_seg_readonly + && ((*p)->flags() & elfcpp::SHF_WRITE) != 0) + { + // Don't put a writable section in the same segment as a + // non-writable section. + need_new_segment = true; + } + else + { + // Otherwise, reuse the existing segment. + need_new_segment = false; + } + + elfcpp::Elf_Word seg_flags = + Layout::section_flags_to_segment((*p)->flags()); + + if (need_new_segment) + { + current_seg = layout->make_output_segment(elfcpp::PT_LOAD, + seg_flags); + current_seg->set_addresses(vma, lma); + if (first_seg == NULL) + first_seg = current_seg; + is_current_seg_readonly = true; + } + + current_seg->add_output_section(*p, seg_flags); + + if (((*p)->flags() & elfcpp::SHF_WRITE) != 0) + is_current_seg_readonly = false; + + plast = p; + last_vma = vma; + last_lma = lma; + last_size = size; + } + + // An ELF program should work even if the program headers are not in + // a PT_LOAD segment. However, it appears that the Linux kernel + // does not set the AT_PHDR auxiliary entry in that case. It sets + // the load address to p_vaddr - p_offset of the first PT_LOAD + // segment. It then sets AT_PHDR to the load address plus the + // offset to the program headers, e_phoff in the file header. This + // fails when the program headers appear in the file before the + // first PT_LOAD segment. Therefore, we always create a PT_LOAD + // segment to hold the file header and the program headers. This is + // effectively what the GNU linker does, and it is slightly more + // efficient in any case. We try to use the first PT_LOAD segment + // if we can, otherwise we make a new one. + + size_t segment_count = layout->segment_count(); + size_t file_header_size; + size_t segment_headers_size; + if (parameters->get_size() == 32) + { + file_header_size = elfcpp::Elf_sizes<32>::ehdr_size; + segment_headers_size = segment_count * elfcpp::Elf_sizes<32>::phdr_size; + } + else if (parameters->get_size() == 64) + { + file_header_size = elfcpp::Elf_sizes<64>::ehdr_size; + segment_headers_size = segment_count * elfcpp::Elf_sizes<64>::phdr_size; + } + else + gold_unreachable(); + + if (first_seg != NULL + && ((first_seg->paddr() & (abi_pagesize - 1)) + >= file_header_size + segment_headers_size)) + return first_seg; + + Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD, + elfcpp::PF_R); + if (first_seg == NULL) + load_seg->set_addresses(0, 0); + else + { + 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); + } + else + { + // We could handle this case by create the file header + // outside of any PT_LOAD segment, and creating a new + // PT_LOAD segment after the others to hold the segment + // headers. + gold_error(_("sections loaded on first page without room for " + "file and program headers are not supported")); + } + } + + return load_seg; +} + +// Create a PT_NOTE segment for each SHT_NOTE section and a PT_TLS +// segment if there are any SHT_TLS sections. + +void +Script_sections::create_note_and_tls_segments( + Layout* layout, + const Layout::Section_list* sections) +{ + bool saw_tls = false; + for (Layout::Section_list::const_iterator p = sections->begin(); + p != sections->end(); + ++p) + { + if ((*p)->type() == elfcpp::SHT_NOTE) + { + elfcpp::Elf_Word seg_flags = + Layout::section_flags_to_segment((*p)->flags()); + Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE, + seg_flags); + oseg->add_output_section(*p, seg_flags); + + // Incorporate any subsequent SHT_NOTE sections, in the + // hopes that the script is sensible. + Layout::Section_list::const_iterator pnext = p + 1; + while (pnext != sections->end() + && (*pnext)->type() == elfcpp::SHT_NOTE) + { + seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); + oseg->add_output_section(*pnext, seg_flags); + p = pnext; + ++pnext; + } + } + + if (((*p)->flags() & elfcpp::SHF_TLS) != 0) + { + if (saw_tls) + gold_error(_("TLS sections are not adjacent")); + + elfcpp::Elf_Word seg_flags = + Layout::section_flags_to_segment((*p)->flags()); + Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS, + seg_flags); + oseg->add_output_section(*p, seg_flags); + + Layout::Section_list::const_iterator pnext = p + 1; + while (pnext != sections->end() + && ((*pnext)->flags() & elfcpp::SHF_TLS) != 0) + { + seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); + oseg->add_output_section(*pnext, seg_flags); + p = pnext; + ++pnext; + } + + saw_tls = true; + } + } +} + // Print the SECTIONS clause to F for debugging. void diff --git a/gold/script-sections.h b/gold/script-sections.h index 4344325..6ac4303 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -37,6 +37,8 @@ struct Input_section_spec; class Expression; class Sections_element; class Output_section_definition; +class Output_section; +class Output_segment; class Script_sections { @@ -79,6 +81,11 @@ class Script_sections 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); @@ -91,6 +98,42 @@ class Script_sections void add_input_section(const Input_section_spec* spec, bool keep); + // 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. + const char* + output_section_name(const char* file_name, const char* section_name, + Output_section*** output_section_slot); + + // 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*); + // Print the contents to the FILE. This is for debugging. void print(FILE*) const; @@ -98,6 +141,18 @@ class Script_sections private: typedef std::vector<Sections_element*> Sections_elements; + // Create segments. + Output_segment* + create_segments(Layout*); + + // 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*); + // True if we ever saw a SECTIONS clause. bool saw_sections_clause_; // True if we are currently processing a SECTIONS clause. diff --git a/gold/script.cc b/gold/script.cc index 5b49a90..734349b 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -913,6 +913,29 @@ Symbol_assignment::add_to_table(Symbol_table* symtab) void Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) { + this->finalize_maybe_dot(symtab, layout, false, false, 0); +} + +// Finalize a symbol value which can refer to the dot symbol. + +void +Symbol_assignment::finalize_with_dot(Symbol_table* symtab, + const Layout* layout, + bool dot_has_value, + uint64_t dot_value) +{ + this->finalize_maybe_dot(symtab, layout, true, dot_has_value, dot_value); +} + +// Finalize a symbol value, internal version. + +void +Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab, + const Layout* layout, + bool is_dot_available, + bool dot_has_value, + uint64_t dot_value) +{ // If we were only supposed to provide this symbol, the sym_ field // will be NULL if the symbol was not referenced. if (this->sym_ == NULL) @@ -924,7 +947,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) if (parameters->get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) - this->sized_finalize<32>(symtab, layout); + this->sized_finalize<32>(symtab, layout, is_dot_available, dot_has_value, + dot_value); #else gold_unreachable(); #endif @@ -932,7 +956,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) else if (parameters->get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) - this->sized_finalize<64>(symtab, layout); + this->sized_finalize<64>(symtab, layout, is_dot_available, dot_has_value, + dot_value); #else gold_unreachable(); #endif @@ -943,10 +968,56 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) template<int size> void -Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout) -{ +Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout, + bool is_dot_available, bool dot_has_value, + uint64_t dot_value) +{ + bool dummy; + uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, + is_dot_available, + dot_has_value, dot_value, + &dummy); Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_); - ssym->set_value(this->val_->eval(symtab, layout)); + ssym->set_value(final_val); +} + +// Set the symbol value if the expression yields an absolute value. + +void +Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout, + bool is_dot_available, bool dot_has_value, + uint64_t dot_value) +{ + if (this->sym_ == NULL) + return; + + bool is_absolute; + uint64_t val = this->val_->eval_maybe_dot(symtab, layout, is_dot_available, + dot_has_value, dot_value, + &is_absolute); + if (!is_absolute) + return; + + if (parameters->get_size() == 32) + { +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) + Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(this->sym_); + ssym->set_value(val); +#else + gold_unreachable(); +#endif + } + else if (parameters->get_size() == 64) + { +#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) + Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(this->sym_); + ssym->set_value(val); +#else + gold_unreachable(); +#endif + } + else + gold_unreachable(); } // Print for debugging. @@ -1006,14 +1077,26 @@ Script_options::add_symbol_assignment(const char* name, size_t length, Expression* value, bool provide, bool hidden) { - if (this->script_sections_.in_sections_clause()) - this->script_sections_.add_symbol_assignment(name, length, value, - provide, hidden); + if (length != 1 || name[0] != '.') + { + if (this->script_sections_.in_sections_clause()) + this->script_sections_.add_symbol_assignment(name, length, value, + provide, hidden); + else + { + Symbol_assignment* p = new Symbol_assignment(name, length, value, + provide, hidden); + this->symbol_assignments_.push_back(p); + } + } else { - Symbol_assignment* p = new Symbol_assignment(name, length, value, - provide, hidden); - this->symbol_assignments_.push_back(p); + if (provide || hidden) + gold_error(_("invalid use of PROVIDE for dot symbol")); + if (!this->script_sections_.in_sections_clause()) + gold_error(_("invalid assignment to dot outside of SECTIONS")); + else + this->script_sections_.add_dot_assignment(value); } } @@ -1041,9 +1124,10 @@ Script_options::add_symbols_to_table(Symbol_table* symtab) p != this->symbol_assignments_.end(); ++p) (*p)->add_to_table(symtab); + this->script_sections_.add_symbols_to_table(symtab); } -// Finalize symbol values. +// Finalize symbol values. Also check assertions. void Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout) @@ -1052,6 +1136,29 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout) p != this->symbol_assignments_.end(); ++p) (*p)->finalize(symtab, layout); + + for (Assertions::iterator p = this->assertions_.begin(); + p != this->assertions_.end(); + ++p) + (*p)->check(symtab, layout); + + this->script_sections_.finalize_symbols(symtab, layout); +} + +// Set section addresses. We set all the symbols which have absolute +// values. Then we let the SECTIONS clause do its thing. This +// returns the segment which holds the file header and segment +// headers, if any. + +Output_segment* +Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout) +{ + for (Symbol_assignments::iterator p = this->symbol_assignments_.begin(); + p != this->symbol_assignments_.end(); + ++p) + (*p)->set_if_absolute(symtab, layout, false, false, 0); + + return this->script_sections_.set_section_addresses(symtab, layout); } // This class holds data passed through the parser to the lexer and to @@ -2279,8 +2386,13 @@ extern "C" String_sort_list_ptr script_string_sort_list_add(String_sort_list_ptr pv, const struct Wildcard_section* string_sort) { - pv->push_back(*string_sort); - return pv; + if (pv == NULL) + return script_new_string_sort_list(string_sort); + else + { + pv->push_back(*string_sort); + return pv; + } } // Create a new list of strings. diff --git a/gold/script.h b/gold/script.h index 24bd513..257b479 100644 --- a/gold/script.h +++ b/gold/script.h @@ -46,6 +46,7 @@ class Input_argument; class Input_objects; class Input_group; class Input_file; +class Output_segment; class Task_token; class Workqueue; struct Version_dependency_list; @@ -65,10 +66,27 @@ class Expression virtual ~Expression() { } - // Return the value of the expression. + // Return the value of the expression which is not permitted to + // refer to the dot symbol. uint64_t eval(const Symbol_table*, const Layout*); + // Return the value of an expression which is permitted to refer to + // the dot symbol. This sets *IS_ABSOLUTE to indicate whether this + // is an absolute value; it will be false if a non-absolute symbol + // was referenced in the expression; this is used to detect invalid + // uses when setting a section address. + uint64_t + eval_with_dot(const Symbol_table*, const Layout*, bool dot_has_value, + uint64_t dot_value, bool* is_absolute); + + // Return the value of an expression which may or may not be + // permitted to refer to the dot symbol, depending on + // is_dot_available. + uint64_t + eval_maybe_dot(const Symbol_table*, const Layout*, bool is_dot_available, + bool dot_has_value, uint64_t dot_value, bool* is_absolute); + // Print the expression to the FILE. This is for debugging. virtual void print(FILE*) const = 0; @@ -181,17 +199,35 @@ class Symbol_assignment add_to_table(Symbol_table*); // Finalize the symbol value. - void finalize(Symbol_table*, const Layout*); + void + finalize(Symbol_table*, const Layout*); + + // Finalize the symbol value when it can refer to the dot symbol. + void + finalize_with_dot(Symbol_table*, const Layout*, bool dot_has_value, + uint64_t dot_value); + + // Set the symbol value, but only if the value is absolute. This is + // used while processing a SECTIONS clause. + void + set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available, + bool dot_has_value, uint64_t dot_value); // Print the assignment to the FILE. This is for debugging. void print(FILE*) const; private: + // Shared by finalize and finalize_with_dot. + void + finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available, + bool dot_has_value, uint64_t dot_value); + // Sized version of finalize. template<int size> void - sized_finalize(Symbol_table*, const Layout*); + sized_finalize(Symbol_table*, const Layout*, bool is_dot_available, + bool dot_has_value, uint64_t dot_value); // Symbol name. std::string name_; @@ -274,7 +310,7 @@ class Script_options void add_symbols_to_table(Symbol_table*); - // Finalize the symbol values. + // Finalize the symbol values. Also check assertions. void finalize_symbols(Symbol_table*, const Layout*); @@ -290,6 +326,18 @@ class Script_options script_sections() { return &this->script_sections_; } + // Whether we saw a SECTIONS clause. + bool + saw_sections_clause() const + { return this->script_sections_.saw_sections_clause(); } + + // Set section addresses using a SECTIONS clause. Return the + // segment which should hold the file header and segment headers; + // this may return NULL, in which case the headers are not in a + // loadable segment. + Output_segment* + set_section_addresses(Symbol_table*, Layout*); + // Print the script to the FILE. This is for debugging. void print(FILE*) const; diff --git a/gold/symtab.cc b/gold/symtab.cc index 78bfec5..288b966 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -298,6 +298,25 @@ Symbol::final_value_is_known() const return parameters->doing_static_link(); } +// Return whether the symbol has an absolute value. + +bool +Symbol::value_is_absolute() const +{ + switch (this->source_) + { + case FROM_OBJECT: + return this->u_.from_object.shndx == elfcpp::SHN_ABS; + case IN_OUTPUT_DATA: + case IN_OUTPUT_SEGMENT: + return false; + case CONSTANT: + return true; + default: + gold_unreachable(); + } +} + // Class Symbol_table. Symbol_table::Symbol_table(unsigned int count, @@ -1336,7 +1355,8 @@ Symbol_table::do_define_as_constant( void Symbol_table::define_symbols(const Layout* layout, int count, - const Define_symbol_in_section* p) + const Define_symbol_in_section* p, + bool only_if_ref) { for (int i = 0; i < count; ++i, ++p) { @@ -1345,11 +1365,12 @@ Symbol_table::define_symbols(const Layout* layout, int count, this->define_in_output_data(p->name, NULL, os, p->value, p->size, p->type, p->binding, p->visibility, p->nonvis, - p->offset_is_from_end, p->only_if_ref); + p->offset_is_from_end, + only_if_ref || p->only_if_ref); else this->define_as_constant(p->name, NULL, 0, p->size, p->type, p->binding, p->visibility, p->nonvis, - p->only_if_ref); + only_if_ref || p->only_if_ref); } } @@ -1357,7 +1378,8 @@ Symbol_table::define_symbols(const Layout* layout, int count, void Symbol_table::define_symbols(const Layout* layout, int count, - const Define_symbol_in_segment* p) + const Define_symbol_in_segment* p, + bool only_if_ref) { for (int i = 0; i < count; ++i, ++p) { @@ -1368,11 +1390,12 @@ Symbol_table::define_symbols(const Layout* layout, int count, this->define_in_output_segment(p->name, NULL, os, p->value, p->size, p->type, p->binding, p->visibility, p->nonvis, - p->offset_base, p->only_if_ref); + p->offset_base, + only_if_ref || p->only_if_ref); else this->define_as_constant(p->name, NULL, 0, p->size, p->type, p->binding, p->visibility, p->nonvis, - p->only_if_ref); + only_if_ref || p->only_if_ref); } } diff --git a/gold/symtab.h b/gold/symtab.h index 73b0cb7..b60256e 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -552,6 +552,10 @@ class Symbol return true; } + // Return whether this symbol currently has an absolute value. + bool + value_is_absolute() const; + // Return whether there should be a warning for references to this // symbol. bool @@ -1053,13 +1057,17 @@ class Symbol_table elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, bool only_if_ref); - // Define a set of symbols in output sections. + // Define a set of symbols in output sections. If ONLY_IF_REF is + // true, only define them if they are referenced. void - define_symbols(const Layout*, int count, const Define_symbol_in_section*); + define_symbols(const Layout*, int count, const Define_symbol_in_section*, + bool only_if_ref); - // Define a set of symbols in output segments. + // Define a set of symbols in output segments. If ONLY_IF_REF is + // true, only defined them if they are referenced. void - define_symbols(const Layout*, int count, const Define_symbol_in_segment*); + define_symbols(const Layout*, int count, const Define_symbol_in_segment*, + bool only_if_ref); // Define SYM using a COPY reloc. POSD is the Output_data where the // symbol should be defined--typically a .dyn.bss section. VALUE is diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index e42b2b3..43d2a66 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -527,6 +527,11 @@ script_test_1_SOURCES = script_test_1.cc script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t +check_PROGRAMS += script_test_2 +script_test_2_SOURCES = script_test_2.cc script_test_2a.cc script_test_2b.cc +script_test_2_DEPENDENCIES = gcctestdir/ld script_test_2.t +script_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_2.t + if OBJDUMP_AND_CPPFILT check_SCRIPTS += ver_matching_test.sh check_DATA += ver_matching_test.stdout diff --git a/gold/testsuite/script_test_2.cc b/gold/testsuite/script_test_2.cc new file mode 100644 index 0000000..24771aa --- /dev/null +++ b/gold/testsuite/script_test_2.cc @@ -0,0 +1,69 @@ +// script_test_2.cc -- linker script test 2 for gold -*- C++ -*- + +// 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. + +// A test of some uses of the SECTIONS clause. Look at +// script_test_2.t to make sense of this test. + +#include <cassert> +#include <cstddef> +#include <cstring> +#include <stdint.h> + +extern char start_test_area[]; +extern char start_test_area_1[]; +extern char start_data[]; +extern char end_data[]; +extern char start_fill[]; +extern char end_fill[]; +extern char end_test_area[]; + +int +main(int, char**) +{ + assert(reinterpret_cast<uintptr_t>(start_test_area) == 0x20000001); + assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000010); + + // We should see the string from script_test_2b.o next. The + // subalign should move it up to 0x20000020. + for (int i = 0; i < 16; ++i) + assert(start_test_area_1[i] == 0); + assert(strcmp(start_test_area_1 + 16, "test b") == 0); + + // Next the string from script_test_2a.o, after the subalign. + for (int i = 16 + 7; i < 48; ++i) + assert(start_test_area_1[i] == 0); + assert(strcmp(start_test_area_1 + 48, "test a") == 0); + + // Move four bytes forward to start_data. + assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 48 + 7 + 4) + == reinterpret_cast<uintptr_t>(start_data)); + assert(memcmp(start_data, "\1\2\0\4\0\0\0\010\0\0\0\0\0\0\0", 15) == 0 + || memcmp(start_data, "\1\0\2\0\0\0\4\0\0\0\0\0\0\0\010", 15) == 0); + assert(end_data == start_data + 15); + + // Check that FILL works as expected. + assert(start_fill == end_data); + assert(memcmp(start_fill, "\x12\x34\x56\x78\x12\x34\x56\0", 8) == 0); + assert(end_fill == start_fill + 8); + + assert(end_test_area == end_fill); +} diff --git a/gold/testsuite/script_test_2.t b/gold/testsuite/script_test_2.t new file mode 100644 index 0000000..e02b7a9 --- /dev/null +++ b/gold/testsuite/script_test_2.t @@ -0,0 +1,63 @@ +/* script_test_2.t -- linker script test 2 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. */ + +SECTIONS +{ + /* With luck this will work everywhere. */ + . = 0x10000000; + + /* With luck this will be enough to get the program working. */ + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } + + /* Now the real test. */ + . = 0x20000001; + start_test_area = .; + .gold_test ALIGN(16) : SUBALIGN(32) { + start_test_area_1 = .; + + /* No sections should wind up here, because of the EXCLUDE_FILE. */ + *( EXCLUDE_FILE(script_test*) .gold_test) + + /* This should match only script_test_2b.o. */ + script_test_2b.o(.gold_test) + + /* This should match the remaining sections. */ + *(.gold_test) + + . = . + 4; + start_data = .; + BYTE(1) + SHORT(2) + LONG(4) + QUAD(8) + end_data = .; + + start_fill = .; + FILL(0x12345678); + . = . + 7; + BYTE(0) + end_fill = .; + } + end_test_area = .; +} diff --git a/gold/testsuite/script_test_2a.cc b/gold/testsuite/script_test_2a.cc new file mode 100644 index 0000000..f4a611c --- /dev/null +++ b/gold/testsuite/script_test_2a.cc @@ -0,0 +1,24 @@ +// script_test_2a.cc -- linker script test 2, file 1 -*- C++ -*- + +// 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. + +char script_test_string_a[] __attribute__ ((section(".gold_test"))) = + "test a"; diff --git a/gold/testsuite/script_test_2b.cc b/gold/testsuite/script_test_2b.cc new file mode 100644 index 0000000..5b6100b --- /dev/null +++ b/gold/testsuite/script_test_2b.cc @@ -0,0 +1,24 @@ +// script_test_2a.cc -- linker script test 2, file 2 -*- C++ -*- + +// 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. + +char script_test_string_b[] __attribute__ ((section(".gold_test"))) = + "test b"; diff --git a/gold/yyscript.y b/gold/yyscript.y index 33023dc..a037906 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -371,7 +371,8 @@ opt_phdr: | /* empty */ ; -/* The value to use to fill an output section. */ +/* The value to use to fill an output section. FIXME: This does not + handle a string of arbitrary length. */ opt_fill: '=' exp { $$ = $2; } |