Specify the memory map
If you tried to execute the image that you created in the last step on the FVP_Base_Cortex-A73x2-A53x4 model, it would not run. This is because the default memory map used by armlink does not match the memory map used by the model. Instead of using the default memory map, you will specify a new memory map that matches the model and allows the image to run successfully. To do this, you will create a scatter file that tells the linker the structure of the memory map.
The memory map describes the different regions of target memory, and what they can be used for. For example, ROM can hold read-only code and data but cannot store read-write data.
You can see the memory map for the model in the following diagram:
Create a scatter file to tell the linker about the structure of the memory map:
-
Create a new file scatter.txt in the same directory as hello_world.c with the following contents:
ROM_LOAD 0x00000000 0x00010000 { ROM_EXEC +0x0 { * (+RO) } RAM_EXEC 0x04000000 0x10000 { * (+RW, +ZI) } ARM_LIB_STACKHEAP 0x04010000 ALIGN 64 EMPTY 0x10000 {} }
-
Rebuild the image using the scatter file:
$ armclang -c -g --target=aarch64-arm-none-eabi hello_world.c $ armlink --scatter=scatter.txt hello_world.o
-
Advanced information
The statements in the scatter file define the different regions of memory and their purpose.
Let's look at them sequentially. The following instruction defines a load region.
ROM_LOAD 0x00000000 0x00010000 {...}
A load region is an area of memory that contains the image file at reset before execution starts. The first number specified gives the starting address of the region, and the second number gives the size of the region.
The following instruction defines an execution region:
ROM_EXEC +0x0 { * (+RO) }
Execution regions define the memory locations in which different parts of the image will be placed at run-time.
An execution region is called a root region if it has the same load-time and execute-time address.
ROM_EXEC
qualifies as a root region because its execute-time is located at an offset of+0x0
from the start of the load region (that is, the region has the same load-time and execute-time addresses). The initial entry point of an image must be in a root region. In our scatter file, all read-only (RO
) code including the entry point__main()
is placed in theROM_EXEC
root region.RAM_EXEC 0x04000000 0x10000 { * (+RW, +ZI) }
RAM_EXEC contains any read-write (RW) or zero-initialised (ZI) data. Because this has been placed in SRAM, it is not a root region.
This instruction specifies the placement of the heap and stack:
ARM_LIB_STACKHEAP 0x04010000 EMPTY 0x10000 {}
- The heap starts at 0x04010000 and grows upward.
- The stack starts at 0x0401FFFF and grows downwards.
The EMPTY declaration reserves
0x10000
of uninitialized memory, starting at0x04010000.
ARM_LIB_STACKHEAP
andEMPTY
are syntactically significant for the linker. However,ROM_LOAD
,ROM_EXEC
, andRAM_EXEC
are not syntactically significant and could be renamed if you like.For more information about memory maps, scatter files, and armlink, please refer to the armlink documentation.