| /* # 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 __sbss }`). |
| |
| - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a |
| symbol if 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 4-byte aligned. These alignments are assumed by the RAM initialization |
| routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see |
| "Address (..) is out of bounds" in the disassembly produced by `objdump`. |
| */ |
| |
| /* Provides information about the memory layout of the device */ |
| /* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ |
| 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(NonMaskableInt = DefaultHandler); |
| EXTERN(HardFaultTrampoline); |
| PROVIDE(MemoryManagement = DefaultHandler); |
| PROVIDE(BusFault = DefaultHandler); |
| PROVIDE(UsageFault = DefaultHandler); |
| PROVIDE(SecureFault = DefaultHandler); |
| PROVIDE(SVCall = DefaultHandler); |
| PROVIDE(DebugMonitor = DefaultHandler); |
| PROVIDE(PendSV = DefaultHandler); |
| PROVIDE(SysTick = DefaultHandler); |
| |
| PROVIDE(DefaultHandler = DefaultHandler_); |
| PROVIDE(HardFault = HardFault_); |
| |
| /* # 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(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); |
| |
| /* ## 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 */ |
| __reset_vector = .; |
| |
| /* Exceptions */ |
| KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ |
| __eexceptions = .; |
| |
| /* 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 */ |
| ASSERT(__reset_vector == 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 + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " |
| ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. |
| Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); |
| |
| /* # 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 | */ |