Now that we know, how to write linker scripts, we will attempt
to write a program, and place the .data
section in RAM.
The add program is modified to load two values from RAM, add
them and store the result back to RAM. The two values and the space
for result is placed in the .data
section.
Listing 9. Add Data in RAM
.data
val1: .4byte 10 @ First number
val2: .4byte 30 @ Second number
result: .4byte 0 @ 4 byte space for result
.text
.align
start:
ldr r0, =val1 @ r0 = &val1
ldr r1, =val2 @ r1 = &val2
ldr r2, [r0] @ r2 = *r0
ldr r3, [r1] @ r3 = *r1
add r4, r2, r3 @ r4 = r2 + r3
ldr r0, =result @ r0 = &result
str r4, [r0] @ *r0 = r4
stop: b stop
When the program is linked, the linker script shown below is used.
SECTIONS {
. = 0x00000000;
.text : { * (.text); }
. = 0xA0000000;
.data : { * (.data); }
}
The dump of the symbol table of .elf
is shown below.
$ arm-none-eabi-nm -n add-mem.elf
00000000 t start
0000001c t stop
a0000000 d val1
a0000001 d val2
a0000002 d result
The linker script seems to have solved the problem of placing
the .data
section in RAM. But wait,
the solution is not complete yet!
RAM is volatile memory, and hence it is not possible to directly make the data available in RAM, on power up.
All code and data should be stored in Flash before
power-up. On power-up, a startup code is supposed to copy the data
from Flash to RAM, and then proceed with the execution of the
program. So the program’s .data
section has two addresses, a load
address in Flash and a run-time address in RAM.
Tip | |
---|---|
In |
The following two modifications have to be done, to make the program work correctly.
.data
section..data
section from Flash (load
address) to RAM (run-time address).The run-time address is what that should be used for determining
the address of labels. In the previous linker script, we have
specified the run-time address for the .data
section. The load address is not explicitly
specified, and defaults to the run-time address. This is OK, with
the previous examples, since the programs were executed directly
from Flash. But, if data is to be placed in RAM during execution,
the load address should correspond to Flash and the run-time
address should correspond to RAM.
A load address different from the run-time address can be
specified using the AT
keyword. The
modified linker script is shown below.
SECTIONS {
. = 0x00000000;
.text : { * (.text); }
etext = .; ❶
. = 0xA0000000;
.data : AT (etext) { * (.data); } ❷
}
Symbols can be created on the fly
within the SECTIONS command by
assigning values to them. Here etext
is assigned the value of the location counter at that position.
etext contains the address of the next
free location in Flash right after all the code. This will be used
later on to specify where the .data
section is to be placed in Flash. Note that etext itself will not be allocated any memory, it
is just an entry in the symbol table. |
|
The AT
keyword specifies the load address of the .data section. An address or symbol (whose value
is a valid address) could be passed as argument to AT . Here the load address of .data is specified as the location right after all
the code in Flash. |
To copy the data from Flash to RAM, the following information is required.
flash_sdata
)ram_sdata
).data
section. (data_size
)With this information the data can be copied from Flash to RAM using the following code snippet.
ldr r0, =flash_sdata
ldr r1, =ram_sdata
ldr r2, =data_size
copy:
ldrb r4, [r0], #1
strb r4, [r1], #1
subs r2, r2, #1
bne copy
The linker script can be slightly modified to provide these information.
Start of data in Flash is right after all the code in Flash. | |
Start of data in RAM is at the base address of RAM. | |
Obtaining the size of data is not straight forward. The data size is calculated from the difference in the start of data in RAM and the end of data in RAM. Yes, simple expressions are allowed within the linker script. |
The add program with data copied to RAM from Flash is listed below.
Listing 11. Add Data in RAM (with copy)
.data
val1: .4byte 10 @ First number
val2: .4byte 30 @ Second number
result: .space 4 @ 1 byte space for result
.text
;; Copy data to RAM.
start:
ldr r0, =flash_sdata
ldr r1, =ram_sdata
ldr r2, =data_size
copy:
ldrb r4, [r0], #1
strb r4, [r1], #1
subs r2, r2, #1
bne copy
;; Add and store result.
ldr r0, =val1 @ r0 = &val1
ldr r1, =val2 @ r1 = &val2
ldr r2, [r0] @ r2 = *r0
ldr r3, [r1] @ r3 = *r1
add r4, r2, r3 @ r4 = r2 + r3
ldr r0, =result @ r0 = &result
str r4, [r0] @ *r0 = r4
stop: b stop
The program is assembled and linked using the linker script listed in Listing 10, “Linker Script with Section Copy Symbols”. The program is executed and tested within Qemu.
qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
(qemu) xp /4dw 0xA0000000
a0000000: 10 30 40 0
Note | |
---|---|
In a real system with an SDRAM, the memory should not be accessed right-away. The memory controller will have to be initialised before performing a memory access. Our code works because the simulated memory does not require the memory controller to be initialised. |