Skip to content

Commit 4383e2a

Browse files
authored
Make depending on "unwinding" conditional on cfg(panic = "unwind"). (#149)
* Make depending on "unwinding" conditional on `cfg(panic = "unwind)`. Using `cfg(panic = "unwind")` in Cargo.toml means we can avoid depending on the "unwinding" crate when unwinding isn't enabled. This avoids nbdd0121/unwinding#39. * Use a unique crate name in origin-start-dynamic-linker. * Add a panic=abort example.
1 parent e19cfe5 commit 4383e2a

File tree

15 files changed

+207
-25
lines changed

15 files changed

+207
-25
lines changed

Cargo.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ errno = { version = "0.3.3", default-features = false, optional = true }
4141
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
4242
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
4343

44-
[target.'cfg(not(target_arch = "arm"))'.dependencies.unwinding]
44+
# Use the unwinding crate if support for unwinding is needed. This depends on
45+
# nightly Rust. And it's not supported on ARM yet.
46+
[target.'cfg(all(panic = "unwind", not(target_arch = "arm")))'.dependencies.unwinding]
4547
version = "0.2.3"
4648
default-features = false
4749
features = ["unwinder"]
@@ -64,8 +66,8 @@ assert_cmd = "2.0.12"
6466
default = ["std", "log", "libc", "errno", "signal", "init-fini-arrays", "program-at-exit", "thread-at-exit"]
6567

6668
# If you're using nightly Rust, enable this feature to let origin use
67-
# nightly-only features, which include proper support for unwinding, better
68-
# safety checks, and better optimizations.
69+
# nightly-only features, which include proper support for unwinding (if
70+
# enabled), better safety checks, and better optimizations.
6971
nightly = ["unwinding"]
7072

7173
# Enable optimizations that reduce code size (at the cost of performance).
@@ -146,7 +148,7 @@ param = ["rustix/param"]
146148
# [the "personality" feature of the unwinding crate] for more details.
147149
#
148150
# [the "personality" feature of the unwinding crate]: https://crates.io/crates/unwinding#personality-and-other-utilities
149-
eh-personality = ["unwinding?/personality"]
151+
eh-personality = ["unwinding/personality"]
150152

151153
# Provide a `#[lang = eh_personality]` function that just returns
152154
# `CONTINUE_UNWIND` (for no-std). Use this if you know your program will never
@@ -162,7 +164,7 @@ eh-personality-continue = ["unwinding?/personality-dummy"]
162164
# [the "panic-handler" feature of the unwinding crate] for more details.
163165
#
164166
# [the "panic-handler" feature of the unwinding crate]: https://crates.io/crates/unwinding#personality-and-other-utilities
165-
panic-handler = ["unwinding?/panic-handler"]
167+
panic-handler = ["unwinding/panic-handler"]
166168

167169
# Provide a `#[panic_handler]` function that just traps (for no-std). Use this
168170
# if you know your program will never panic and don't want any extra code.

example-crates/origin-start-dynamic-linker/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "origin-start"
2+
name = "origin-start-dynamic-linker"
33
version = "0.0.0"
44
edition = "2021"
55
publish = false
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "origin-start-panic-abort"
3+
version = "0.0.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
# Origin can be depended on just like any other crate. For no_std, disable
9+
# the default features, and the desired features.
10+
origin = { path = "../..", default-features = false, features = ["origin-start", "program-at-exit", "thread-at-exit", "eh-personality-continue", "panic-handler-trap", "nightly"] }
11+
12+
# Crates to help writing no_std code.
13+
atomic-dbg = { version = "0.1.8", default-features = false }
14+
rustix-dlmalloc = { version = "0.1.0", features = ["global"] }
15+
16+
[profile.dev]
17+
panic = "abort"
18+
[profile.release]
19+
panic = "abort"
20+
21+
# This is just an example crate, and not part of the origin workspace.
22+
[workspace]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Like the [origin-start example], but uses panic=abort in Cargo.toml instead of
2+
enabling origin's "unwinding" feature.
3+
4+
[origin-start example]: https://github.com/sunfishcode/origin/blob/main/example-crates/origin-start/README.md
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
// Pass -nostartfiles to the linker. In the future this could be obviated
3+
// by a `no_entry` feature: <https://github.com/rust-lang/rfcs/pull/2735>
4+
println!("cargo:rustc-link-arg=-nostartfiles");
5+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! A simple example using `no_std` and `no_main` and origin's start.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
extern crate alloc;
7+
8+
use alloc::boxed::Box;
9+
use atomic_dbg::eprintln;
10+
use origin::{program, thread};
11+
12+
#[global_allocator]
13+
static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;
14+
15+
#[no_mangle]
16+
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
17+
eprintln!("Hello from main thread");
18+
19+
program::at_exit(Box::new(|| {
20+
eprintln!("Hello from a `program::at_exit` handler")
21+
}));
22+
thread::at_exit(Box::new(|| {
23+
eprintln!("Hello from a main-thread `thread::at_exit` handler")
24+
}));
25+
26+
let thread = thread::create(
27+
|_args| {
28+
eprintln!("Hello from child thread");
29+
thread::at_exit(Box::new(|| {
30+
eprintln!("Hello from child thread's `thread::at_exit` handler")
31+
}));
32+
None
33+
},
34+
&[],
35+
thread::default_stack_size(),
36+
thread::default_guard_size(),
37+
)
38+
.unwrap();
39+
40+
thread::join(thread);
41+
42+
eprintln!("Goodbye from main");
43+
program::exit(0);
44+
}

src/arch/aarch64.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
//! Architecture-specific assembly code.
22
3+
#[cfg(any(
4+
feature = "take-charge",
5+
all(not(feature = "unwinding"), feature = "panic-handler-trap")
6+
))]
37
use core::arch::asm;
48
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
59
#[cfg(relocation_model = "pic")]
610
use linux_raw_sys::elf::{Elf_Dyn, Elf_Ehdr};
11+
#[cfg(feature = "take-charge")]
712
#[cfg(feature = "signal")]
813
#[cfg(test)]
914
use linux_raw_sys::general::__NR_rt_sigreturn;
1015
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
1116
#[cfg(relocation_model = "pic")]
1217
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
18+
#[cfg(feature = "take-charge")]
1319
#[cfg(feature = "thread")]
1420
use {
1521
core::ffi::c_void,
@@ -43,6 +49,10 @@ naked_fn!(
4349
/// Execute a trap instruction.
4450
///
4551
/// This is roughly equivalent to `core::intrinsics::abort()`.
52+
#[cfg(any(
53+
feature = "take-charge",
54+
all(not(feature = "unwinding"), feature = "panic-handler-trap")
55+
))]
4656
pub(super) fn trap() -> ! {
4757
unsafe {
4858
asm!("brk #0x1", options(noreturn, nostack));
@@ -178,6 +188,7 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
178188
}
179189

180190
/// The required alignment for the stack pointer.
191+
#[cfg(feature = "take-charge")]
181192
#[cfg(feature = "thread")]
182193
pub(super) const STACK_ALIGNMENT: usize = 16;
183194

@@ -186,6 +197,7 @@ pub(super) const STACK_ALIGNMENT: usize = 16;
186197
/// This can't be implemented in `rustix` because the child starts executing at
187198
/// the same point as the parent and we need to use inline asm to have the
188199
/// child jump to our new-thread entrypoint.
200+
#[cfg(feature = "take-charge")]
189201
#[cfg(feature = "thread")]
190202
#[inline]
191203
pub(super) unsafe fn clone(
@@ -228,6 +240,7 @@ pub(super) unsafe fn clone(
228240
}
229241

230242
/// Write a value to the platform thread-pointer register.
243+
#[cfg(feature = "take-charge")]
231244
#[cfg(feature = "thread")]
232245
#[inline]
233246
pub(super) unsafe fn set_thread_pointer(ptr: *mut c_void) {
@@ -236,6 +249,7 @@ pub(super) unsafe fn set_thread_pointer(ptr: *mut c_void) {
236249
}
237250

238251
/// Read the value of the platform thread-pointer register.
252+
#[cfg(feature = "take-charge")]
239253
#[cfg(feature = "thread")]
240254
#[inline]
241255
pub(super) fn thread_pointer() -> *mut c_void {
@@ -248,11 +262,13 @@ pub(super) fn thread_pointer() -> *mut c_void {
248262
}
249263

250264
/// TLS data starts at the location pointed to by the thread pointer.
265+
#[cfg(feature = "take-charge")]
251266
#[cfg(feature = "thread")]
252267
pub(super) const TLS_OFFSET: usize = 0;
253268

254269
/// `munmap` the current thread, then carefully exit the thread without
255270
/// touching the deallocated stack.
271+
#[cfg(feature = "take-charge")]
256272
#[cfg(feature = "thread")]
257273
#[inline]
258274
pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usize) -> ! {
@@ -271,6 +287,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
271287
);
272288
}
273289

290+
#[cfg(feature = "take-charge")]
274291
#[cfg(feature = "signal")]
275292
naked_fn!(
276293
"
@@ -289,7 +306,8 @@ naked_fn!(
289306
"udf #16";
290307
//__NR_rt_sigreturn = const __NR_rt_sigreturn // TODO: Use this when `asm_const` is stabilized.
291308
);
292-
#[cfg(test)] // TODO: obviate this
309+
#[cfg(feature = "take-charge")]
310+
#[test] // TODO: obviate this
293311
fn test_rt_sigreturn() {
294312
assert_eq!(__NR_rt_sigreturn, 139);
295313
}
@@ -302,5 +320,6 @@ fn test_rt_sigreturn() {
302320
///
303321
/// This function must never be called other than by the `sa_restorer`
304322
/// mechanism.
323+
#[cfg(feature = "take-charge")]
305324
#[cfg(feature = "signal")]
306325
pub(super) use return_from_signal_handler as return_from_signal_handler_noinfo;

src/arch/arm.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
//! Architecture-specific assembly code.
22
3+
#[cfg(any(
4+
feature = "take-charge",
5+
all(not(feature = "unwinding"), feature = "panic-handler-trap")
6+
))]
37
use core::arch::asm;
48
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
59
#[cfg(relocation_model = "pic")]
610
use linux_raw_sys::elf::{Elf_Dyn, Elf_Ehdr};
711
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
812
#[cfg(relocation_model = "pic")]
913
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
14+
#[cfg(feature = "take-charge")]
1015
#[cfg(feature = "signal")]
1116
#[cfg(test)]
1217
use linux_raw_sys::general::{__NR_rt_sigreturn, __NR_sigreturn};
18+
#[cfg(feature = "take-charge")]
1319
#[cfg(feature = "thread")]
1420
use {
1521
core::ffi::c_void,
@@ -43,6 +49,10 @@ naked_fn!(
4349
/// Execute a trap instruction.
4450
///
4551
/// This is roughly equivalent to `core::intrinsics::abort()`.
52+
#[cfg(any(
53+
feature = "take-charge",
54+
all(not(feature = "unwinding"), feature = "panic-handler-trap")
55+
))]
4656
pub(super) fn trap() -> ! {
4757
unsafe {
4858
asm!(".inst 0xe7ffdefe", options(noreturn, nostack));
@@ -190,6 +200,7 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
190200
}
191201

192202
/// The required alignment for the stack pointer.
203+
#[cfg(feature = "take-charge")]
193204
#[cfg(feature = "thread")]
194205
pub(super) const STACK_ALIGNMENT: usize = 4;
195206

@@ -198,6 +209,7 @@ pub(super) const STACK_ALIGNMENT: usize = 4;
198209
/// This can't be implemented in `rustix` because the child starts executing at
199210
/// the same point as the parent and we need to use inline asm to have the
200211
/// child jump to our new-thread entrypoint.
212+
#[cfg(feature = "take-charge")]
201213
#[cfg(feature = "thread")]
202214
#[inline]
203215
pub(super) unsafe fn clone(
@@ -241,6 +253,7 @@ pub(super) unsafe fn clone(
241253
}
242254

243255
/// Write a value to the platform thread-pointer register.
256+
#[cfg(feature = "take-charge")]
244257
#[cfg(feature = "thread")]
245258
#[inline]
246259
pub(super) unsafe fn set_thread_pointer(ptr: *mut c_void) {
@@ -250,6 +263,7 @@ pub(super) unsafe fn set_thread_pointer(ptr: *mut c_void) {
250263
}
251264

252265
/// Read the value of the platform thread-pointer register.
266+
#[cfg(feature = "take-charge")]
253267
#[cfg(feature = "thread")]
254268
#[inline]
255269
pub(super) fn thread_pointer() -> *mut c_void {
@@ -262,11 +276,13 @@ pub(super) fn thread_pointer() -> *mut c_void {
262276
}
263277

264278
/// TLS data starts at the location pointed to by the thread pointer.
279+
#[cfg(feature = "take-charge")]
265280
#[cfg(feature = "thread")]
266281
pub(super) const TLS_OFFSET: usize = 0;
267282

268283
/// `munmap` the current thread, then carefully exit the thread without
269284
/// touching the deallocated stack.
285+
#[cfg(feature = "take-charge")]
270286
#[cfg(feature = "thread")]
271287
#[inline]
272288
pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usize) -> ! {
@@ -285,6 +301,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
285301
);
286302
}
287303

304+
#[cfg(feature = "take-charge")]
288305
#[cfg(feature = "signal")]
289306
naked_fn!(
290307
"
@@ -303,11 +320,13 @@ naked_fn!(
303320
"udf #16";
304321
//__NR_rt_sigreturn = const __NR_rt_sigreturn // TODO: Use this when `asm_const` is stabilized.
305322
);
306-
#[cfg(test)] // TODO: obviate this
323+
#[cfg(feature = "take-charge")]
324+
#[test] // TODO: obviate this
307325
fn test_rt_sigreturn() {
308326
assert_eq!(__NR_rt_sigreturn, 173);
309327
}
310328

329+
#[cfg(feature = "take-charge")]
311330
#[cfg(feature = "signal")]
312331
naked_fn!(
313332
"
@@ -326,7 +345,8 @@ naked_fn!(
326345
"udf #16";
327346
//__NR_sigreturn = const __NR_sigreturn // TODO: Use this when `asm_const` is stabilized.
328347
);
329-
#[cfg(test)] // TODO: obviate this
348+
#[cfg(feature = "take-charge")]
349+
#[test] // TODO: obviate this
330350
fn test_sigreturn() {
331351
assert_eq!(__NR_sigreturn, 119);
332352
}

0 commit comments

Comments
 (0)