-
-
Notifications
You must be signed in to change notification settings - Fork 38
/
samd21g18a.ld
556 lines (447 loc) · 19.2 KB
/
samd21g18a.ld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
/*
The Most Thoroughly Commented Linker Script in The World
This is a linker script for the Atmel/Microchip SAM D21
with an absolutely obscene amount of documentation.
*/
/*
OUTPUT_FORMAT configures the linker to use a platform-specific BFD
backend to generate ELF files. BFD backends instruct the linker on
how to properly create the ELF sections for a given platform.
The first is the default BFD. The second and third arguments are used
when big (-EB) or little (-EL) endian is requested.
Since the SAM D series are configured with only little endian support,
"elf32-littlearm" is used across the board. This option seems to be
included by Atmel/Microchip out of an abundance of caution, as
arm-none-eabi-ld will do the right thing and use "elf32-littlearm" by
default.
The list of acceptable values can be obtained using `objdump -i`.
References:
* https://sourceware.org/binutils/docs/ld/Format-Commands.html#Format-Commands
* https://sourceware.org/binutils/docs/ld/BFD.html
* https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf
Section 11.1.11, Cortex M0+ Configuration
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*
CPU memory configuration variables.
These variables are used by the following "MEMORY" command to define
the various memory spaces.
For the SAMD21G18A used by this project, the available Flash is
256kB and the available SRAM is 32kB.
This project also reserves 8kB for the bootloader and 1kB for
"non-volatile memory" (NVM) - which is used by the application
to store calibration and user settings.
Also it's useful to note that you can actually use unit suffixes
here: I could have written `FLASH_SIZE = 256KB` instead of
`FLASH_SIZE = 0x40000`. However, I generally prefer the hex
representation because there's less ambiguity.
References:
* https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf
Section 10.2, Physical Memory Map
*/
FLASH_SIZE = 0x40000; /* 256kB, 262,144 bytes */
BOOTLOADER_SIZE = 0x2000; /* 8kB, 8,192 bytes */
NVM_SIZE = 0x400; /* 1kB, 1,024 bytes */
SRAM_SIZE = 0x8000; /* 32kB, 32,768 bytes */
/*
ARM Cortex-M processors use a descending stack and generally
require stack space to be set aside in RAM.
The application's behavior determines just how much stack space
should be reserved. I generally start with 2kB (0x800) of
stack space for Cortex-M0+ projects programmed in C .
You can analyze stack usage in GCC using the `-fstack-usage`
flag and you can enable compiler warnings for stack usage
with `-Wstack-usage=STACK_SIZE`.
References:
* https://embeddedartistry.com/blog/2020/08/17/three-gcc-flags-for-analyzing-memory-usage/
* https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/how-much-stack-memory-do-i-need-for-my-arm-cortex--m-applications
* https://gcc.gnu.org/onlinedocs/gnat_ugn/Static-Stack-Usage-Analysis.html
* https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
*/
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x800;
/*
Memory space definition.
This section declare blocks of memories for specific purposes. Since an
ARM's address space is generally split between Flash, SRAM, peripherals,
and other regions, it's necessary to tell the linker where different
types of data can go in the address space.
These blocks will be used in the "SECTIONS" command below.
References:
* https://sourceware.org/binutils/docs/ld/MEMORY.html#MEMORY
* https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf
Section 10.2, Physical Memory Map
*/
MEMORY
{
/*
Start with the Flash memory region. On the SAMD21, Flash starts at
the beginning of the address space (0x00000000) and is contiguous
right up to the size of the Flash. Flash is marked a "rx" so
that the linker knows that this space is read-only (r) and
executable (x).
*/
/*
The "bootloader" section allows this firmware to work with the uf2
bootloader. The bootloader takes the first 0x2000 bytes of flash
memory.
References:
* https://github.com/adafruit/uf2-samdx1#configuration
*/
bootloader (rx) : ORIGIN = 0x00000000, LENGTH = BOOTLOADER_SIZE
/*
Following the bootloader is the flash memory used by the application,
called "rom" here - even though it's flash, the name is just a name
and doesn't carry special meaning.
If your application isn't using a bootloader then this section
would start at 0x00000000, but, since this project does use
a bootloader it instead starts right after the end of the bootloader.
The total length of the rom block is the MCU's flash size minus the
bootloader's size and any space reserved for "non-volatile memory"
by the application.
*/
rom (rx) : ORIGIN = BOOTLOADER_SIZE, LENGTH = FLASH_SIZE - BOOTLOADER_SIZE - NVM_SIZE
/*
The "nvm" block is space set aside for the application to store
user settings and calibration data in the MCU's flash.
The block is located right at the end of the flash space. This
is useful because it means that it stays in a fixed location
regardless of how much flash space the application takes up
in "rom". Explicitly defining this section also lets the
linker ensure that application code doesn't overwrite the
data in this region.
This block is marked as read-only (r) because flash can not
be written in the same way as normal memory, however, the
application can use the SAMD's NVM peripheral to write data in
this region.
*/
nvm (r) : ORIGIN = FLASH_SIZE - NVM_SIZE, LENGTH = NVM_SIZE
/*
The "ram" block is mapped to the CPU's SRAM and it's where
the stack, heap, and all variables will go.
For the SAMD21, SRAM starts at 0x20000000 and is contiguous
for the size of the SRAM. This is noted in the Physical
Memory Map section of the datasheet.
*/
ram (rwx) : ORIGIN = 0x20000000, LENGTH = SRAM_SIZE
}
/*
The sections command tells the linker how to combine the
input files into an output ELF and where segments belong
in memory.
The linker takes a set of input files containing the "input
sections" and uses this to map them to "output sections"
which are placed in the output ELF file.
While the most important sections to think about here
are the ones that'll be placed into the memory (segments)
some sections are just placed in the output ELF for debugging.
References:
* https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
*/
SECTIONS
{
/*
The text segment contains program code and read-only data.
References:
* https://developer.arm.com/documentation/dui0101/a/
Page 5, Segments
* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#special_sections
*/
.text :
{
/*
This segment must be 4-byte aligned as defined in ARM ELF
File Format specification.
*/
. = ALIGN(4);
/*
The vector table defines the initial stack pointer and
interrupt/exception routines for the ARM CPU and device
peripherals. Every Cortex-M project needs this.
For the SAM D series the vector table is expected
to be at address 0x00000000 after reset. Since
flash memory starts at 0x00000000, the first values
in flash should be the vector table.
When defining the vector table in code you must use
`__attribute__ ((section(".vectors")))` to tell
GCC to place the vector table into the section
named ".vectors" in the input object file so that
the linker can find it.
Also notice the use of `KEEP` here. To save on size,
the firmware is compiled with options that let GCC
discard unused functions and data (`--gc-sections`).
Without `KEEP`, the linker would throw away the vector
table!
Note that since this project uses the UF2 bootloader,
this actually gets placed at the beginning of the
program's flash area (0x2000). The Cortex-M allows
changing the vector table after initialization,
so the startup script sets the Vector Table Offset
Register (`SCB->VTOR`) to `_sfixed` during its
intialization. The `_efixed` symbol is unused but
included for completeness.
References:
* https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf
Secion 8.3.3, Fetching of Initial Instructions
* https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf
Section B1.5.3, The vector table
Section B3.2.5, Vector Table Offset Register, VTOR
* ../third_party/samd21/gcc/gcc/startup_samd21.c
* https://gcc.gnu.org/onlinedocs/gnat_ugn/Compilation-options.html
*/
_sfixed = .;
KEEP(*(.vectors .vectors.*))
/*
Include code and read-only data sections from all
input files.
By default, GCC places all program code into a section named
".text" and read-only data (such as const static variables) into
a section named ".rodata" in the input object files. This naming
convention is from the ELF ABI specification.
GCC generates three "flavors" of sections in object files:
- .{section}: the basic section.
- .{section}.*: sections generated by "-ffunction-sections" and
"-fdata-sections" so that each function/data has a unique
section.
- .gnu.linkonce.{type}.*: sections generated by GCC so the
linker can remove duplicates. Seems to be related to
Vague Linking.
References:
* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#special_sections
* https://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html
* https://stackoverflow.com/questions/5518083/what-is-a-linkonce-section
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.rodata .rodata* .gnu.linkonce.r.*)
/*
The following sections support the C & C++ runtime.
These are generally used by crt0.
References:
* https://en.wikipedia.org/wiki/Crt0
*/
/*
C++ Runtime: initializers for static variables.
C Runtime: designated constructors
For C++, handles variables at file scope like this:
int f = some_func()
For C, handles functions designated as constructors:
void intialize_thing(void) __attribute__((constructor));
Executed by the C runtime at startup via __libc_init_array.
References:
* https://github.com/gcc-mirror/gcc/blob/master/libgcc/crtstuff.c
* https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/misc/init.c;
* https://gcc.gnu.org/onlinedocs/gccint/Initialization.html
* https://developer.arm.com/documentation/dui0475/h/the-arm-c-and-c---libraries/c---initialization--construction-and-destruction
* https://stackoverflow.com/questions/15265295/understanding-the-libc-init-array
*/
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
/*
C++ runtime: destructors for static variables.
C runtime: designated finializers
For C, handles functions designated as destructors:
void destroy_thing(void) __attribute__((destructor));
References:
* https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/misc/fini.c
*/
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
/*
C++ runtime: static constructors
References:
* https://gcc.gnu.org/onlinedocs/gccint/Initialization.html
* https://github.com/gcc-mirror/gcc/blob/master/libgcc/crtstuff.c
*/
. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
/*
C++ runtime: static destructors and atexit()
Note that in usual practice these aren't ever called because the program
doesn't exit - except when powered off or reset.
References:
* https://gcc.gnu.org/onlinedocs/gccint/Initialization.html
* https://github.com/gcc-mirror/gcc/blob/master/libgcc/crtstuff.c
*/
. = ALIGN(4);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .;
} > rom
/*
ARM defines several special sections for exception handling.
These are require for C++ and for C programs that try to
examine backtraces.
- exidx is used to contain index entries for stack unwinding.
- extab names sections containing exception unwinding information.
Essentially, each function that can throw an exception will
have entries in the exidx and extab sections.
References:
- https://developer.arm.com/documentation/ihi0038/b/
- https://stackoverflow.com/a/57463515
*/
.ARM.extab : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > rom
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > rom
/*
The `.relocate` section includes mutable variables that have a
default value and specially marked functions that should execute
from RAM.
This data is stored in ROM but is referenced from RAM. The
program/runtime must copy the data from ROM to RAM on reset,
hence, "relocate".
Performance sensitive/critical functions can also be placed in
RAM using this section:
#define RAMFUNC __attribute__((section(".ramfunc")))
void fast_function(void) RAMFUNC;
In other linker scripts you might see this named as the `.data`
section. That's what the ELF specification calls for, but the
Microchip-provided SAM D startup scripts expect `.relocate`.
This also sets the symbol `_etext` to the start of the relocation
segment in flash. The startup script copies the data starting at
`_etext` to `_srelocate` and ends when it reaches `_erelocate`.
The `_etext` name is a bit unfortunate since it's not the end of
the text segment, but rather the start of the read-only copy of the
relocate section in flash. If I wrote the startup script I would have
named these symbols differently.
References:
* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#special_sections
* https://www.sourceware.org/binutils/docs/ld/Output-Section-LMA.html#Output-Section-LMA
* ../third_party/samd21/gcc/gcc/startup_samd21.c
*/
.relocate :
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram AT> rom
_etext = LOADADDR(.relocate);
/*
The BSS section reserves RAM space for declared but uninitialized
variables.
This is zeroed out by the startup script. The start-up script
zeros out the area of RAM starting at `_szero` and ending at
`_ezero`.
This includes `COMMON` which is a bit of a legacy section. GCC
defaults to `-fno-common` these days so there shouldn't be
anything in there, but it's included for completeness.
References:
* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#special_sections
* https://en.wikipedia.org/wiki/.bss
* https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
Section -fcommon
* ../third_party/samd21/gcc/gcc/startup_samd21.c
*/
.bss (NOLOAD) :
{
. = ALIGN(4);
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ezero = .;
} > ram
/*
Reserve the stack space in RAM.
Cortex-M stacks grow down, so the stack starts at `_estack` and
grows towards `_sstack`. The startup script sets the vector
table's stack pointer to `_estack` on startup. `_sstack` is
unused but included for completeness.
The ARM procedure call standard (AAPCS) requires the stack to be
aligned on an eight byte boundary.
References:
* ../third_party/samd21/gcc/gcc/startup_samd21.c
* https://developer.arm.com/documentation/ihi0042/e/
Section 5.2.1.2, Stack constraints at a public interface
*/
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram
/*
Mark the end of the RAM and the start of unallocated space.
If the program uses the malloc and the heap, then `_heap_start`
can be used as the start of the heap. If the program doesn't
use the heap then the `_heap_start` symbol is unused and could
be removed. With `-specs=nano.specs`, the `_sbrk` syscall has
to be implemented for malloc to work:
extern int _heap_start;
void *_sbrk(int incr) {
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) {
heap = (unsigned char *)&_heap_start;
}
prev_heap = heap;
heap += incr;
return prev_heap;
}
Another memory layout strategy is to place the stack at the end
of RAM and the heap after bss. That way the heap can grow upwards
towards the stack and the stack can grow downwards to the heap.
However, I'm not a big fan of that approach- it's possible for the
heap to overwrite the stack. Leaving the entire end of RAM available
as the heap works well for my purposes.
References:
* https://en.wikipedia.org/wiki/Sbrk
* https://interrupt.memfault.com/blog/boostrapping-libc-with-newlib
* https://embeddedartistry.com/blog/2017/02/15/implementing-malloc-first-fit-free-list/
*/
. = ALIGN(4);
PROVIDE(_heap_start = .);
_end = . ;
}
/*
Absolute symbol definitions.
This section defines some useful absolute symbols for the application
to use.
*/
/*
Symbols for the settings section in the NVM memory block.
Gemini uses the first half of the NVM block for user settings.
This symbol is used by the settings module to know where to
load and save settings.
References:
* ../src/gem_settings_load_save.c
*/
_nvm_settings_base_address = ORIGIN(nvm);
_nvm_settings_length = LENGTH(nvm) / 2;
/*
Symbols for the calibration/look-up table in the NVM memory block.
Gemini uses the other half of the NVM block to store the factory-
calibrated look-up table for translating ADC -> frequency/DAC codes.
References:
* ../src/gem_ramp_table_load_save.c
*/
_nvm_lut_base_address = ORIGIN(nvm) + LENGTH(nvm) / 2;
_nvm_lut_length = LENGTH(nvm) / 2;