A linker script section does not appear on ELF - c

I am using gcc to create an hex file por a pic32 microcontroller and I need to place the configuration words at special memory addresses in the program flash.
I am using this simple linker script:
MEMORY {
boot_flash : ORIGIN = 0x1FC00000, LENGTH = 0xBF0
sfr : ORIGIN = 0x1F800000, LENGTH = 0x100000
program_flash : ORIGIN = 0x1D000000, LENGTH = 0x20000
ram : ORIGIN = 0x00000000, LENGTH = 0x8000
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
}
SECTIONS {
.text : {
*( .text )
} >boot_flash
.text : {
*(.text)
} >program_flash
.bss : {
*( .bss )
} >ram
.data : {
*( .data )
} >ram
.config0 : {
*( .config0 )
} >config0
.config1 : {
*( .config1 )
} >config1
.config2 : {
*( .config2 )
} >config2
.config3 : {
*( .config3 )
} >config3
}
Then, I compile this simple code:
...
uint32_t config0 __attribute__ ((section(".config0"))) = 0xFFFFFFFF;
uint32_t config1 __attribute__ ((section(".config1"))) = 0xFFFFAF0F;
uint32_t config2 __attribute__ ((section(".config2"))) = 0xFFFFFDFF;
uint32_t config3 __attribute__ ((section(".config3"))) = 0xFFFFFDFF;
...
An finally I check with mips-elf-objdump the resulting ELF file. The code and the data are ok but there are no .config sections in the output ELF.
What am I doing wrong?

The code is ok. The problem was on mips-elf-objdump: I was using it with the -d option that does not show me the other ELF sections :-/
Sorry and thanks you your help! :-)

Try adding some code somewhere in the app to reference the config items, like this:
volatile uint32_t dummy;
dummy = config0;
dummy = config1;
dummy = config2;
dummy = config3;
You may find that the linker has been discarding them because they're not referenced - you can tell the linker not to discard unused symbols, but I have had problems with recent versions with sections being discarded regardless.

Related

Load Address (LMA) for a ld link script when using non volatile memory (NVRAM)

I am working on baremetal application for an MSP430 MCU from TI. This MCU uses FRAM, a non volatile memory. The following script for SRAM works well:
SECTIONS {
__data_load_start = .;
.data : AT ( __data_load_start )
{
. = ALIGN(2);
__data_start = .;
*(.data*)
__data_end = .;
} >RAM
}
__data_load_start gets the load memory address in flash (implicitly?), and reserves some space in RAM.
Now, I want to use it for non volatile memory. This memory zone, under certain circumstances will be re-initialized to their initial value, so the Load Address (LMA) and Virtual Address (VMA) will be different, as explained in the ld documentation.
SECTIONS {
__nvdata_load_start = .;
.NVdata : AT ( __nvdata_load_start ) {
. = ALIGN(2);
__nvdata_start = .;
*(.nvdata*)
__nvdata_end = .;
} >FRAM
However, it doesn't work. A look to the .map output file shows that the load address has been set out of any memory section :/
.NVdata 0x0000000000004400 0x4 load address 0x0000000000010000
I would like to specify explicitly the location of the initial value of this memory region. Do anyone can help?
EDIT:
I have tried to update the script not to have any implicit rule:
SECTIONS {
.NVdata : AT ( __nvdata_load_start ) {
. = ALIGN(2);
__nvdata_start = .;
*(.nvdata*)
__nvdata_end = .;
} >FRAM
.NVdataInit : {
. = ALIGN(2);
__nvdata_load_start = .;
/* reserve space for non volatile data init value */
. += SIZEOF(.NVdata);
} >FRAM
}
But in this case, each section that is declared after gets an offset between the VMA and LMA. For instance, the section that just follows gives (.map file):
.textInit 0x0000000000004408 0x416 load address 0x000000000000440c
But both adresses should be same :/
I found a workaround.
When I have declared the section .NVdata and .NVdataInit (just above), there was an offset between the LMA and VMA and the binary code was incorrect.
In the section that just follows, I have forced LMA and VMA to be the same:
SECTIONS {
/* we make sure that both
* - VMA (virtual memory address) and
* - LMA (load memory address)
* are the same */
.textInit __nvdata_load_end : AT(__nvdata_load_end) {
KEEP(*(.init)) /* start here after reset */
} > FRAM
}
It now works perfectly, even if I don't understand why this offset has appeared :/

Alignment in linker scripts

I am looking at trezor's bootloader linker script:
/* TREZORv2 bootloader linker script */
ENTRY(reset_handler)
MEMORY {
FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 128K
CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K
SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K
}
main_stack_base = ORIGIN(CCMRAM) + LENGTH(CCMRAM); /* 8-byte aligned full descending stack */
/* used by the startup code to populate variables used by the C code */
data_lma = LOADADDR(.data);
data_vma = ADDR(.data);
data_size = SIZEOF(.data);
/* used by the startup code to wipe memory */
ccmram_start = ORIGIN(CCMRAM);
ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
/* used by the startup code to wipe memory */
sram_start = ORIGIN(SRAM);
sram_end = ORIGIN(SRAM) + LENGTH(SRAM);
_codelen = SIZEOF(.flash) + SIZEOF(.data);
SECTIONS {
.header : ALIGN(4) {
KEEP(*(.header));
} >FLASH AT>FLASH
.flash : ALIGN(512) {
KEEP(*(.vector_table));
. = ALIGN(4);
*(.text*);
. = ALIGN(4);
*(.rodata*);
. = ALIGN(512);
} >FLASH AT>FLASH
.data : ALIGN(4) {
*(.data*);
. = ALIGN(512);
} >CCMRAM AT>FLASH
.bss : ALIGN(4) {
*(.bss*);
. = ALIGN(4);
} >CCMRAM
.stack : ALIGN(8) {
. = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */
} >CCMRAM
}
It can be found here.
I understand that the code needs to be 32bit ( ALIGN(4) ) aligned, because the ARM processor can crash if it tries to access unaligned address, but I do not understand why the stack alignment is 8 bytes and furthermore why the hell do you need to waste(?) 512 bytes for alignment of the flash section?!
I would like to understand how the alignment is decided when writing a linker script.
Thank you in advance for your answers!
EDIT:
I think i answered my own question:
1. .flash section:
It is aligned like that, because the vector table, that is inside it always needs to be "32-word aligned". This can also be seen be the case in Trezor's boardloader linker script. As you can see the vector table is 512 byte (4 x 32-word) aligned.
2. .stack section:
According to ARM's own documentation the stack section needs to always be 8 byte aligned.
P.S. Of course if this is not the case, please correct me.
Okay, so since cooperised confirmed my theory I can now close this question.
1. .flash section:
It is aligned like that, because the vector table, that is inside it always needs to be "32-word aligned". This can also be seen be the case in Trezor's boardloader linker script. As you can see the vector table is 512 byte (4 x 32-word) aligned.
2. .stack section:
According to ARM's own documentation the stack section needs to always be 8 byte aligned.
Thank you cooperised for the confirmation!

Send variable to linker via source code

In some header I've got FLASH_BASE and FLASH_SIZE makro and I would like to use them in linker script. I have tried something like this:
// main.c
long CURRENT_FLASH_START = FLASH_BASE + FLASH_SIZE / 2;
int main(void) {
return 0;
}
// s_FLASH.ld
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
RAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 16K
FLASH (rx) : ORIGIN = CURRENT_FLASH_START, LENGTH = 256K
}
But in map file I see that place for code in flash starts at address 0. Is there any possibilty to use variable from makro (from .h file) in linker script file? I use Ac6 STM32 MCU GCC with Gnu Make builder.

Allocate an array in C a specific location using linker commands

I am a beginner... I would like to write to a specific memory location in my embedded flash...How do I mention it in my C header file? And then link it with the specific memory location using linker scripts. Right now I have declared the array as extern and it compiles properly. While liking, I need to tell the linker that I need it at this particular location. Should it be given in .ld file? What is a .dld file? This is not for GCC, for diab compiler. I have seen a sample code bubble.dld for bubble sort. But in some projects .dld files are created while making the project. In what step is it actually created?
First solution
in ".c":
// Talk to linker to place this in ".mysection"
__attribute__((section(".mysection"))) char MyArrray[52];
in ".ld":
MEMORY {
m_interrupts (RX) : ORIGIN = 0x00040000, LENGTH = 0x000001E8
m_text (RX) : ORIGIN = 0x00050000, LENGTH = 0x000BFE18
/* memory which will contain secion ".mysection" */
m_my_memory (RX) : ORIGIN = 0x00045000, LENGTH = 0x00000100
}
SECTIONS
{
/***** Other sections *****/
/* place "mysection" inside "m_my_memory" */
.mysection :
{
. = ALIGN(4);
KEEP(*(.mysection));
. = ALIGN(4);
} > m_my_memory
/***** Other sections *****/
}
Second solution
in ".c"
extern char myArray[52];
in ".ld"
MEMORY {
m_interrupts (RX) : ORIGIN = 0x00040000, LENGTH = 0x000001E8
m_text (RX) : ORIGIN = 0x00050000, LENGTH = 0x000BFE18
/* memory which will contain secion "myArray" */
m_my_memory (RX) : ORIGIN = 0x00045000, LENGTH = 0x00000100
}
SECTIONS
{
/***** Other sections *****/
/* place "myArray" inside "m_my_memory" */
.mysection :
{
. = ALIGN(4);
myArray = .; /* Place myArray at current address, ie first address of m_my_memory */
. = ALIGN(4);
} > m_my_memory
/***** Other sections *****/
}
See this good manual to learn more how to place elements where you want

GNU LD fill empty linker section

I'm writing bare-metal code for a microcontroller (MSP430 series) using the GCC/binutils toolchain and I'd like to use my linker script to fill unused interrupt vectors with the "loop forever" opcode (in dev, in production the "SW reset" opcode). I can't seem to make this happen.
Here's my linker script (or the relevant sections):
MEMORY {
SFR : ORIGIN = 0x0000, LENGTH = 0x0010 /* END=0x0010, size 16 */
PERIPHERAL_8BIT : ORIGIN = 0x0010, LENGTH = 0x00F0 /* END=0x0100, size 240 */
PERIPHERAL_16BIT : ORIGIN = 0x0100, LENGTH = 0x0100 /* END=0x0200, size 256 */
RAM : ORIGIN = 0x1C00, LENGTH = 0x0800 /* END=0x23FF, size 2048 */
INFOMEM : ORIGIN = 0x1800, LENGTH = 0x0200 /* END=0x19FF, size 512 as 4 128-byte segments */
INFOA : ORIGIN = 0x1980, LENGTH = 0x0080 /* END=0x19FF, size 128 */
INFOB : ORIGIN = 0x1900, LENGTH = 0x0080 /* END=0x197F, size 128 */
INFOC : ORIGIN = 0x1880, LENGTH = 0x0080 /* END=0x18FF, size 128 */
INFOD : ORIGIN = 0x1800, LENGTH = 0x0080 /* END=0x187F, size 128 */
FRAM (rxw) : ORIGIN = 0x4400, LENGTH = 0xBB80 /* END=0xFF7F, size 48000 */
VECT1 : ORIGIN = 0xFF90, LENGTH = 0x0002
VECT2 : ORIGIN = 0xFF92, LENGTH = 0x0002
VECT3 : ORIGIN = 0xFF94, LENGTH = 0x0002
... snip ...
VECT54 : ORIGIN = 0xFFFA, LENGTH = 0x0002
VECT55 : ORIGIN = 0xFFFC, LENGTH = 0x0002
RESETVEC : ORIGIN = 0xFFFE, LENGTH = 0x0002
BSL : ORIGIN = 0x1000, LENGTH = 0x0800
HIFRAM (rxw) : ORIGIN = 0x00010000, LENGTH = 0x00003FFF
}
SECTIONS
{
__interrupt_vector_1 : { KEEP (*(__interrupt_vector_1 )) } > VECT1 =0x3C00
__interrupt_vector_2 : { KEEP (*(__interrupt_vector_2 )) } > VECT2 =0x3C00
__interrupt_vector_3 : { KEEP (*(__interrupt_vector_3 )) } > VECT3 =0x3C00
__interrupt_vector_4 : { KEEP (*(__interrupt_vector_4 )) } > VECT4 =0x3C00
__interrupt_vector_5 : { KEEP (*(__interrupt_vector_5 )) } > VECT5 =0x3C00
__interrupt_vector_6 : { KEEP (*(__interrupt_vector_6 )) } > VECT6 =0x3C00
... snip ...
__interrupt_vector_52 : { KEEP (*(__interrupt_vector_52)) KEEP (*(__interrupt_vector_timer0_b0)) } > VECT52 =0x3C00
__interrupt_vector_53 : { KEEP (*(__interrupt_vector_53)) KEEP (*(__interrupt_vector_comp_e)) } > VECT53 =0x3C00
__interrupt_vector_54 : { KEEP (*(__interrupt_vector_54)) KEEP (*(__interrupt_vector_unmi)) } > VECT54 =0x3C00
__interrupt_vector_55 : { KEEP (*(__interrupt_vector_55)) KEEP (*(__interrupt_vector_sysnmi)) } > VECT55 =0x3C00
__reset_vector :
{
KEEP (*(__interrupt_vector_56))
KEEP (*(__interrupt_vector_reset))
KEEP (*(.resetvec))
} > RESETVEC
... and all the usual stuff, .data, .bss, etc ...
(0x3C00 is the "jump forever" opcode)
This doesn't seem to produce the sections at all if there's not at least one symbol on the input.
I tried messing around with . = .; and similar commands to get the section to be created even when there's nothing in the input sections, which sometimes worked, but I need the sections generated to be type PROGBITS and have the A flag set, otherwise they won't be loaded to the target. None of my attempts managed to produce this configuration.
What can I do to generate a section filled with 0x3C00, which is type PROGBITS and has the A flag set, when there is nothing in the input sections?
Thanks in advance for your help!
Can you use the SHORT(0x3C00) syntax?
__interrupt_vector_1 : { SHORT(0x3C00) } > VECT1
This tells the linker to put two bytes 0x3C,00 into the section named __interrupt_vector_1 which is allocated in memory region VECT1. I don't think you need the KEEP directive anymore either. The name of the section, if not used, can be anything you want too. I usually match my sections to my memory regions in cases like this, e.g.
.vect1 : { SHORT(0x3C00) } >vect1
note the dot on the section name.
Also your VECT1 should be:
VECT1 (x) : ORIGIN = 0xFF90, LENGTH = 0x0002
Because it's executable code.

Resources