Allow symbols in MEMORY region specification
authorSenthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
Wed, 28 Jan 2015 04:31:50 +0000 (15:01 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 28 Jan 2015 04:36:48 +0000 (15:06 +1030)
This patch fixes PR 4643 by allowing symbols in the LENGTH and ORIGIN
fields of MEMORY regions.  Previously, only constants and constant
expressions are allowed.

For the AVR target, this helps define memory constraints more
accurately (per device), without having to create a ton of device
specific linker scripts.

ld/
PR 4643
* ldexp.c (fold_name): Fold LENGTH only after
lang_first_phase_enum.
* ldgram.y (memory_spec): Don't evaluate ORIGIN and LENGTH
rightaway.
* ldlang.h (struct memory_region_struct): Add origin_exp and
length_exp fields.
* ldlang.c (lang_do_memory_regions): New.
(lang_memory_region_lookup): Initialize origin_exp and
length_exp fields.
(lang_process): Call lang_do_memory_regions.
ld/testsuite/
* ld-scripts/memory.t: Define new symbol tred.
* ld-scripts/memory_sym.t: New.
* ld-scripts/script.exp: Perform MEMORY with symbols test, and
conditionally check values of linker symbols.

ld/ChangeLog
ld/ldexp.c
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/testsuite/ChangeLog
ld/testsuite/ld-scripts/memory.t
ld/testsuite/ld-scripts/memory_sym.t [new file with mode: 0644]
ld/testsuite/ld-scripts/script.exp

index 5a97e32c64914415d1b768f9598b10762da8b1af..c61baaef36515e6c65f05d831560607a129f2449 100644 (file)
@@ -1,3 +1,17 @@
+2015-01-28  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       PR 4643
+       * ldexp.c (fold_name): Fold LENGTH only after
+       lang_first_phase_enum.
+       * ldgram.y (memory_spec): Don't evaluate ORIGIN and LENGTH
+       rightaway.
+       * ldlang.h (struct memory_region_struct): Add origin_exp and
+       length_exp fields.
+       * ldlang.c (lang_do_memory_regions): New.
+       (lang_memory_region_lookup): Initialize origin_exp and
+       length_exp fields.
+       (lang_process): Call lang_do_memory_regions.
+
 2015-01-20  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * ldlang.c (print_assignment): Only evaluate the expression for a
index f2c8620a4651aa2604b66291513db4c69697ad76..ac66cc02aef23556cf6b3d8b8c104498a4026d21 100644 (file)
@@ -828,15 +828,18 @@ fold_name (etree_type *tree)
 
     case LENGTH:
       {
-        lang_memory_region_type *mem;
-
-        mem = lang_memory_region_lookup (tree->name.name, FALSE);
-        if (mem != NULL)
-          new_number (mem->length);
-        else
-          einfo (_("%F%S: undefined MEMORY region `%s'"
-                  " referenced in expression\n"),
-                tree, tree->name.name);
+      if (expld.phase != lang_first_phase_enum)
+        {
+          lang_memory_region_type *mem;
+
+          mem = lang_memory_region_lookup (tree->name.name, FALSE);
+          if (mem != NULL)
+            new_number (mem->length);
+          else
+            einfo (_("%F%S: undefined MEMORY region `%s'"
+             " referenced in expression\n"),
+           tree, tree->name.name);
+        }
       }
       break;
 
index 736f77d722060b888763c0ff4a51fa1693039ed9..f46aa9ea21096914603c7045290fb0f27aa51ce3 100644 (file)
@@ -817,7 +817,7 @@ memory_spec:        NAME
 origin_spec:
        ORIGIN '=' mustbe_exp
                {
-                 region->origin = exp_get_vma ($3, 0, "origin");
+                 region->origin_exp = $3;
                  region->current = region->origin;
                }
        ;
@@ -825,7 +825,7 @@ origin_spec:
 length_spec:
              LENGTH '=' mustbe_exp
                {
-                 region->length = exp_get_vma ($3, -1, "length");
+                 region->length_exp = $3;
                }
        ;
 
index 3ea22c2f530d3d90066dde6c5d358db71ea5a3cb..5344e5e401433818c75832b733d8a6a8f4886ced 100644 (file)
@@ -85,6 +85,7 @@ static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
   (struct bfd_elf_version_expr_head *);
+static void lang_do_memory_regions (void);
 
 /* Exported variables.  */
 const char *output_target;
@@ -1305,7 +1306,9 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   new_region->name_list.name = xstrdup (name);
   new_region->name_list.next = NULL;
   new_region->next = NULL;
+  new_region->origin_exp = NULL;
   new_region->origin = 0;
+  new_region->length_exp = NULL;
   new_region->length = ~(bfd_size_type) 0;
   new_region->current = 0;
   new_region->last_os = NULL;
@@ -6707,6 +6710,8 @@ lang_process (void)
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
   lang_do_assignments (lang_mark_phase_enum);
+
+  lang_do_memory_regions();
   expld.phase = lang_first_phase_enum;
 
   /* Size up the common data.  */
@@ -7970,6 +7975,37 @@ lang_do_version_exports_section (void)
                           lang_new_vers_node (greg, lreg), NULL);
 }
 
+/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */
+
+static void
+lang_do_memory_regions (void)
+{
+  lang_memory_region_type *r = lang_memory_region_list;
+
+  for (; r != NULL; r = r->next)
+    {
+      if (r->origin_exp)
+      {
+        exp_fold_tree_no_dot (r->origin_exp);
+        if (expld.result.valid_p)
+          {
+            r->origin = expld.result.value;
+            r->current = r->origin;
+          }
+        else
+          einfo (_("%F%P: invalid origin for memory region %s\n"), r->name_list.name);
+      }
+      if (r->length_exp)
+      {
+        exp_fold_tree_no_dot (r->length_exp);
+        if (expld.result.valid_p)
+          r->length = expld.result.value;
+        else
+          einfo (_("%F%P: invalid length for memory region %s\n"), r->name_list.name);
+      }
+    }
+}
+
 void
 lang_add_unique (const char *name)
 {
index 48d7e4e1698552144249fb6ae06fcd438f3f77b9..69d21a723096cc7ead383c1d426d0369b7ed674c 100644 (file)
@@ -55,8 +55,10 @@ typedef struct memory_region_struct
 {
   lang_memory_region_name name_list;
   struct memory_region_struct *next;
+  union etree_union *origin_exp;
   bfd_vma origin;
   bfd_size_type length;
+  union etree_union *length_exp;
   bfd_vma current;
   union lang_statement_union *last_os;
   flagword flags;
index 21cf40e3e6bec0b861b9730c5f67180556f98798..4746f14a4aa851f44e89a286aaff37f4e2c573c4 100644 (file)
@@ -1,3 +1,10 @@
+2015-01-28  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * ld-scripts/memory.t: Define new symbol tred.
+       * ld-scripts/memory_sym.t: New.
+       * ld-scripts/script.exp: Perform MEMORY with symbols test, and
+       conditionally check values of linker symbols.
+
 2015-01-20  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * ld-scripts/provide-4-map.d: Update expected output.
index 129bd7c12372e2e9443e55d6ad8104e9d894dc19..937394f522f741e56795da11f5c102f5ba6a46f1 100644 (file)
@@ -29,5 +29,6 @@ SECTIONS
     data_end = .;
   } >DATAMEM
 
-  fred = ORIGIN(DATAMEM) + LENGTH(DATAMEM);  
+  fred = ORIGIN(DATAMEM) + LENGTH(DATAMEM);
+  tred = ORIGIN(TEXTMEM) + LENGTH(TEXTMEM);
 }
diff --git a/ld/testsuite/ld-scripts/memory_sym.t b/ld/testsuite/ld-scripts/memory_sym.t
new file mode 100644 (file)
index 0000000..4ccec55
--- /dev/null
@@ -0,0 +1,36 @@
+TXT_ORIGIN = 0x100;
+TXT_LENGTH = 32K;
+MEMORY
+{
+  R_TEXTMEM (ARX) : ORIGIN = TXT_ORIGIN, LENGTH = TXT_LENGTH
+  R_DATAMEM (AW)  : org = DATA_ORIGIN, l = DATA_LENGTH
+}
+
+REGION_ALIAS ("A_TEXTMEM", R_TEXTMEM);
+REGION_ALIAS ("A_DATAMEM", R_DATAMEM);
+
+REGION_ALIAS ("TEXTMEM", A_TEXTMEM);
+REGION_ALIAS ("DATAMEM", A_DATAMEM);
+
+SECTIONS
+{
+  . = 0;
+  .text :
+  {
+    text_start = ORIGIN (TEXTMEM);
+    *(.text)
+    *(.pr)
+    text_end = .;
+  } > TEXTMEM
+  
+  data_start = ORIGIN (DATAMEM);
+  .data :
+  {
+    *(.data)
+    *(.rw)
+    data_end = .;
+  } >DATAMEM
+
+  fred = ORIGIN(DATAMEM) + LENGTH(DATAMEM);  
+  tred = ORIGIN(TEXTMEM) + LENGTH(TEXTMEM);  
+}
index cee706f7557d16c479eeb36c61f49bd7c9265a97..6ab04ec01e013622390bf689ead7e49565b18f1f 100644 (file)
@@ -66,6 +66,13 @@ proc check_script { } {
        set passes 0
     } 
 
+    if {[info exists nm_output(tred)] \
+        && $nm_output(tred) != (0x100 + 0x8000)} {
+       send_log "tred == $nm_output(tred)\n"
+       verbose "tred == $nm_output(tred)"
+       set passes 0
+    }
+
     if {$nm_output(text_end) < $text_end \
            || $nm_output(text_end) > 0x110} {
        send_log "text_end == $nm_output(text_end)\n"
@@ -79,6 +86,13 @@ proc check_script { } {
        set passes 0
     } 
 
+    if {[info exists nm_output(fred)] \
+        && $nm_output(fred) != (0x1000 + 0x10000)} {
+       send_log "fred == $nm_output(fred)\n"
+       verbose "fred == $nm_output(fred)"
+       set passes 0
+    }
+
     if {$nm_output(data_end) < $data_end \
            || $nm_output(data_end) > 0x1010} {
        send_log "data_end == $nm_output(data_end)\n"
@@ -126,6 +140,13 @@ if ![ld_simple_link $ld tmpdir/script "$flags -T $srcdir/$subdir/memory.t tmpdir
     check_script
 }
 
+set testname "MEMORY with symbols"
+if ![ld_simple_link $ld tmpdir/script "$flags -defsym DATA_ORIGIN=0x1000 -defsym DATA_LENGTH=0x10000 -T $srcdir/$subdir/memory_sym.t tmpdir/script.o"] {
+    fail $testname
+} else {
+    check_script
+}
+
 set test_script_list [lsort [glob $srcdir/$subdir/region-alias-*.t]]
 
 foreach test_script $test_script_list {