- Notifications
You must be signed in to change notification settings - Fork 0
Memory Maps and Linker Scripts
Linker script is a special file which specifies where to put different sections of ELF file and defines particular symbols which may be referenced by an application. Linker emulation is basically way to select one of the predetermined linker scripts of the GNU linker. A linker script for a default linker emulation for ARCv2 may be observed this way:
$ arc-elf32-ld --verbose GNU ld (ARCompact/ARCv2 ISA elf32 toolchain - build 1360) 2.40.50.20230314 Supported emulations: arcelf arclinux arclinux_nps arcv2elf arcv2elfx using internal linker script: ================================================== /* Default linker script, for normal executables */ OUTPUT_FORMAT("elf32-littlearc", "elf32-bigarc", "elf32-littlearc") OUTPUT_ARCH(arc) ENTRY(__start) ... SECTIONS { /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x100)); . = SEGMENT_START("text-segment", 0x100); .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.init : { *(.rel.init) } .rela.init : { *(.rela.init) } ... Linux user-space applications are loaded by the dynamic linker in their own virtual memory address space, where they do not collide with other applications. On the other side, baremetal applications are loaded into target's memory by debugger, bootloader or they are already in the ROM mapped to a specific location.
If linker uses an invalid memory map for a particular platform, then some parts of the application will be loaded to the memory incorrectly. For example, it may be accidentally written to peripherals' region and cause an error.
That default linker emulation places all loadable ELF sections in a row after each other starting at address 0x0. This is usually enough for an application prototyping, however real systems often have much more complex memory maps with CCM regions, peripherals' region, etc.
Default linker emulation also puts interrupt vector table (.ivt section) between code and data sections and doesn't align .ivt properly (.ivt must be 1KiB-aligned for ARC processors). Here is an example:
$ arc-elf32-gcc -mcpu=em4_dmips main.c -o main.elf $ arc-elf32-objdump -h main.elf main.elf: file format elf32-littlearc Sections: Idx Name Size VMA LMA File off Algn 0 .init 00000022 00000100 00000100 00000100 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .text 00003c28 00000124 00000124 00000124 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .fini 00000016 00003d4c 00003d4c 00003d4c 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 3 .rodata 00000014 00003d64 00003d64 00003d64 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .ivt 00000054 00003d78 00003d78 00003d78 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .data 00000530 00005dcc 00005dcc 00003dcc 2**2 CONTENTS, ALLOC, LOAD, DATA Therefore the default linker emulation is not applicable for applications which handle interrupts. It can be used safely only with applications which don't handle interrupts and only on simulations which simulate whole address space, like following templates: em6_dmips, em6_gp, em6_mini, em7d_nrg, em7d_voice_audio, em11d_nrg, em11d_voice_audio, hs36_base, hs36, hs38_base, hs38, hs38_full, hs38_slc_full.
If you use arcv2elfx linker emulation, then linker searches for memory.x file with definition of a custom memory map. It is searched in the current working directory and in directories listed via -L option.
Here is an example of memory.x for EM11D core in EM Starter Kit v2.3:
MEMORY { ICCM : ORIGIN = 0x00000000, LENGTH = 64K DRAM : ORIGIN = 0x10000000, LENGTH = 128M DCCM : ORIGIN = 0x80000000, LENGTH = 64K } REGION_ALIAS("startup", ICCM) REGION_ALIAS("text", ICCM) REGION_ALIAS("data", DRAM) REGION_ALIAS("sdata", DRAM) PROVIDE (__stack_top = (0x17FFFFFF & -4) ); PROVIDE (__end_heap = (0x17FFFFFF) ); MEMORY section specifies platform's memory regions: base addresses and lengths. You can use arbitrary names for these regions. REGION_ALIAS commands translate platform's regions to standard region names expected by the linker emulation. There are 4 such standard regions:
-
startup- interrupt vector table and initialization code. By default it's mapped to0x0address and if you mapstartupto a different one, then you also need to pass this address to the linker using--defsym=ivtbase_addr=<...>option or to GCC itself using-Wl,--defsym=ivtbase_addr=<...>option. -
text- other code sections. -
data- data sections. -
sdata- small data sections.
Also, the example provides these symbols (both of them may be omitted and default values will be used):
-
__stack_toppoints to the top of the stack. It must be 4-byte aligned In the example it points to the end of DRAM regions, because stack grows downward. -
__end_heappoints to the end of the heap. Heap starts at the end of data sections and grows upward to__end_heap.
You can compile your application against that memory.x file by passing -marcv2elfx to the linker or -Wl,-marcv2elfx to GCC itself:
$ ls main.c memory.x $ arc-elf32-gcc -mcpu=em4_dmips -Wl,-marcv2elfx main.c -o main.elf Here is an example of memory.x for HS Development Kit:
MEMORY { DRAM : ORIGIN = 0x90000000, LENGTH = 0x50000000 } REGION_ALIAS("startup", DRAM) REGION_ALIAS("text", DRAM) REGION_ALIAS("data", DRAM) REGION_ALIAS("sdata", DRAM) startup is mapped to 0x90000000. It means that you have to pass -Wl,--defsym=ivtbase_addr=<...> option too. You can compile your application against that memory.x this way:
$ ls main.c memory.x $ arc-elf32-gcc -mcpu=archs -Wl,-marcv2elfx -Wl,--defsym=ivtbase_addr=0x90000000 main.c -o main.elf You can find valid memory mappings for particular hardware platforms in documentation. Here is a list of resources with memory maps for Synopsys' development platforms:
- ARC Development Systems Forum Wiki contains documentation for all Synopsys' development platforms. User guides contain descriptions of memory mappings.
- Newlib repository for ARC contains predefined memory maps for some of development platforms in
libgloss/arcdirectory. - toolchain repository also contains predefined memory maps for some of development platforms in
extras/dev_systemsdirectory.