* README: Remove claim that MEMORY is not supported.
authorNick Clifton <nickc@redhat.com>
Wed, 8 Sep 2010 16:10:33 +0000 (16:10 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 8 Sep 2010 16:10:33 +0000 (16:10 +0000)
        * 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.

14 files changed:
gold/ChangeLog
gold/README
gold/expression.cc
gold/layout.cc
gold/script-c.h
gold/script-sections.cc
gold/script-sections.h
gold/script.cc
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/memory_test.s [new file with mode: 0644]
gold/testsuite/memory_test.sh [new file with mode: 0755]
gold/testsuite/memory_test.t [new file with mode: 0644]
gold/yyscript.y

index 667caaea45114a649f968cafb1901f2342c12e57..45b3d7ccefc7853e04229fadb9b56f3a9a5f5ab9 100644 (file)
@@ -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
index 80da4558aa7a68d0813e4c2a882fa51a1a2ae5d9..43c6897c4e844e5b0347509d16d3859ae2e877b3 100644 (file)
@@ -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
index 6d18679971c3fd3e93f0e00d6346f512cdc584ca..e630dad515dca9f11a6f8b4a40201c4b601aadb0 100644 (file)
@@ -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.
index 5edba48aae57a8d987ca024e7195860424581713..bfe6a5eea66d3dc061c8cd4d47e6598e94c4524d 100644 (file)
@@ -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;
        }
index d1148e4d91837ab280c4613975d10783dbc90388..28079503c446e63c874dc4932a8b792d9584157b 100644 (file)
@@ -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
index f7ed68200e4d6295a4e0d90d6a3896ef34003f70..8183bf2d3ff4eee983e2d9694f55486f564b1c55 100644 (file)
 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.
index f18b06c7d13a1f2625c56f6ac59dc3ff330c38e4..1a0b760793b2d41df0a0313e62844fc01530787f 100644 (file)
@@ -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
index d5983f6e5f48039ac34e4f9e5c6c4483f26a49c7..300b19b783adc3fd6d4f647e35c75cfacf2b66bf 100644 (file)
@@ -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;
+}
index bd8bfbd1eff7a456a8e3e43cc1c8ea2edf33f71a..161b86a98443c3408d7d686e4c2f1dc661d36a0e 100644 (file)
@@ -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
 
index 29caa06de3109588aed13c288c6a645b476fbfed..09dc84add383795940acdf621a5d1db857e8034f 100644 (file)
@@ -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 (file)
index 0000000..dbb63ea
--- /dev/null
@@ -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 (executable)
index 0000000..8a223ad
--- /dev/null
@@ -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 (file)
index 0000000..7bcb877
--- /dev/null
@@ -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.  */
+}
index 203deb7cbf86fc8f0b3b960856afd11a3b798202..18f949600c9b3c93bb7c863955e73db7275a90e7 100644 (file)
 %token INFO
 %token INPUT
 %token KEEP
+%token LEN
 %token LENGTH          /* LENGTH, l, len */
 %token LOADADDR
 %token LOCAL           /* local */
 %token NOLOAD
 %token ONLY_IF_RO
 %token ONLY_IF_RW
+%token ORG
 %token ORIGIN          /* ORIGIN, o, org */
 %token OUTPUT
 %token OUTPUT_ARCH
 %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 ')'