I'm just getting started with embedded arm development, and there's a snippet of code that's really bugging me:
/* Initialize the relocate segment */
pSrc = &_etext;
pDest = &_srelocate;
if (pSrc != pDest)
{
while (pDest < &_erelocate)
{
*pDest++ = *pSrc++;
}
}
Where _etext and _srelocate are symbols defined in the linker script:
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
Where ram is a memory segment whose origin is 0x20000000. The issue as I see it is that _etext is a symbol that marks the end boundary of the .text segment, which is a part of a different memory segment, rom. This means that unless the aforementioned memory segment was 100% full, _etext != _srelocate will always be true. What this means is that we're copying memory beyond the .text section where nothing is defined to live according to the linker script.
To me, this leads to one of three scenarios, either A) There is garbage present in rom beyond the .text section, and it gets copied into .relocate (and subsequently .data), or B) The memory beyond .text is empty following a chip erase operation prior to device programming, in which case .relocate is zeroed, or C) There is some slight of hand magic happening here where .data values are placed after .text in rom, and must be loaded into ram; in which case the comment should be s/relocate/data.
The third scenario seems the most likely, but according to the linker script this can't be true. Can someone shed some light on this?
You're right, it's the third option. The AT() tells the linker to put the .ramfunc and .data sections (both of which are read/write) in the object file starting at _etext. The "> ram" tells the linker to resolve relocations as if the sections were placed in RAM this is done using a MEMORY command as decribed here: https://sourceware.org/binutils/docs/ld/MEMORY.html#MEMORY The result is that the copy loop moves the data from the read only area to the read/write area when the program starts up.
Here's a link to the gnu ld documentation where controlling the LMA (load address) is described: https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html
Related
I would like to locate a 32bit constant value at a specific address (0x080017FC) within the .text (code) section.
To be honest, when it comes to modifying the linker script to this extent I'm naïve and feel like I do not have a clue what to do.
I've modified my linker script to contain this new section (.systemid) within the .text section.
.text :
{
. = ALIGN(4);
KEEP(*(.systemid))
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
To ensure it does not get optimized away, I used KEEP.
I then declared my constant in the new section (.systemid). This is where I start to wonder what am I supposed to do. If .systemid was a section on its own, I would have declared the constant as follows:
const uint32_t __attribute__((used, section (".systemid"))) SYSTEM_ID_U32 = 0x11223344;
But since this is a section within a section, should it not be?:
uint32_t __attribute__((used, section (".text.systemid"))) SYSTEM_ID_U32 = 0x11223344;
So the linker will locate the constant at the beginning of the .text section (0x000001A0). Great, it is inside the text section but not at the correct address. I would like to locate the constant at 0x08001F7C.
To try and achieve this, I pass the following to the linker:
-Wl,--section-start=.text.systemid=0x080017FC
Again I'm not sure if it should be .systemid or .text.systemid
Either way, it does not locate the constant at 0x080017FC
How do I get my constant to be located at 0x080017FC within the .text (code) section without any overlap errors?
It will not work this way. There is no way I am aware of placing section at the particular address without problems from the linker if it is part of another section. Linker is quite a simple program and will not optimize the memory to avoid your location.
I use two methods:
Place this id at the end of the FLASH. You cant do this at the beginning as there is the vector table.
const uint32_t __attribute__((used, section (".systemid"))) SYSTEM_ID_U32 = 0x11223344;
Place after all other sections in FLASH (it can be the last section definition
.systemid :
{
. = ORIGIN(FLASH) + LENGTH(FLASH) - 4;
KEEP(*(.systemid))
} >FLASH
or
.systemid ORIGIN(FLASH) + LENGTH(FLASH) - 4:
{
KEEP(*(.systemid))
} >FLASH
[Compiler gcc-arm-8.2-2019.01]
I have a variable in .c:int ep;I expect it is put in .bss section and having 0 initial value, but it is excluded from .bss section after I check the .map file.
If I change the line to:
int ep = 0;
The var is put into .bss section.
My guess is compiler found that the var is a writeonly, so no need initialize its value to 0.
But this var is read by assembly code, also read by another program, which compiler seems not knowing and make the wrong optimize choice.
Any help on this behavior?
excluded from .bss means, in linkscript file I write:
.bss :
{
. = ALIGN(64);
__bss_start = .;
*(.bss)
*(.bss.*)
__bss_end = .;
} > DRAM
but var ep is not between __bss_start and __bss_end, where assembly code use them to do memory clear before jump in C code
I'm working on an Arm bare-metal application and I've marked some sections with NOLOAD. According to the explanation in Understanding linker script NOLOAD sections in embedded software
, I expected the resulting ELF file to not have a loadable segment (program header) for these sections, but it does.
Is this correct? Why are those sections marked as loadable in the ELF file?
As the linker is still placing the data in .bss, how a loader is supposed to know that the sections shouldn't be loaded? Or am I missing the meaning of 'load' in the sense that NOLOAD only makes sense for initialized symbols (which would normally be placed into .data)?
This is a part of my linker script:
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .;
} >DRAM
.noinit (NOLOAD) :
{
. = ALIGN(4);
__noinit_start__ = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
__noinit_end__ = .;
} > DRAM
/* Check if there is enough space to allocate the main stack */
._stack (NOLOAD) :
{
. = ALIGN(4);
. = . + __Main_Stack_Size ;
. = ALIGN(4);
} >DRAM
This is the output ELF file:
arm-none-eabi-readelf.exe -l test.elf
Elf file type is EXEC (Executable file)
Entry point 0x601b9
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00060000 0x00060000 0x06840 0x06840 RWE 0x10000
LOAD 0x020000 0x20010000 0x20010000 0x00000 0x06084 RW 0x10000
Section to Segment mapping:
Segment Sections...
00 .text .ARM.exidx.reset .data
01 .systemclock .bss ._stack
Why are the .bss and ._stack sections there?
Thanks!!
The FileSiz of the second segment is 0 which means that there is no data that will be loaded from the elf file into this segment.
The reason why this segment exists in the table is that on a non-embedded system, the program loader would still need to request memory for sections in that segment and mark the relevant pages with the relevant attributes (readable and writable in this case).
Edit: After reading the question again, I did a bit more experimenting and it seems that all (NOLOAD) seems to do is to set the type of the section in the output file to SHT_NOBITS. The elf specification calls that a section that occupies no space in the file but is still part of the program's memory image.
If the goal is to link against code that is already present in the rom before the program is loaded, those symbols should be defined in the linker script outside of any section. E.g. already_present_code = 0x06000000; SECTIONS { .text : {*(.text*)} /* ... */}. That seems to have the desired effect.
I am working on an embedded system (Stellaris Launchpad) and writing a simple OS (as a hobby project). The used toolchain is gcc-none-eabi.
My next step is to get used to the MPU to allow the kernel to prevent user programs from altering specific data. I have a bunch of C files and I splitted them in two parts: kernel and other.
I have the following linker script to start out with:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.text :
{
_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
_stack_top = ORIGIN(SRAM) + LENGTH(SRAM) - 1; /*The starting point of the stack, at the very bottom of the RAM*/
}
And after reading up on linker scripts I know that I can replace the stars with filenames, and thus start splitting the flash in multiple parts. I would for example create a .kernel.bss section and put all of the kernel object files instead of the stars in that section.
My only problem left is that the kernel is not one file, it is a whole lot of files. And files might be added, removed etc. So how do I do this? How do I change my linker script so that a dynamic first group of files is mapped to the first place and a dynamic second group of files is mapped to a second place?
you know that you can specify what files are used as input for a section?
We use this for separating kernel and application code into fast internal flash, and slower external flash memory, like so:
.kernel_text :
{
build/kernel/*.o (.text*) /*text section from files in build/kernel*/
} > INT_FLASH
.app_text:
{
build/app/*.o(.text*)
} > EXT_FLASH
Section 4.6.4 might be helpful, (describes input sections in more detail)
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html
I found a solution, allthough it feels a bit hacky. It does work though:
I found out that a linker script is OK with working on .a files if they are statically linked with ar. So lets say you have a buch of .o files that, together form the kernel: a.o, b.o, c.o. Use ar rcs kernel.a a.o, b.o, c.o. kernel.a is now your kernel, which you want to store seperately in memory.
The next thing you need to know is that the * in a linker script is actually a wildcard for everything not used yet. So we can create the following linker script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.kernel.text :
{
_kernel_text = .;
KEEP(kernel.a(.isr_vector))
KEEP(kernel.a(_sbrk))
kernel.a(.text*)
kernel.a(.rodata*)
_kernel_etext = .;
_kernel_flash_data = ALIGN(0x4);
} > FLASH
.kernel.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_kernel_data = .;
kernel.a(vtable)
kernel.a(.data*)
_kernel_edata = .;
} > SRAM AT > FLASH
.kernel.bss :
{
_kernel_bss = .;
kernel.a(.bss*)
kernel.a(COMMON)
_kernel_ebss = .;
} > SRAM
.text : /*AT (ADDR(.core.text) + SIZEOF(.core.text) + SIZEOF(.core.data))*/
{
_text = .;
*(.text*)
*(.rodata*)
_etext = .;
_flash_data = ALIGN(0x4);
} > FLASH
.data :
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
}
This works but will probably lead to a new problem: the linker treats libraries as.. well, libraries. So if they contain the program start (as in my case) the linker does not actually look for it, the linker only looks trough the library for functions refered to by the actual o files. The solution I found for this is to add the -u <name> flag to the linker invocation. This flag causes a symbol to become undefined, so the linker will look for this symbol plus all symbols that are needed by this synbol.
My invocation, for references sake:
arm-none-eabi-ld -Tlinker_script.ld -nostdlib --entry ResetISR
--gc-sections -u _sbrk -u .isr_vector
-L./lib//hardfp
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/arm-none-eabi/lib/armv7e-m/fpu
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/lib/gcc/arm-none-eabi/4.9.3/armv7e-m/fpu
-Lrelease/
-o release/os
./user/obj/release/ledsDance.c.o ./user/obj/release/main.c.o ./validation/obj/release/val_floattest.c.o ./validation/obj/release/val_genTest.c.o ./validation/obj/release/val_gpiotest.c.o ./validation/obj/release/val_iotest.c.o ./validation/obj/release/val_proctest.c.o ./validation/obj/release/val_schedTest.c.o release/kernel.a release/core.a
-ldriver-cm4f
-luartstdio
-lm
-lc
-lgcc
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_ram_entry)
SECTIONS
{
. = 0xA0008000;
. = ALIGN(4);
.text : { *(.text) }
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = ALIGN(4);
.bss : { *(.bss) }
}
I get the output_format, output_arch, entry... maybe meaning that the output will be as elf32-littlearm and so on.
But the Sections part is what I don't get.
this '. =' is the start.
and '. = ALIGN(4)' and .text : { *(.text) } ....
can anybody help me on this T_T
thanks for reading.
Actually, this linker description language is defined in the documentation for ld last I checked. It's not as bad as it looks. Basically, the '.' operator refers to the "current location pointer". So, the line
. = 0xA0008000
says move the location pointer to that value. The next entry, .text, basically says place all text objects into a .text section in the final ELF file starting at the location pointer (which is also adjusted to have a 4-byte (32-bit) alignment.) Note that the first use of the ALIGN is probably redundant since 0xA0008000 is already 32-bit aligned!
The next sections simply instructs the linker to emit the collection of all .rodata, .data, .got and .bss sections from all input objects into their final respective sections of the ELF binary in order, starting at 32-bit aligned addresses.
So the final ELF binary that the linker produces will have those five sections respectively and sequentially. You can see the structure of that final ELF binary using the readelf utility. It's quite useful and helps to make sense of all of this stuff. Usually there is a cross-version of readelf, something like arm-linux-gnueabi-readelf, or whatever prefix was used to generate the compiler/linker you are using. Start with readelf -S to get a summary of the sections that your ELF file contains. Then you can explore from there. Happy reading!
. = 0xA0008000;
I think, but I'm not 100% sure, is where the arm will start executing the binary
. = ALIGN(4);
defines how to align the following instruction.
.text, .data, .rodata, .got and .bss are the sections of the program. text is for instructions, data and rodata for initialized data sections and bss for uninitialized data section. got is global offset table.
.text : { *(.text) }
This copies all the instructions, similar commands are for data and global offset table.