| /* Based on GCC ARM embedded samples. |
| Defines the following symbols for use by code: |
| __exidx_start |
| __exidx_end |
| __etext |
| __data_start__ |
| __preinit_array_start |
| __preinit_array_end |
| __init_array_start |
| __init_array_end |
| __fini_array_start |
| __fini_array_end |
| __data_end__ |
| __bss_start__ |
| __bss_end__ |
| __end__ |
| end |
| __HeapLimit |
| __StackLimit |
| __StackTop |
| __stack (== StackTop) |
| */ |
| |
| MEMORY |
| { |
| INCLUDE "pico_flash_region.ld" |
| RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k |
| SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k |
| SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k |
| } |
| |
| ENTRY(_entry_point) |
| |
| SECTIONS |
| { |
| /* Second stage bootloader is prepended to the image. It must be 256 bytes big |
| and checksummed. It is usually built by the boot_stage2 target |
| in the Raspberry Pi Pico SDK |
| */ |
| |
| .flash_begin : { |
| __flash_binary_start = .; |
| } > FLASH |
| |
| .boot2 : { |
| __boot2_start__ = .; |
| KEEP (*(.boot2)) |
| __boot2_end__ = .; |
| } > FLASH |
| |
| ASSERT(__boot2_end__ - __boot2_start__ == 256, |
| "ERROR: Pico second stage bootloader must be 256 bytes in size") |
| |
| /* The second stage will always enter the image at the start of .text. |
| The debugger will use the ELF entry point, which is the _entry_point |
| symbol if present, otherwise defaults to start of .text. |
| This can be used to transfer control back to the bootrom on debugger |
| launches only, to perform proper flash setup. |
| */ |
| |
| .flashtext : { |
| __logical_binary_start = .; |
| KEEP (*(.vectors)) |
| KEEP (*(.binary_info_header)) |
| __binary_info_header_end = .; |
| KEEP (*(.embedded_block)) |
| __embedded_block_end = .; |
| KEEP (*(.reset)) |
| } |
| |
| .rodata : { |
| /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ |
| *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) |
| . = ALIGN(4); |
| } > FLASH |
| |
| .ARM.extab : |
| { |
| *(.ARM.extab* .gnu.linkonce.armextab.*) |
| } > FLASH |
| |
| __exidx_start = .; |
| .ARM.exidx : |
| { |
| *(.ARM.exidx* .gnu.linkonce.armexidx.*) |
| } > FLASH |
| __exidx_end = .; |
| |
| /* Machine inspectable binary information */ |
| . = ALIGN(4); |
| __binary_info_start = .; |
| .binary_info : |
| { |
| KEEP(*(.binary_info.keep.*)) |
| *(.binary_info.*) |
| } > FLASH |
| __binary_info_end = .; |
| . = ALIGN(4); |
| |
| /* Vector table goes first in RAM, to avoid large alignment hole */ |
| .ram_vector_table (NOLOAD): { |
| *(.ram_vector_table) |
| } > RAM |
| |
| .uninitialized_data (NOLOAD): { |
| . = ALIGN(4); |
| *(.uninitialized_data*) |
| } > RAM |
| |
| .text : { |
| __ram_text_start__ = .; |
| *(.init) |
| *(.text*) |
| *(.fini) |
| /* Pull all c'tors into .text */ |
| *crtbegin.o(.ctors) |
| *crtbegin?.o(.ctors) |
| *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) |
| *(SORT(.ctors.*)) |
| *(.ctors) |
| /* Followed by destructors */ |
| *crtbegin.o(.dtors) |
| *crtbegin?.o(.dtors) |
| *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) |
| *(SORT(.dtors.*)) |
| *(.dtors) |
| |
| *(.eh_frame*) |
| . = ALIGN(4); |
| __ram_text_end__ = .; |
| } > RAM AT> FLASH |
| __ram_text_source__ = LOADADDR(.text); |
| . = ALIGN(4); |
| |
| .data : { |
| __data_start__ = .; |
| *(vtable) |
| |
| *(.time_critical*) |
| |
| . = ALIGN(4); |
| *(.rodata*) |
| . = ALIGN(4); |
| |
| *(.data*) |
| |
| . = ALIGN(4); |
| *(.after_data.*) |
| . = ALIGN(4); |
| /* preinit data */ |
| PROVIDE_HIDDEN (__mutex_array_start = .); |
| KEEP(*(SORT(.mutex_array.*))) |
| KEEP(*(.mutex_array)) |
| PROVIDE_HIDDEN (__mutex_array_end = .); |
| |
| . = ALIGN(4); |
| /* preinit data */ |
| PROVIDE_HIDDEN (__preinit_array_start = .); |
| KEEP(*(SORT(.preinit_array.*))) |
| KEEP(*(.preinit_array)) |
| PROVIDE_HIDDEN (__preinit_array_end = .); |
| |
| . = ALIGN(4); |
| /* init data */ |
| PROVIDE_HIDDEN (__init_array_start = .); |
| KEEP(*(SORT(.init_array.*))) |
| KEEP(*(.init_array)) |
| PROVIDE_HIDDEN (__init_array_end = .); |
| |
| . = ALIGN(4); |
| /* finit data */ |
| PROVIDE_HIDDEN (__fini_array_start = .); |
| *(SORT(.fini_array.*)) |
| *(.fini_array) |
| PROVIDE_HIDDEN (__fini_array_end = .); |
| |
| *(.jcr) |
| . = ALIGN(4); |
| } > RAM AT> FLASH |
| |
| .tdata : { |
| . = ALIGN(4); |
| *(.tdata .tdata.* .gnu.linkonce.td.*) |
| /* All data end */ |
| __tdata_end = .; |
| } > RAM AT> FLASH |
| PROVIDE(__data_end__ = .); |
| |
| /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ |
| __etext = LOADADDR(.data); |
| |
| .tbss (NOLOAD) : { |
| . = ALIGN(4); |
| __bss_start__ = .; |
| __tls_base = .; |
| *(.tbss .tbss.* .gnu.linkonce.tb.*) |
| *(.tcommon) |
| |
| __tls_end = .; |
| } > RAM |
| |
| .bss : { |
| . = ALIGN(4); |
| __tbss_end = .; |
| |
| *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) |
| *(COMMON) |
| . = ALIGN(4); |
| __bss_end__ = .; |
| } > RAM |
| |
| .heap (NOLOAD): |
| { |
| __end__ = .; |
| end = __end__; |
| KEEP(*(.heap*)) |
| /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however |
| to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ |
| . = ORIGIN(RAM) + LENGTH(RAM); |
| __HeapLimit = .; |
| } > RAM |
| |
| /* Start and end symbols must be word-aligned */ |
| .scratch_x : { |
| __scratch_x_start__ = .; |
| *(.scratch_x.*) |
| . = ALIGN(4); |
| __scratch_x_end__ = .; |
| } > SCRATCH_X AT > FLASH |
| __scratch_x_source__ = LOADADDR(.scratch_x); |
| |
| .scratch_y : { |
| __scratch_y_start__ = .; |
| *(.scratch_y.*) |
| . = ALIGN(4); |
| __scratch_y_end__ = .; |
| } > SCRATCH_Y AT > FLASH |
| __scratch_y_source__ = LOADADDR(.scratch_y); |
| |
| /* .stack*_dummy section doesn't contains any symbols. It is only |
| * used for linker to calculate size of stack sections, and assign |
| * values to stack symbols later |
| * |
| * stack1 section may be empty/missing if platform_launch_core1 is not used */ |
| |
| /* by default we put core 0 stack at the end of scratch Y, so that if core 1 |
| * stack is not used then all of SCRATCH_X is free. |
| */ |
| .stack1_dummy (NOLOAD): |
| { |
| *(.stack1*) |
| } > SCRATCH_X |
| .stack_dummy (NOLOAD): |
| { |
| KEEP(*(.stack*)) |
| } > SCRATCH_Y |
| |
| .flash_end : { |
| KEEP(*(.embedded_end_block*)) |
| PROVIDE(__flash_binary_end = .); |
| } > FLASH |
| |
| /* stack limit is poorly named, but historically is maximum heap ptr */ |
| __StackLimit = ORIGIN(RAM) + LENGTH(RAM); |
| __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); |
| __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); |
| __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); |
| __StackBottom = __StackTop - SIZEOF(.stack_dummy); |
| PROVIDE(__stack = __StackTop); |
| |
| /* picolibc and LLVM */ |
| PROVIDE (__heap_start = __end__); |
| PROVIDE (__heap_end = __HeapLimit); |
| PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); |
| PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); |
| PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); |
| |
| /* llvm-libc */ |
| PROVIDE (_end = __end__); |
| PROVIDE (__llvm_libc_heap_limit = __HeapLimit); |
| |
| /* Check if data + heap + stack exceeds RAM limit */ |
| ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") |
| |
| ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") |
| /* todo assert on extra code */ |
| } |
| |