I had a complicated problem that I needed to access the .data
initialization data as a separate segment for an Arm bare-metal application.
I was able to achieve it using Output Section Region.
My original linker script went something like this:
SECTIONS
{
/*
* For Cortex-M devices, the beginning of the startup code is stored in
* the .interrupt_vector section, which goes to FLASH
*/
.text :
{
. = ALIGN(4);
KEEP(*(.interrupt_vector))
KEEP(*(.reset))
*(.text .text.*) /* all remaining code */
*(.rodata .rodata.*) /* read-only data (constants) */
. = ALIGN(4);
} >FLASH
/*
* This address is used by the startup code to
* initialize the .data section.
*/
. = ALIGN(4);
__data_init__ = .;
.data : AT ( __data_init__ )
{
. = ALIGN(4);
/* This is used by the startup code to initialize the .data section */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
. = ALIGN(4);
/* This is used by the startup code to initialize the .data section */
__data_end__ = . ;
} >RAM
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .;
} >RAM
And my startup function has:
/* Copy .data from FLASH to RAM */
src = &__data_init__;
dest = &__data_start__;
end = &__data_end__;
while(dest < end) {
*dest++ = *src++;
}
I changed my linker script to:
SECTIONS
{
/*
* For Cortex-M devices, the beginning of the startup code is stored in
* the .interrupt_vector section, which goes to FLASH
*/
.text :
{
. = ALIGN(4);
KEEP(*(.interrupt_vector))
KEEP(*(.reset))
*(.text .text.*) /* all remaining code */
*(.rodata .rodata.*) /* read-only data (constants) */
. = ALIGN(4);
} >FLASH
.data :
{
. = ALIGN(4);
__data_init__ = LOADADDR (.data);
/* This is used by the startup code to initialize the .data section */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
. = ALIGN(4);
/* This is used by the startup code to initialize the .data section */
__data_end__ = . ;
} >RAM AT > FLASH
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .;
} >RAM AT > RAM
And now I have .data
as an entirely separate ELF segment:
arm-none-eabi-readelf.exe -l ../../../firmware/Cortex-M3/cm3-bootloader/Release/cm3-bootloader.elf
Elf file type is EXEC (Executable file)
Entry point 0x601b9
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00060000 0x00060000 0x067fc 0x067fc R E 0x10000
LOAD 0x019b30 0x20019b30 0x000667fc 0x00064 0x00064 RW 0x10000
LOAD 0x029b2c 0x20019b2c 0x20019b2c 0x00000 0x060e8 RW 0x10000
Section to Segment mapping:
Segment Sections...
00 .text .ARM.exidx.reset
01 .data
02 .systemclock .bss ._stack
Also, __data_init__
still points exactly where .data
LMA is:
.data 0x20019b30 0x64 load address 0x000680f4
0x20019b30 . = ALIGN (0x4)
0x000680f4 __data_init__ = LOADADDR (.data)
0x20019b30 __data_start__ = .
This is not a question, this is just to register how I did this in case it's helpful to someone else.