@@ -17,10 +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 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
23- monomorphized (non generic) Rust function.
22+ Symbols, in turn, can be data (a static variable), or instructions (a Rust function).
2423
2524[ linker scripts ] : https://sourceware.org/binutils/docs/ld/Scripts.html
2625
@@ -40,19 +39,20 @@ section placement via these attributes:
4039 ` #[no_mangle] fn bar() ` will produce a symbol named ` bar ` .
4140- ` #[link_section = ".bar"] ` places the symbol in a section named ` .bar ` .
4241
43- With these attributes we can expose a stable ABI from the program and use it in the linker script.
42+ With these attributes, we can expose a stable ABI of the program and use it in the linker script.
4443
4544## The Rust side
4645
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.
46+ Like mentioned before, for Cortex-M devices, we need to populate the first two entries of the
47+ vector table. The first one, the initial value for the stack pointer, can be populated using
48+ only the linker script. The second one, the reset vector, needs to be created in Rust code
49+ and placed correctly using the linker script.
5050
5151The reset vector is a pointer into the reset handler. The reset handler is the function that the
5252device will execute after a system reset, or after it powers up for the first time. The reset
5353handler is always the first stack frame in the hardware call stack; returning from it is undefined
5454behavior 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(/* .. */) -> ! ` .
55+ returns by making it a divergent function, which is a function with signature ` fn(/* .. */) -> ! ` .
5656
5757``` rust
5858// The reset handler
@@ -70,16 +70,16 @@ pub unsafe extern "C" fn Reset() -> ! {
7070pub static RESET_VECTOR : unsafe extern " C" fn () -> ! = Reset ;
7171```
7272
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 .
73+ The hardware expects a certain format here, to which we adhere by using ` extern "C" ` to tell the
74+ compiler to lower the function using the C ABI, instead of the Rust ABI, which is unstable .
7575
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.
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 in a known section, ` .vector_table.reset_vector ` . The exact location of the reset handler
79+ itself, ` Reset ` , is not important. We just stick to the default compiler generated section.
8080
8181Also, 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
82+ the list of input object files, so we need our two symbols to have external linkage. The only way to
8383make a symbol external in Rust is to make its corresponding item public (` pub ` ) and * reachable* (no
8484private module between the item and the root of the crate).
8585
@@ -137,35 +137,35 @@ in the target. The values used here correspond to the LM3S6965 microcontroller.
137137
138138Here we indicate to the linker that the reset handler -- whose symbol name is ` Reset ` -- is the
139139* 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.
140+ entry point and functions called from it as * used* so they won't discard them. Without this line,
141+ the linker would discard the ` Reset ` function and all subsequent functions called from it.
142142
143143### ` EXTERN `
144144
145145Linkers 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 ` .
146+ symbols that are recursively referenced from the entry point. ` EXTERN ` forces the linker to look
147+ for ` EXTERN ` 's argument even after all other referenced symbols have been found. As a rule of thumb,
148+ if you need a symbol that's not called from the entry point to always be present in the output binary,
149+ you should use ` EXTERN ` in conjunction with ` KEEP ` .
150150
151151### ` SECTIONS `
152152
153153This 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:
154+ in the sections of the output object file, AKA output sections; or if they should be discarded. Here
155+ we define two output sections:
156156
157157```
158158 .vector_table ORIGIN(FLASH) : { /* .. */ } > FLASH
159159```
160160
161- ` .vector_table ` , which contains the vector table and its located at the start of ` FLASH ` memory;
161+ ` .vector_table ` , which contains the vector table and is located at the start of ` FLASH ` memory,
162162
163163```
164164 .text : { /* .. */ } > FLASH
165165```
166166
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,
167+ and ` .text ` , which contains the program subroutines and is located somewhere in ` FLASH ` . Its start
168+ address is not specified, but the linker will place it after the previous output section,
169169` .vector_table ` .
170170
171171The output ` .vector_table ` section contains:
@@ -187,25 +187,25 @@ memory block.
187187
188188Next, we use ` KEEP ` to force the linker to insert all input sections named
189189` .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.
190+ section is ` RESET_VECTOR ` , so this will effectively place ` RESET_VECTOR ` second in the vector table.
191191
192192The output ` .text ` section contains:
193193
194194```
195195 *(.text .text.*);
196196```
197197
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.
198+ This includes all the input sections named ` .text ` and ` .text.* ` . Note that we don't use ` KEEP `
199+ here to let the linker discard unused sections.
200200
201- Finally, we use the special ` /DISCARD/ ` section to discard:
201+ Finally, we use the special ` /DISCARD/ ` section to discard
202202
203203```
204204 *(.ARM.exidx.*);
205205```
206206
207207input 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.
208+ doing stack unwinding on panics and they take up space in Flash memory, so we just discard them.
209209
210210## Putting it all together
211211
@@ -221,10 +221,13 @@ use core::panic::PanicInfo;
221221// The reset handler
222222#[no_mangle]
223223pub unsafe extern " C" fn Reset () -> ! {
224+ let x = 42 ;
225+
226+ // can't return so we go into an infinite loop here
224227 loop {}
225228}
226229
227- // The reset vector.
230+ // The reset vector, a pointer into the reset handler
228231#[link_section = " .vector_table.reset_vector" ]
229232#[no_mangle]
230233pub static RESET_VECTOR : unsafe extern " C" fn () -> ! = Reset ;
@@ -236,7 +239,7 @@ fn panic(_panic: &PanicInfo) -> ! {
236239}
237240```
238241
239- We'll use the LLVM linker, LLD, shipped with the Rust toolchain. That way you won't need to install
242+ We'll use the LLVM linker, LLD, shipped with the Rust toolchain. That way, you won't need to install
240243the ` arm-none-eabi-gcc ` linker that the ` thumbv7m-none-eabi ` target uses by default. Changing the
241244linker is done via rustc flags; the full Cargo invocation to change the linker and pass the linker
242245script to the linker is shown below:
0 commit comments