diff --git a/example-crates/basic/src/main.rs b/example-crates/basic/src/main.rs index 4562889..eb1e49c 100644 --- a/example-crates/basic/src/main.rs +++ b/example-crates/basic/src/main.rs @@ -1,5 +1,5 @@ -use origin::thread::*; use origin::program::*; +use origin::thread::*; fn main() { eprintln!("Hello from main thread"); diff --git a/example-crates/external-start/src/main.rs b/example-crates/external-start/src/main.rs index fac5ca2..53a9143 100644 --- a/example-crates/external-start/src/main.rs +++ b/example-crates/external-start/src/main.rs @@ -13,8 +13,8 @@ extern crate libc; use alloc::boxed::Box; use atomic_dbg::{dbg, eprintln}; use core::sync::atomic::{AtomicBool, Ordering}; -use origin::thread::*; use origin::program::*; +use origin::thread::*; #[panic_handler] fn panic(panic: &core::panic::PanicInfo<'_>) -> ! { @@ -56,7 +56,7 @@ static EARLY_INIT_ARRAY: unsafe extern "C" fn(i32, *mut *mut u8) = { }; #[no_mangle] -extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -77,10 +77,15 @@ extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { ) .unwrap(); - unsafe { - join_thread(thread); - } + join_thread(thread); eprintln!("Goodbye from main"); 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 fn main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { + core::intrinsics::abort(); +} diff --git a/example-crates/no-std/src/main.rs b/example-crates/no-std/src/main.rs index ee98fdf..be20a0d 100644 --- a/example-crates/no-std/src/main.rs +++ b/example-crates/no-std/src/main.rs @@ -10,8 +10,8 @@ extern crate alloc; use alloc::boxed::Box; use atomic_dbg::{dbg, eprintln}; -use origin::thread::*; use origin::program::*; +use origin::thread::*; #[panic_handler] fn panic(panic: &core::panic::PanicInfo<'_>) -> ! { diff --git a/example-crates/origin-start-lto/src/main.rs b/example-crates/origin-start-lto/src/main.rs index a998553..96a35c3 100644 --- a/example-crates/origin-start-lto/src/main.rs +++ b/example-crates/origin-start-lto/src/main.rs @@ -27,7 +27,7 @@ extern "C" fn eh_personality() {} static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc; #[no_mangle] -extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -48,9 +48,7 @@ extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { ) .unwrap(); - unsafe { - join_thread(thread); - } + join_thread(thread); eprintln!("Goodbye from main"); exit(0); diff --git a/example-crates/origin-start-no-alloc/src/main.rs b/example-crates/origin-start-no-alloc/src/main.rs index 8500ec1..c84b76a 100644 --- a/example-crates/origin-start-no-alloc/src/main.rs +++ b/example-crates/origin-start-no-alloc/src/main.rs @@ -21,7 +21,7 @@ fn panic(panic: &core::panic::PanicInfo<'_>) -> ! { extern "C" fn eh_personality() {} #[no_mangle] -extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { eprintln!("Hello!"); // Unlike origin-start, this example can't create threads because origin's diff --git a/example-crates/origin-start/src/main.rs b/example-crates/origin-start/src/main.rs index a998553..96a35c3 100644 --- a/example-crates/origin-start/src/main.rs +++ b/example-crates/origin-start/src/main.rs @@ -27,7 +27,7 @@ extern "C" fn eh_personality() {} static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc; #[no_mangle] -extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -48,9 +48,7 @@ extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { ) .unwrap(); - unsafe { - join_thread(thread); - } + join_thread(thread); eprintln!("Goodbye from main"); exit(0); diff --git a/example-crates/tiny/src/main.rs b/example-crates/tiny/src/main.rs index 526028d..fbbd894 100644 --- a/example-crates/tiny/src/main.rs +++ b/example-crates/tiny/src/main.rs @@ -6,8 +6,8 @@ #![feature(lang_items)] #![feature(core_intrinsics)] -extern crate origin; extern crate compiler_builtins; +extern crate origin; #[panic_handler] fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { @@ -18,6 +18,6 @@ fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { extern "C" fn eh_personality() {} #[no_mangle] -extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { 42 } diff --git a/src/program.rs b/src/program.rs index 78103a9..6c99744 100644 --- a/src/program.rs +++ b/src/program.rs @@ -1,4 +1,27 @@ //! Program startup and shutdown. +//! +//! To use origin's program startup, define a function named `origin_main` like +//! this: +//! +//! ```no_run +//! #[no_mangle] +//! fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 { +//! todo!("Run the program and return the program exit status.") +//! } +//! ``` +//! +//! Origin will call this function after starting up the program and running +//! the constructors. `argc` is the number of command-line arguments with a +//! value of at most `c_int::MAX`, and `argv` is a pointer to a NULL-terminated +//! array of pointers to NUL-terminated C strings. `argc` and `argv` describe +//! the command-line arguments. `envp` is a pointer to a NULL-terminated array +//! of pointers to NUL-terminated C strings containing a key followed by `b'='` +//! followed by a value. It describes the environment variables. The function +//! should return a value for the program exit status. +//! +//! This is a low-level and somewhat C-flavored interface, which is in tension +//! with origin's goal of providing Rust-idiomatic interfaces, however it does +//! mean that origin can avoid doing any work that users might not need. #[cfg(feature = "origin-thread")] use crate::thread::initialize_main_thread; @@ -116,8 +139,8 @@ unsafe fn init_runtime(mem: *mut usize, envp: *mut *mut u8) { #[cfg(any(feature = "origin-start", feature = "external-start"))] #[allow(unused_variables)] unsafe fn call_user_code(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 { - extern "C" { - fn main(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> c_int; + extern "Rust" { + fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32; } // Call the functions registered via `.init_array`. @@ -125,13 +148,13 @@ unsafe fn call_user_code(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> call_ctors(argc, argv, envp); #[cfg(feature = "log")] - log::trace!("Calling `main({:?}, {:?}, {:?})`", argc, argv, envp); + log::trace!("Calling `origin_main({:?}, {:?}, {:?})`", argc, argv, envp); - // Call `main`. - let status = main(argc, argv, envp); + // Call `origin_main`. + let status = origin_main(argc as usize, argv, envp); #[cfg(feature = "log")] - log::trace!("`main` returned `{:?}`", status); + log::trace!("`origin_main` returned `{:?}`", status); status }