/* # 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 - In this linker script, you may find symbols that look like `${...}` (e.g., `${ARCH_WIDTH}`). These are wildcards used by the `build.rs` script to adapt to different target particularities. Check `build.rs` for more details about these symbols. - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* the LMA of .data are all `${ARCH_WIDTH}`-byte aligned. These alignments are assumed by the RAM initialization routine. There's also a second benefit: `${ARCH_WIDTH}`-byte aligned boundaries means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. */ PROVIDE(_stext = ORIGIN(REGION_TEXT)); PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)); PROVIDE(_max_hart_id = 0); PROVIDE(_hart_stack_size = 2K); PROVIDE(_heap_size = 0); /** TRAP ENTRY POINTS **/ /* Default trap entry point. The riscv-rt crate provides a weak alias of this function, which saves caller saved registers, calls _start_trap_rust, restores caller saved registers and then returns. Users can override this alias by defining the symbol themselves */ EXTERN(_start_trap); /* Default interrupt trap entry point. When vectored trap mode is enabled, the riscv-rt crate provides an implementation of this function, which saves caller saved registers, calls the the DefaultHandler ISR, restores caller saved registers and returns. */ PROVIDE(_start_DefaultHandler_trap = _start_trap); /* When vectored trap mode is enabled, each interrupt source must implement its own trap entry point. By default, all interrupts start in _start_trap. However, users can override these alias by defining the symbol themselves */ PROVIDE(_start_SupervisorSoft_trap = _start_DefaultHandler_trap); PROVIDE(_start_MachineSoft_trap = _start_DefaultHandler_trap); PROVIDE(_start_SupervisorTimer_trap = _start_DefaultHandler_trap); PROVIDE(_start_MachineTimer_trap = _start_DefaultHandler_trap); PROVIDE(_start_SupervisorExternal_trap = _start_DefaultHandler_trap); PROVIDE(_start_MachineExternal_trap = _start_DefaultHandler_trap); /** EXCEPTION HANDLERS **/ /* Default exception handler. The riscv-rt crate provides a weak alias of this function, which is a busy loop. Users can override this alias by defining the symbol themselves */ EXTERN(ExceptionHandler); /* It is possible to define a special handler for each exception type. By default, all exceptions are handled by ExceptionHandler. However, users can override these alias by defining the symbol themselves */ 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); /** INTERRUPT HANDLERS **/ /* Default interrupt handler. The riscv-rt crate provides a weak alias of this function, which is a busy loop. Users can override this alias by defining the symbol themselves */ EXTERN(DefaultHandler); /* It is possible to define a special handler for each interrupt type. By default, all interrupts are handled by DefaultHandler. However, users can override these alias by defining the symbol themselves */ PROVIDE(SupervisorSoft = DefaultHandler); PROVIDE(MachineSoft = DefaultHandler); PROVIDE(SupervisorTimer = DefaultHandler); PROVIDE(MachineTimer = DefaultHandler); PROVIDE(SupervisorExternal = DefaultHandler); PROVIDE(MachineExternal = DefaultHandler); SECTIONS { .text.dummy (NOLOAD) : { /* This section is intended to make _stext address work */ . = ABSOLUTE(_stext); } > REGION_TEXT .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); KEEP(*(.init.trap)); . = ALIGN(4); *(.trap); *(.trap.rust); *(.text.abort); *(.text .text.*); } > REGION_TEXT .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); } > REGION_RODATA .data : ALIGN(${ARCH_WIDTH}) { _sidata = LOADADDR(.data); _sdata = .; /* Must be called __global_pointer$ for linker relaxations to work. */ PROVIDE(__global_pointer$ = . + 0x800); *(.sdata .sdata.* .sdata2 .sdata2.*); *(.data .data.*); . = ALIGN(${ARCH_WIDTH}); _edata = .; } > REGION_DATA AT > REGION_RODATA .bss (NOLOAD) : ALIGN(${ARCH_WIDTH}) { _sbss = .; *(.sbss .sbss.* .bss .bss.*); . = ALIGN(${ARCH_WIDTH}); _ebss = .; } > REGION_BSS /* fictitious region that represents the memory available for the heap */ .heap (NOLOAD) : { _sheap = .; . += _heap_size; . = ALIGN(4); _eheap = .; } > REGION_HEAP /* fictitious region that represents the memory available for the stack */ .stack (NOLOAD) : { _estack = .; . = ABSOLUTE(_stack_start); _sstack = .; } > REGION_STACK /* 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) } } /* Do not exceed this mark in the error messages above | */ ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned"); ASSERT(ORIGIN(REGION_DATA) % ${ARCH_WIDTH} == 0, " ERROR(riscv-rt): the start of the REGION_DATA must be ${ARCH_WIDTH}-byte aligned"); ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned"); ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); ASSERT(ORIGIN(REGION_STACK) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned"); ASSERT(_stext % 4 == 0, " ERROR(riscv-rt): `_stext` must be 4-byte aligned"); ASSERT(_sdata % ${ARCH_WIDTH} == 0 && _edata % ${ARCH_WIDTH} == 0, " BUG(riscv-rt): .data is not ${ARCH_WIDTH}-byte aligned"); ASSERT(_sidata % ${ARCH_WIDTH} == 0, " BUG(riscv-rt): the LMA of .data is not ${ARCH_WIDTH}-byte aligned"); ASSERT(_sbss % ${ARCH_WIDTH} == 0 && _ebss % ${ARCH_WIDTH} == 0, " BUG(riscv-rt): .bss is not ${ARCH_WIDTH}-byte aligned"); ASSERT(_sheap % 4 == 0, " BUG(riscv-rt): start of .heap is not 4-byte aligned"); ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), " ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region. Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'"); 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 | */