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:

Specify the memory map diagram.

Create a scatter file to tell the linker about the structure of the memory map:

  1. 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
        {}
      }
    
  2. 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 the ROM_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 at 0x04010000.

    ARM_LIB_STACKHEAP and EMPTY are syntactically significant for the linker. However, ROM_LOAD, ROM_EXEC, and RAM_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.

Previous Next