GNU LD fill empty linker section - c

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.

Related

Tell the linker to avoid a region

Esteemed Colleagues!
If I want the linker to not place anything into an area of memory, I can simply omit the region from the "MEMORY" section in the linker script file. I could also put a comment in there to make it clear what I'm doing. Perhaps like this:
MEMORY
{
...
good_one : ORIGIN = 0x00400000, LENGTH = 0x00010000 /* 64 kiB */
/* Avoid the "special" area 0x00410000 -> 0x00480000 */
good_two : ORIGIN = 0x00480000, LENGTH = 0x00010000 /* 64 kiB */
...
}
Instead, is there a way that I could define a memory region, but attach attributes to it to keep the linker from placing anything in there? Perhaps like this:
MEMORY
{
...
good_one : ORIGIN = 0x00400000, LENGTH = 0x00010000 /* 64 kiB */
avoid (!rwiax) : ORIGIN = 0x00410000, LENGTH = 0x00070000 /* 448 kiB */
good_two : ORIGIN = 0x00480000, LENGTH = 0x00010000 /* 64 kiB */
...
}
Could I also create some symbols (and "KEEP" them) in the linker script file that would show up in the ELF to clearly indicate what is going on? Perhaps like this:
SECTIONS
{
...
avoid 0x00410000 (NOLOAD) :
{
_avoid_region_start = . ; /* KEEP() ??? */
. = . + 0x00070000 ;
_avoid_region_end = . ; /* KEEP() ??? */
} > avoid ;
...
I'm using a wide variety of GNU "ld" versions (from 2.20.51 through 2.36.1), cross-compiling to a broad set of target architectures (riscv32/64, aarch32/64, etc...), if that matters...

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

A linker script section does not appear on ELF

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.

FreeRTOS allocation error

I am using FreeRTOS V6.1.1 on a STM32F107VC and get frequent malloc errors. The heap area is defined in the linker script but it keeps getting stuck in this loop of pvPortMalloc() after a few allocations:
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
pxBlock: 0x20002300
pxPreviousBlock: 0x20002300
pxNewBlockLink: 0x00
xHeapHasBeenInitialised: 0x01
linker script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20010000; /* end of 64K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x200; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
...
How can this be?
This was probably caused by fragmentation in heap_2.c. Even though the allocations were pretty small, the behaviour was consistent. Using heap_4.c solved it.

Resources