This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: Trouble with linker script for a paged silicon
- From: Erik Christiansen <dvalin at internode dot on dot net>
- To: binutils at sourceware dot org
- Date: Mon, 17 Dec 2012 01:15:07 +1100
- Subject: Re: Trouble with linker script for a paged silicon
- References: <50CDAF6F.8010707@gjlay.de>
- Reply-to: dvalin at internode dot on dot net
On 16.12.12 12:24, Georg-Johann Lay wrote:
> 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.
It does not need to be "placed anywhere ...". When empty, it becomes
essentially invisible to the location process, as shown by test results
at the end of this post. (Check the last test, where .hightext "snugs
down" _without_ a wasted byte, and other similar results.)
Please try the appended linker script. It provides the paged memory
model which you require. The tests and results appended after the script
show that it does NOT waste memory, because the empty output sections do
not affect the location counter, so everything butts up. (Except where
the user specifies a hole by asking for a modulo 2^16 page start,
obviously)
> 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].
It should be noted that the .text input section is _above_ __flashN, and
therefore occupies unused __flashN from _above_, _not_ from below. For
this reason, ld's default behaviour of butting up to the preceding
section solves this imagined problem. I think you will find that, if you
read through and repeat the tests already done. Please try it.
Johann, the nifty sourcecode used to test the linker script is your own.
Please run any test you like on the appended script, and report what
might be improved. AFAICT, it satisfies all the requirements which have
recently appeared on avr-gcc-list.
If any tweaks are required, please post your test results, or just state
what extra the tested working script should do. (Soon, please. I'm
incommunicado for several weeks from Wednesday.)
Reporting the size of a page overflow is the one new minor requirement
that I detect, and yes, the ability to include variables in an ASSERT
message would be brilliant for that.
It is after 1 a.m. here, but if you take the trouble to check out what
has been developed, I can reply to any questions in the morning.
Best Regards,
Erik
file: avr6.x
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:6)
MEMORY
{
text (rx) : ORIGIN = 0, LENGTH = 1024K
data (rw!x) : ORIGIN = 0x800200, LENGTH = 0xfe00
eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
fuse (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
lock (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}
SECTIONS
{
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
/* Internal text space or external memory. */
.lowtext :
{
*(.vectors)
KEEP(*(.vectors))
/* For data that needs to reside in the lower 64k of progmem. */
*(.progmem.gcc*)
. = ALIGN(2);
__trampolines_start = . ;
/* The jump trampolines for the 16-bit limited relocs will reside here. */
*(.trampolines)
*(.trampolines*)
__trampolines_end = . ;
/* For future tablejump instruction arrays for 3 byte pc devices.
We don't relax jump/call instructions within these sections. */
*(.jumptables)
*(.jumptables*)
/* For code that needs to reside in the lower 128k progmem. */
*(.lowtext)
*(.lowtext*)
__ctors_start = . ;
*(.ctors)
__ctors_end = . ;
__dtors_start = . ;
*(.dtors)
__dtors_end = . ;
KEEP(SORT(*)(.ctors))
KEEP(SORT(*)(.dtors))
*(.progmem.data*) /* Explicitly page 0 input sections */
_elowtext = . ;
x = ASSERT (. <= 0x20000, "Error: .lowtext (128KiB limit) overflow. Try shrinking .progmem?") ;
} > text
.flash1 0x10000 :
{ *(.progmem1.data*) /* Page 1 */
} > text
.flash2 0x20000 :
{ *(.progmem2.data*) /* Page 2 */
} > text
.flash3 0x30000 :
{ *(.progmem3.data*) /* Page 3 */
} > text
.flash4 0x40000 :
{ *(.progmem4.data*) /* Page 4 */
} > text
.flash5 0x50000 :
{ *(.progmem5.data*) /* Page 5 */
} > text
.hightext :
{
/* The following is OK to follow preceding sections
at any even byte address, on any page. */
. = ALIGN(2) ;
*(.init0) /* Start here after reset. */
KEEP (*(.init0))
*(.init1)
KEEP (*(.init1))
*(.init2) /* Clear __zero_reg__, set up stack pointer. */
KEEP (*(.init2))
*(.init3)
KEEP (*(.init3))
*(.init4) /* Initialize data and BSS. */
KEEP (*(.init4))
*(.init5)
KEEP (*(.init5))
*(.init6) /* C++ constructors. */
KEEP (*(.init6))
*(.init7)
KEEP (*(.init7))
*(.init8)
KEEP (*(.init8))
*(.init9) /* Call main(). */
KEEP (*(.init9))
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini9) /* _exit() starts here. */
KEEP (*(.fini9))
*(.fini8)
KEEP (*(.fini8))
*(.fini7)
KEEP (*(.fini7))
*(.fini6) /* C++ destructors. */
KEEP (*(.fini6))
*(.fini5)
KEEP (*(.fini5))
*(.fini4)
KEEP (*(.fini4))
*(.fini3)
KEEP (*(.fini3))
*(.fini2)
KEEP (*(.fini2))
*(.fini1)
KEEP (*(.fini1))
*(.fini0) /* Infinite loop after program termination. */
KEEP (*(.fini0))
_etext = . ;
} > text
.data : AT (_etext)
{
PROVIDE (__data_start = .) ;
/* --gc-sections will delete empty .data. This leads to wrong start
addresses for subsequent sections because -Tdata= from the command
line will have no effect, see PR13697. Thus, keep .data */
KEEP (*(.data))
*(.data*)
*(.rodata) /* We need to include .rodata here if gcc is used */
*(.rodata*) /* with -fdata-sections. */
*(.gnu.linkonce.d*)
. = ALIGN(2);
_edata = . ;
PROVIDE (__data_end = .) ;
} > data
.bss : AT (ADDR (.bss))
{
PROVIDE (__bss_start = .) ;
*(.bss)
*(.bss*)
*(COMMON)
PROVIDE (__bss_end = .) ;
} > data
__data_load_start = LOADADDR(.data);
__data_load_end = __data_load_start + SIZEOF(.data);
/* Global data not cleared after reset. */
.noinit :
{
PROVIDE (__noinit_start = .) ;
*(.noinit*)
PROVIDE (__noinit_end = .) ;
_end = . ;
PROVIDE (__heap_start = .) ;
} > data
.eeprom :
{
*(.eeprom*)
__eeprom_end = . ;
} > eeprom
.fuse :
{
KEEP(*(.fuse))
KEEP(*(.lfuse))
KEEP(*(.hfuse))
KEEP(*(.efuse))
} > fuse
.lock :
{
KEEP(*(.lock*))
} > lock
.signature :
{
KEEP(*(.signature*))
} > signature
x = ASSERT (SIZEOF(.flash1) <= 0x10000, "Error: __flash1 (64KiB limit) overflow. Need to shrink it.") ;
x = ASSERT (SIZEOF(.flash2) <= 0x10000, "Error: __flash2 (64KiB limit) overflow. Need to shrink it.") ;
x = ASSERT (SIZEOF(.flash3) <= 0x10000, "Error: __flash3 (64KiB limit) overflow. Need to shrink it.") ;
x = ASSERT (SIZEOF(.flash4) <= 0x10000, "Error: __flash4 (64KiB limit) overflow. Need to shrink it.") ;
x = ASSERT (SIZEOF(.flash5) <= 0x10000, "Error: __flash5 (64KiB limit) overflow. Need to shrink it.") ;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
}
end avr6.x
file: script_tests
Tests and Expected Results
--------------------------
Trampolines, etc., must be in lower 128 KiB:
Just fits in:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP0=0x1f000 -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Idx Name Size VMA LMA File off Algn
0 .data 00000000 00800200 0003f16e 0003f1e2 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .lowtext 0001f10c 00000000 00000000 00000074 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .hightext 00020062 0001f10c 0001f10c 0001f180 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
.data LMA butts up to .hightext, which butts up to .lowtext.
Overflows:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP0=0x20000 -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Error: .lowtext (128KiB limit) overflow. Try shrinking .progmem?
Locate __flashN at 0xN0000:
Just fits in:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP1=0x10000 -DP3=0x87ff -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Idx Name Size VMA LMA File off Algn
0 .data 00000000 00800200 00058862 00038a22 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .lowtext 0000010c 00000000 00000000 000000b4 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .flash1 00010000 00010000 00010000 000001c0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .flash3 000087ff 00030000 00030000 000101c0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .hightext 00020063 000387ff 000387ff 000189bf 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
Note: .hightext (where input section .text goes) butts up to 000387ff, using
all spare .flash3. (From the next even byte address, inside .hightext.)
.data in flash does the same with .hightext, at 00058862.
Overflows:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP1=0x10001 -DP3=0x10001 -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Error: __flash1 (64KiB limit) overflow. Need to shrink it
Error: __flash3 (64KiB limit) overflow. Need to shrink it.
Overlaps prior section:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP0=0x10000 -DP1=0x87ff -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
section .flash1 loaded at [00010000,000187fe] overlaps section .lowtext
loaded at [00000000,0001010b]
flash.elf: section .flash1 vma 0x10000 overlaps previous sections
but ld also says this, which isn't helpful:
section .hightext vma 0x187ff overlaps previous sections
Overlaps following section:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DP1=0x10001 -DP2=0x87ff -DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Error: __flash1 (64KiB limit) overflow. Need to shrink it.
section .flash2 loaded at [00020000,000287fe] overlaps section .flash1 loaded
at [00010000,00020000]
flash.elf: section .flash2 vma 0x20000 overlaps previous sections
and again:
flash.elf: section .hightext vma 0x287ff overlaps previous sections
The bulk of code (.text -> .hightext) snugs down if there are no __flashN:
$ avr-gcc -T avr6.x-new -Wl,-Map,flash.map -o flash.elf -DSTUBS=10 \
-DTEXT=0x20000 -mmcu=atmega2560 flash.sx
Idx Name Size VMA LMA File off Algn
0 .data 00000000 00800200 0002016e 000201e2 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .lowtext 0000010c 00000000 00000000 00000074 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .hightext 00020062 0000010c 0000010c 00000180 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
.hightext now follows imediately from .lowtext.
--
A computer is like an air conditioner, it works poorly when you open Windows.