Allow symbols in MEMORY region specification

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.
This commit is contained in:
Senthil Kumar Selvaraj 2015-01-28 15:01:50 +10:30 committed by Alan Modra
parent e5fe4957b4
commit cc9ad334a7
9 changed files with 131 additions and 11 deletions

View 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

View File

@ -828,15 +828,18 @@ fold_name (etree_type *tree)
case LENGTH:
{
lang_memory_region_type *mem;
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);
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;

View 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;
}
;

View 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)
{

View 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;

View 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.

View File

@ -29,5 +29,6 @@ SECTIONS
data_end = .;
} >DATAMEM
fred = ORIGIN(DATAMEM) + LENGTH(DATAMEM);
fred = ORIGIN(DATAMEM) + LENGTH(DATAMEM);
tred = ORIGIN(TEXTMEM) + LENGTH(TEXTMEM);
}

View File

@ -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);
}

View 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 {