|
| 1 | +/* # Developer notes |
| 2 | + |
| 3 | +- Symbols that start with a double underscore (__) are considered "private" |
| 4 | + |
| 5 | +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be |
| 6 | + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { |
| 7 | + static mut __sbss }`). |
| 8 | + |
| 9 | +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a |
| 10 | + symbol if not dropped if it appears in or near the front of the linker arguments and "it's not |
| 11 | + needed" by any of the preceding objects (linker arguments) |
| 12 | + |
| 13 | +- `PROVIDE` is used to provide default values that can be overridden by a user linker script |
| 14 | + |
| 15 | +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* |
| 16 | + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization |
| 17 | + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see |
| 18 | + "Address (..) is out of bounds" in the disassembly produced by `objdump`. |
| 19 | +*/ |
| 20 | + |
| 21 | +/* Provides information about the memory layout of the device */ |
| 22 | +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ |
| 23 | +INCLUDE memory.x |
| 24 | + |
| 25 | +/* # Entry point = reset vector */ |
| 26 | +EXTERN(__RESET_VECTOR); |
| 27 | +EXTERN(Reset); |
| 28 | +ENTRY(Reset); |
| 29 | + |
| 30 | +/* # Exception vectors */ |
| 31 | +/* This is effectively weak aliasing at the linker level */ |
| 32 | +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. |
| 33 | + the `exception!` macro) */ |
| 34 | +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ |
| 35 | + |
| 36 | +EXTERN(DefaultHandler); |
| 37 | + |
| 38 | +PROVIDE(NonMaskableInt = DefaultHandler); |
| 39 | +EXTERN(HardFaultTrampoline); |
| 40 | +PROVIDE(MemoryManagement = DefaultHandler); |
| 41 | +PROVIDE(BusFault = DefaultHandler); |
| 42 | +PROVIDE(UsageFault = DefaultHandler); |
| 43 | +PROVIDE(SecureFault = DefaultHandler); |
| 44 | +PROVIDE(SVCall = DefaultHandler); |
| 45 | +PROVIDE(DebugMonitor = DefaultHandler); |
| 46 | +PROVIDE(PendSV = DefaultHandler); |
| 47 | +PROVIDE(SysTick = DefaultHandler); |
| 48 | + |
| 49 | +PROVIDE(DefaultHandler = DefaultHandler_); |
| 50 | +PROVIDE(HardFault = HardFault_); |
| 51 | + |
| 52 | +/* # Interrupt vectors */ |
| 53 | +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ |
| 54 | + |
| 55 | +/* # Pre-initialization function */ |
| 56 | +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, |
| 57 | + then the function this points to will be called before the RAM is initialized. */ |
| 58 | +PROVIDE(__pre_init = DefaultPreInit); |
| 59 | + |
| 60 | +/* # Sections */ |
| 61 | +SECTIONS |
| 62 | +{ |
| 63 | + PROVIDE(_ram_start = ORIGIN(RAM)); |
| 64 | + PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM)); |
| 65 | + PROVIDE(_stack_start = _ram_end); |
| 66 | + |
| 67 | + /* ## Sections in FLASH */ |
| 68 | + /* ### Vector table */ |
| 69 | + .vector_table ORIGIN(FLASH) : |
| 70 | + { |
| 71 | + __vector_table = .; |
| 72 | + |
| 73 | + /* Initial Stack Pointer (SP) value. |
| 74 | + * We mask the bottom three bits to force 8-byte alignment. |
| 75 | + * Despite having an assert for this later, it's possible that a separate |
| 76 | + * linker script could override _stack_start after the assert is checked. |
| 77 | + */ |
| 78 | + LONG(_stack_start & 0xFFFFFFF8); |
| 79 | + |
| 80 | + /* Reset vector */ |
| 81 | + KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ |
| 82 | + __reset_vector = .; |
| 83 | + |
| 84 | + /* Exceptions */ |
| 85 | + KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ |
| 86 | + __eexceptions = .; |
| 87 | + |
| 88 | + /* Device specific interrupts */ |
| 89 | + KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ |
| 90 | + } > FLASH |
| 91 | + |
| 92 | + PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); |
| 93 | + |
| 94 | + /* ### .text */ |
| 95 | + .text _stext : |
| 96 | + { |
| 97 | + __stext = .; |
| 98 | + *(.Reset); |
| 99 | + |
| 100 | + *(.text .text.*); |
| 101 | + |
| 102 | + /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, |
| 103 | + so must be placed close to it. */ |
| 104 | + *(.HardFaultTrampoline); |
| 105 | + *(.HardFault.*); |
| 106 | + |
| 107 | + . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ |
| 108 | + __etext = .; |
| 109 | + } > FLASH |
| 110 | + |
| 111 | + /* ### .rodata */ |
| 112 | + .rodata : ALIGN(4) |
| 113 | + { |
| 114 | + . = ALIGN(4); |
| 115 | + __srodata = .; |
| 116 | + *(.rodata .rodata.*); |
| 117 | + |
| 118 | + /* 4-byte align the end (VMA) of this section. |
| 119 | + This is required by LLD to ensure the LMA of the following .data |
| 120 | + section will have the correct alignment. */ |
| 121 | + . = ALIGN(4); |
| 122 | + __erodata = .; |
| 123 | + } > FLASH |
| 124 | + |
| 125 | + /* ## Sections in RAM */ |
| 126 | + /* ### .data */ |
| 127 | + .data : ALIGN(4) |
| 128 | + { |
| 129 | + . = ALIGN(4); |
| 130 | + __sdata = .; |
| 131 | + *(.data .data.*); |
| 132 | + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ |
| 133 | + } > RAM AT>FLASH |
| 134 | + /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to |
| 135 | + * use the .data loading mechanism by pushing __edata. Note: do not change |
| 136 | + * output region or load region in those user sections! */ |
| 137 | + . = ALIGN(4); |
| 138 | + __edata = .; |
| 139 | + |
| 140 | + /* LMA of .data */ |
| 141 | + __sidata = LOADADDR(.data); |
| 142 | + |
| 143 | + /* ### .gnu.sgstubs |
| 144 | + This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ |
| 145 | + /* Security Attribution Unit blocks must be 32 bytes aligned. */ |
| 146 | + /* Note that this pads the FLASH usage to 32 byte alignment. */ |
| 147 | + .gnu.sgstubs : ALIGN(32) |
| 148 | + { |
| 149 | + . = ALIGN(32); |
| 150 | + __veneer_base = .; |
| 151 | + *(.gnu.sgstubs*) |
| 152 | + . = ALIGN(32); |
| 153 | + } > FLASH |
| 154 | + /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are |
| 155 | + * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol. |
| 156 | + */ |
| 157 | + . = ALIGN(32); |
| 158 | + __veneer_limit = .; |
| 159 | + |
| 160 | + /* ### .bss */ |
| 161 | + .bss (NOLOAD) : ALIGN(4) |
| 162 | + { |
| 163 | + . = ALIGN(4); |
| 164 | + __sbss = .; |
| 165 | + *(.bss .bss.*); |
| 166 | + *(COMMON); /* Uninitialized C statics */ |
| 167 | + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ |
| 168 | + } > RAM |
| 169 | + /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to |
| 170 | + * use the .bss zeroing mechanism by pushing __ebss. Note: do not change |
| 171 | + * output region or load region in those user sections! */ |
| 172 | + . = ALIGN(4); |
| 173 | + __ebss = .; |
| 174 | + |
| 175 | + /* ### .uninit */ |
| 176 | + .uninit (NOLOAD) : ALIGN(4) |
| 177 | + { |
| 178 | + . = ALIGN(4); |
| 179 | + __suninit = .; |
| 180 | + *(.uninit .uninit.*); |
| 181 | + . = ALIGN(4); |
| 182 | + __euninit = .; |
| 183 | + } > RAM |
| 184 | + |
| 185 | + /* Place the heap right after `.uninit` in RAM */ |
| 186 | + PROVIDE(__sheap = __euninit); |
| 187 | + |
| 188 | + /* ## .got */ |
| 189 | + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in |
| 190 | + the input files and raise an error if relocatable code is found */ |
| 191 | + .got (NOLOAD) : |
| 192 | + { |
| 193 | + KEEP(*(.got .got.*)); |
| 194 | + } |
| 195 | + |
| 196 | + /* ## Discarded sections */ |
| 197 | + /DISCARD/ : |
| 198 | + { |
| 199 | + /* Unused exception related info that only wastes space */ |
| 200 | + *(.ARM.exidx); |
| 201 | + *(.ARM.exidx.*); |
| 202 | + *(.ARM.extab.*); |
| 203 | + } |
| 204 | +} |
| 205 | + |
| 206 | +/* Do not exceed this mark in the error messages below | */ |
| 207 | +/* # Alignment checks */ |
| 208 | +ASSERT(ORIGIN(FLASH) % 4 == 0, " |
| 209 | +ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); |
| 210 | + |
| 211 | +ASSERT(ORIGIN(RAM) % 4 == 0, " |
| 212 | +ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); |
| 213 | + |
| 214 | +ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " |
| 215 | +BUG(cortex-m-rt): .data is not 4-byte aligned"); |
| 216 | + |
| 217 | +ASSERT(__sidata % 4 == 0, " |
| 218 | +BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); |
| 219 | + |
| 220 | +ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " |
| 221 | +BUG(cortex-m-rt): .bss is not 4-byte aligned"); |
| 222 | + |
| 223 | +ASSERT(__sheap % 4 == 0, " |
| 224 | +BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); |
| 225 | + |
| 226 | +ASSERT(_stack_start % 8 == 0, " |
| 227 | +ERROR(cortex-m-rt): stack start address is not 8-byte aligned. |
| 228 | +If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes. |
| 229 | +If you haven't, stack starts at the end of RAM by default. Check that both RAM |
| 230 | +origin and length are set to multiples of 8 in the `memory.x` file."); |
| 231 | + |
| 232 | +/* # Position checks */ |
| 233 | + |
| 234 | +/* ## .vector_table */ |
| 235 | +ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " |
| 236 | +BUG(cortex-m-rt): the reset vector is missing"); |
| 237 | + |
| 238 | +ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " |
| 239 | +BUG(cortex-m-rt): the exception vectors are missing"); |
| 240 | + |
| 241 | +ASSERT(SIZEOF(.vector_table) > 0x40, " |
| 242 | +ERROR(cortex-m-rt): The interrupt vectors are missing. |
| 243 | +Possible solutions, from most likely to less likely: |
| 244 | +- Link to a svd2rust generated device crate |
| 245 | +- Check that you actually use the device/hal/bsp crate in your code |
| 246 | +- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency |
| 247 | +may be enabling it) |
| 248 | +- Supply the interrupt handlers yourself. Check the documentation for details."); |
| 249 | + |
| 250 | +/* ## .text */ |
| 251 | +ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " |
| 252 | +ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section |
| 253 | +Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); |
| 254 | + |
| 255 | +ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " |
| 256 | +ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. |
| 257 | +Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); |
| 258 | + |
| 259 | +/* # Other checks */ |
| 260 | +ASSERT(SIZEOF(.got) == 0, " |
| 261 | +ERROR(cortex-m-rt): .got section detected in the input object files |
| 262 | +Dynamic relocations are not supported. If you are linking to C code compiled using |
| 263 | +the 'cc' crate then modify your build script to compile the C code _without_ |
| 264 | +the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); |
| 265 | +/* Do not exceed this mark in the error messages above | */ |
0 commit comments