|
9 | 9 | //! relocation memory accesses, so that Rust semantics don't have to be aware |
10 | 10 | //! of them. |
11 | 11 | //! |
12 | | -//! However, we need to be careful to avoid making any calls to other crates. |
13 | | -//! This includes functions in `core` that aren't implemented by the compiler, |
14 | | -//! so we can do `ptr == null()` but we can't do `ptr.is_null()` because `null` |
15 | | -//! is implemented by the compiler while `is_null` is not. And, it includes |
16 | | -//! code patterns that the compiler might implement as calls to functions like |
17 | | -//! `memset`. |
18 | | -//! |
19 | | -//! And we have to avoid reading any static variables that contain addresses, |
20 | | -//! including any tables the compiler might implicitly emit. |
21 | | -//! |
22 | | -//! Implicit calls to `memset` etc. could possibly be prevented by using |
23 | | -//! `#![no_builtins]`, however wouldn't fix the other problems, so we'd still |
24 | | -//! need to rely on testing the code to make sure it doesn't segfault in any |
25 | | -//! case. And, `#![no_builtins]` interferes with LTO, so we don't use it. |
| 12 | +//! See the comments on the `relocate` function for additional special |
| 13 | +//! considerations. |
26 | 14 |
|
27 | 15 | #![allow(clippy::cmp_null)] |
28 | 16 |
|
@@ -74,17 +62,27 @@ macro_rules! debug_assert_eq { |
74 | 62 | /// guarantees that this code won't segfault at any moment. |
75 | 63 | /// |
76 | 64 | /// In practice, things work if we don't make any calls to functions outside |
77 | | -/// of this crate, not counting functions directly implemented by the compiler. |
78 | | -/// So we can do eg. `x == null()` but we can't do `x.is_null()`, because |
79 | | -/// `null` is directly implemented by the compiler, while `is_null` is not 🙃. |
| 65 | +/// of this crate, not counting `inline(always)` functions. So we can do eg. |
| 66 | +/// `x == null()` but we can't do `x.is_null()`, because `null` is |
| 67 | +/// `inline(always)`, while `is_null` is not 🙃. And, it includes code |
| 68 | +/// patterns that the compiler might implement as calls to functions like |
| 69 | +/// `memset`. |
| 70 | +/// |
| 71 | +/// Implicit calls to `memset` etc. could possibly be prevented by using |
| 72 | +/// `#![no_builtins]`, however wouldn't fix the other problems, so we'd still |
| 73 | +/// need to rely on testing the code to make sure it doesn't segfault in any |
| 74 | +/// case. And, `#![no_builtins]` interferes with LTO, so we don't use it. |
| 75 | +/// |
| 76 | +/// And, we have to avoid reading any static variables that contain addresses, |
| 77 | +/// including any tables the compiler might implicitly emit. |
80 | 78 | /// |
81 | | -/// We do all the relocation memory accesses using `asm`, as they happen |
| 79 | +/// And, we do all the relocation memory accesses using `asm`, as they happen |
82 | 80 | /// outside the Rust memory model. They read and write and `mprotect` memory |
83 | 81 | /// that Rust wouldn't think could be accessed. |
84 | 82 | /// |
85 | | -/// We also need to take care to avoid panics as panicking will segfault due to |
86 | | -/// `core::fmt` making use of statics that need relocation. Even after all |
87 | | -/// relocations are done we still need to avoid panicking as libstd's panic |
| 83 | +/// And, we also need to take care to avoid panics as panicking will segfault |
| 84 | +/// due to `core::fmt` making use of statics that need relocation. Even after |
| 85 | +/// all relocations are done we still need to avoid panicking as libstd's panic |
88 | 86 | /// handler makes use of TLS, which won't be initialized until much later. |
89 | 87 | /// |
90 | 88 | /// So yes, there's a reason this code is behind a feature flag. |
@@ -375,7 +373,7 @@ unsafe fn compute_auxp(envp: *mut *mut u8) -> *const Elf_auxv_t { |
375 | 373 | // Locate the AUX records we need. We don't use rustix to do this because |
376 | 374 | // that would involve calling a function in another crate. |
377 | 375 | let mut auxp = envp; |
378 | | - // Don't use `is_null` because that's a call. |
| 376 | + // Don't use `is_null` because that's not `inline(always)`. |
379 | 377 | while (*auxp) != null_mut() { |
380 | 378 | auxp = auxp.add(1); |
381 | 379 | } |
|
0 commit comments