This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[Patch, PR 4643] Allow symbols in MEMORY region specification
- From: Senthil Kumar Selvaraj <senthil_kumar dot selvaraj at atmel dot com>
- To: <binutils at sourceware dot org>
- Cc: <amodra at gmail dot com>, <nickc at redhat dot com>
- Date: Tue, 20 Jan 2015 06:29:38 +0530
- Subject: [Patch, PR 4643] Allow symbols in MEMORY region specification
- Authentication-results: sourceware.org; auth=none
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/ : { *(*) }
+}