MEMORY { BOOT_LOADER : ORIGIN = 0x10000000, LENGTH = 0x100 FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 RAM : ORIGIN = 0x20000000, LENGTH = 256K } EXTERN(BOOT2_FIRMWARE) SECTIONS { /* ### Boot loader */ .boot_loader ORIGIN(BOOT_LOADER) : { KEEP(*(.boot_loader*)); } > BOOT_LOADER } INSERT BEFORE .text; /* INCLUDE memory.x */ /* # Entry point = reset vector */ EXTERN(__RESET_VECTOR); EXTERN(RESET); ENTRY(RESET); /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ /* The user can override any of these aliases by defining the corresponding symbol themselves (cf. the `exception!` macro) */ EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ EXTERN(DefaultHandler); /* PROVIDE(TIMER_IRQ_0 = DefaultHandler); */ PROVIDE(TIMER_IRQ_1 = DefaultHandler); PROVIDE(TIMER_IRQ_2 = DefaultHandler); PROVIDE(TIMER_IRQ_3 = DefaultHandler); PROVIDE(PWM_IRQ_WRAP = DefaultHandler); PROVIDE(USBCTRL_IRQ = DefaultHandler); PROVIDE(XIP_IRQ = DefaultHandler); PROVIDE(PIO0_IRQ_0 = DefaultHandler); PROVIDE(PIO0_IRQ_1 = DefaultHandler); PROVIDE(PIO1_IRQ_0 = DefaultHandler); PROVIDE(PIO1_IRQ_1 = DefaultHandler); PROVIDE(DMA_IRQ_0 = DefaultHandler); PROVIDE(DMA_IRQ_1 = DefaultHandler); PROVIDE(IO_IRQ_BANK0 = DefaultHandler); PROVIDE(IO_IRQ_QSPI = DefaultHandler); PROVIDE(SIO_IRQ_PROC0 = DefaultHandler); PROVIDE(SIO_IRQ_PROC1 = DefaultHandler); PROVIDE(CLOCKS_IRQ = DefaultHandler); PROVIDE(SPI0_IRQ = DefaultHandler); PROVIDE(SPI1_IRQ = DefaultHandler); PROVIDE(UART0_IRQ = DefaultHandler); PROVIDE(UART1_IRQ = DefaultHandler); PROVIDE(ADC_IRQ_FIFO = DefaultHandler); PROVIDE(I2C0_IRQ = DefaultHandler); PROVIDE(I2C1_IRQ = DefaultHandler); PROVIDE(RTC_IRQ = DefaultHandler); PROVIDE(SWI_IRQ_0 = DefaultHandler); PROVIDE(SWI_IRQ_1 = DefaultHandler); PROVIDE(SWI_IRQ_2 = DefaultHandler); PROVIDE(SWI_IRQ_3 = DefaultHandler); PROVIDE(SWI_IRQ_4 = DefaultHandler); PROVIDE(SWI_IRQ_5 = DefaultHandler); /* EXTERN(PWM_HANDLER); */ /* EXTERN(USB_HANDLER); */ /* EXTERN(XIP_HANDLER); */ /* EXTERN(PIO_HANDLER); */ /* EXTERN(DMA_HANDLER); */ /* EXTERN(IO_HANDLER); */ /* EXTERN(SIO_HANDLER); */ /* EXTERN(CLOCKS_HANDLER); */ /* EXTERN(SPI_HANDLER); */ /* EXTERN(UART_HANDLER); */ /* EXTERN(ADC_HANDLER); */ /* EXTERN(I2C_HANDLER); */ /* EXTERN(RTC_HANDLER); */ /*EXTERN(SW_HANDLER); */ EXTERN(HardFaultTrampoline); PROVIDE(NON_MASKABLE_INT = DefaultHandler); PROVIDE(HARD_FAULT = DefaultHandler); PROVIDE(SV_CALL = DefaultHandler); PROVIDE(PEND_SV = DefaultHandler); PROVIDE(SYS_TICK = DefaultHandler); PROVIDE(MemoryManagement = DefaultHandler); PROVIDE(BusFault = DefaultHandler); PROVIDE(UsageFault = DefaultHandler); PROVIDE(SecureFault = DefaultHandler); PROVIDE(DebugMonitor = DefaultHandler); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # Pre-initialization function */ /* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, then the function this points to will be called before the RAM is initialized. */ PROVIDE(__pre_init = DefaultPreInit); /* # Sections */ SECTIONS { PROVIDE(_ram_start = ORIGIN(RAM)); PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM)); PROVIDE(_stack_start = _ram_end); /* ## Sections in FLASH */ /* ### Vector table */ .vector_table ORIGIN(FLASH) : { __vector_table = .; /* Initial Stack Pointer (SP) value. * We mask the bottom three bits to force 8-byte alignment. * Despite having an assert for this later, it's possible that a separate * linker script could override _stack_start after the assert is checked. */ LONG(_stack_start & 0xFFFFFFF8); /* Reset vector */ KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ /* Exceptions */ __exceptions = .; /* start of exceptions */ KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ __eexceptions = .; /* end of exceptions */ /* Device specific interrupts */ KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ } > FLASH PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); /* ### .text */ .text _stext : { __stext = .; *(.Reset); *(.text .text.*); /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, so must be placed close to it. */ *(.HardFaultTrampoline); *(.HardFault.*); . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ __etext = .; } > FLASH /* ### .rodata */ .rodata : ALIGN(4) { . = ALIGN(4); __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); __erodata = .; } > FLASH /* ## Sections in RAM */ /* ### .data */ .data : ALIGN(4) { . = ALIGN(4); __sdata = .; *(.data .data.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ } > RAM AT>FLASH /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to * use the .data loading mechanism by pushing __edata. Note: do not change * output region or load region in those user sections! */ . = ALIGN(4); __edata = .; /* LMA of .data */ __sidata = LOADADDR(.data); /* ### .gnu.sgstubs This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ /* Security Attribution Unit blocks must be 32 bytes aligned. */ /* Note that this pads the FLASH usage to 32 byte alignment. */ .gnu.sgstubs : ALIGN(32) { . = ALIGN(32); __veneer_base = .; *(.gnu.sgstubs*) . = ALIGN(32); } > FLASH /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol. */ . = ALIGN(32); __veneer_limit = .; /* ### .bss */ .bss (NOLOAD) : ALIGN(4) { . = ALIGN(4); __sbss = .; *(.bss .bss.*); *(COMMON); /* Uninitialized C statics */ . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ } > RAM /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to * use the .bss zeroing mechanism by pushing __ebss. Note: do not change * output region or load region in those user sections! */ . = ALIGN(4); __ebss = .; /* ### .uninit */ .uninit (NOLOAD) : ALIGN(4) { . = ALIGN(4); __suninit = .; *(.uninit .uninit.*); . = ALIGN(4); __euninit = .; } > RAM /* Place the heap right after `.uninit` in RAM */ PROVIDE(__sheap = __euninit); /* ## .got */ /* 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 (NOLOAD) : { KEEP(*(.got .got.*)); } /* ## Discarded sections */ /DISCARD/ : { /* Unused exception related info that only wastes space */ *(.ARM.exidx); *(.ARM.exidx.*); *(.ARM.extab.*); } } /* Do not exceed this mark in the error messages below | */ /* # Alignment checks */ ASSERT(ORIGIN(FLASH) % 4 == 0, " ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); ASSERT(ORIGIN(RAM) % 4 == 0, " ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " BUG(cortex-m-rt): .data is not 4-byte aligned"); ASSERT(__sidata % 4 == 0, " BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " BUG(cortex-m-rt): .bss is not 4-byte aligned"); ASSERT(__sheap % 4 == 0, " BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); ASSERT(_stack_start % 8 == 0, " ERROR(cortex-m-rt): stack start address is not 8-byte aligned. If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes. If you haven't, stack starts at the end of RAM by default. Check that both RAM origin and length are set to multiples of 8 in the `memory.x` file."); /* # Position checks */ /* ## .vector_table * * If the *start* of exception vectors is not 8 bytes past the start of the * vector table, then we somehow did not place the reset vector, which should * live 4 bytes past the start of the vector table. */ ASSERT(__exceptions == ADDR(.vector_table) + 0x8, " BUG(cortex-m-rt): the reset vector is missing"); ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " BUG(cortex-m-rt): the exception vectors are missing"); ASSERT(SIZEOF(.vector_table) > 0x40, " ERROR(cortex-m-rt): The interrupt vectors are missing. Possible solutions, from most likely to less likely: - Link to a svd2rust generated device crate - Check that you actually use the device/hal/bsp crate in your code - Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency may be enabling it) - Supply the interrupt handlers yourself. Check the documentation for details."); /* ## .text */ ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); ASSERT(_stext > ORIGIN(FLASH) && _stext < ORIGIN(FLASH) + LENGTH(FLASH), " ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. Set _stext to an address within the FLASH region."); /* # Other checks */ ASSERT(SIZEOF(.got) == 0, " ERROR(cortex-m-rt): .got section detected in the input object files Dynamic relocations are not supported. If you are linking to C code compiled using the 'cc' crate then modify your build script to compile the C code _without_ the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); /* Do not exceed this mark in the error messages above | */ /* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ /* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ /*INCLUDE device.x*/ ASSERT(SIZEOF(.vector_table) <= 0xc0, " There can't be more than 32 interrupt handlers. This may be a bug in your device crate, or you may have registered more than 32 interrupt handlers.");