7 ms·
Halfway through the article and we have unsafe { asm!( "mov edi, 42", "mov eax, 60", "syscall", options
by blovescoffee 3y ago
Halfway through the article and we have
unsafe {
asm!(
"mov edi, 42",
"mov eax, 60",
"syscall",
options(nostack, noreturn)
)
// nostack prevents `asm!` from push/pop rax
// noreturn prevents it putting a 'ret' at the end
// but it does put a ud2 (undefined instruction) instead
}
and
> We will need to tell the C compiler that we’re providing our own entry point, telling it not to include it’s own start files.
So it's a Rust program but it's just calling inline assembly and using a C compiler?
- remexre 3y agoRust uses the C compiler as a linker, because this is often the only way to ensure all the libraries needed by the system toolchain are included. (Compare to the CCLD variable in autotools -- it refers to the command to use the C compiler as a linker, and exists for this very reason.) This isn't only libc -- it also includes libgcc (or compiler-rt, depending on your system toolchain), which, despite the name, may still be called "behind your back" by the LLVM toolchain. > So it's a Rust program but it's just calling inline assembly and using a C compiler? Yeah, I think this article is more in the tradition of [0] (but trying hard not to drop rustc) than being completely practical advice on making the binary you ship to users smaller. [0]: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm...
- andrewaylett 3y agoWell, not quite -- https://github.com/grahamking/demeter-deploy/blob/master/seed/src/main.rs https://github.com/grahamking/demeter-deploy/blob/master/see... is the Rust version of a program that used to be written entirely in assembly, and it seems that it ends up being the same size. There's a few bits of asm in amongst the Rust, but it's still definitely a Rust program. 800 lines of ASM file reduced to 600 lines of Rust, including comments and constants in both cases. He might be pushing the limits, and everything's unsafe Rust, but unsafe Rust is still safer than raw assembly.
- vacuity 3y ago> unsafe Rust is still safer than raw assembly I don't think I would go that far. Assembly doesn't have undefined behavior, and especially not with the strict constraints around references as in Rust. The safe/unsafe dichotomy in Rust is better than only using C or C++ when there are concise, robust encapsulations around broken invariants.
- lmm 3y ago> Assembly doesn't have undefined behavior Certainly some assembly languages do.
- vacuity 3y agoWhich ones? I assume at least the 1:1 machine code kind doesn't, and you mean something more like bytecode, but it'd be interesting if I'm wrong on that count.
- lmm 3y ago> I assume at least the 1:1 machine code kind doesn't They do, because the machine code sometimes has undefined behaviour. E.g. on the 6502 famously 1/4 of the instructions are undefined (all of the 0b.....11 ones), and many of them behave differently on different implementations of the processor (up to and including halting it, or placing it in a strange state).
- flohofwoe 3y agoMost of those undocumented instructions are what in C would be called "implementation defined behaviour" and have properly defined results, they might just differ between specific CPU models. There's only a very small number of unstable instructions which have unpredictable results (caused by "cross talk" due to incomplete instruction decoding).
- 3y ago
- estebank 3y agoNote that that step sheds libc entirely (so the binary needs to provide the minimal things that libc does for your platform, namely that assembly you mention, and you'd have to do the same for a C binary that did that) and gets rid of 3kb (16kb -> 13kb), but changing the linker flags to avoid page-aligning the binary brings it down to 400 bytes. I would have loved if the author had tried that on the libc version too, just for comparison's sake. In a lot of conversations around Rust binary sizes some people extrapolate from the "Hello, World!" size difference as if the additional cost on top of a bare C binary was linear, when in reality it is (approximately) a constant cost. That on top of completely disregarding that the "bloat" is doing something (panic machinery, string formatting, DWARF symbol storage, DWARF symbol parsing, etc.).
- tremon 3y agoIt's definitely not a constant cost, presumably due to the link-time optimization that rustc does. I've had binaries go from 800kB to 6MB simply by switching from getopts to the clap crate, for example.
- pornel 3y agoBinary using clap with all the bells and whistles, even without LTO, is 900KB after strip. The standard library has 4MB of debug info baked in, which due to its special integration with Cargo is always added, even when you explicitly configure `debug=false`. This is what usually surprises people and makes Rust executables seem huge.
- LtWorf 3y agoSo it doesn't strip unneeded stuff?
- joseluis 3y agoI found that the stripping of the libc made impossible for me to manage signals that didn't exit the program. E.g. Sigint worked fine as long as the callback didnt return to the caller but e.g. trying to use Sigwinch or sigcontinue segfaulted and I never found a way to make that work from scratch in this type of binaries without linking to libc... I wonder if that's even possible.