mirror of
https://github.com/NotAShelf/microfetch.git
synced 2026-04-12 12:57:41 +00:00
various: (ab)use the new syscall wrappers and symbols; drop libc entirely
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I19ecd9801cf6e04adcedd3003d9fc59d6a6a6964
This commit is contained in:
parent
0f5fc124da
commit
d6977bafe5
3 changed files with 55 additions and 35 deletions
|
|
@ -1,3 +1,5 @@
|
|||
# https://github.com/rui314/mold?tab=readme-ov-file#how-to-use
|
||||
# Link with Mold, and without libc! We use nostartfiles to avoid the C runtime
|
||||
# See:
|
||||
# <https://github.com/rui314/mold?tab=readme-ov-file#how-to-use>
|
||||
[target.'cfg(target_os = "linux")']
|
||||
rustflags = [ "-C", "link-arg=-fuse-ld=mold", "-C", "link-arg=-lc", "-C", "link-arg=-lgcc_s" ]
|
||||
rustflags = [ "-C", "link-arg=-fuse-ld=mold", "-C", "link-arg=-nostartfiles" ]
|
||||
|
|
|
|||
|
|
@ -142,22 +142,34 @@ impl<T> Drop for OnceLock<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Access to the environ pointer (provided by libc startup code)
|
||||
unsafe extern "C" {
|
||||
static environ: *const *const u8;
|
||||
}
|
||||
// Store the environment pointer internally,initialized from `main()`. This
|
||||
// helps avoid the libc dependency *completely*.
|
||||
static ENVP: AtomicPtr<*const u8> = AtomicPtr::new(core::ptr::null_mut());
|
||||
|
||||
/// Gets an environment variable by name (without using std).
|
||||
/// Initialize the environment pointer. Must be called before any `getenv()`
|
||||
/// calls. This is called from `main()` with the calculated `envp`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function reads from the environ global which is initialized
|
||||
/// by the C runtime before `main()` is called.
|
||||
/// envp must be a valid null-terminated array of C strings, or null if
|
||||
/// no environment is available.
|
||||
#[inline]
|
||||
pub unsafe fn init_env(envp: *const *const u8) {
|
||||
ENVP.store(envp.cast_mut(), Ordering::Release);
|
||||
}
|
||||
|
||||
/// Gets the current environment pointer.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn get_envp() -> *const *const u8 {
|
||||
ENVP.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
/// Gets an environment variable by name without using std or libc by reading
|
||||
/// from the environment pointer set by [`init_env`].
|
||||
#[must_use]
|
||||
pub fn getenv(name: &str) -> Option<&'static [u8]> {
|
||||
// SAFETY: environ is set up by the C runtime before main() runs
|
||||
// and remains valid for the lifetime of the program
|
||||
let envp = unsafe { environ };
|
||||
let envp = get_envp();
|
||||
if envp.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -237,6 +249,7 @@ impl UtsName {
|
|||
if unsafe { sys_uname(uts.as_mut_ptr()) } != 0 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(Self(unsafe { uts.assume_init() }))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,40 +3,49 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use microfetch_alloc::BumpAlloc;
|
||||
use microfetch_asm::sys_write;
|
||||
#[cfg(not(test))]
|
||||
use {core::panic::PanicInfo, microfetch_asm::sys_exit};
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
use microfetch_alloc::BumpAllocator;
|
||||
// Re-export libc replacement functions from asm crate
|
||||
pub use microfetch_asm::{memcpy, memset, strlen};
|
||||
use microfetch_asm::{sys_exit, sys_write};
|
||||
|
||||
// Global allocator
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: BumpAlloc = BumpAlloc::new();
|
||||
static ALLOCATOR: BumpAllocator = BumpAllocator::new();
|
||||
|
||||
/// Receives argc and argv directly. The C runtime will call this after
|
||||
/// initializing the environment. Cool right?
|
||||
/// Main application entry point. Called by the asm crate's entry point
|
||||
/// after setting up argc, argv, and envp.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// argv must be a valid pointer to an array of argc C strings.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 {
|
||||
// SAFETY: argc and argv are provided by the C runtime and are valid
|
||||
// Calculate envp from argv. On Linux, envp is right after argv on the stack
|
||||
// but I bet 12 cents that there will be at least one exception.
|
||||
let argc_usize = usize::try_from(argc).unwrap_or(0);
|
||||
let envp = unsafe { argv.add(argc_usize + 1) };
|
||||
|
||||
// Initialize the environment pointer
|
||||
unsafe {
|
||||
match microfetch_lib::run(argc, argv) {
|
||||
microfetch_lib::init_env(envp);
|
||||
}
|
||||
|
||||
// Run the main application logic
|
||||
match unsafe { microfetch_lib::run(argc, argv) } {
|
||||
Ok(()) => 0,
|
||||
Err(e) => {
|
||||
// Print error message to stderr (fd 2)
|
||||
let msg = alloc::format!("Error: {e}\n");
|
||||
let _ = sys_write(2, msg.as_ptr(), msg.len());
|
||||
let _ = unsafe { sys_write(2, msg.as_ptr(), msg.len()) };
|
||||
1
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
// Write "panic" to stderr and exit
|
||||
const PANIC_MSG: &[u8] = b"panic\n";
|
||||
unsafe {
|
||||
let _ = sys_write(2, PANIC_MSG.as_ptr(), PANIC_MSG.len());
|
||||
|
|
@ -44,11 +53,7 @@ fn panic(_info: &PanicInfo) -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Stubs for Rust exception handling symbols needed when using alloc with
|
||||
// panic=abort These are normally provided by the unwinding runtime, but we're
|
||||
// using panic=abort. I don't actually think this is the correct approach, but I
|
||||
// cannot think of anything better.
|
||||
|
||||
// Stubs for Rust exception handling
|
||||
#[cfg(not(test))]
|
||||
#[unsafe(no_mangle)]
|
||||
const extern "C" fn rust_eh_personality() {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue