@@ -1413,31 +1413,73 @@ r[asm.naked-rules.unwind]
1413
1413
``` rust
1414
1414
# #[cfg(target_arch = " x86_64" )] {
1415
1415
#[unsafe (naked)]
1416
- extern " C -unwind" fn naked_function () {
1416
+ extern " sysv64 -unwind" fn unwinding_naked () {
1417
1417
core :: arch :: naked_asm! (
1418
+ // "CFI" here stands for "call frame information".
1418
1419
" .cfi_startproc" ,
1420
+ // The CFA (canonical frame address) is the value of `rsp`
1421
+ // before the `call`, i.e. before the return address, `rip`,
1422
+ // was pushed to `rsp`, so it's eight bytes higher in memory
1423
+ // than `rsp` upon function entry (after `rip` has been
1424
+ // pushed).
1425
+ //
1426
+ // This is the default, so we don't have to write it.
1427
+ // ".cfi_def_cfa rsp, 8",
1428
+ //
1429
+ // The traditional thing to do is to preserve the base
1430
+ // pointer, so we'll do that.
1419
1431
" push rbp" ,
1420
- " .cfi_def_cfa_offset 16" ,
1432
+ // Since we've now extended the stack downward by 8 bytes in
1433
+ // memory, we need to adjust the offset to the CFA from `rsp`
1434
+ // by another 8 bytes.
1435
+ " .cfi_adjust_cfa_offset 8" ,
1436
+ // We also then annotate where we've stored the caller's value
1437
+ // of `rbp`, relative to the CFA, so that when unwinding into
1438
+ // the caller we can find it, in case we need it to calculate
1439
+ // the caller's CFA relative to it.
1440
+ //
1441
+ // Here, we've stored the caller's `rbp` starting 16 bytes
1442
+ // below the CFA. I.e., starting from the CFA, there's first
1443
+ // the `rip` (which starts 8 bytes below the CFA), then
1444
+ // there's the caller's `rbp` that we just pushed.
1421
1445
" .cfi_offset rbp, -16" ,
1446
+ // As is traditional, we set the base pointer to the value of
1447
+ // the stack pointer. This way, the base pointer stays the
1448
+ // same throughout the function body.
1422
1449
" mov rbp, rsp" ,
1450
+ // We can now track the offset to the CFA from the base
1451
+ // pointer. This means we don't need to make any further
1452
+ // adjustments until the end, as we don't change `rbp`.
1423
1453
" .cfi_def_cfa_register rbp" ,
1424
- "" ,
1425
- " call {function}" ,
1426
- "" ,
1454
+ // We can now call a function that may panic.
1455
+ " call {f}" ,
1456
+ // Upon return, we restore `rbp` in preparation for returning
1457
+ // ourselves.
1427
1458
" pop rbp" ,
1459
+ // Now that we've restored `rbp`, we must specify the offset
1460
+ // to the CFA again in terms of `rsp`.
1428
1461
" .cfi_def_cfa rsp, 8" ,
1462
+ // Now we can return.
1429
1463
" ret" ,
1430
1464
" .cfi_endproc" ,
1431
- function = sym function_that_panics ,
1465
+ f = sym may_panic ,
1432
1466
)
1433
1467
}
1434
1468
1435
- extern " C -unwind" fn function_that_panics () {
1469
+ extern " sysv64 -unwind" fn may_panic () {
1436
1470
panic! (" unwind!" );
1437
1471
}
1438
1472
# }
1439
1473
```
1440
1474
1475
+ > [ !NOTE]
1476
+ >
1477
+ > For more information on the ` cfi ` assembler directives above, see these resources:
1478
+ >
1479
+ > - [ Using ` as ` - CFI directives] ( https://sourceware.org/binutils/docs/as/CFI-directives.html )
1480
+ > - [ DWARF Debugging Information Format Version 5] ( https://dwarfstd.org/doc/DWARF5.pdf )
1481
+ > - [ ImperialViolet - CFI directives in assembly files] ( https://www.imperialviolet.org/2017/01/18/cfi.html )
1482
+
1441
1483
r[ asm.validity]
1442
1484
### Correctness and Validity
1443
1485
0 commit comments