MEMORY { /* * The RP2350 has either external or internal flash. * * 2 MiB is a safe default here, although a Pico 2 has 4 MiB. */ FLASH : ORIGIN = 0x10000000, LENGTH = 2048K /* * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping. * This is usually good for performance, as it distributes load on * those banks evenly. */ RAM : ORIGIN = 0x20000000, LENGTH = 512K /* * RAM banks 8 and 9 use a direct mapping. They can be used to have * memory areas dedicated for some specific job, improving predictability * of access times. * Example: Separate stacks for core0 and core1. */ SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K } /* # Developer notes - Symbols that start with a double underscore (__) are considered "private" - Symbols that start with a single underscore (_) are considered "semi-public"; they can be overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { static mut _heap_size }`). - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a symbol is not dropped if it appears in or near the front of the linker arguments and "it's not needed" by any of the preceding objects (linker arguments) - `PROVIDE` is used to provide default values that can be overridden by a user linker script - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* the LMA of .data are all `32`-byte aligned. These alignments are assumed by the RAM initialization routine. There's also a second benefit: `32`-byte aligned boundaries means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. */ PROVIDE(_stext = ORIGIN(FLASH)); PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); PROVIDE(_max_hart_id = 0); PROVIDE(_hart_stack_size = 2K); PROVIDE(_heap_size = 0); PROVIDE(InstructionMisaligned = ExceptionHandler); PROVIDE(InstructionFault = ExceptionHandler); PROVIDE(IllegalInstruction = ExceptionHandler); PROVIDE(Breakpoint = ExceptionHandler); PROVIDE(LoadMisaligned = ExceptionHandler); PROVIDE(LoadFault = ExceptionHandler); PROVIDE(StoreMisaligned = ExceptionHandler); PROVIDE(StoreFault = ExceptionHandler); PROVIDE(UserEnvCall = ExceptionHandler); PROVIDE(SupervisorEnvCall = ExceptionHandler); PROVIDE(MachineEnvCall = ExceptionHandler); PROVIDE(InstructionPageFault = ExceptionHandler); PROVIDE(LoadPageFault = ExceptionHandler); PROVIDE(StorePageFault = ExceptionHandler); PROVIDE(SupervisorSoft = DefaultHandler); PROVIDE(MachineSoft = DefaultHandler); PROVIDE(SupervisorTimer = DefaultHandler); PROVIDE(MachineTimer = DefaultHandler); PROVIDE(SupervisorExternal = DefaultHandler); PROVIDE(MachineExternal = DefaultHandler); PROVIDE(DefaultHandler = DefaultInterruptHandler); PROVIDE(ExceptionHandler = DefaultExceptionHandler); /* # Pre-initialization function */ /* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function, then the function this points to will be called before the RAM is initialized. */ PROVIDE(__pre_init = default_pre_init); /* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ PROVIDE(_setup_interrupts = default_setup_interrupts); /* # Multi-processing hook function fn _mp_hook() -> bool; This function is called from all the harts and must return true only for one hart, which will perform memory initialization. For other harts it must return false and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt). */ PROVIDE(_mp_hook = default_mp_hook); /* # Start trap function override By default uses the riscv crates default trap handler but by providing the `_start_trap` symbol external crates can override. */ PROVIDE(_start_trap = default_start_trap); SECTIONS { .text.dummy (NOLOAD) : { /* This section is intended to make _stext address work */ . = ABSOLUTE(_stext); } > FLASH .text _stext : { /* Put reset handler first in .text section so it ends up as the entry */ /* point of the program. */ KEEP(*(.init)); KEEP(*(.init.rust)); . = ALIGN(4); __start_block_addr = .; KEEP(*(.start_block)); KEEP(*(.boot_info)); . = ALIGN(4); *(.trap); *(.trap.rust); *(.text.abort); *(.text .text.*); . = ALIGN(4); } > FLASH /* ### Picotool 'Binary Info' Entries * * Picotool looks through this block (as we have pointers to it in our * header) to find interesting information. */ .bi_entries : ALIGN(4) { /* We put this in the header */ __bi_entries_start = .; /* Here are the entries */ KEEP(*(.bi_entries)); /* Keep this block a nice round size */ . = ALIGN(4); /* We put this in the header */ __bi_entries_end = .; } > FLASH .rodata : ALIGN(4) { *(.srodata .srodata.*); *(.rodata .rodata.*); /* 4-byte align the end (VMA) of this section. This is required by LLD to ensure the LMA of the following .data section will have the correct alignment. */ . = ALIGN(4); } > FLASH .data : ALIGN(32) { _sidata = LOADADDR(.data); __sidata = LOADADDR(.data); _sdata = .; __sdata = .; /* Must be called __global_pointer$ for linker relaxations to work. */ PROVIDE(__global_pointer$ = . + 0x800); *(.sdata .sdata.* .sdata2 .sdata2.*); *(.data .data.*); . = ALIGN(32); _edata = .; __edata = .; } > RAM AT > FLASH .bss (NOLOAD) : ALIGN(32) { _sbss = .; *(.sbss .sbss.* .bss .bss.*); . = ALIGN(32); _ebss = .; } > RAM .end_block : ALIGN(4) { __end_block_addr = .; KEEP(*(.end_block)); } > FLASH /* fictitious region that represents the memory available for the heap */ .heap (NOLOAD) : { _sheap = .; . += _heap_size; . = ALIGN(4); _eheap = .; } > RAM /* fictitious region that represents the memory available for the stack */ .stack (NOLOAD) : { _estack = .; . = ABSOLUTE(_stack_start); _sstack = .; } > RAM /* fake output .got section */ /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in the input files and raise an error if relocatable code is found */ .got (INFO) : { KEEP(*(.got .got.*)); } .eh_frame (INFO) : { KEEP(*(.eh_frame)) } .eh_frame_hdr (INFO) : { *(.eh_frame_hdr) } } PROVIDE(start_to_end = __end_block_addr - __start_block_addr); PROVIDE(end_to_start = __start_block_addr - __end_block_addr); /* Do not exceed this mark in the error messages above | */ ASSERT(ORIGIN(FLASH) % 4 == 0, " ERROR(riscv-rt): the start of the FLASH must be 4-byte aligned"); ASSERT(ORIGIN(RAM) % 32 == 0, " ERROR(riscv-rt): the start of the RAM must be 32-byte aligned"); ASSERT(_stext % 4 == 0, " ERROR(riscv-rt): `_stext` must be 4-byte aligned"); ASSERT(_sdata % 32 == 0 && _edata % 32 == 0, " BUG(riscv-rt): .data is not 32-byte aligned"); ASSERT(_sidata % 32 == 0, " BUG(riscv-rt): the LMA of .data is not 32-byte aligned"); ASSERT(_sbss % 32 == 0 && _ebss % 32 == 0, " BUG(riscv-rt): .bss is not 32-byte aligned"); ASSERT(_sheap % 4 == 0, " BUG(riscv-rt): start of .heap is not 4-byte aligned"); ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " ERROR(riscv-rt): The .text section must be placed inside the FLASH region. Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, " ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts. Consider changing `_max_hart_id` or `_hart_stack_size`."); ASSERT(SIZEOF(.got) == 0, " .got section detected in the input files. Dynamic relocations are not supported. If you are linking to C code compiled using the `gcc` crate then modify your build script to compile the C code _without_ the -fPIC flag. See the documentation of the `gcc::Config.fpic` method for details."); /* Do not exceed this mark in the error messages above | */