mirror of
https://github.com/NotAShelf/microfetch.git
synced 2026-04-13 05:13:50 +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")']
|
[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)
|
// Store the environment pointer internally,initialized from `main()`. This
|
||||||
unsafe extern "C" {
|
// helps avoid the libc dependency *completely*.
|
||||||
static environ: *const *const u8;
|
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
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function reads from the environ global which is initialized
|
/// envp must be a valid null-terminated array of C strings, or null if
|
||||||
/// by the C runtime before `main()` is called.
|
/// 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]
|
#[must_use]
|
||||||
pub fn getenv(name: &str) -> Option<&'static [u8]> {
|
pub fn getenv(name: &str) -> Option<&'static [u8]> {
|
||||||
// SAFETY: environ is set up by the C runtime before main() runs
|
let envp = get_envp();
|
||||||
// and remains valid for the lifetime of the program
|
|
||||||
let envp = unsafe { environ };
|
|
||||||
if envp.is_null() {
|
if envp.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -237,6 +249,7 @@ impl UtsName {
|
||||||
if unsafe { sys_uname(uts.as_mut_ptr()) } != 0 {
|
if unsafe { sys_uname(uts.as_mut_ptr()) } != 0 {
|
||||||
return Err(Error::last_os_error());
|
return Err(Error::last_os_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self(unsafe { uts.assume_init() }))
|
Ok(Self(unsafe { uts.assume_init() }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,40 +3,49 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use microfetch_alloc::BumpAlloc;
|
use core::panic::PanicInfo;
|
||||||
use microfetch_asm::sys_write;
|
|
||||||
#[cfg(not(test))]
|
|
||||||
use {core::panic::PanicInfo, microfetch_asm::sys_exit};
|
|
||||||
|
|
||||||
|
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]
|
#[global_allocator]
|
||||||
static ALLOCATOR: BumpAlloc = BumpAlloc::new();
|
static ALLOCATOR: BumpAllocator = BumpAllocator::new();
|
||||||
|
|
||||||
/// Receives argc and argv directly. The C runtime will call this after
|
/// Main application entry point. Called by the asm crate's entry point
|
||||||
/// initializing the environment. Cool right?
|
/// after setting up argc, argv, and envp.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// argv must be a valid pointer to an array of argc C strings.
|
/// argv must be a valid pointer to an array of argc C strings.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 {
|
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 {
|
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,
|
Ok(()) => 0,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Print error message to stderr (fd 2)
|
|
||||||
let msg = alloc::format!("Error: {e}\n");
|
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
|
1
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &PanicInfo) -> ! {
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
// Write "panic" to stderr and exit
|
|
||||||
const PANIC_MSG: &[u8] = b"panic\n";
|
const PANIC_MSG: &[u8] = b"panic\n";
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = sys_write(2, PANIC_MSG.as_ptr(), PANIC_MSG.len());
|
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
|
// Stubs for Rust exception handling
|
||||||
// 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.
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
const extern "C" fn rust_eh_personality() {}
|
const extern "C" fn rust_eh_personality() {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue