I'm writing an application for an embedded system using an Atmel ARM core processor using GCC tools provided with Atmel Studio. The production programming device I'll be using can write a serial number to a specified ROM location during programming which is nice because it's an automated process and avoids the potential for human error.
I'd like to set aside space in my binary to ensure that a given address is ALWAYS free for this purpose, and also so that my application can read its serial number from Flash.
I've looked at some other questions on SO such as this one that appear very similar to my problem but seem to omit key details from the answers because I am unable to reproduce the results.
The linker script that was provided for my processor is as follows:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00800000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + __stack_size__;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
}
This script works with no problems. I've attempted to add a small section of memory to store the serial number in Flash but always end up with the linker happily storing data well outside the specified rom area.
I have tried adding code to the linker script as follows:
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
/**** START ADDED CODE ****/
_metastart = 0x47FF00;
.metadata :
{
. = _metastart;
*(.metadata)
} > rom
/**** END ADDED CODE ****/
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
and to my main.cpp like this:
static uint8_t nvSerial[4] __attribute__((used,section(".metadata"))) = { 0xDE, 0xAD, 0xBE, 0xEF };
But end up with a huge binary file with data well above 0x00480000 and below 0x200000000. I've also tried writing the linker script addition as follows (in the same location as above):
_metastart = 0x47FF00;
.metadata : AT(_metastart)
{
*(.metadata)
} > rom
But then my serial number seems to be left out entirely (i.e., there's nothing present at 0x47FF00). Similarly, there's no data to be found if I set up my linker file like this:
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x0007FF00
meta (rx) : ORIGIN = 0x0047FF00, LENGTH = 0x00000100 /** ADDED **/
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/** snip **/
.metadata :
{
*(.metadata)
} > meta
Can anyone offer any advice as to what I'm doing wrong?
EDIT
So the "solution" to the problem was to change my linker to make use of the KEEP command to describe the metadata section AFTER the value of _etext gets updated. If I describe metadata BEFORE _etext gets assigned, then the linker for some reason stores a bunch of constant data after metadata and into an undefined memory region. Relevant sections of the new linker file are below:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x0007FF00
meta (rx) : ORIGIN = 0x0047FF00, LENGTH = 0x00000100
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/** snip **/
. = ALIGN(4);
_etext = .;
.metadata :
{
KEEP(*(.metadata))
} > meta
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
So this works but my question is now WHY does this work?
Related
I am trying to build firmware for Cortex-M0 with clang. The gcc build works of course fine. The build fails during linking
ld.lld: error: baremetal.ld:72: ( expected, but got )
>>> KEEP(*.init_array)
>>> ^
clang-12: error: ld.lld command failed with exit code 1 (use -v to see invocation)
The linker script is pretty standard (and the offending line is also in scripts provided by CMSIS). Relevant part:
.rodata : ALIGN(4)
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = . ;
KEEP(*(.preinit_array))
__preinit_array_end = . ;
. = ALIGN(4);
__init_array_start = . ;
KEEP(*(SORT(.init_array.*)))
KEEP(*.init_array) <<======== error here
__init_array_end = . ;
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = . ;
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
__fini_array_end = . ;
. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(0x4);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
*(.init .init.*)
*(.fini .fini.*)
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN (8);
*(.rom)
*(.rom.b)
_etext = . ;
_sidata = _etext; /* first address of initialized data in FLASH */
} >FLASH
My LLD version
$ ld.lld -V
LLD 13.0.0 (compatible with GNU linkers)
How can I fix the linking?
This linker script is not valid. The error message tells you exactly what you have got wrong: "expected (".
The specification is filename(section) or KEEP(filename(section)).
You can't write: KEEP(*.init_array) because there isn't a "(" between the filename and section name.
If what you mean is "keep the section .init_array from any file", then you need:
KEEP(*(.init_array))
If this script was really provided with a released version of CMSIS (and you haven't just made a typo yourself) then you should report this as a bug.
I am trying to relocate the entry point of a statically-linked binary I am building to a fixed value, so it can be loaded into that area of memory by a bootloader and jumped into with a function pointer dereference. Here is the loader script I am using:
ENTRY(main)
SECTIONS
{
. = 0x0000000000200000;
.text : {
*(.text)
. = ALIGN(8);
}
.data : {
*(.data)
*(.rodata)
. = ALIGN(8);
}
__bss_start = .;
.bss : {
bss = .; _bss = .; __bss = .;
*(.bss);
}
end = .; _end = .; __end = .;
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
}
Here is the command line I am using for the final link:
...
CC = g++
CFLAGS = -g -mcmodel=large -fPIC -T src/controlix.ld -Wl,--no-relax -static -nostdlib -static-libgcc
...
$(CC) $(CFLAGS) $(shell find bin/ -name "*.o") -o $(TARGET_OBJ)
(Details of the rest of the build system omitted for brevity, I don't think any of it is pertinent)
So, I am assuming that when I look at the resultant controlix.o binary, I should see the main() symbol located at 0x200000, right? Wrong:
$ nm bin/controlix.o |grep main
000000000021d0c6 t _GLOBAL__sub_D_main.cpp
000000000021d087 t _GLOBAL__sub_I_main.cpp
000000000021cef1 T main
0000000000256e11 t _ZL8eiremainPtS_P7LDPARMS
What am I doing wrong?
I should see the main() symbol located at 0x200000, right?
No. Imagine how many things have to be done before main is called. Libraries have to be initialized, constructors and destructors called (C++), on many systems .bss zeroed and .data initialized + many other things I do not remember now.
The main is the entry point of the C program but is not (in almost all known implementarions) the entry point of the executable file.
if you want your function to be called first, place it in the separate segment and amend the linker script
.text : {
*(.beforetext)
. = ALIGN(8);
__text_start = .;
*(.text)
. = ALIGN(8);
}
extern unsigned __text_start;
void __attribute__((section(".beforetext"))) myEntryFunc(void)
{
....
((void (*)(void))(&__text_start))(); // call the original executable entry point
}
Assuming ELF, the ENTRY directive defines main as the entry poin in the ELF file header with no effect on the address of main.
To force main to be at the start of the text segment, one technique is to put main in its own section and then positioning this section before the .text section.
With recent GCC and Clang, you may use __attribute__((section(".main"))__ or [[gnu::section(".main")]] in a variable or function declaration to set the section.
I created my first gcc linker script for a SAMD51J19 microcontroller through atmel studio and it compiles great without issues but when loaded into the device weird quirky errors happen.
Sometimes it hard-faults, sometimes it doesn't, sometimes interrupts aren't sent to the handler, sometimes they are. Sometimes functions are run with nothing happening like it should and sometimes not. The debugger was all over the place, I didn't have any of these problems with the old stock linker code and I have no idea why it's happening.
Most all of it was just re-used from the original file. Mainly what I did was add some spacing or better alignment between areas and moved some sections around that weren't mandatory placed there. For example Read-Only data at the end of rom bank 0 rather than the middle. so I really don't get why this is happening
below is my linker script
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/*
* NVM = 2 Banks (512KB) (352KB usable) (160KB reserved for SEEPROM)
* 1 Bank = 32 blocks (256K) and 16 Regions
* Bank 1 (Main) = 32 blocks (256K) and 16 Regions
* Bank 2 (Aux) = 12 Blocks (96KB) and 6 Regions
* 1 Region = 2 Blocks (16KB) (Protection Alignment)
* 1 Block = 16 Pages (8KB) (Division Alignment)
* 1 Page = 32 QWords (512B) (Section Alignment)
* 1 QWord = 16 Bytes (Sub-Section Alignment)
* 1 DWord = 8 Bytes
* 1 Word = 4 Bytes (Default Alignment)
*
* Alignments:
* 4 Bytes: New piece
* 16 Bytes: New Subsection
* 512 Bytes: New Section
* 8,192 Bytes: New division
* 16,384 Bytes: New protection region
*/
/* Memory Spaces Definitions */
MEMORY
{
rom0 (rx) : ORIGIN = 0x00000000, LENGTH = 0x0003F800 /*Rom Bank 0: Main Bank (For Code)*/
lnl (rx) : ORIGIN = 0x0003F800, LENGTH = 0x00000800 /*Load-N-Lock 0-Wait State Speed: 2KB*/
rom1 (rx) : ORIGIN = 0x00040000, LENGTH = 0x00018000 /*Rom Bank 1: Aux Bank (For Data)*/
qspi (rx) : ORIGIN = 0x04000000, LENGTH = 0x01000000 /*External NVM: (Additional Aux Data on seperate chip)*/
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 /*Ram (Default RAM)*/
seeprom (rx) : ORIGIN = 0x44000000, LENGTH = 0x00010000 /*SEEPROM: Runtime Permanent Data*/
bkupram (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000 /*Backup Ram: Program Data*/
}
/* The stack size used by the application*/
STACK_SIZE = 0xC000;
/* Section Definitions */
SECTIONS
{
/*
Program Code
Gameplan for .text output section
No support for exceptions or unwinding tables
Vectors go at start
Program Code is placed on the next QWord
Thumb/Arm Glue code is placed on the next QWord
Read-Only Data is placed in it's own page
Relocate Data is placed in it's own page
*/
.text :
{
/*Start at top*/
. = 0x00000000;
_stext = .;
_sfixed = .;
/*Vector Table*/
/*Place Vectors at start of rom0 as required*/
KEEP(*(.vectors .vectors.*))
/*Program Code*/
. = ALIGN(16); /*New Subsection*/
*(.text .text.* .gnu.linkonce.t.*)
/*C & C++ Special Generated Code, part of main program code*/
/*C++ Setup Code*/
. = ALIGN(4); /*New piece*/
KEEP(*(.init))
. = ALIGN(4); /*New piece*/
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4); /*New piece*/
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
/*C++ Constructor Code*/
. = ALIGN(4); /*New piece*/
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
/*C++ Teardown Code*/
. = ALIGN(4); /*New piece*/
KEEP(*(.fini))
. = ALIGN(4); /*New piece*/
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
/*C++ Deconstructor Code*/
. = ALIGN(4); /*New piece*/
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
/*Thumb <==> ARM Code Translation Glue*/
. = ALIGN(16); /*New Subsection*/
*(.glue_7t) *(.glue_7)
/*Read-Only/Constant Data, placing in a new page*/
. = ALIGN(512); /*New Page*/
*(.rodata .rodata* .gnu.linkonce.r.*)
/*This is for relocating data, place it in it's own page*/
. = ALIGN(512); /*New Page*/
_placeRelocate = .;
_efixed = .;
_etext = .;
} > rom0 /*These of course go in the main rom bank*/
/*
Rom 0 Custom Code
Gameplan for .rom0 output section
This is sort of a workarea for program-specific usage unrelated to generated
code. It needs to go into it's own block.
*/
.rom0 (NOLOAD):
{
. = ALIGN(8192); /*New block*/
_srom0 = .;
*(.rom0*)
_erom0 = .;
} > rom0
/*
Load-N-Lock 0-Wait State Speed
Gameplan for .lnl output section
LNL is placed in it's own reserved memory area of a specific size in rom0. Space is
immensely cramped and every byte counts. No alignment will be done.
*/
.lnl (NOLOAD):
{
_slnl = .;
*(.lnl*)
_elnl = .;
} > lnl /*Goes into it's own specific area*/
/*
Rom 1 Custom Code
Gameplan for .rom1 output section
Rom Bank 1 is more relaxed given the entire bank is for program usage.
This needs to be placed after the first page. The first page is reserved
for program-specific header data and work area.
*/
.rom1 (NOLOAD):
{
. = 512; /*2nd page from start*/
_srom1 = .;
*(.rom1*)
_erom1 = .;
} > rom1 /*Goes into rom bank 1*/
/*
QSPI Custom Code
Gameplan for .qspi output section
QSPI is similar to ROM1 in that it's just an area that can be used
for custom usage or work area.
*/
.qspi (NOLOAD):
{
. = ALIGN(4); /*New piece*/
_sqspi = .;
*(.qspi*)
_eqspi = .;
} > qspi /*Goes into QSPI*/
/*
Uninitialized Data
Gameplan for .bss output section
Uninitialized data goes into main RAM at the start
*/
.bss (NOLOAD) :
{
. = ALIGN(4); /*New piece*/
_sbss = . ;
_szero = .;
*(.bss .bss.*) /*Place BSS Data at start of RAM*/
. = ALIGN(4); /*New piece*/
*(COMMON) /*Place common data after*/
_ebss = . ;
_ezero = .;
/*Relocate data comes after bss*/
. = ALIGN(4); /*New piece*/
_relocateStart = .;
} > ram
/*
Relocate data
Gameplan for .relocate output section
This needs to be placed at rom0 in it's own defined section. It will
be copied to the end of bss.
*/
.relocate : AT (_placeRelocate)
{
. = ALIGN(4); /*New piece*/
_srelocate = .;
*(.data .data.*);
. = ALIGN(4); /*New Piece*/
*(.ramfunc .ramfunc.*);
_erelocate = .;
} > ram /*Place in RAM*/
/*
Stack data
Gameplan for .stack output section
Placed at end of RAM an empty area large enough for the stack
*/
.stack (NOLOAD):
{
. = ALIGN(8); /*New larger piece*/
_sstack = .; /*Begin Stack*/
. = . + STACK_SIZE; /*Insert large blank area for stack*/
. = ALIGN(8); /*New larger piece*/
_estack = .; /*End stack placement*/
} > ram
/*
SEEPROM Data
Gameplan for .seeprom output section
The SEEPROM section is like rom1 just byte-writable rather than
block/page eraseable/writable. Unlike ROM1 however SEEPROM can start
at the beginning.
*/
.seeprom (NOLOAD):
{
. = ALIGN(4); /*New piece*/
_seeprom = .;
*(.seeprom*)
_eseeprom = .;
} > seeprom /*Goes into seeprom area*/
/*
Custom Backup RAM
Gameplan for .bkupram output section
Like ROM1 and SEEPROM, this is another potential usage area.
*/
.bkupram (NOLOAD):
{
. = ALIGN(4); /*New piece*/
_sbkupram = .;
*(.bkupram*)
_ebkupram = .;
} > bkupram /*Goes into bkupram area*/
. = ALIGN(4); /*New piece*/
_end = . ; /*End of everything*/
}
And the original file here that came with the ide
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom0 (rx) : ORIGIN = 0x00000000, LENGTH = 0x0003F800
lnl (rx) : ORIGIN = 0x0003F800, LENGTH = 0x00000800 /*Load-N-Lock 0-Wait State Caching: 2KB*/
rom1 (rx) : ORIGIN = 0x00040000, LENGTH = 0x00018000
qspi (rx) : ORIGIN = 0x04000000, LENGTH = 0x01000000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000
seeprom (rx) : ORIGIN = 0x44000000, LENGTH = 0x00010000
bkupram (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0xC000;
/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom0
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom0
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.lnl :
{
/*. = ALIGN(4);*/
__lnl_start__ = .;
*(.lnl*)
__lnl_end__ = .;
} > lnl
.rom1 (NOLOAD):
{
. = ALIGN(8);
_rom1 = .;
*(.rom1 .rom1.*);
. = ALIGN(8);
_rom1 = .;
} > rom1
.seeprom (NOLOAD):
{
. = ALIGN(8);
_seeprom = .;
*(.seeprom .seeprom.*);
. = ALIGN(8);
_eseeprom = .;
} > seeprom
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
.bkupram (NOLOAD):
{
. = ALIGN(8);
_sbkupram = .;
*(.bkupram .bkupram.*);
. = ALIGN(8);
_ebkupram = .;
} > bkupram
.qspi (NOLOAD):
{
. = ALIGN(8);
_sqspi = .;
*(.qspi .qspi.*);
. = ALIGN(8);
_eqspi = .;
} > qspi
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
}
It turns out after much experimentation, trial, and error that the ram section have to seemingly be "relocate" then "bss" then "stack" in that order.
What I was trying to do was place "bss" above "relocate" and that caused everything to not work. So that's the answer but can anybody explain why "bss" has to be above "relocate". I did that because I was wanting static members to be placed at the top and I understand relocate is for non-static members.
For my embedded application on Atmel SAM4E16C i need to place an array with firmware information at the end of the .hex file. I'm using Atmel Studio 7 with GCC.
I've already done this for Atmega168PB but somehow it doesn't work for this project.
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00420000, LENGTH = 0x000E0000 /* changed to leave space for 128KB Bootloader -> was ORIGIN = 0x00400000, LENGTH = 0x00100000 */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;
/* Firmware Info - 8 Bytes long at the end of ROM */
__FWInfo_start__ = ORIGIN(rom) + LENGTH(rom) - 8;
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + __stack_size__;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
/* 8 Byte Firmware Info Section */
.FWInfo : AT (__FWInfo_start__)
{
*(.FWInfo)
} > rom
}
This is the linker script i'm using. I've added the __FWInfo_start__ and the .FWInfo section.
In my application i tried to define the firmware info block with attribute section .FWInfo but i'm unable to locate the data in my .hex file.
#define SIZE_OF_FWINFO 8
const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO] __attribute__((section(".FWInfo"))) = {
0xff, // reserved for future
0xff, // reserved for future
DEVICE_TYPE, // DeviceType
BUILD_NR, // BuildNr of Firmware
VERSION_MINOR, // VersionMinor of Firmware
VERSION_MAJOR, // VersionMajor of Firmware
0xFF, // Checksum
0xFF // Checksum
};
I hope someone can help me why this isn't working. Thanks in advance.
EDIT: Here are the entries in the .map file:
.data 0x00000000 0x0 src/main.o
.FWInfo 0x00000000 0x8 src/main.o
.debug_macro 0x00000000 0x8b0 src/main.o
and..
*fill* 0x200133b0 0x3000
0x200163b0 . = ALIGN (0x8)
0x200163b0 _estack = .
0x200163b0 . = ALIGN (0x4)
0x200163b0 _end = .
.FWInfo
*(.FWInfo)
OUTPUT(Dali4Net.elf elf32-littlearm)
as far as i can read from the context in the second block there should be an address written after the .FWInfo or?
From GCC variable attribute documentation:
used
This attribute, attached to a variable with static storage, means that the variable must be emitted even if it appears that the variable is not referenced.
So to prevent the unused data being removed by the linker, use:
const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
__attribute__((used,section(".FWInfo"))) =
{ ... } ;
An alternative but perhaps less attractive solution is to declare the array volatile and then perform a dummy read i.e.:
const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
__attribute__((section(".FWInfo"))) =
{ ... } ;
int main()
{
uint8_t dummy = nFirmwareInfoBlock[0] ;
...
}
The third method is to avoid toolchain dependencies altogether and to use the excellent if somewhat arcane SRecord utility to patch the data directly to the hex file as a post-build operation. This has the advantage of being tool-chain independent, but you will need a step perhaps to generate the data to be patched in, but writing a generator for that is probably trivial.
From my experience in Atmel studio 6 and 8bit AVR core:
define the section .FWInfo (I do it without makefile sorry)
And doing
const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
__attribute__((used,section(".FWInfo"))) =
{ ... } ;
is not enough, because only the compiler will keep the variable. Then the linker may discard it if it is not used. Of course a simple reference is enough to keep it but if it only used in the bootloader for example you can define a linker flag.
Again I did it graphically (sorry).
I know this post is pretty old, but anyways...
As already stated, the use of KEEP directive to keep the section even if unused may be needed, or just ensuring it will always be kept no matter what.
More than that, I wanted to do something similar for a STM32.
It seems that the order of sections is important too (even when an address is explicitly given).
I had to place my extra section just before the start of RAM sections.
Here, you have sections that goes to ROM > rom and RAM > ram. You may also have some other section of initialized datas which are denoted >RAM AT> FLASH (for STM32 gcc). In this example, it seems that it's denoted as .relocate : AT (_etext).
Anyways, if it works the same way, you should place your own section just before the .bss which is the start of uninitialized datas (first section related to RAM only):
...
_erelocate = .;
} > ram
/* 8 Byte Firmware Info Section */
.FWInfo : AT (__FWInfo_start__)
{
KEEP(*(.FWInfo))
} > rom
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
...
If it still doesn't work as expected, you may try to place this section before the .relocate : AT (_etext) section; which is located after the latest mentioned rom section, but as this section is relocated from ROM to RAM even if ambigous in the notation, I think the first guess should work.
I'm developing an embedded application using GCC/G++ compiled for arm-eabi. Due to resource constraints, I'm trying to disable the standard C++ exception handling. I'm compiling the code with "-fno-exceptions
-nostartfiles -ffreestanding".
When a global instance of a class exists, and that class contains an instance of another class as a member, then a lot of exception handling code is being linked in. This wouldn't be so bad, except that it's also bringing in lots of stdio stuff, like printf, fopen, fclose and other FILE functions. This application has no filesystem, and even if it did, these functions waste too much code space.
I understand that even with -fno-exceptions, G++ links in an operator new that uses exceptions, because the library doesn't have a non-exception-using operator new (except new(nothrow)). I created replacements for operator new and delete, and these are linked into the output as well as the unwanted standard-library functions.
What puzzles me is that I'm not calling new anywhere. It's only when a global object contains another object that all this code is linked in.
For example:
class UartA {
...
private:
Ringbuffer* rxbuf;
};
class UartB {
...
private:
Ringbuffer rxbuf;
};
If a global instance of UartA is created, the exception handling, operator new, and stdio stuff are not linked in. This is what I want.
If a global instance of UartB is created (where rxbuf is an instance instead of a pointer), the unwanted code is linked in.
Neither UartA nor UartB use operator new, exceptions or stdio. They differ only by the type of rxbuf.
Can you suggest how to prevent linking the extra code? Also, why is this being linked in for UartB, but not UartA?
since you are basically doing the things that an OS developer would do to get a standalone c or c++ environment. You may want to look into just using a custom linker script. You just need to be careful because things like global constructors no longer happen automatically..but you will also not get anything you didn't explicitly ask for (and it isn't hard to write the code to call the global constructors). Here's the linker script from my OS.
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
virt = 0xc0100000; /* 3.1 gig */
phys = 0x00100000; /* 1 meg */
SECTIONS
{
.text virt : AT(phys)
{
code = .; _code = .; __code = .;
*(.text)
*(.gnu.linkonce.t*)
. = ALIGN(4096);
}
.rodata : AT(phys + (rodata - code))
{
rodata = .; _rodata = .; __rodata = .;
*(.rodata*)
*(.gnu.linkonce.r*)
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;
. = ALIGN(4096);
}
.data : AT(phys + (data - code))
{
data = .; _data = .; __data = .;
*(.data)
*(.gnu.linkonce.d*)
. = ALIGN(4096);
}
.tbss : AT(phys + (tbss - code))
{
tbss = .; _tbss = .; __tbss = .;
*(.tbss)
*(.tbss.*)
. = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{
bss = .; _bss = .; __bss = .;
*(.bss)
*(.bss.*)
*(COMMON)
*(.gnu.linkonce.b*)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
It probably does more than you need (aligns sections to 4k boundaries, has all symbols at > 3GB mark) but is a good starting place.
You can use it like this:
ld -T link_script.ld *.o -lc -o appname
the "-lc" should link in libc as well if that's what you want.
I think the closest you can get is compiling and linking with -fno-exceptions and -fno-rtti. If there's a better way to get rid of the rest, I'd be glad to hear it myself.
As far as getting rid of new, try -nostdlib.
You might try trapping new to see if it is really being called anyway.
New can occur implicitly under some circumstances, such as copy-construction.
You may be able to remove these by writing your code slightly differently.
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter11_013.html