aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2010-09-08 16:10:33 +0000
committerNick Clifton <nickc@redhat.com>2010-09-08 16:10:33 +0000
commit7f8cd8440375de26ebca766ab281c34522262b53 (patch)
treeada43984d6bc35a3487c093cb6b1c5b1a988527b
parentab3e2b4a1c329818752fe855215d81fe21f88a8b (diff)
downloadbinutils-7f8cd8440375de26ebca766ab281c34522262b53.zip
binutils-7f8cd8440375de26ebca766ab281c34522262b53.tar.gz
binutils-7f8cd8440375de26ebca766ab281c34522262b53.tar.bz2
* 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.
-rw-r--r--gold/ChangeLog29
-rw-r--r--gold/README1
-rw-r--r--gold/expression.cc15
-rw-r--r--gold/layout.cc5
-rw-r--r--gold/script-c.h19
-rw-r--r--gold/script-sections.cc342
-rw-r--r--gold/script-sections.h36
-rw-r--r--gold/script.cc119
-rw-r--r--gold/testsuite/Makefile.am10
-rw-r--r--gold/testsuite/Makefile.in18
-rw-r--r--gold/testsuite/memory_test.s14
-rwxr-xr-xgold/testsuite/memory_test.sh48
-rw-r--r--gold/testsuite/memory_test.t29
-rw-r--r--gold/yyscript.y57
14 files changed, 706 insertions, 36 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 667caae..45b3d7c 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,32 @@
+2010-09-08 Nick Clifton <nickc@redhat.com>
+
+ * 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 <dougkwan@google.com>
* gold/resolve.cc (Symbol_table::should_override): Let a weak
diff --git a/gold/README b/gold/README
index 80da455..43c6897 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 6d18679..e630dad 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 5edba48..bfe6a5e 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 d1148e4..2807950 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 f7ed682..8183bf2 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 <name,namelen> 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<Output_section_definition*> 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 f18b06c..1a0b760 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_region*> Memory_regions;
typedef std::vector<Phdrs_element*> 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 d5983f6..300b19b 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<Parser_closure*>(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<Parser_closure*>(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<Parser_closure*>(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<Parser_closure*>(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 bd8bfbd..161b86a 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 29caa06..09dc84a 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 0000000..dbb63ea
--- /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 0000000..8a223ad
--- /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 <nickc@redhat.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.
+
+
+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 0000000..7bcb877
--- /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 203deb7..18f9496 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_section> wildcard_file wildcard_section
%type <string_list> exclude_names
%type <string> wildcard_name
-%type <integer> phdr_type
+%type <integer> phdr_type memory_attr
%type <phdr_info> phdr_info
%type <versyms> vers_defns
%type <versnode> 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 ')'