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