Skip to content
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
build: [ubuntu, i686-linux, aarch64-linux, riscv64-linux]
rust: [1.84, nightly-2025-03-05]
rust: [1.85, nightly-2025-04-28]
include:
- build: ubuntu
os: ubuntu-latest
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
qemu: qemu-riscv64 -L /usr/riscv64-linux-gnu
qemu_target: riscv64-linux-user
host_target: riscv64gc-unknown-linux-gnu
- rust: nightly-2025-03-05
- rust: nightly-2025-04-28
features: nightly
steps:
- uses: actions/checkout@v4
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ description = "Program startup and thread support written in Rust"
documentation = "https://docs.rs/origin"
license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
repository = "https://github.com/sunfishcode/origin"
edition = "2021"
edition = "2024"
keywords = ["linux"]
categories = ["no-std"]
include = ["src", "Cargo.toml", "COPYRIGHT", "LICENSE*", "/*.md"]
rust-version = "1.84"
rust-version = "1.85"

[dependencies]
linux-raw-sys = { version = "0.9.2", default-features = false, optional = true, features = ["general", "no_std", "elf"] }
Expand Down Expand Up @@ -44,7 +44,7 @@ alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-all
# Use the unwinding crate if support for unwinding is needed. This depends on
# nightly Rust. And it's not supported on ARM yet.
[target.'cfg(not(target_arch = "arm"))'.dependencies.unwinding]
version = "0.2.5"
version = "0.2.6"
default-features = false
features = ["unwinder"]
optional = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This is used by [Mustang] and [Eyra] in their libc implementations, and in the
[Origin Studio] project in its std implementation, which are three different
ways to support building Rust programs written entirely in Rust.

It works with both stable (currently Rust >= 1.78) and nightly Rust. If you're
It works with both stable (currently Rust >= 1.85) and nightly Rust. If you're
using nightly Rust, enable the feature "nightly" to let origin use nightly-only
features, which include proper support for unwinding, better safety checks, and
better optimizations.
Expand Down
2 changes: 1 addition & 1 deletion example-crates/basic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "basic"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion example-crates/external-start/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "external-start"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[dependencies]
Expand Down
80 changes: 42 additions & 38 deletions example-crates/external-start/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,62 +19,66 @@ static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::Glob
/// and start running the constructors but to immediately take over.
///
/// [here]: https://github.com/rust-lang/rfcs/pull/2735
#[link_section = ".init_array.00000"]
#[unsafe(link_section = ".init_array.00000")]
#[used]
static EARLY_INIT_ARRAY: unsafe extern "C" fn(i32, *mut *mut u8) = {
unsafe extern "C" fn function(_argc: i32, argv: *mut *mut u8) {
// Libc was calling constructors (we're one of them), but origin will
// be doing that now, so just exit when we're called a second time.
static FIRST: AtomicBool = AtomicBool::new(false);
if FIRST
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
return;
}
unsafe {
// Libc was calling constructors (we're one of them), but origin will
// be doing that now, so just exit when we're called a second time.
static FIRST: AtomicBool = AtomicBool::new(false);
if FIRST
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
return;
}

// Compute the initial stack address provided by the kernel.
let mem = argv.sub(1);
// Compute the initial stack address provided by the kernel.
let mem = argv.sub(1);

origin::program::start(mem as _);
origin::program::start(mem as _);
}
}
function
};

#[no_mangle]
#[unsafe(no_mangle)]
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
eprintln!("Hello from main thread");
unsafe {
eprintln!("Hello from main thread");

program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));
program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));

let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();
let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();

thread::join(thread);
thread::join(thread);

eprintln!("Goodbye from main");
program::exit(0);
eprintln!("Goodbye from main");
program::exit(0);
}
}

// Libc calls `main` so we need to provide a definition to satisfy the
// linker, however origin gains control before libc can call this `main`.
#[no_mangle]
#[unsafe(no_mangle)]
unsafe fn main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
eprintln!("Main was not supposed to be called!");
program::trap();
Expand Down
2 changes: 1 addition & 1 deletion example-crates/origin-start-dynamic-linker/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "origin-start-dynamic-linker"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[lib]
Expand Down
58 changes: 30 additions & 28 deletions example-crates/origin-start-dynamic-linker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,35 @@ use origin::{program, thread};
#[global_allocator]
static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;

#[no_mangle]
#[unsafe(no_mangle)]
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
eprintln!("Hello from main thread");

program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));

let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();

thread::join(thread);

eprintln!("Goodbye from main");
program::exit(0);
unsafe {
eprintln!("Hello from main thread");

program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));

let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();

thread::join(thread);

eprintln!("Goodbye from main");
program::exit(0);
}
}
2 changes: 1 addition & 1 deletion example-crates/origin-start-lto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "origin-start-lto"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[dependencies]
Expand Down
58 changes: 30 additions & 28 deletions example-crates/origin-start-lto/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,35 @@ use origin::{program, thread};
#[global_allocator]
static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;

#[no_mangle]
#[unsafe(no_mangle)]
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
eprintln!("Hello from main thread");

program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));

let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();

thread::join(thread);

eprintln!("Goodbye from main");
program::exit(0);
unsafe {
eprintln!("Hello from main thread");

program::at_exit(Box::new(|| {
eprintln!("Hello from a `program::at_exit` handler")
}));
thread::at_exit(Box::new(|| {
eprintln!("Hello from a main-thread `thread::at_exit` handler")
}));

let thread = thread::create(
|_args| {
eprintln!("Hello from child thread");
thread::at_exit(Box::new(|| {
eprintln!("Hello from child thread's `thread::at_exit` handler")
}));
None
},
&[],
thread::default_stack_size(),
thread::default_guard_size(),
)
.unwrap();

thread::join(thread);

eprintln!("Goodbye from main");
program::exit(0);
}
}
2 changes: 1 addition & 1 deletion example-crates/origin-start-no-alloc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "origin-start-no-alloc"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion example-crates/origin-start-no-alloc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use atomic_dbg::eprintln;
use origin::program;

#[no_mangle]
#[unsafe(no_mangle)]
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
eprintln!("Hello!");

Expand Down
2 changes: 1 addition & 1 deletion example-crates/origin-start-panic-abort/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "origin-start-panic-abort"
version = "0.0.0"
edition = "2021"
edition = "2024"
publish = false

[dependencies]
Expand Down
Loading