From 77d9edb34de31f7deab7753b8481fc4fb899a1c6 Mon Sep 17 00:00:00 2001 From: Federico Maria Morrone Date: Sun, 3 Sep 2023 17:29:30 +0200 Subject: [PATCH 1/5] Change main from extern "C" to extern "Rust". This function is called from Rust code, so it doesn't need to be `extern "C"`. --- example-crates/external-start/src/main.rs | 2 +- example-crates/origin-start-lto/src/main.rs | 2 +- example-crates/origin-start-no-alloc/src/main.rs | 2 +- example-crates/origin-start/src/main.rs | 2 +- example-crates/tiny/src/main.rs | 2 +- src/program.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example-crates/external-start/src/main.rs b/example-crates/external-start/src/main.rs index fac5ca2..32da12c 100644 --- a/example-crates/external-start/src/main.rs +++ b/example-crates/external-start/src/main.rs @@ -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 { +fn main(_argc: i32, _argv: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); diff --git a/example-crates/origin-start-lto/src/main.rs b/example-crates/origin-start-lto/src/main.rs index a998553..7fb3193 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 { +fn main(_argc: i32, _argv: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); diff --git a/example-crates/origin-start-no-alloc/src/main.rs b/example-crates/origin-start-no-alloc/src/main.rs index 8500ec1..f1c91fd 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 { +fn main(_argc: i32, _argv: *const *const 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..7fb3193 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 { +fn main(_argc: i32, _argv: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); diff --git a/example-crates/tiny/src/main.rs b/example-crates/tiny/src/main.rs index 526028d..cc0a954 100644 --- a/example-crates/tiny/src/main.rs +++ b/example-crates/tiny/src/main.rs @@ -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 { +fn main(_argc: i32, _argv: *const *const u8) -> i32 { 42 } diff --git a/src/program.rs b/src/program.rs index 78103a9..b44bad4 100644 --- a/src/program.rs +++ b/src/program.rs @@ -116,7 +116,7 @@ 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" { + extern "Rust" { fn main(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> c_int; } From 9fb32df09177da341398fd035213d3d80da687b6 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 8 Sep 2023 05:12:27 -0700 Subject: [PATCH 2/5] Rename `main` to `origin_main`. This isn't the C ABI `main` function, so give it a different name. Also, make it an `unsafe fn`, and add the `envp` arguments so that we don't rely on the ABI to ignore extra arguments. --- example-crates/basic/src/main.rs | 2 +- example-crates/external-start/src/main.rs | 15 ++++++++++----- example-crates/no-std/src/main.rs | 2 +- example-crates/origin-start-lto/src/main.rs | 6 ++---- example-crates/origin-start-no-alloc/src/main.rs | 2 +- example-crates/origin-start/src/main.rs | 6 ++---- example-crates/tiny/src/main.rs | 4 ++-- src/program.rs | 10 +++++----- 8 files changed, 24 insertions(+), 23 deletions(-) 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 32da12c..5300c24 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] -fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -77,10 +77,15 @@ 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: *const *const u8, _envp: *const *const 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 7fb3193..1bfb064 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] -fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -48,9 +48,7 @@ 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 f1c91fd..b474a05 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] -fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const 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 7fb3193..1bfb064 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] -fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { eprintln!("Hello from main thread"); at_exit(Box::new(|| eprintln!("Hello from an at_exit handler"))); @@ -48,9 +48,7 @@ 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 cc0a954..3b94eda 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] -fn main(_argc: i32, _argv: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { 42 } diff --git a/src/program.rs b/src/program.rs index b44bad4..b7d2912 100644 --- a/src/program.rs +++ b/src/program.rs @@ -117,7 +117,7 @@ unsafe fn init_runtime(mem: *mut usize, envp: *mut *mut u8) { #[allow(unused_variables)] unsafe fn call_user_code(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 { extern "Rust" { - fn main(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> c_int; + fn origin_main(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> c_int; } // Call the functions registered via `.init_array`. @@ -125,13 +125,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, argv, envp); #[cfg(feature = "log")] - log::trace!("`main` returned `{:?}`", status); + log::trace!("`origin_main` returned `{:?}`", status); status } From fd5771398f362f92972de729dce886531d2871fc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 9 Sep 2023 03:43:17 -0700 Subject: [PATCH 3/5] Use `*mut` pointers for argv and envp. This memory is mutable, and users may want to mutate it, so use `*mut`. --- example-crates/external-start/src/main.rs | 4 ++-- example-crates/origin-start-lto/src/main.rs | 2 +- example-crates/origin-start-no-alloc/src/main.rs | 2 +- example-crates/origin-start/src/main.rs | 2 +- example-crates/tiny/src/main.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example-crates/external-start/src/main.rs b/example-crates/external-start/src/main.rs index 5300c24..29eb88d 100644 --- a/example-crates/external-start/src/main.rs +++ b/example-crates/external-start/src/main.rs @@ -56,7 +56,7 @@ static EARLY_INIT_ARRAY: unsafe extern "C" fn(i32, *mut *mut u8) = { }; #[no_mangle] -unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _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"))); @@ -86,6 +86,6 @@ unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const // 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: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { core::intrinsics::abort(); } diff --git a/example-crates/origin-start-lto/src/main.rs b/example-crates/origin-start-lto/src/main.rs index 1bfb064..a1f3b7e 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] -unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _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"))); diff --git a/example-crates/origin-start-no-alloc/src/main.rs b/example-crates/origin-start-no-alloc/src/main.rs index b474a05..d5abed6 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] -unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _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 1bfb064..a1f3b7e 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] -unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _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"))); diff --git a/example-crates/tiny/src/main.rs b/example-crates/tiny/src/main.rs index 3b94eda..01bc2dc 100644 --- a/example-crates/tiny/src/main.rs +++ b/example-crates/tiny/src/main.rs @@ -18,6 +18,6 @@ fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { extern "C" fn eh_personality() {} #[no_mangle] -unsafe fn origin_main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 { +unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 { 42 } From 706c529f3f3c4845758716dce304ffc32aebdc9c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 9 Sep 2023 05:32:21 -0700 Subject: [PATCH 4/5] Change `origin_main`'s signature to avoid `c_int`. Change `argc` to `usize` because a common use case is to pass it to `slice::from_raw_parts`. Change the return value to `i32`. This matches the type used by `std::process::exit`. --- example-crates/external-start/src/main.rs | 2 +- example-crates/origin-start-lto/src/main.rs | 2 +- example-crates/origin-start-no-alloc/src/main.rs | 2 +- example-crates/origin-start/src/main.rs | 2 +- example-crates/tiny/src/main.rs | 2 +- src/program.rs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example-crates/external-start/src/main.rs b/example-crates/external-start/src/main.rs index 29eb88d..53a9143 100644 --- a/example-crates/external-start/src/main.rs +++ b/example-crates/external-start/src/main.rs @@ -56,7 +56,7 @@ static EARLY_INIT_ARRAY: unsafe extern "C" fn(i32, *mut *mut u8) = { }; #[no_mangle] -unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut 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"))); diff --git a/example-crates/origin-start-lto/src/main.rs b/example-crates/origin-start-lto/src/main.rs index a1f3b7e..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] -unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut 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"))); diff --git a/example-crates/origin-start-no-alloc/src/main.rs b/example-crates/origin-start-no-alloc/src/main.rs index d5abed6..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] -unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut 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 a1f3b7e..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] -unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut 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"))); diff --git a/example-crates/tiny/src/main.rs b/example-crates/tiny/src/main.rs index 01bc2dc..fbbd894 100644 --- a/example-crates/tiny/src/main.rs +++ b/example-crates/tiny/src/main.rs @@ -18,6 +18,6 @@ fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { extern "C" fn eh_personality() {} #[no_mangle] -unsafe fn origin_main(_argc: i32, _argv: *mut *mut u8, _envp: *mut *mut 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 b7d2912..c14f072 100644 --- a/src/program.rs +++ b/src/program.rs @@ -117,7 +117,7 @@ unsafe fn init_runtime(mem: *mut usize, envp: *mut *mut u8) { #[allow(unused_variables)] unsafe fn call_user_code(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 { extern "Rust" { - fn origin_main(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> c_int; + fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32; } // Call the functions registered via `.init_array`. @@ -128,7 +128,7 @@ unsafe fn call_user_code(argc: c_int, argv: *mut *mut u8, envp: *mut *mut u8) -> log::trace!("Calling `origin_main({:?}, {:?}, {:?})`", argc, argv, envp); // Call `origin_main`. - let status = origin_main(argc, argv, envp); + let status = origin_main(argc as usize, argv, envp); #[cfg(feature = "log")] log::trace!("`origin_main` returned `{:?}`", status); From 16bcfafcda75e2f34f3a22509ba6dd1dea8d6f1a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 9 Sep 2023 04:07:25 -0700 Subject: [PATCH 5/5] Document `origin_main`. --- src/program.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/program.rs b/src/program.rs index c14f072..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;