Trouble with linker script for a paged silicon

Georg-Johann Lay avr@gjlay.de
Sun Dec 16 11:25:00 GMT 2012


Hi.

I am struggling with a new default linker script for AVR.

This device has its flash layout in 64Ki byte chunks, and in order to 
put non-volatile data there, avr-gcc 4.7 and newer supports address 
spaces __flash1, __flash2, etc. according to ISO/IEC 18037 (Embedded C).

avr-gcc will drop data for __flash1 at input section .progmem1, similar 
for other __flashN spaces.

This input section must be located in such a way that it is a subset of 
[0x10000, 0x1ffff].  Notice this is trivially true for the empty set. 
This means that if .progmem1 is empty, it may be placed anywhere in 
order to minimize memory cutoff.

My current attempt reads like that:

SECTIONS
{
   ...

   .text :
   {
     ...
     *(.text)
     *(.text.*)
      _etext = . ;
   }  > text

   .flash1 MAX (1 << 16, ADDR(.text) + SIZEOF(.text)) :
   {
      PROVIDE (__flash1_start = .) ;
     *(.progmem1)
     *(.progmem1.*)
   }  > text

   ...

   .flash3 MAX (3 << 16, ADDR (.flash2) + SIZEOF (.flash2)) :
   {
      PROVIDE (__flash3_start = .) ;
     *(.progmem3)
     *(.progmem3.*)
   }  > text

   .data : AT (ADDR(.flash3) + SIZEOF(.flash3))
   {
     ...
   }
   ...
} /* SECTIONS */


Questions:

1) Is it possible not to waste memory if .flashN is empty?  What I tried is:

   .flash1 MAX (SIZEOF(.flash1) ? 1 << 16 : 0,
                ADDR(.text) + SIZEOF(.text)) :
   { ...

But it will evaluate as if SIZEOF(.flash1) was zero.

The docs read:

 > SIZEOF(section)
 >     Return the size in bytes of the named section, if that section
 >     has been allocated. If the section has not been allocated when
 >     this is evaluated, the linker will report an error.

As I don't get an error, the conclusion is that SIZEOF(.flash1) is known 
and brings a reasonable value.  However, with the following linker script

   _sizeof_flash1  = SIZEOF(.flash1) ;
   _endof_text     = ADDR(.text) + SIZEOF(.text) ;
   _startof_flash1 = MAX (_sizeof_flash1 ? 1<<16 : 0, _endof_text) ;
   .flash1 _startof_flash1 :
   {
     ...
   }

and a non-empty .flash1 with 0xa bytes the map file reads:

                 0x0000212e                _etext = .
                 0x0000000a                _sizeof_flash1 = SIZEOF (.flash1)
                 0x0000212e                _endof_text = (ADDR (.text) + 
SIZEOF (.text))
                 0x00010000                _startof_flash1 = MAX 
(_sizeof_flash1?0x10000:0x0, _endof_text)

.flash1         0x0000212e        0xa
                 0x0000212e                PROVIDE (__flash1_start, .)
  *(.progmem1)
  *(.progmem1.*)
  .progmem1.data.foo1
                 0x0000212e        0xa c:\Temp\ccMUm0N4.o
                 0x0000212e                flash1_start

Obviously, the right values are calculated for _startof_flash1 but not 
transferred correctly to the section start.

Is this a bug (in the documentation, in the linker) or a feature?

Can this be fixed in the AVR part of ld?


2) How do I express this correctly?  The requirement is to move the 
location (counter) forward only if the stuff that follows is non-empty.

What works is

   . = MAX (. , 0x10000)

but that moves the location unconditionally and wasted memory because 
the location counted is moved (an thus data bumped to a high address) 
for no reason.  What I need is something like

   . = MAX (. , __some_end == __some_start ? 0 : 0x10000)
   __some_start = .
   *(.some.stuff*)
   __some_end = .

i.e. there is no need to advance the location for nothing.  ld will 
complain on the forward references.

Notice that neither ALIGN nor NEXT will do this.

Id there a way to pre-compute the difference? The different won't change 
its value, no matter where stuff is located in the end.  as can handle 
label differences, maybe ld can, too?


3)  The end of the script contains assertions:

/* Sanity check the progmem stuff: .progmemN must be located within the
    N-th 64Ki byte chunk.  The low end needs no checking because the MAX
    with .flashN sets the right start address if .flashN is non-empty.  */

__assert_flash2
   = ASSERT (!SIZEOF (.flash2)
             || ADDR (.flash2) + SIZEOF (.flash2) <= 3 << 16,
             "section overflow: .progmem2 (__flash2)");

This works correctly but gives no indication on how much the section 
overflowed.  This means the user must trial-and-error juggle his data 
until he finds a working configuration.  He can not infer from the 
message how much data he has to move away from flash1 in order to 
satisfy the assertion, which is quite annoying.

Is there a way to report numerical values / values of expressions in a 
diagnostic?  Similar to GCC's error() or warning() that implement a 
printf-like interface?  Something like a %d together with a varargs ASSERT?

I observed that there are neat messages that report overlapping memory 
regions.  However, the pages mentioned above are not mutually exclusive 
because .text. and .progmemN may use and will use the same flash.

If, for example, .text extends at [0, 0x2a000] and the user puts 10 
bytes into .flash2, we can locate them at [0x2a001, 0x2a00a] and there 
is no need to throw an error because .text overlaps [0x20000, 0x2ffff].


Many thanks for your advice

Georg-Johann



More information about the Binutils mailing list