@@ -17,9 +17,9 @@ the rest of pointers are related to exceptions -- we'll ignore them for now.
1717[ vector table ] : https://developer.arm.com/docs/dui0552/latest/the-cortex-m3-processor/exception-model/vector-table
1818
1919Linkers decide the final memory layout of programs, but we can use [ linker scripts] to have some
20- control over the memory layout . The control granularity that linker scripts give us over the layout
20+ control over the it . The control granularity that linker scripts give us over the layout
2121is at the level of * sections* . A section is a collection of * symbols* laid out in contiguous memory.
22- A symbol can be a statically allocated variable, a ` static ` variable, or a set of instructions, a
22+ A symbol can be a statically allocated variable, a ` static ` variable, a set of instructions, or a
2323monomorphized (non generic) Rust function.
2424
2525[ linker scripts ] : https://sourceware.org/binutils/docs/ld/Scripts.html
@@ -40,19 +40,20 @@ section placement via these attributes:
4040 ` #[no_mangle] fn bar() ` will produce a symbol named ` bar ` .
4141- ` #[link_section = ".bar"] ` places the symbol in a section named ` .bar ` .
4242
43- With these attributes we can expose a stable ABI from the program and use it in the linker script.
43+ With these attributes, we can expose a stable ABI of the program and use it in the linker script.
4444
4545## The Rust side
4646
47- We need to populate the first two entries of the vector table. The first one, the initial value for
48- the stack pointer, can be populated using only the linker script. The second one, the reset vector,
49- needs to be created in Rust code and placed in the right place using the linker script.
47+ Like mentioned before, for Cortex-M devices, we need to populate the first two entries of the
48+ vector table. The first one, the initial value for the stack pointer, can be populated using
49+ only the linker script. The second one, the reset vector, needs to be created in Rust code
50+ and placed correctly using the linker script.
5051
5152The reset vector is a pointer into the reset handler. The reset handler is the function that the
5253device will execute after a system reset, or after it powers up for the first time. The reset
5354handler is always the first stack frame in the hardware call stack; returning from it is undefined
5455behavior as there's no other stack frame to return to. We can enforce that the reset handler never
55- returns by making it a divergent function, a function with signature ` fn(/* .. */) -> ! ` .
56+ returns by making it a divergent function, which is a function with signature ` fn(/* .. */) -> ! ` .
5657
5758``` rust
5859// The reset handler
@@ -70,16 +71,16 @@ pub unsafe extern "C" fn Reset() -> ! {
7071pub static RESET_VECTOR : unsafe extern " C" fn () -> ! = Reset ;
7172```
7273
73- We use ` extern "C" ` to tell the compiler to lower the function using the C ABI instead of the Rust
74- ABI, which is unstable, as that's what the hardware expects .
74+ The hardware expects a certain format here, to which we adhere by using ` extern "C" ` to tell the
75+ compiler to lower the function using the C ABI, instead of the Rust ABI, which is unstable .
7576
76- To refer to the reset handler and reset vector from the linker script we need them to have a stable
77- symbol name so we use ` #[no_mangle] ` . We need fine control over the location of ` RESET_VECTOR ` so we
78- place it on a known section, ` .vector_table.reset_vector ` . The exact location of the reset handler
79- itself, ` Reset ` , is not important so we just stick to the default compiler generated section.
77+ To refer to the reset handler and reset vector from the linker script, we need them to have a stable
78+ symbol name so we use ` #[no_mangle] ` . We need fine control over the location of ` RESET_VECTOR ` , so we
79+ place it in a known section, ` .vector_table.reset_vector ` . The exact location of the reset handler
80+ itself, ` Reset ` , is not important. We just stick to the default compiler generated section.
8081
8182Also, the linker will ignore symbols with internal linkage, AKA internal symbols, while traversing
82- the list of input object files so we need our two symbols to have external linkage. The only way to
83+ the list of input object files, so we need our two symbols to have external linkage. The only way to
8384make a symbol external in Rust is to make its corresponding item public (` pub ` ) and * reachable* (no
8485private module between the item and the root of the crate).
8586
@@ -137,35 +138,35 @@ in the target. The values used here correspond to the LM3S6965 microcontroller.
137138
138139Here we indicate to the linker that the reset handler -- whose symbol name is ` Reset ` -- is the
139140* entry point* of the program. Linkers aggressively discard unused sections. Linkers consider the
140- entry point and functions called from it as * used* so they won't discard them. Without this line the
141- linker would discard the ` Reset ` function and all other functions called from it.
141+ entry point and functions called from it as * used* so they won't discard them. Without this line,
142+ the linker would discard the ` Reset ` function and all subsequent functions called from it.
142143
143144### ` EXTERN `
144145
145146Linkers are lazy; they will stop looking into the input object files once they have found all the
146- symbols recursively referenced from the entry point. ` EXTERN ` forces the linker to look for its
147- argument even after all other referenced symbol have been found. As a rule of thumb, if you need a
148- symbol that's not called from the entry point to always be present in the output binary you should
149- use ` EXTERN ` in conjunction with ` KEEP ` .
147+ symbols that are recursively referenced from the entry point. ` EXTERN ` forces the linker to look
148+ for ` EXTERN ` 's argument even after all other referenced symbols have been found. As a rule of thumb,
149+ if you need a symbol that's not called from the entry point to always be present in the output binary,
150+ you should use ` EXTERN ` in conjunction with ` KEEP ` .
150151
151152### ` SECTIONS `
152153
153154This part describes how sections in the input object files, AKA * input sections* , are to be arranged
154- in the sections the output object file, AKA output sections; or if they should be discarded. Here we
155- define two output sections:
155+ in the sections of the output object file, AKA output sections; or if they should be discarded. Here
156+ we define two output sections:
156157
157158```
158159 .vector_table ORIGIN(FLASH) : { /* .. */ } > FLASH
159160```
160161
161- ` .vector_table ` , which contains the vector table and its located at the start of ` FLASH ` memory;
162+ ` .vector_table ` , which contains the vector table and is located at the start of ` FLASH ` memory,
162163
163164```
164165 .text : { /* .. */ } > FLASH
165166```
166167
167- and ` .text ` , which contains the program subroutines and its located somewhere in ` FLASH ` . Its start
168- address is not specified but the linker will place after the previous output section,
168+ and ` .text ` , which contains the program subroutines and is located somewhere in ` FLASH ` . Its start
169+ address is not specified, but the linker will place it after the previous output section,
169170` .vector_table ` .
170171
171172The output ` .vector_table ` section contains:
@@ -187,25 +188,25 @@ memory block.
187188
188189Next, we use ` KEEP ` to force the linker to insert all input sections named
189190` .vector_table.reset_vector ` right after the initial SP value. The only symbol located in that
190- section is ` RESET_VECTOR ` so this will effectively place ` RESET_VECTOR ` second in the vector table.
191+ section is ` RESET_VECTOR ` , so this will effectively place ` RESET_VECTOR ` second in the vector table.
191192
192193The output ` .text ` section contains:
193194
194195```
195196 *(.text .text.*);
196197```
197198
198- All the input sections named ` .text ` and ` .text.* ` . Note that we don't use ` KEEP ` here to let the
199- linker discard the unused sections.
199+ This includes all the input sections named ` .text ` and ` .text.* ` . Note that we don't use ` KEEP `
200+ here to let the linker discard unused sections.
200201
201- Finally, we use the special ` /DISCARD/ ` section to discard:
202+ Finally, we use the special ` /DISCARD/ ` section to discard
202203
203204```
204205 *(.ARM.exidx.*);
205206```
206207
207208input sections named ` .ARM.exidx.* ` . These sections are related to exception handling but we are not
208- doing stack unwinding on panics and they take up space in Flash memory so we just discard them.
209+ doing stack unwinding on panics and they take up space in Flash memory, so we just discard them.
209210
210211## Putting it all together
211212
@@ -221,10 +222,13 @@ use core::panic::PanicInfo;
221222// The reset handler
222223#[no_mangle]
223224pub unsafe extern " C" fn Reset () -> ! {
225+ let x = 42 ;
226+
227+ // can't return so we go into an infinite loop here
224228 loop {}
225229}
226230
227- // The reset vector.
231+ // The reset vector, a pointer into the reset handler
228232#[link_section = " .vector_table.reset_vector" ]
229233#[no_mangle]
230234pub static RESET_VECTOR : unsafe extern " C" fn () -> ! = Reset ;
@@ -236,7 +240,7 @@ fn panic(_panic: &PanicInfo) -> ! {
236240}
237241```
238242
239- We'll use the LLVM linker, LLD, shipped with the Rust toolchain. That way you won't need to install
243+ We'll use the LLVM linker, LLD, shipped with the Rust toolchain. That way, you won't need to install
240244the ` arm-none-eabi-gcc ` linker that the ` thumbv7m-none-eabi ` target uses by default. Changing the
241245linker is done via rustc flags; the full Cargo invocation to change the linker and pass the linker
242246script to the linker is shown below:
0 commit comments