Allocate an array in C a specific location using linker commands - c

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

Related

using the same linker ld script file target for two files

lets assume I have a memory allocation that looks like this:
MEMORY
{
firstfile : ORIGIN = 0x00000000, LENGTH = 0x2000
secondfile : ORIGIN = 0x00002000, LENGTH = 0x6000
}
now I want to use the same ld script for two different files. 'firstfile.c' and 'secondfile.c'
how to I make firstfile entire allocation go under 'firstfile' section, and the second file under 'secondfile' section?
currently .text all goes under secondfile section.
using special attribute section on each of the functions in firstfile.c doesnt help
In your linker script fragment firstfile and secondfile are MEMORY regions not SECTIONS, so the section attributes will (I guess) be ignored because the sections do not exist.
You must create the MEMORY regions, in which you place SECTIONS, then you assign sections defined in the object code to sections declared in the linker script. Note that it is the object code that is located, not the source file - the linker knows nothing about source files:
Something like:
MEMORY
{
FIRST_MEMORY : ORIGIN = 0x00000000, LENGTH = 0x2000
SECOND_MEMORY : ORIGIN = 0x00002000, LENGTH = 0x6000
}
SECTIONS
{
.firstsection :
{
. = ALIGN(4);
*firstfile.o (.text .text*) /* Locate firstfile text sections here */
} > FIRST_MEMORY
.secondsection :
{
. = ALIGN(4);
*secondfile.o (.text .text*) /* Locate secondfile text sections here */
} > SECOND_MEMORY
}
You can then locate any number of modules explicitly to each section.
You might want a default location to place modules not explicitly located. In which case you should add:
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
to one of the sections (or create a separate default .text section).
Also if you add:
*(.firstsection*) /* Locate anything with firstsection attribute here */
or
*(.secondsection*) /* Locate anything with secondsection attribute here */
to the respective sections you can use __section__ attributes in the code to locate specific functions (or data) to to these sections as you attempted previously. But locating an entire module is preferable as it does not require code modification and maintenance.

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.

Understanding the Location Counter of GNU Linker Scripts

I'm working on a university project where I'm writing software for an Atmel SAM7S256 microcontroller from the ground up. This is more in depth than other MCUs I've worked with before, as a knowledge of linker scripts and assembly language is necessary this time around.
I've been really scrutinizing example projects for the SAM7S chips in order to fully understand how to start a SAM7/ARM project from scratch. A notable example is Miro Samek's "Building Bare-Metal ARM Systems with GNU" tutorial found here (where the code in this question is from). I've also spent a lot of time reading the linker and assembler documentation from sourceware.org.
I'm quite happy that I understand the following linker script for the most part. There's just one thing involving the location counter that doesn't make sense to me. Below is the linker script provided with the above tutorial:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_vectors)
MEMORY { /* memory map of AT91SAM7S64 */
ROM (rx) : ORIGIN = 0x00100000, LENGTH = 64k
RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 16k
}
/* The sizes of the stacks used by the application. NOTE: you need to adjust */
C_STACK_SIZE = 512;
IRQ_STACK_SIZE = 0;
FIQ_STACK_SIZE = 0;
SVC_STACK_SIZE = 0;
ABT_STACK_SIZE = 0;
UND_STACK_SIZE = 0;
/* The size of the heap used by the application. NOTE: you need to adjust */
HEAP_SIZE = 0;
SECTIONS {
.reset : {
*startup.o (.text) /* startup code (ARM vectors and reset handler) */
. = ALIGN(0x4);
} >ROM
.ramvect : { /* used for vectors remapped to RAM */
__ram_start = .;
. = 0x40;
} >RAM
.fastcode : {
__fastcode_load = LOADADDR (.fastcode);
__fastcode_start = .;
*(.glue_7t) *(.glue_7)
*isr.o (.text.*)
*(.text.fastcode)
*(.text.Blinky_dispatch)
/* add other modules here ... */
. = ALIGN (4);
__fastcode_end = .;
} >RAM AT>ROM
.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 (NOTE: placed already in .fastcode) */
*(.glue_7t)/* glue thumb to arm (NOTE: placed already in .fastcode) */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* global symbol at end of code */
} >ROM
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ROM
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >ROM
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >ROM
.data : {
__data_load = LOADADDR (.data);
__data_start = .;
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .;
} >RAM AT>ROM
.bss : {
__bss_start__ = . ;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = .;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE ( __end__ = _ebss );
.heap : {
__heap_start__ = . ;
. = . + HEAP_SIZE;
. = ALIGN(4);
__heap_end__ = . ;
} >RAM
.stack : {
__stack_start__ = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end__ = .;
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ : {
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
Throughout the example (such as in the .ramvect, .fastcode and .stack sections) there are symbol definitions such as __ram_start = .;. These addresses are used by the startup assembly code and initialization C code in order to initialize the correct locations in the MCU's RAM.
What I have a problem understanding, is how these symbol definitions result in the correct values being assigned. This does happen, the script is correct, I just don't understand how.
The way I understand it, when you use the location counter within a section, it only contains a relative offset from the virtual memory address (VMA) of the section itself.
So for example, in the line __ram_start = .;, I would expect __ram_start to be assigned a value of 0x0 - as it is assigned the value of the location counter at the very beginning of the .ramvect section. However, for the initialization code to work correctly (which it does), __ram_start must be getting assigned as 0x00200000 (the address for the beginning of RAM).
I would have thought this would only work as intended if the line was instead __ram_start = ABSOLUTE(.); or __ram_start = ADDR(.ramvect);.
The same goes for __fastcode_start and __stack_start__. They can't all be getting defined as address 0x0, otherwise the program wouldn't work. But the documentation linked here seems to suggest that that's what should be happening. Here's the quote from the documentation:
Note: . actually refers to the byte offset from the start of the current containing object. Normally this is the SECTIONS statement, whose start address is 0, hence . can be used as an absolute address. If . is used inside a section description however, it refers to the byte offset from the start of that section, not an absolute address.
So the location counter values during those symbol assignments should be offsets from the corresponding section VMAs. So those "_start" symbols should all be getting set to 0x0. Which would break the program.
So obviously I'm missing something. I suppose it could simply be that assigning the location counter value to a symbol (within a section) results in ABSOLUTE() being used by default. But I haven't been able to find a clear explanation anywhere that confirms this.
Thanks in advance if anybody can clear this up.
I think I may have figured out the answer to my own question. I'm not sure I'm right, but it's the first explanation I've been able to think of that actually makes sense. What made me rethink things was this page of the documentation. Particularly this quote:
Addresses and symbols may be section relative, or absolute. A section
relative symbol is relocatable. If you request relocatable output
using the `-r' option, a further link operation may change the value
of a section relative symbol. On the other hand, an absolute symbol
will retain the same value throughout any further link operations.
and this quote:
You can use the builtin function ABSOLUTE to force an expression to be
absolute when it would otherwise be relative. For example, to create
an absolute symbol set to the address of the end of the output section
.data:
SECTIONS
{
.data : { *(.data) _edata = ABSOLUTE(.); }
}
If ABSOLUTE were not used, _edata would be relative to the .data
section.
I had read them before, but this time I saw them from a new perspective.
So I think my misinterpretation was thinking that a symbol, when assigned a relative byte offset address, is simply set to the value of that offset while the base address information is lost.
That was based on this quote from my original question:
Note: . actually refers to the byte offset from the start of the
current containing object. Normally this is the SECTIONS statement,
whose start address is 0, hence . can be used as an absolute address.
If . is used inside a section description however, it refers to the
byte offset from the start of that section, not an absolute address.
Instead what I now understand to be happening is that the base address information is not lost. The symbol does not simply get assigned the value of the offset from the base address. The symbol will still eventually resolves to an absolute address, but only when there's no chance its base address can change.
So where I thought that something like __stack_start__ = . ; should have to be changed to __stack_start__ = ABSOLUTE(.) ;, which does work, I now think it is unnecessary. What's more, I understand from the first quote in this response that you can relink an ELF file?
So if I used __stack_start__ = ABSOLUTE(.) ;, ran the linker script to create the ELF executable, then tried to relink it and moved the .stack section somewhere else, the __stack_start__ symbol would still be pointing to the same absolute address from the first link, and thus be incorrect.
This is probably hard to follow, but I've written it as articulately as I could. I suspect I've got close to the right idea, but I still need someone who actually knows about this stuff to confirm or deny this.
The placement of the section is determined by the memory region after the closing brace (>RAM AT>ROM). So the execution address is in RAM at 0x00200000 and following, but the load address is in ROM (flash) at 0x00100000. The startup code must copy the .fastcode output section from its load to its execution address, that's what the symbols are for.
Note that these need not be at address 0, because the AT91SAM7S remaps either RAM or ROM to address 0. Usually it starts up with ROM mapped, and the startup code switches that to RAM.
This question also troubled me, Give my understandingļ¼š
.ramvect : { /* used for vectors remapped to RAM */
__ram_start = .;
. = 0x40;
} >RAM
The above statement tells the linker to place the __ram_start symbol at location counter, that is at the start of the .ramvect segment.
Since the __ram_start symbol is located at the head of the .ramvect segment, when the C code is used to get the __ramvect address, it will get the starting address of the.ramvect segment, i.e. its absolute address.

Resources