This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, PR 4643] Allow symbols in MEMORY region specification


Hi,

  This patch fixes PR 4643 by allowing symbols in the LENGTH and ORIGIN 
  fields of MEMORY regions. Right now, 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. One of the PR commentors also had a similar
  motivation.

  The patch adds two fields (length_exp and origin_exp) to
  memory_region_struct, and assigns them when the corresponding
  production executes in ldgram.y. The fields are evaluated after
  lang_do_assignments runs with lang_mark_phase_enum. The patch also
  defers evaluation of expressions involving LENGTH nameop until
  lang_first_phase_enum completes (this was already being done for ORIGIN).

  I ran a make check-ld for an AVR and native build, and both passed without
  regressions.

  Is this the right approach? Does this look ok? If yes, could someone commit 
  it please? I don't have commit access.

Regards
Senthil

ld/ChangeLog

2015-01-20  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.

ld/testsuite/ChangeLog
2015-01-20  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>

	PR 4643
	* ld-scripts/pr4643.d: New test.
	* ld-scripts/pr4643.t: Linker script for new test.
	* ld-scripts/expr.exp: Run new test.

diff --git a/ld/ldexp.c b/ld/ldexp.c
index f2c8620..ac66cc0 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -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;
 
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 736f77d..f46aa9e 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -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;
 		}
 	;
 
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 0c72333..cf4f41b 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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;
@@ -6699,6 +6702,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.  */
@@ -7962,6 +7967,34 @@ 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;
+        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)
 {
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 48d7e4e..69d21a7 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -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;
diff --git a/ld/testsuite/ld-scripts/expr.exp b/ld/testsuite/ld-scripts/expr.exp
index 85242ed..25a4211 100644
--- a/ld/testsuite/ld-scripts/expr.exp
+++ b/ld/testsuite/ld-scripts/expr.exp
@@ -25,3 +25,4 @@ run_dump_test sane1
 run_dump_test assign-loc
 run_dump_test pr14962
 run_dump_test pr14962-2
+run_dump_test pr4643
diff --git a/ld/testsuite/ld-scripts/pr4643.d b/ld/testsuite/ld-scripts/pr4643.d
new file mode 100644
index 0000000..8bbd5b3
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr4643.d
@@ -0,0 +1,19 @@
+#ld: -defsym TXT_ORIGIN=0x100 -defsym TXT_LENGTH=0x200 -T pr4643.t
+#source: script.s
+#objdump: -h -t
+# Make sure .text starts at TXT_ORIGIN, and that LENGTH and ORIGIN
+# work correctly.
+
+#...
+  0 .text         0+4  0+100  0+100.*
+#...
+SYMBOL TABLE:
+#...
+0+8 .* data_length
+#...
+0+200 .* text_length
+#...
+0+100 .* text_start
+#...
+0+1000 .* data_start
+#pass
diff --git a/ld/testsuite/ld-scripts/pr4643.t b/ld/testsuite/ld-scripts/pr4643.t
new file mode 100644
index 0000000..919e179
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr4643.t
@@ -0,0 +1,36 @@
+MEMORY
+{
+  TEXTMEM (ARX) : ORIGIN = TXT_ORIGIN, LENGTH = TXT_LENGTH
+  DATAMEM (AW)  : ORIGIN = 0x1000, LENGTH = (2 * 4)
+}
+
+SECTIONS
+{
+  . = 0;
+  .text :
+  {
+    text_start = ORIGIN (TEXTMEM);
+    *(.text)
+    *(.pr)
+    text_end = .;
+  } > TEXTMEM
+
+  text_length = LENGTH(TEXTMEM);
+
+  data_start = ORIGIN (DATAMEM);
+  .data :
+  {
+    *(.data)
+    *(.rw)
+    data_end = .;
+  } >DATAMEM
+
+  data_length = LENGTH(DATAMEM);
+}
+
+SECTIONS
+{ 
+  .text : { *(.text) }
+  .data : { *(.data) }
+  /DISCARD/ : { *(*) }
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]