"AT > region" interpreted as "> region" in linker script

Nick Clifton nickc@redhat.com
Fri Jan 2 19:21:00 GMT 2004


Hi Galit,

> The following is an undocumented (and perhaps unintended) behavior
> of ld linker scripts:
>
> When using the "AT > load_region" expression in an output section
> statement, if the statement does not include a "> virtual_region"
> expression as well, then the "AT >" expression is interpreted as an
> ">" expression, i.e. load_region is used as the virtual region.
>
> Examples:
>
> Suppose the memory is allocated as follows:
>
> MEMORY {
>         ram         : ORIGIN = 0x10,     LENGTH = 0x100
>         rom         : ORIGIN = 0xF00,    LENGTH = 0x100
> }
>
> This sets the virtual address to 0x10 and the load address to 0xF00,
> as expected:
>
> SECTIONS { .data :  {*(.data) } > ram AT > rom }
>
> However, this statement results in the error (for .data size of 8
> bytes): "ld: address 0x18 of a.out section .data is not within
> region rom".
>
> SECTIONS { .data 0x10 :  {*(.data) } AT > rom }
>
> And the following simply sets the virtual address to 0xf00, w/o any
> load address:
>
> SECTIONS { . = 0x10; .data :  { *(.data) } AT > rom }
>
> Is this a documentation issue or a bug ?


I believe that it is a bit of both.  In the second example, I think
that the linker should accept the explicitly provided VMA address for
the .data section and not attempt to use the "rom" region to provide
the VMA.

In the third example however, I think that the linker is correct.  No
VMA has been provided for the .data section.  (The assignment to dot
does not force a section to start at the indicated address, it just
prevents the section from starting before that address).  The linker
is allowed to move sections froward through memory if this makes
things simpler, so moving the .data section so that its VMA and LMA
address are the same, (by making it use the "rom" region for both VMA
and LMA) is permissible.

Here is a patch to address both problems.  It updates the
lang_get_region() function in ldlang.c so that the VMA region is only
set to the LMA region if a VMA address has not been set, and it
updates the documentation to describe this behaviour.

Do you agree with this patch ?

Cheers
        Nick

ld/ChangeLog
2004-01-02  Nick Clifton  <nickc@redhat.com>

	* ldlang.c (lang_get_regions): Add extra parameter 'have_vma'
	which if true will prevent the LMA region being used as a
	replacement for a default VMA region.
        (lang_leave_output_section_statement): Pass extra parameter.
        (lang_leave_overlay): Likewise.
        * ld.texinfo (Output Section LMA): Document that the LMA
	region can be set to the VMA region if no VMA has been set.

Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.131
diff -c -3 -p -r1.131 ldlang.c
*** ld/ldlang.c	8 Dec 2003 03:43:33 -0000	1.131
--- ld/ldlang.c	2 Jan 2004 19:16:05 -0000
*************** lang_get_regions (struct memory_region_s
*** 4496,4513 ****
  		  struct memory_region_struct **lma_region,
  		  const char *memspec,
  		  const char *lma_memspec,
! 		  int have_lma_p)
  {
    *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
  
!   /* If no runtime region has been given, but the load region has
!      been, use the load region.  */
!   if (lma_memspec != 0 && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
      *region = *lma_region;
    else
      *region = lang_memory_region_lookup (memspec, FALSE);
  
!   if (have_lma_p && lma_memspec != 0)
      einfo (_("%X%P:%S: section has both a load address and a load region\n"));
  }
  
--- 4496,4516 ----
  		  struct memory_region_struct **lma_region,
  		  const char *memspec,
  		  const char *lma_memspec,
! 		  bfd_boolean have_lma,
! 		  bfd_boolean have_vma)
  {
    *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
  
!   /* If no runtime region or VMA has been specified, but the load region has
!      been specified, then use the load region for the runtime region as well.  */
!   if (lma_memspec != NULL
!       && ! have_vma
!       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
      *region = *lma_region;
    else
      *region = lang_memory_region_lookup (memspec, FALSE);
  
!   if (have_lma && lma_memspec != 0)
      einfo (_("%X%P:%S: section has both a load address and a load region\n"));
  }
  
*************** lang_leave_output_section_statement
*** 4519,4525 ****
    lang_get_regions (&current_section->region,
  		    &current_section->lma_region,
  		    memspec, lma_memspec,
! 		    current_section->load_base != 0);
    current_section->fill = fill;
    current_section->phdrs = phdrs;
    stat_ptr = &statement_list;
--- 4522,4529 ----
    lang_get_regions (&current_section->region,
  		    &current_section->lma_region,
  		    memspec, lma_memspec,
! 		    current_section->load_base != NULL,
! 		    current_section->addr_tree != NULL);
    current_section->fill = fill;
    current_section->phdrs = phdrs;
    stat_ptr = &statement_list;
*************** lang_leave_overlay (etree_type *lma_expr
*** 4917,4923 ****
  
    lang_get_regions (&region, &lma_region,
  		    memspec, lma_memspec,
! 		    lma_expr != 0);
  
    nocrossref = NULL;
  
--- 4921,4927 ----
  
    lang_get_regions (&region, &lma_region,
  		    memspec, lma_memspec,
! 		    lma_expr != NULL, FALSE);
  
    nocrossref = NULL;
  
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.102
diff -c -3 -p -r1.102 ld.texinfo
*** ld/ld.texinfo	2 Dec 2003 15:38:46 -0000	1.102
--- ld/ld.texinfo	2 Jan 2004 19:16:13 -0000
*************** Address}).
*** 3362,3369 ****
  The linker will normally set the LMA equal to the VMA.  You can change
  that by using the @code{AT} keyword.  The expression @var{lma} that
  follows the @code{AT} keyword specifies the load address of the
! section.  Alternatively, with @samp{AT>@var{lma_region}} expression,
! you may specify a memory region for the section's load address. @xref{MEMORY}.
  
  @cindex ROM initialized data
  @cindex initialized data in ROM
--- 3362,3374 ----
  The linker will normally set the LMA equal to the VMA.  You can change
  that by using the @code{AT} keyword.  The expression @var{lma} that
  follows the @code{AT} keyword specifies the load address of the
! section.
! 
! Alternatively, with @samp{AT>@var{lma_region}} expression, you may
! specify a memory region for the section's load address. @xref{MEMORY}.
! Note that if the section has not had a VMA assigned to it then the
! linker will use the @var{lma_region} as the VMA region as well.
! @xref{Output Section Region}.
  
  @cindex ROM initialized data
  @cindex initialized data in ROM
        



More information about the Binutils mailing list