From: Nick Clifton Date: Wed, 8 Sep 2010 16:10:33 +0000 (+0000) Subject: * README: Remove claim that MEMORY is not supported. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7f8cd8440375de26ebca766ab281c34522262b53;p=binutils-gdb.git * README: Remove claim that MEMORY is not supported. * expression.cc (script_exp_function_origin) (script_exp_function_length): Move from here to ... * script.cc: ... here. (script_set_section_region, script_add_memory) (script_parse_memory_attr, script_include_directive): New functions. * script-sections.cc (class Memory_region): New class. (class Output_section_definition): Add set_memory_region, set_section_vma, set_section_lma and get_section_name methods. (class Script_Sections): Add add_memory_region, find_memory_region, find_memory_region_origin, find_memory_region_length and set_memory_region methods. Have set_section_addresses method walk the list of set memory regions. Extend the print methos to display memory regions. * script-sections.h: Add prototypes for new methods. Add enum for MEMORY region attributes. * yyscript.y: Add support for parsing MEMORY regions. * script-c.h: Add prototypes for new functions. * testsuite/Makefile.am: Add test of MEMORY region functionality. * testsuite/Makefile.in: Regenerate. * testsuite/memory_test.sh: New script. * testsuite/memory_test.s: New assembler source file. * testsuite/memory_test.t: New linker script. --- diff --git a/gold/ChangeLog b/gold/ChangeLog index 667caaea451..45b3d7ccefc 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,32 @@ +2010-09-08 Nick Clifton + + * README: Remove claim that MEMORY is not supported. + * expression.cc (script_exp_function_origin) + (script_exp_function_length): Move from here to ... + * script.cc: ... here. + (script_set_section_region, script_add_memory) + (script_parse_memory_attr, script_include_directive): New + functions. + * script-sections.cc + (class Memory_region): New class. + (class Output_section_definition): Add set_memory_region, + set_section_vma, set_section_lma and get_section_name methods. + (class Script_Sections): Add add_memory_region, + find_memory_region, find_memory_region_origin, + find_memory_region_length and set_memory_region methods. + Have set_section_addresses method walk the list of set memory + regions. + Extend the print methos to display memory regions. + * script-sections.h: Add prototypes for new methods. + Add enum for MEMORY region attributes. + * yyscript.y: Add support for parsing MEMORY regions. + * script-c.h: Add prototypes for new functions. + * testsuite/Makefile.am: Add test of MEMORY region functionality. + * testsuite/Makefile.in: Regenerate. + * testsuite/memory_test.sh: New script. + * testsuite/memory_test.s: New assembler source file. + * testsuite/memory_test.t: New linker script. + 2010-08-27 Doug Kwan * gold/resolve.cc (Symbol_table::should_override): Let a weak diff --git a/gold/README b/gold/README index 80da4558aa7..43c6897c4e8 100644 --- a/gold/README +++ b/gold/README @@ -15,7 +15,6 @@ documentation for features which gold supports. gold supports most of the features of the GNU linker for ELF targets. Notable omissions--features of the GNU linker not currently supported in gold--are: - * MEMORY regions in linker scripts * MRI compatible linker scripts * cross-reference reports (--cref) * various other minor options diff --git a/gold/expression.cc b/gold/expression.cc index 6d18679971c..e630dad515d 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -1237,19 +1237,4 @@ script_exp_function_segment_start(const char* segment_name, default_value); } -// Functions for memory regions. These can not be implemented unless -// and until we implement memory regions. - -extern "C" Expression* -script_exp_function_origin(const char*, size_t) -{ - gold_fatal(_("ORIGIN not implemented")); -} - -extern "C" Expression* -script_exp_function_length(const char*, size_t) -{ - gold_fatal(_("LENGTH not implemented")); -} - } // End namespace gold. diff --git a/gold/layout.cc b/gold/layout.cc index 5edba48aae5..bfe6a5eea66 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -503,10 +503,15 @@ Layout::choose_output_section(const Relobj* relobj, const char* name, const char* file_name = relobj == NULL ? NULL : relobj->name().c_str(); Output_section** output_section_slot; Script_sections::Section_type script_section_type; + const char* orig_name = name; name = ss->output_section_name(file_name, name, &output_section_slot, &script_section_type); if (name == NULL) { + gold_debug(DEBUG_SCRIPT, _("Unable to create output section '%s' " + "because it is not allowed by the " + "SECTIONS clause of the linker script"), + orig_name); // The SECTIONS clause says to discard this input section. return NULL; } diff --git a/gold/script-c.h b/gold/script-c.h index d1148e4d918..28079503c44 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -421,6 +421,21 @@ script_data_segment_relro_end(void* closure); extern void script_saw_segment_start_expression(void* closure); +/* Called by the bison parser for MEMORY regions. */ + +extern void +script_add_memory(void*, const char*, size_t, unsigned int, + Expression_ptr, Expression_ptr); + +extern unsigned int +script_parse_memory_attr(void*, const char*, size_t, int); + +extern void +script_set_section_region(void*, const char*, size_t, int); + +extern void +script_include_directive(void *, const char*, size_t); + /* Called by the bison parser for expressions. */ extern Expression_ptr @@ -488,9 +503,9 @@ script_exp_function_addr(const char*, size_t); extern Expression_ptr script_exp_function_loadaddr(const char*, size_t); extern Expression_ptr -script_exp_function_origin(const char*, size_t); +script_exp_function_origin(void*, const char*, size_t); extern Expression_ptr -script_exp_function_length(const char*, size_t); +script_exp_function_length(void*, const char*, size_t); extern Expression_ptr script_exp_function_constant(const char*, size_t); extern Expression_ptr diff --git a/gold/script-sections.cc b/gold/script-sections.cc index f7ed68200e4..8183bf2d3ff 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -43,6 +43,174 @@ namespace gold { +// A region of memory. +class Memory_region +{ + public: + Memory_region(const char* name, size_t namelen, unsigned int attributes, + Expression* start, Expression* length) + : name_(name, namelen), + attributes_(attributes), + start_(start), + length_(length), + current_vma_offset_(0), + current_lma_offset_(0), + vma_sections_(NULL), + lma_sections_(NULL) + { } + + // Return the name of this region. + const std::string& + name() const + { return this->name_; } + + // Return the start address of this region. + Expression* + start_address() const + { return this->start_; } + + // Return the length of this region. + Expression* + length() const + { return this->length_; } + + // Print the region (when debugging). + void + print(FILE*) const; + + // Return true if matches this region. + bool + name_match(const char* name, size_t namelen) + { + return (this->name_.length() == namelen + && strncmp(this->name_.c_str(), name, namelen) == 0); + } + + Expression* + get_current_vma_address(void) const + { + return + script_exp_binary_add(this->start_, + script_exp_integer(this->current_vma_offset_)); + } + + Expression* + get_current_lma_address(void) const + { + return + script_exp_binary_add(this->start_, + script_exp_integer(this->current_lma_offset_)); + } + + void + increment_vma_offset(std::string section_name, uint64_t amount, + const Symbol_table* symtab, const Layout* layout) + { + this->current_vma_offset_ += amount; + + if (this->current_vma_offset_ + > this->length_->eval(symtab, layout, false)) + gold_error (_("section %s overflows end of region %s"), + section_name.c_str(), this->name_.c_str()); + } + + void + increment_lma_offset(std::string section_name, uint64_t amount, + const Symbol_table* symtab, const Layout* layout) + { + this->current_lma_offset_ += amount; + + if (this->current_lma_offset_ + > this->length_->eval(symtab, layout, false)) + gold_error (_("section %s overflows end of region %s (based on load address)"), + section_name.c_str(), this->name_.c_str()); + } + + void + add_section(Output_section_definition* sec, bool vma) + { + if (vma) + this->vma_sections_.push_back(sec); + else + this->lma_sections_.push_back(sec); + } + + typedef std::vector Section_list; + + // Return the start of the list of sections + // whose VMAs are taken from this region. + Section_list::const_iterator + get_vma_section_list_start(void) const + { return this->vma_sections_.begin(); } + + // Return the start of the list of sections + // whose LMAs are taken from this region. + Section_list::const_iterator + get_lma_section_list_start(void) const + { return this->lma_sections_.begin(); } + + // Return the end of the list of sections + // whose VMAs are taken from this region. + Section_list::const_iterator + get_vma_section_list_end(void) const + { return this->vma_sections_.end(); } + + // Return the end of the list of sections + // whose LMAs are taken from this region. + Section_list::const_iterator + get_lma_section_list_end(void) const + { return this->lma_sections_.end(); } + + private: + + std::string name_; + unsigned int attributes_; + Expression* start_; + Expression* length_; + uint64_t current_vma_offset_; + uint64_t current_lma_offset_; + // A list of sections whose VMAs are set inside this region. + Section_list vma_sections_; + // A list of sections whose LMAs are set inside this region. + Section_list lma_sections_; +}; + +// Print a memory region. + +void +Memory_region::print(FILE* f) const +{ + fprintf(f, " %s", this->name_.c_str()); + + unsigned int attrs = this->attributes_; + if (attrs != 0) + { + fprintf(f, " ("); + do + { + switch (attrs & - attrs) + { + case MEM_EXECUTABLE: fputc('x', f); break; + case MEM_WRITEABLE: fputc('w', f); break; + case MEM_READABLE: fputc('r', f); break; + case MEM_ALLOCATABLE: fputc('a', f); break; + case MEM_INITIALIZED: fputc('i', f); break; + default: + gold_unreachable(); + } + attrs &= ~ (attrs & - attrs); + } + while (attrs != 0); + fputc(')', f); + } + + fprintf(f, " : origin = "); + this->start_->print(f); + fprintf(f, ", length = "); + this->length_->print(f); + fprintf(f, "\n"); +} + // Manage orphan sections. This is intended to be largely compatible // with the GNU linker. The Linux kernel implicitly relies on // something similar to the GNU linker's orphan placement. We @@ -415,6 +583,11 @@ class Sections_element get_output_section() const { return NULL; } + // Set the section's memory regions. + virtual void + set_memory_region(Memory_region*, bool) + { gold_error(_("Attempt to set a memory region for a non-output section")); } + // Print the element for debugging purposes. virtual void print(FILE* f) const = 0; @@ -1675,6 +1848,22 @@ class Output_section_definition : public Sections_element Script_sections::Section_type section_type() const; + // Store the memory region to use. + void + set_memory_region(Memory_region*, bool set_vma); + + void + set_section_vma(Expression* address) + { this->address_ = address; } + + void + set_section_lma(Expression* address) + { this->load_address_ = address; } + + std::string + get_section_name(void) const + { return this->name_; } + private: static const char* script_section_type_name(Script_section_type); @@ -2331,6 +2520,14 @@ Output_section_definition::script_section_type_name( } } +void +Output_section_definition::set_memory_region(Memory_region* mr, bool set_vma) +{ + gold_assert(mr != NULL); + // Add the current section to the specified region's list. + mr->add_section(this, set_vma); +} + // 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 @@ -2580,6 +2777,85 @@ Phdrs_element::print(FILE* f) const fprintf(f, ";\n"); } +// Add a memory region. + +void +Script_sections::add_memory_region(const char* name, size_t namelen, + unsigned int attributes, + Expression* start, Expression* length) +{ + if (this->memory_regions_ == NULL) + this->memory_regions_ = new Memory_regions(); + else if (this->find_memory_region(name, namelen)) + { + gold_error (_("region '%.*s' already defined"), namelen, name); + // FIXME: Add a GOLD extension to allow multiple regions with the same + // name. This would amount to a single region covering disjoint blocks + // of memory, which is useful for embedded devices. + } + + // FIXME: Check the length and start values. Currently we allow + // non-constant expressions for these values, whereas LD does not. + + // FIXME: Add a GOLD extension to allow NEGATIVE LENGTHS. This would + // describe a region that packs from the end address going down, rather + // than the start address going up. This would be useful for embedded + // devices. + + this->memory_regions_->push_back(new Memory_region(name, namelen, attributes, + start, length)); +} + +// Find a memory region. + +Memory_region* +Script_sections::find_memory_region(const char* name, size_t namelen) +{ + if (this->memory_regions_ == NULL) + return NULL; + + for (Memory_regions::const_iterator m = this->memory_regions_->begin(); + m != this->memory_regions_->end(); + ++m) + if ((*m)->name_match(name, namelen)) + return *m; + + return NULL; +} + +// Find a memory region's origin. + +Expression* +Script_sections::find_memory_region_origin(const char* name, size_t namelen) +{ + Memory_region* mr = find_memory_region(name, namelen); + if (mr == NULL) + return NULL; + + return mr->start_address(); +} + +// Find a memory region's length. + +Expression* +Script_sections::find_memory_region_length(const char* name, size_t namelen) +{ + Memory_region* mr = find_memory_region(name, namelen); + if (mr == NULL) + return NULL; + + return mr->length(); +} + +// Set the memory region to use for the current section. + +void +Script_sections::set_memory_region(Memory_region* mr, bool set_vma) +{ + gold_assert(!this->sections_elements_->empty()); + this->sections_elements_->back()->set_memory_region(mr, set_vma); +} + // Class Script_sections. Script_sections::Script_sections() @@ -2587,6 +2863,7 @@ Script_sections::Script_sections() in_sections_clause_(false), sections_elements_(NULL), output_section_(NULL), + memory_regions_(NULL), phdrs_elements_(NULL), orphan_section_placement_(NULL), data_segment_align_start_(), @@ -2910,6 +3187,41 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout) { gold_assert(this->saw_sections_clause_); + // Walk the memory regions specified in this script, if any. + if (this->memory_regions_ != NULL) + { + for (Memory_regions::const_iterator mr = this->memory_regions_->begin(); + mr != this->memory_regions_->end(); + ++mr) + { + // FIXME: What should we do with the attributes of the regions ? + + // For each region, set the VMA of the sections associated with it. + for (Memory_region::Section_list::const_iterator s = + (*mr)->get_vma_section_list_start(); + s != (*mr)->get_vma_section_list_end(); + ++s) + { + (*s)->set_section_vma((*mr)->get_current_vma_address()); + (*mr)->increment_vma_offset((*s)->get_section_name(), + (*s)->get_output_section()->current_data_size(), + symtab, layout); + } + + // Similarly, set the LMA values. + for (Memory_region::Section_list::const_iterator s = + (*mr)->get_lma_section_list_start(); + s != (*mr)->get_lma_section_list_end(); + ++s) + { + (*s)->set_section_lma((*mr)->get_current_lma_address()); + (*mr)->increment_lma_offset((*s)->get_section_name(), + (*s)->get_output_section()->current_data_size(), + symtab, layout); + } + } + } + // Implement ONLY_IF_RO/ONLY_IF_RW constraints. These are a pain // for our representation. for (Sections_elements::iterator p = this->sections_elements_->begin(); @@ -3654,6 +3966,26 @@ Script_sections::release_segments() void Script_sections::print(FILE* f) const { + if (this->phdrs_elements_ != NULL) + { + fprintf(f, "PHDRS {\n"); + for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin(); + p != this->phdrs_elements_->end(); + ++p) + (*p)->print(f); + fprintf(f, "}\n"); + } + + if (this->memory_regions_ != NULL) + { + fprintf(f, "MEMORY {\n"); + for (Memory_regions::const_iterator m = this->memory_regions_->begin(); + m != this->memory_regions_->end(); + ++m) + (*m)->print(f); + fprintf(f, "}\n"); + } + if (!this->saw_sections_clause_) return; @@ -3665,16 +3997,6 @@ Script_sections::print(FILE* f) const (*p)->print(f); fprintf(f, "}\n"); - - if (this->phdrs_elements_ != NULL) - { - fprintf(f, "PHDRS {\n"); - for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin(); - p != this->phdrs_elements_->end(); - ++p) - (*p)->print(f); - fprintf(f, "}\n"); - } } } // End namespace gold. diff --git a/gold/script-sections.h b/gold/script-sections.h index f18b06c7d13..1a0b760793b 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -37,6 +37,7 @@ struct Parser_output_section_trailer; struct Input_section_spec; class Expression; class Sections_element; +class Memory_region; class Phdrs_element; class Output_data; class Output_section_definition; @@ -220,6 +221,27 @@ class Script_sections set_saw_segment_start_expression(bool value) { this->saw_segment_start_expression_ = value; } + // Add a memory region. + void + add_memory_region(const char*, size_t, unsigned int, + Expression*, Expression*); + + // Find a memory region's origin. + Expression* + find_memory_region_origin(const char*, size_t); + + // Find a memory region's length. + Expression* + find_memory_region_length(const char*, size_t); + + // Find a memory region. + Memory_region* + find_memory_region(const char*, size_t); + + // Set the memory region of the section. + void + set_memory_region(Memory_region*, bool); + // Print the contents to the FILE. This is for debugging. void print(FILE*) const; @@ -228,6 +250,7 @@ class Script_sections typedef Sections_elements::iterator Elements_iterator; private: + typedef std::vector Memory_regions; typedef std::vector Phdrs_elements; // Create segments. @@ -271,6 +294,8 @@ class Script_sections Sections_elements* sections_elements_; // The current output section, if there is one. Output_section_definition* output_section_; + // The list of memory regions in the MEMORY clause. + Memory_regions* memory_regions_; // The list of program headers in the PHDRS clause. Phdrs_elements* phdrs_elements_; // Where to put orphan sections. @@ -286,6 +311,17 @@ class Script_sections bool saw_segment_start_expression_; }; +// Attributes for memory regions. +enum +{ + MEM_EXECUTABLE = (1 << 0), + MEM_WRITEABLE = (1 << 1), + MEM_READABLE = (1 << 2), + MEM_ALLOCATABLE = (1 << 3), + MEM_INITIALIZED = (1 << 4), + MEM_ATTR_MASK = (1 << 5) - 1 +}; + } // End namespace gold. #endif // !defined(GOLD_SCRIPT_SECTIONS_H diff --git a/gold/script.cc b/gold/script.cc index d5983f6e5f4..300b19b783a 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -3220,3 +3220,122 @@ script_saw_segment_start_expression(void* closurev) Script_sections* ss = closure->script_options()->script_sections(); ss->set_saw_segment_start_expression(true); } + +extern "C" void +script_set_section_region(void* closurev, const char* name, size_t namelen, + int set_vma) +{ + Parser_closure* closure = static_cast(closurev); + if (!closure->script_options()->saw_sections_clause()) + { + gold_error(_("%s:%d:%d: MEMORY region '%.*s' referred to outside of " + "SECTIONS clause"), + closure->filename(), closure->lineno(), closure->charpos(), + namelen, name); + return; + } + + Script_sections* ss = closure->script_options()->script_sections(); + Memory_region* mr = ss->find_memory_region(name, namelen); + if (mr == NULL) + { + gold_error(_("%s:%d:%d: MEMORY region '%.*s' not declared"), + closure->filename(), closure->lineno(), closure->charpos(), + namelen, name); + return; + } + + ss->set_memory_region(mr, set_vma); +} + +extern "C" void +script_add_memory(void* closurev, const char* name, size_t namelen, + unsigned int attrs, Expression* origin, Expression* length) +{ + Parser_closure* closure = static_cast(closurev); + Script_sections* ss = closure->script_options()->script_sections(); + ss->add_memory_region(name, namelen, attrs, origin, length); +} + +extern "C" unsigned int +script_parse_memory_attr(void* closurev, const char* attrs, size_t attrlen, + int invert) +{ + int attributes = 0; + + while (attrlen--) + switch (*attrs++) + { + case 'R': + case 'r': + attributes |= MEM_READABLE; break; + case 'W': + case 'w': + attributes |= MEM_READABLE | MEM_WRITEABLE; break; + case 'X': + case 'x': + attributes |= MEM_EXECUTABLE; break; + case 'A': + case 'a': + attributes |= MEM_ALLOCATABLE; break; + case 'I': + case 'i': + case 'L': + case 'l': + attributes |= MEM_INITIALIZED; break; + default: + yyerror(closurev, _("unknown MEMORY attribute")); + } + + if (invert) + attributes = (~ attributes) & MEM_ATTR_MASK; + + return attributes; +} + +extern "C" void +script_include_directive(void* closurev, const char*, size_t) +{ + // FIXME: Implement ? + yyerror (closurev, _("GOLD does not currently support INCLUDE directives")); +} + +// Functions for memory regions. + +extern "C" Expression* +script_exp_function_origin(void* closurev, const char* name, size_t namelen) +{ + Parser_closure* closure = static_cast(closurev); + Script_sections* ss = closure->script_options()->script_sections(); + Expression* origin = ss->find_memory_region_origin(name, namelen); + + if (origin == NULL) + { + gold_error(_("undefined memory region '%s' referenced " + "in ORIGIN expression"), + name); + // Create a dummy expression to prevent crashes later on. + origin = script_exp_integer(0); + } + + return origin; +} + +extern "C" Expression* +script_exp_function_length(void* closurev, const char* name, size_t namelen) +{ + Parser_closure* closure = static_cast(closurev); + Script_sections* ss = closure->script_options()->script_sections(); + Expression* length = ss->find_memory_region_length(name, namelen); + + if (length == NULL) + { + gold_error(_("undefined memory region '%s' referenced " + "in LENGTH expression"), + name); + // Create a dummy expression to prevent crashes later on. + length = script_exp_integer(0); + } + + return length; +} diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index bd8bfbd1eff..161b86a9844 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -1779,6 +1779,16 @@ start_lib_test: start_lib_test_main.o libstart_lib_test.a start_lib_test_2.o sta libstart_lib_test.a: start_lib_test_1.o $(TEST_AR) rc $@ $^ +# Test that MEMORY region support works. +check_SCRIPTS += memory_test.sh +check_DATA += memory_test.stdout +MOSTLYCLEANFILES += memory_test.stdout memory_test memory_test.o +memory_test: memory_test.s + $(COMPILE) -c $< -o memory_test.o + $(LINK) -Bgcctestdir/ -nostartfiles -nostdlib -T $(srcdir)/memory_test.t -o $@ memory_test.o +memory_test.stdout: memory_test + $(TEST_READELF) -lS $< > $@ + endif GCC endif NATIVE_LINKER diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 29caa06de31..09dc84add38 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -312,13 +312,15 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ # Test that a strong weak reference remains strong if there is another # weak reference in a DSO. + +# Test that MEMORY region support works. @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.sh \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.sh +@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.sh memory_test.sh @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = exclude_libs_test.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test1.syms \ @@ -327,7 +329,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.stdout \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_29 = exclude_libs_test.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_1.a \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \ @@ -351,7 +354,9 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref_1.so \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref_2.so \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout memory_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.o @GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_30 = large @GCC_FALSE@large_DEPENDENCIES = @MCMODEL_MEDIUM_FALSE@large_DEPENDENCIES = @@ -3282,6 +3287,8 @@ strong_ref_weak_def.sh.log: strong_ref_weak_def.sh @p='strong_ref_weak_def.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) dyn_weak_ref.sh.log: dyn_weak_ref.sh @p='dyn_weak_ref.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +memory_test.sh.log: memory_test.sh + @p='memory_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_i386.sh.log: split_i386.sh @p='split_i386.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_x86_64.sh.log: split_x86_64.sh @@ -4476,6 +4483,11 @@ uninstall-am: @GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--start-lib start_lib_test_2.o start_lib_test_3.o -Wl,--end-lib @GCC_TRUE@@NATIVE_LINKER_TRUE@libstart_lib_test.a: start_lib_test_1.o @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^ +@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test: memory_test.s +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c $< -o memory_test.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -nostartfiles -nostdlib -T $(srcdir)/memory_test.t -o $@ memory_test.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test.stdout: memory_test +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lS $< > $@ @DEFAULT_TARGET_I386_TRUE@split_i386_1.o: split_i386_1.s @DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $< @DEFAULT_TARGET_I386_TRUE@split_i386_2.o: split_i386_2.s diff --git a/gold/testsuite/memory_test.s b/gold/testsuite/memory_test.s new file mode 100644 index 00000000000..dbb63ea34cb --- /dev/null +++ b/gold/testsuite/memory_test.s @@ -0,0 +1,14 @@ + .section .sec0, "a" + .word 0 + + .section .sec1, "a" + .word 0x11 + + .section .sec2, "a" + .word 0x22 + + .section .sec3, "a" + .word 0x33 + + .section .sec4, "a" + .word 0x44 diff --git a/gold/testsuite/memory_test.sh b/gold/testsuite/memory_test.sh new file mode 100755 index 00000000000..8a223ad3a93 --- /dev/null +++ b/gold/testsuite/memory_test.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# memory_test.sh -- test MEMORY regions. + +# Copyright 2010 Free Software Foundation, Inc. +# Written by Nick Clifton + +# 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. + + +check() +{ + file=$1 + pattern=$2 + found=`grep "$pattern" $file` + if test -z "$found"; then + echo "pattern \"$pattern\" not found in file $file." + echo $found + exit 1 + fi +} + +check memory_test.stdout \ + " LOAD 0x001000 0x00000000 0x00000000 0x00002 0x00002 R 0x1000" +check memory_test.stdout \ + " LOAD 0x00112c 0x00001000 0x0000012c 0x00002 0x00002 R 0x1000" +check memory_test.stdout \ + " LOAD 0x002000 0x00005000 0x00005000 0x00002 0x00002 R 0x1000" +check memory_test.stdout \ + " LOAD 0x00203c 0x00004000 0x0000603c 0x0002a 0x0002a R E 0x1000" + + +exit 0 diff --git a/gold/testsuite/memory_test.t b/gold/testsuite/memory_test.t new file mode 100644 index 00000000000..7bcb877e523 --- /dev/null +++ b/gold/testsuite/memory_test.t @@ -0,0 +1,29 @@ +MEMORY +{ + region1 : ORIGIN = 0x1000, LENGTH = 0x1000 , + region2 (r) : org = 0x2000, len = 300 + region3 (wx) : o = 0x4000, l = 4 + region4 (!r) : o = 0x6000 + 60, len = 0x30 * 0x6 +} + +SECTIONS +{ + .sec0 : { *(*.sec0) } + + .sec1 ORIGIN (region1) : AT(LENGTH (region2)) { *(*.sec1) } + + fred = ORIGIN (region1) + LENGTH (region1) ; + + .sec2 : { *(*.sec2) } > region3 AT> region4 + + .sec3 0x5000 : { *(*.sec3) } + + /* In theory we could put: + + /DISCARD/ : { *(*) } + + here as we do not need any other sections for this test. + In practice however doing so breaks GOLD as it relies upon + being able to create/find various other sections such as + .dynamic, .dynsym and .gnu.hash. */ +} diff --git a/gold/yyscript.y b/gold/yyscript.y index 203deb7cbf8..18f949600c9 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -143,6 +143,7 @@ %token INFO %token INPUT %token KEEP +%token LEN %token LENGTH /* LENGTH, l, len */ %token LOADADDR %token LOCAL /* local */ @@ -157,6 +158,7 @@ %token NOLOAD %token ONLY_IF_RO %token ONLY_IF_RW +%token ORG %token ORIGIN /* ORIGIN, o, org */ %token OUTPUT %token OUTPUT_ARCH @@ -215,7 +217,7 @@ %type wildcard_file wildcard_section %type exclude_names %type wildcard_name -%type phdr_type +%type phdr_type memory_attr %type phdr_info %type vers_defns %type vers_tag @@ -250,6 +252,7 @@ file_cmd: | INHIBIT_COMMON_ALLOCATION { script_set_common_allocation(closure, 0); } | INPUT '(' input_list ')' + | MEMORY '{' memory_defs '}' | OPTION '(' string ')' { script_parse_option(closure, $3.value, $3.length); } | OUTPUT_FORMAT '(' string ')' @@ -471,14 +474,14 @@ section_trailer: /* A memory specification for an output section. */ opt_memspec: '>' string - { yyerror(closure, "memory regions are not supported"); } + { script_set_section_region(closure, $2.value, $2.length, 1); } | /* empty */ ; /* A memory specification for where to load an output section. */ opt_at_memspec: AT '>' string - { yyerror(closure, "memory regions are not supported"); } + { script_set_section_region(closure, $3.value, $3.length, 0); } | /* empty */ ; @@ -688,6 +691,50 @@ file_or_sections_cmd: { script_add_assertion(closure, $3, $5.value, $5.length); } ; +/* A list of MEMORY definitions. */ +memory_defs: + memory_defs opt_comma memory_def + | /* empty */ + ; + +/* A single MEMORY definition. */ +memory_def: + string memory_attr ':' memory_origin '=' parse_exp opt_comma memory_length '=' parse_exp + { script_add_memory(closure, $1.value, $1.length, $2, $6, $10); } + | + /* LD supports an INCLUDE directive here, currently GOLD does not. */ + INCLUDE string + { script_include_directive(closure, $2.value, $2.length); } + | + ; + +/* The (optional) attributes of a MEMORY region. */ +memory_attr: + '(' string ')' + { $$ = script_parse_memory_attr(closure, $2.value, $2.length, 0); } + | /* Inverted attributes. */ + '(' '!' string ')' + { $$ = script_parse_memory_attr(closure, $3.value, $3.length, 1); } + | /* empty */ + { $$ = 0; } + ; + +memory_origin: + ORIGIN + | + ORG + | + 'o' + ; + +memory_length: + LENGTH + | + LEN + | + 'l' + ; + /* A list of program header definitions. */ phdrs_defs: phdrs_defs phdr_def @@ -885,9 +932,9 @@ exp: | LOADADDR '(' string ')' { $$ = script_exp_function_loadaddr($3.value, $3.length); } | ORIGIN '(' string ')' - { $$ = script_exp_function_origin($3.value, $3.length); } + { $$ = script_exp_function_origin(closure, $3.value, $3.length); } | LENGTH '(' string ')' - { $$ = script_exp_function_length($3.value, $3.length); } + { $$ = script_exp_function_length(closure, $3.value, $3.length); } | CONSTANT '(' string ')' { $$ = script_exp_function_constant($3.value, $3.length); } | ABSOLUTE '(' exp ')'