GCC Linker - Locate a section/constant at a specific address within the .text section - c

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

Related

GCC LD NOLOAD linker section generates loadable segment

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'm not able to exclude a file from .text section in linker script

.text :
{
. = ALIGN(4);
*(EXCLUDE_FILE(*blink.c.obj) .text .text*) /* Exclude blink from this section */
*(.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
_load_flash_start = _etext; /* define a global symbol that starts at LOAD_FLASH */
.fast_code_section:
{
/*. = ALIGN(4);*/
. = _etext;
_fast_code_start = .; /* define a global symbol at start of FAST_RAM */
*(.fast_code_section*)
*blink.c.obj (.text .text*)
_fast_code_end = .; /* define a global symbol at end of FAST_RAM */
} >FAST_RAM AT> LOAD_FLASH
I want to exclude the file blink.c to be allocated into .text section (FLASH), by using the EXCLUDE_FILE in linker script.
And I want the blink.c file in another section (.fast_code_section).
When I look in the .map file I can see that all functions in blink.c is still allocated to .text section.
i'm using gcc and the target platform is a stm32

Use of ALIGN command in gnu linker script

Why ALIGN(4) statement are used at the starting and the ending of each output sections in linker script??
Does it create some kind of spacing between each sections?
code
SECTIONS
{
/* The startup code goes first into internal flash */
.interrupts :
{
__VECTOR_TABLE = .;
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} > m_interrupts
.flash_config :
{
. = ALIGN(4);
KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */
. = ALIGN(4);
} > m_flash_config
/* The program code and other data goes into internal flash */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} > m_text
Disclaimer: I'm not a compiler or linker developer, this is just my impression and experience.
Memory accesses of 32-bit processors are a lot faster when done aligned, and some of these processors even can't access unaligned wide words. ARM is not that kind AFAIK.
However, the compiler presumes that the sections are properly aligned when it lays out its code and data, which will get linked finally. Therefore the linker script has to fulfill that presumption.

Understanding ARM Cortex-M0+ relocation

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

Meaning of arm loader script

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.

Resources