Skip to content
Snippets Groups Projects
Commit 737371dc authored by Per's avatar Per
Browse files

bare0

parent 94ebfa71
Branches master
No related tags found
No related merge requests found
......@@ -322,7 +322,7 @@ unsafe extern "C" fn reset_handler() -> ! {
```
Here we see that the `reset_handler` intitates static heap variables (by 0 or value accordingly) before calling `main` (and puts the processor in sleep mode in case `main` returns). The user `main` has the symbol `bare0::main`, which is unknown to the `cortex-m-rt` library (defining the generic `reset_handler`). Hence the, `reset_handler` calls a compiler generated (trampoline) `main`, that in turn calls `bare0::main` (the user `main`).
Here we see that the `reset_handler` intitates static heap variables (by 0 or value accordingly) before calling `main` (and puts the processor in sleep mode in case `main` returns). The user `main` has the symbol `bare0::main`, which is unknown to the `cortex-m-rt` library (defining the generic `reset_handler`). Hence the, `reset_handler` calls a compiler generated start item `main`, that in turn trampolines to `bare0::main` (the user `main`).
Finally, we can have a look at the user `main`.
......@@ -348,83 +348,7 @@ fn main() {
x += 1;
80004a2: 9802 ldr r0, [sp, #8]
80004a4: 1c41 adds r1, r0, #1
80004a6: 2201 movs r2, #1
80004a8: 4281 cmp r1, r0
80004aa: bf28 it cs
80004ac: 2200 movcs r2, #0
80004ae: 2a00 cmp r2, #0
80004b0: 9101 str r1, [sp, #4]
80004b2: d146 bne.n 8000542 <bare0::main+0xb4>
80004b4: e7ff b.n 80004b6 <bare0::main+0x28>
80004b6: 9801 ldr r0, [sp, #4]
80004b8: 9002 str r0, [sp, #8]
unsafe {
X += 1;
80004ba: f240 0104 movw r1, #4
80004be: f2c2 0100 movt r1, #8192 ; 0x2000
80004c2: 6809 ldr r1, [r1, #0]
80004c4: 1c4a adds r2, r1, #1
80004c6: 2301 movs r3, #1
80004c8: 428a cmp r2, r1
80004ca: bf28 it cs
80004cc: 2300 movcs r3, #0
80004ce: 2b00 cmp r3, #0
80004d0: 9200 str r2, [sp, #0]
80004d2: d13d bne.n 8000550 <bare0::main+0xc2>
80004d4: e7ff b.n 80004d6 <bare0::main+0x48>
80004d6: f240 0004 movw r0, #4
80004da: f2c2 0000 movt r0, #8192 ; 0x2000
80004de: 9900 ldr r1, [sp, #0]
80004e0: 6001 str r1, [r0, #0]
Y = X;
80004e2: 6802 ldr r2, [r0, #0]
80004e4: f240 0300 movw r3, #0
80004e8: f2c2 0300 movt r3, #8192 ; 0x2000
80004ec: 601a str r2, [r3, #0]
assert!(x == X && X == Y);
80004ee: 9a02 ldr r2, [sp, #8]
80004f0: 6800 ldr r0, [r0, #0]
80004f2: 4282 cmp r2, r0
80004f4: d008 beq.n 8000508 <bare0::main+0x7a>
80004f6: e003 b.n 8000500 <bare0::main+0x72>
80004f8: 2001 movs r0, #1
80004fa: f807 0c01 strb.w r0, [r7, #-1]
80004fe: e010 b.n 8000522 <bare0::main+0x94>
8000500: 2000 movs r0, #0
8000502: f807 0c01 strb.w r0, [r7, #-1]
8000506: e00c b.n 8000522 <bare0::main+0x94>
8000508: f240 0004 movw r0, #4
800050c: f2c2 0000 movt r0, #8192 ; 0x2000
8000510: 6800 ldr r0, [r0, #0]
8000512: f240 0100 movw r1, #0
8000516: f2c2 0100 movt r1, #8192 ; 0x2000
800051a: 6809 ldr r1, [r1, #0]
800051c: 4288 cmp r0, r1
800051e: d0eb beq.n 80004f8 <bare0::main+0x6a>
8000520: e7ee b.n 8000500 <bare0::main+0x72>
8000522: f817 0c01 ldrb.w r0, [r7, #-1]
8000526: 43c0 mvns r0, r0
8000528: 07c0 lsls r0, r0, #31
800052a: 2800 cmp r0, #0
800052c: d008 beq.n 8000540 <bare0::main+0xb2>
800052e: e7ff b.n 8000530 <bare0::main+0xa2>
8000530: f640 10dc movw r0, #2524 ; 0x9dc
8000534: f6c0 0000 movt r0, #2048 ; 0x800
8000538: 6800 ldr r0, [r0, #0]
800053a: f000 f9c1 bl 80008c0 <core::panicking::panic>
800053e: defe udf #254 ; 0xfe
loop {
8000540: e7af b.n 80004a2 <bare0::main+0x14>
x += 1;
8000542: f640 106c movw r0, #2412 ; 0x96c
8000546: f6c0 0000 movt r0, #2048 ; 0x800
800054a: f000 f9b9 bl 80008c0 <core::panicking::panic>
800054e: defe udf #254 ; 0xfe
X += 1;
8000550: f640 1084 movw r0, #2436 ; 0x984
8000554: f6c0 0000 movt r0, #2048 ; 0x800
8000558: f000 f9b2 bl 80008c0 <core::panicking::panic>
800055c: defe udf #254 ; 0xfe
...
````
We see that the compiler has genereted quite some code for the small `main` function.
......@@ -433,8 +357,58 @@ We can compile the `bare0` application in -- release mode instead.
``` shell
> xargo build --release --example bare0
> arm-none-eabi-objdump -S -C target/thumbv7em-none-eabihf/release/examples/bare0 > objdump_release
```
The resulting user main now looks like this.
``` rust
8000476 <_ZN5bare04main17h1039292c3948856dE.llvm.453292E5>:
loop {
x += 1;
unsafe {
X += 1;
Y = X;
assert!(x == X && X == Y);
8000476: e7fe b.n 8000476 <_ZN5bare04main17h1039292c3948856dE.llvm.453292E5>
```
The compiler has optimized away ALL your code!!! (`8000476: e7fe b.n 8000476` implements an infinite loop). Why you might ask, well it figures out that your the program has no *observable* effect (it will not output or change anything).
We can make a small change to the program (violating the assertion, by commenting out `X += 1;`. After compilation the oject dump of user main looks like this:
``` rust
08000476 <_ZN5bare04main17h1039292c3948856dE.llvm.E032C40E>:
static mut X: u32 = X_INIT;
static mut Y: u32 = 0;
#[inline(never)]
fn main() {
8000476: b580 push {r7, lr}
8000478: 466f mov r7, sp
loop {
x += 1;
unsafe {
//X += 1;
Y = X;
assert!(x == X && X == Y);
800047a: f240 5034 movw r0, #1332 ; 0x534
800047e: f6c0 0000 movt r0, #2048 ; 0x800
8000482: f000 f802 bl 800048a <core::panicking::panic>
8000486: defe udf #254 ; 0xfe
```
So the Rust compiler is able to figure out that the assertion will be violated and merely calls the `panic` routine. So be aware, the Rust compiler is extremely aggressive in optimizing your code. On a side note the semantics of integer additions is slightly different between `dev` (normal/non-optimized) and `--release` (optimized) builds. In `dev` build the arithmics are checked and overflows result in a `panic`, in `--release`, arithmetics are unchecked (for performance reasons), and oveflows wrap (under two's complement semantics). To avoid ambiguity, you may use methods defined in the std/core library:
- `wrapping_add`, `wrapping_sub`,returns the straight two’s complement result,
- `saturating_add`, `saturating_sub`, returns the largest/smallest value (as appropriate) of the type when overflow occurs,
- `overflowing_add`, `overflowing_sub`, returns the two’s complement result along with a boolean indicating if overflow occured, and
- `checked_add`, `checked_sub`, returns an `Option` that’s `None` when overflow occurs, and `Some(v)` elsewise.
Those methods never `panic`, but code might be verbose, e.g., expressing `x - y + z` under wrapping arithmetics equates to `x.wrapping_sub(y).wrapping_add(z)`. To this end you may choose to use the [Wrapping](https://doc.rust-lang.org/std/num/struct.Wrapping.html) type.
# License
......
......@@ -21,7 +21,7 @@ fn main() {
loop {
x += 1;
unsafe {
X += 1;
//X += 1;
Y = X;
assert!(x == X && X == Y);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment