This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
ld lma assignment
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Wed, 26 Jul 2006 14:39:14 +0930
- Subject: ld lma assignment
While playing with overlays recently, I noticed an annoying linker
script requirement. An output section following an overlay must have
its lma specified (with AT or AT>). As must any section following one
with an lma adjustment, because ld defaults to setting lma equal to
vma and this may cause lma overlap. So I decided to teach ld how to
track lma assignments, to make following sections have reasonable
default lmas. In the process I discovered a bug with LOADADDR
expressions, easily fixed, and found that code setting load_base for
orphans and overlays was no longer needed.
BTW, does anyone know why section lmas are set by lang_do_assignhments
rather than lang_size_sections? If there is no good reason, I'll move
the code so that both vma and lma are set in lang_size_sections.
ld/
* ldexp.c (fold_name <LOADADDR>): Use the lma.
* ldlang.h (lang_memory_region_type): Delete old_length. Add
last_os.
* ldlang.c (lang_memory_region_lookup): Init new field.
(lang_reset_memory_regions): Reset new field.
(lang_insert_orphan): Don't set load_base.
(lang_leave_overlay): Likewise.
(lang_size_sections_1): Delete unnecessary code setting lma_region
to region. Correct lma region check.
(lang_do_assignments_1): Rename output_section_statement parm
to current_os. Set lma from previous section in region.
ld/testsuite/
* ld-scripts/overlay-size-map.d: Update.
Index: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.60
diff -u -p -r1.60 ldexp.c
--- ld/ldexp.c 19 Jun 2006 13:17:44 -0000 1.60
+++ ld/ldexp.c 26 Jul 2006 01:08:19 -0000
@@ -577,7 +577,8 @@ fold_name (etree_type *tree)
if (os != NULL && os->processed)
{
if (os->load_base == NULL)
- new_rel (0, NULL, os->bfd_section);
+ new_rel (os->bfd_section->lma - os->bfd_section->vma,
+ NULL, os->bfd_section);
else
exp_fold_tree_1 (os->load_base);
}
Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.63
diff -u -p -r1.63 ldlang.h
--- ld/ldlang.h 20 Jun 2006 16:37:29 -0000 1.63
+++ ld/ldlang.h 26 Jul 2006 01:08:23 -0000
@@ -54,7 +54,7 @@ typedef struct memory_region_struct
bfd_vma origin;
bfd_size_type length;
bfd_vma current;
- bfd_size_type old_length;
+ union lang_statement_union *last_os;
flagword flags;
flagword not_flags;
bfd_boolean had_full_message;
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.229
diff -u -p -r1.229 ldlang.c
--- ld/ldlang.c 26 Jul 2006 00:42:33 -0000 1.229
+++ ld/ldlang.c 26 Jul 2006 01:08:22 -0000
@@ -1164,16 +1164,17 @@ lang_memory_region_lookup (const char *c
new->name = xstrdup (name);
new->next = NULL;
-
- *lang_memory_region_list_tail = new;
- lang_memory_region_list_tail = &new->next;
new->origin = 0;
- new->flags = 0;
- new->not_flags = 0;
new->length = ~(bfd_size_type) 0;
new->current = 0;
+ new->last_os = NULL;
+ new->flags = 0;
+ new->not_flags = 0;
new->had_full_message = FALSE;
+ *lang_memory_region_list_tail = new;
+ lang_memory_region_list_tail = &new->next;
+
return new;
}
@@ -1462,7 +1463,6 @@ lang_insert_orphan (asection *s,
lang_statement_list_type *old;
lang_statement_list_type add;
const char *ps;
- etree_type *load_base;
lang_output_section_statement_type *os;
lang_output_section_statement_type **os_tail;
@@ -1506,20 +1506,10 @@ lang_insert_orphan (asection *s,
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop (0);
- load_base = NULL;
- if (after != NULL && after->load_base != NULL)
- {
- etree_type *lma_from_vma;
- lma_from_vma = exp_binop ('-', after->load_base,
- exp_nameop (ADDR, after->name));
- load_base = exp_binop ('+', lma_from_vma,
- exp_nameop (ADDR, secname));
- }
-
os_tail = ((lang_output_section_statement_type **)
lang_output_section_statement.tail);
os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
- load_base, 0);
+ NULL, 0);
if (add_child == NULL)
add_child = &os->children;
@@ -4417,20 +4407,16 @@ lang_size_sections_1
os_region_check (os, os->region, os->addr_tree,
os->bfd_section->vma);
- /* If there's no load address specified, use the run
- region as the load region. */
- if (os->lma_region == NULL && os->load_base == NULL)
- os->lma_region = os->region;
-
if (os->lma_region != NULL && os->lma_region != os->region)
{
/* Set load_base, which will be handled later. */
os->load_base = exp_intop (os->lma_region->current);
os->lma_region->current +=
TO_ADDR (os->bfd_section->size);
+
if (check_regions)
os_region_check (os, os->lma_region, NULL,
- os->bfd_section->lma);
+ os->lma_region->current);
}
}
}
@@ -4709,11 +4695,10 @@ lang_size_sections (bfd_boolean *relax,
/* Worker function for lang_do_assignments. Recursiveness goes here. */
static bfd_vma
-lang_do_assignments_1
- (lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- fill_type *fill,
- bfd_vma dot)
+lang_do_assignments_1 (lang_statement_union_type *s,
+ lang_output_section_statement_type *current_os,
+ fill_type *fill,
+ bfd_vma dot)
{
for (; s != NULL; s = s->header.next)
{
@@ -4721,9 +4706,7 @@ lang_do_assignments_1
{
case lang_constructors_statement_enum:
dot = lang_do_assignments_1 (constructor_list.head,
- output_section_statement,
- fill,
- dot);
+ current_os, fill, dot);
break;
case lang_output_section_statement_enum:
@@ -4733,22 +4716,61 @@ lang_do_assignments_1
os = &(s->output_section_statement);
if (os->bfd_section != NULL && !os->ignored)
{
+ lang_memory_region_type *r;
+
dot = os->bfd_section->vma;
- lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+ r = os->region;
+ if (r == NULL)
+ r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+
+ if (os->load_base)
+ os->bfd_section->lma
+ = exp_get_abs_int (os->load_base, 0, "load base");
+ else if (r->last_os != NULL)
+ {
+ asection *last;
+ bfd_vma lma;
+
+ last = r->last_os->output_section_statement.bfd_section;
+
+ /* If the current vma overlaps the previous section,
+ then set the current lma to that at the end of
+ the previous section. The previous section was
+ probably an overlay. */
+ if ((dot >= last->vma
+ && dot < last->vma + last->size)
+ || (last->vma >= dot
+ && last->vma < dot + os->bfd_section->size))
+ lma = last->lma + last->size;
+
+ /* Otherwise, keep the same lma to vma relationship
+ as the previous section. */
+ else
+ lma = dot + last->lma - last->vma;
+
+ if (os->section_alignment != -1)
+ lma = align_power (lma, os->section_alignment);
+ os->bfd_section->lma = lma;
+ }
+
+ lang_do_assignments_1 (os->children.head,
+ os, os->fill, dot);
+
/* .tbss sections effectively have zero size. */
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
|| link_info.relocatable)
- dot += TO_ADDR (os->bfd_section->size);
- }
- if (os->load_base)
- {
- /* If nothing has been placed into the output section then
- it won't have a bfd_section. */
- if (os->bfd_section && !os->ignored)
{
- os->bfd_section->lma
- = exp_get_abs_int (os->load_base, 0, "load base");
+ dot += TO_ADDR (os->bfd_section->size);
+
+ /* Keep track of normal sections using the default
+ lma region. We use this to set the lma for
+ following sections. Overlays or other linker
+ script assignment to lma might mean that the
+ default lma == vma is incorrect. */
+ if (!link_info.relocatable
+ && os->lma_region == NULL)
+ r->last_os = s;
}
}
}
@@ -4757,8 +4779,7 @@ lang_do_assignments_1
case lang_wild_statement_enum:
dot = lang_do_assignments_1 (s->wild_statement.children.head,
- output_section_statement,
- fill, dot);
+ current_os, fill, dot);
break;
case lang_object_symbols_statement_enum:
@@ -4827,7 +4848,7 @@ lang_do_assignments_1
case lang_assignment_statement_enum:
exp_fold_tree (s->assignment_statement.exp,
- output_section_statement->bfd_section,
+ current_os->bfd_section,
&dot);
break;
@@ -4837,8 +4858,7 @@ lang_do_assignments_1
case lang_group_statement_enum:
dot = lang_do_assignments_1 (s->group_statement.children.head,
- output_section_statement,
- fill, dot);
+ current_os, fill, dot);
break;
default:
@@ -5423,8 +5443,8 @@ lang_reset_memory_regions (void)
for (p = lang_memory_region_list; p != NULL; p = p->next)
{
- p->old_length = (bfd_size_type) (p->current - p->origin);
p->current = p->origin;
+ p->last_os = NULL;
}
for (os = &lang_output_section_statement.head->output_section_statement;
@@ -6350,10 +6370,6 @@ lang_leave_overlay (etree_type *lma_expr
an LMA region was specified. */
if (l->next == 0)
l->os->load_base = lma_expr;
- else if (lma_region == 0)
- l->os->load_base = exp_binop ('+',
- exp_nameop (LOADADDR, l->next->os->name),
- exp_nameop (SIZEOF, l->next->os->name));
if (phdrs != NULL && l->os->phdrs == NULL)
l->os->phdrs = phdrs;
Index: ld/testsuite/ld-scripts/overlay-size-map.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-scripts/overlay-size-map.d,v
retrieving revision 1.1
diff -u -p -r1.1 overlay-size-map.d
--- ld/testsuite/ld-scripts/overlay-size-map.d 7 May 2002 11:08:57 -0000 1.1
+++ ld/testsuite/ld-scripts/overlay-size-map.d 26 Jul 2006 01:08:25 -0000
@@ -1,9 +1,9 @@
#...
\.bss1 *0x0*20000 *0x10
#...
-\.bss2 *0x0*20000 *0x30 load address 0x0*20010
+\.bss2 *0x0*20000 *0x30
#...
-\.bss3 *0x0*20000 *0x20 load address 0x0*20040
+\.bss3 *0x0*20000 *0x20
#...
\.mtext *0x0*10000 *0x20 load address 0x0*30000
#...
--
Alan Modra
IBM OzLabs - Linux Technology Centre