MEMORY { ITCM (rx): ORIGIN = 0x00000000, LENGTH = 512K DTCM (rw): ORIGIN = 0x20000000, LENGTH = 512K RAM (rw): ORIGIN = 0x20200000, LENGTH = 512K FLASH (rx): ORIGIN = 0x60000000, LENGTH = 7936K ERAM (rw): ORIGIN = 0x70000000, LENGTH = 32768K } ENTRY(ImageVectorTable) SECTIONS { .text.headers : { KEEP(*(.flashconfig)) FILL(0xFF) . = ORIGIN(FLASH) + 0x1000; KEEP(*(.ivt)) KEEP(*(.bootdata)) . = ALIGN(1024); } > FLASH .text.code : { KEEP(*(.startup)) *(.flashmem*) /* Route the heavy crypto libraries (secp256k1, PQClean, ed25519, * nostr_utils) into FLASH (.text.code) instead of ITCM (.text.itcm). * This frees up RAM1 (ITCM) so the DTCM stack is larger, avoiding * stack overflows in the ed25519/x25519/PQ key-derivation paths * whose SHA-512 W[80] + HMAC ikey/okey buffers are ~2-3 KB on the * stack. The crypto code runs from flash (slightly slower) but the * stack headroom is the critical constraint on the Teensy 4.1. */ *secp256k1.c.o(.text*) *secp256k1.c.o(.rodata*) /* Note: ed25519.c .text is already in .flashmem (functions are * marked __attribute__((section(".flashmem")))). We do NOT move * ed25519.c.o(.rodata*) to flash — the ed_K SHA-512 round constants * and ed_X/ed_Y base point must stay in DTCM (.data) for correct * access. Moving them to flash produced an all-zeros pubkey. */ *nostr_utils.c.o(.text*) *nostr_utils.c.o(.rodata*) *nostr_secp256k1.c.o(.text*) *nostr_secp256k1.c.o(.rodata*) *cbd.c.o(.text*) *cbd.c.o(.rodata*) *indcpa.c.o(.text*) *indcpa.c.o(.rodata*) *kem.c.o(.text*) *kem.c.o(.rodata*) *mlkem768_ntt.c.o(.text*) *mlkem768_ntt.c.o(.rodata*) *mlkem768_poly.c.o(.text*) *mlkem768_poly.c.o(.rodata*) *reduce.c.o(.text*) *reduce.c.o(.rodata*) *symmetric.c.o(.text*) *symmetric.c.o(.rodata*) *verify.c.o(.text*) *verify.c.o(.rodata*) *mldsa65_ntt.c.o(.text*) *mldsa65_ntt.c.o(.rodata*) *mldsa65_poly.c.o(.text*) *mldsa65_poly.c.o(.rodata*) *mldsa65_sign.c.o(.text*) *mldsa65_sign.c.o(.rodata*) *address.c.o(.text*) *address.c.o(.rodata*) *fors.c.o(.text*) *fors.c.o(.rodata*) *hash.c.o(.text*) *hash.c.o(.rodata*) *slhdsa128s_sign.c.o(.text*) *slhdsa128s_sign.c.o(.rodata*) *slhdsa128s_utils.c.o(.text*) *slhdsa128s_utils.c.o(.rodata*) *thash.c.o(.text*) *thash.c.o(.rodata*) *wots.c.o(.text*) *wots.c.o(.rodata*) /* Route the SdFat library (SD card access) into FLASH too, so it * doesn't consume ITCM and overflow the flexRAM DTCM partition. * Without this, including crashes the device before * setup() runs (ITCM grows past 12 blocks, reducing DTCM below * what .data needs). See plans/teensy41_otp_sd_pad.md §BLOCKER. */ *FatFile.cpp.o(.text*) *FatFile.cpp.o(.rodata*) *FatFileLFN.cpp.o(.text*) *FatFileLFN.cpp.o(.rodata*) *FatFileSFN.cpp.o(.text*) *FatFileSFN.cpp.o(.rodata*) *FatFilePrint.cpp.o(.text*) *FatFilePrint.cpp.o(.rodata*) *FatPartition.cpp.o(.text*) *FatPartition.cpp.o(.rodata*) *FatVolume.cpp.o(.text*) *FatVolume.cpp.o(.rodata*) *FatName.cpp.o(.text*) *FatName.cpp.o(.rodata*) *FatFormatter.cpp.o(.text*) *FatFormatter.cpp.o(.rodata*) *FatDbg.cpp.o(.text*) *FatDbg.cpp.o(.rodata*) *FsCache.cpp.o(.text*) *FsCache.cpp.o(.rodata*) *FsFile.cpp.o(.text*) *FsFile.cpp.o(.rodata*) *FsVolume.cpp.o(.text*) *FsVolume.cpp.o(.rodata*) *FsName.cpp.o(.text*) *FsName.cpp.o(.rodata*) *FsStructs.cpp.o(.text*) *FsStructs.cpp.o(.rodata*) *FsNew.cpp.o(.text*) *FsNew.cpp.o(.rodata*) *FsUtf.cpp.o(.text*) *FsUtf.cpp.o(.rodata*) *FsDateTime.cpp.o(.text*) *FsDateTime.cpp.o(.rodata*) *FmtNumber.cpp.o(.text*) *FmtNumber.cpp.o(.rodata*) *FreeStack.cpp.o(.text*) *FreeStack.cpp.o(.rodata*) *MinimumSerial.cpp.o(.text*) *MinimumSerial.cpp.o(.rodata*) *istream.cpp.o(.text*) *istream.cpp.o(.rodata*) *ostream.cpp.o(.text*) *ostream.cpp.o(.rodata*) /* SDIO driver stays in ITCM (not FLASH) for fast interrupt response. * Only the FAT filesystem layer goes to FLASH. */ /* Move ALL .rodata to FLASH (it's read-only, cache-friendly from * FLASH via the D-cache) to free up DTCM for stack. This reclaims * an estimated 40-90 KB of DTCM. The ed25519.c.o rodata is excluded * because ed_K/ed_X/ed_Y base point constants must stay in DTCM * (moving them to FLASH produced an all-zeros pubkey — see the * note at the top of this file). */ *(EXCLUDE_FILE(*ed25519.c.o) .rodata*) . = ALIGN(4); KEEP(*(.init)) __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; __init_array_start = .; KEEP (*(.init_array)) __init_array_end = .; . = ALIGN(4); } > FLASH .text.progmem : { *(.progmem*) . = ALIGN(4); } > FLASH .text.itcm : { . = . + 32; /* MPU to trap NULL pointer deref */ *(.fastrun) *(.text*) . = ALIGN(16); } > ITCM AT> FLASH .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .ARM.extab.text* .gnu.linkonce.armexidx.*) __exidx_end = .; } > ITCM AT> FLASH .data : { *(.endpoint_queue) *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.data*))) KEEP(*(.vectorsram)) } > DTCM AT> FLASH .bss ALIGN(4) : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) *(SORT_BY_ALIGNMENT(SORT_BY_NAME(COMMON))) . = ALIGN(32); . = . + 32; /* MPU to trap stack overflow */ } > DTCM .bss.dma (NOLOAD) : { *(.hab_log) *(.dmabuffers) . = ALIGN(32); } > RAM .bss.extram (NOLOAD) : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.externalram))) . = ALIGN(32); } > ERAM .text.csf : { FILL(0xFF) . = ALIGN(1024); KEEP(*(.csf)) __text_csf_end = .; } > FLASH _stext = ADDR(.text.itcm); _etext = ADDR(.text.itcm) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx); _stextload = LOADADDR(.text.itcm); _sdata = ADDR(.data); _edata = ADDR(.data) + SIZEOF(.data); _sdataload = LOADADDR(.data); _sbss = ADDR(.bss); _ebss = ADDR(.bss) + SIZEOF(.bss); _heap_start = ADDR(.bss.dma) + SIZEOF(.bss.dma); _heap_end = ORIGIN(RAM) + LENGTH(RAM); _extram_start = ADDR(.bss.extram); _extram_end = ADDR(.bss.extram) + SIZEOF(.bss.extram); _itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + 0x7FFF) >> 15; _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1); _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15); _flashimagelen = __text_csf_end - ORIGIN(FLASH); _teensy_model_identifier = 0x25; .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } }