5 ms·
I got bored the other day and tried to achieve something similar on MacOS with Rust: #![no_std] #![no_main] use core::panic::PanicInfo;
by MuffinFlavored 3y ago
I got bored the other day and tried to achieve something similar on MacOS with Rust:
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[panic_handler]
fn panic_handler(_panic: &PanicInfo<'_>) -> ! {
// TODO: write panic message to stderr
write(2, "Panic occured\n".as_bytes()); // TODO: panic location + message
unsafe { sc::syscall!(EXIT, 255 as u32) };
loop {}
}
fn write(fd: usize, buf: &[u8]) {
unsafe {
sc::syscall!(WRITE, fd, buf.as_ptr(), buf.len());
}
}
#[no_mangle]
pub extern "C" fn main() -> u32 {
write(1, "Hello, world!\n".as_bytes());
return 0;
}
Then I inspected the ELF output in Ghidra. No matter what it was about ~16kb. I'm sure some code golf could be done to get it done (which has obviously been done + written about + documented before)
- 082349872349872 3y agoit's fun to golf, but how big are pages these days, anyway? (and if you're using a language with a stack, your executable probably ultimately loads as at least two pages: r/o and r/w)
- anyfoo 3y ago16kB on a Mac, so that was probably what they were running into. You effectively can’t make a program whose code occupies less than 16kB.
- speed_spread 3y agoRust or not, 16kb is entirely satisfactory. I mean, it fits in a Commodore 64's memory!
- _the_inflator 3y agoCompared to a Hello World program on C64 written in assembler probably not. ;) I need roughly 24 bytes. 16kb means 16.384 bytes. I can think of better usage of $4000 space in memory, FLI for example.
- anyfoo 3y agoThe majority of these 16384 bytes could be zeroes. They fill a single page, and if so, the only use you could make of those other ~16000 bytes would be to fill it with other code and/or read-only data for the same program, which just wasn't done here. In that sense, they are not "lost", just merely "unused". So now it would be interesting to see how much of the 16kB were not padding, though. OP said they looked at it with Ghidra, so did they see 16kB of actual code?
- ChrisSD 3y agoA similar program on Windows is 3072 bytes. I compiled it using: rustc hello.rs -C panic=abort -C opt-level=3 -C link-arg=/entry:main Here's the program: #![no_std] #![no_main] #[panic_handler] fn panic_handler(_panic: &core::panic::PanicInfo<'_>) -> ! { unsafe { ExitProcess(111) }; } #[no_mangle] pub extern "C" fn main() -> u32 { let msg = b"Hello, world!\n"; unsafe { let stdout = GetStdHandle(-11); let mut written = 0; WriteFile( stdout, msg.as_ptr(), msg.len() as u32, &mut written, core::ptr::null_mut(), ); } 0 } #[link(name = "kernel32")] extern "system" { fn ExitProcess(uExitCode: u32) -> !; fn GetStdHandle(nStdHandle: i32) -> isize; fn WriteFile( hFile: isize, lpBuffer: *const u8, nNumberOfBytesToWrite: u32, lpNumberOfBytesWritten: *mut u32, lpOverlapped: *mut (), ) -> i32; } I didn't bother much with the panic handler because there's no reason to in hello world. Though the binary contains a fair bit of padding still so it could have a few more things added to it without increasing the size. Alternatively I could shrink it a bit further by doing crimes but I'm not sure there's much point. It may be worth noting that the associated pdb (aka debug database) is 208,896 bytes.
- ChrisSD 3y agoOk, I committed some mild linker crimes and got the same program down to 800 bytes. rustc hello.rs -C panic=abort -C opt-level=3 -C link-args="/ENTRY:main /DEBUG:NONE /EMITPOGOPHASEINFO /EMITTOOLVERSIONINFO:NO /ALIGN:16"
- archargelod 3y agoCool. That reminded me of this blog post[0], with Hello World Nim binary in just 150 bytes! [0] - https://hookrace.net/blog/nim-binary-size/ https://hookrace.net/blog/nim-binary-size/
- themoonisachees 3y agoDon't x64 binaries have to be 4k-aligned or something like that? I remember a video about runnable qr codes where this was a major point because they had to do trickery to make windows run binaries that were less than that.
- saagarjha 3y agoXNU will not load any Mach-Os that are smaller than a page, so unfortunately there is not much fun to be had on that platform.
- clemiclemen 3y agoThe min-sized-rust project [1], which you may already be aware of, has a lot of optimisations to decrease the size of a Rust binay. I think with all the optimisations, at the end, it was around 8kb for the hello world. [1]: https://github.com/johnthagen/min-sized-rust https://github.com/johnthagen/min-sized-rust
- qweqwe14 3y agoTo achieve the smallest size, you have to ditch main entirely and use _start, along with passing certain linker flags not to align sections. See https://darkcoding.net/software/a-very-small-rust-binary-indeed/ https://darkcoding.net/software/a-very-small-rust-binary-ind... You can easily get around 500 bytes this way