I'm disappointed. In C I can get a 1k Hello Word binary simply be writing int main(void) { puts("Hello World!"); return 0; } The Rust version is a mess [0] [0] https://github.com/mcountryman/min-sized-rust-windows/blob/m...
The smallest executable gcc (on Ubuntu) compiles that to is 8296 bytes (tried every -O optimization).
Show HN: Tiny 1k Rust binary on Windows
51–60 of 66 posts
Re: Show HN: Tiny 1k Rust binary on Windows
#52Earlier quoted context omitted.
The Win32 loader will always load kernel32 no matter what. You don't even need it in your import table. It's just a matter of finding where it's loaded and calling into the right functions.
Between a 40b strcmp method (If I had/if it was more widely supported I could use sse4.2 strcmp) and ~74b of resolving said exports a couple syscalls sounds pretty nice provided the context switch isn't more expensive than resolving the imports.
Re: Show HN: Tiny 1k Rust binary on Windows
#53Earlier quoted context omitted.
The Win32 loader will always load kernel32 no matter what. You don't even need it in your import table. It's just a matter of finding where it's loaded and calling into the right functions.
Between a 40b strcmp method (If I had/if it was more widely supported I could use sse4.2 strcmp) and ~74b of resolving said exports a couple syscalls sounds pretty nice provided the context switch isn't more expensive than resolving the imports.
[0]: https://processhacker.sourceforge.io/doc/struct___r_t_l___u_...
[1]: https://docs.microsoft.com/en-us/windows-hardware/drivers/dd...
Re: Show HN: Tiny 1k Rust binary on Windows
#54Earlier quoted context omitted.
It's very easy and fast to try: using 0.7.0+51d7c14ce from https://ziglang.org/download/ and: const std = @import("std"); pub fn main() void { std.debug.print("Hello, world!\n", .{}); } ---------- zig build-exe hello.zig -O ReleaseSmall --strip --single-threaded -target x86_64-windows Resulting hello.exe is 3072 bytes. From these 2560 are zero bytes . The only system calls from the resulting binary are to ExitProcess…
@Edit2 I saw that, and that's pretty cool in regards to how the zig std is a wrapper rather than a rewrite. Although, if we were optimizing for size in this case it might be more optimal to have only one entry in the import table :D
Re: Show HN: Tiny 1k Rust binary on Windows
#55Note that a typical "Hello World" executable written in C does not contain any code capable of actually printing anything. It links to libc shipped with the operating system. That is about 30MB of code that C executables get for free. You can link libc statically and dead-code-eliminate everything except print. That's what Rust does too, but Rust has fancier machinery for formatting and handling of panics with backtr…
Rant: And below libc is probably X or Wayland which tells the kernel where to put pixels. And below that is the kernel and graphics driver which figures out how to do that and communicates it to the GPU. And below that is the actual GPU which figures out how to modulate an array of pixels into an HDMI signal. When do we stop quibbling about the size of binaries? It’s pointless to point out that small code relies on o…
C64 demos and 8088 DOS demos use very little OS infrastructure. Obviously things like JavaScript demos do.
The challenges presented by a particular piece of hardware or software in the demo scene are chosen for different reasons.
Sometimes, the demo author wants to show how well they can use the existing OS infrastructure. Sometimes they want to show what can be done without it. In both cases, small sizes are impressive.
Re: Show HN: Tiny 1k Rust binary on Windows
#56Note that a typical "Hello World" executable written in C does not contain any code capable of actually printing anything. It links to libc shipped with the operating system. That is about 30MB of code that C executables get for free. You can link libc statically and dead-code-eliminate everything except print. That's what Rust does too, but Rust has fancier machinery for formatting and handling of panics with backtr…
Rant: And below libc is probably X or Wayland which tells the kernel where to put pixels. And below that is the kernel and graphics driver which figures out how to do that and communicates it to the GPU. And below that is the actual GPU which figures out how to modulate an array of pixels into an HDMI signal. When do we stop quibbling about the size of binaries? It’s pointless to point out that small code relies on o…
It's just worth knowing when you compare exe sizes that C doesn't have an order of magnitude more efficient code generation. It just had a >30-year head start to get its standard library shipped with every operating system. Other languages typically don't have that advantage, and either have to reuse libc, or take a hit from statically linking their own libstd.
Re: Show HN: Tiny 1k Rust binary on Windows
#57Earlier quoted context omitted.
@Edit2 I saw that, and that's pretty cool in regards to how the zig std is a wrapper rather than a rewrite. Although, if we were optimizing for size in this case it might be more optimal to have only one entry in the import table :D
Maybe "zig std is a wrapper rather than a rewrite" was the slip and what's written is the opposite of the idea? I wouldn't call zig's std "a wrapper" in this case where it implements the functionality without the C standard library? Had it called something in the C library, then I'd call it a wrapper.
Re: Show HN: Tiny 1k Rust binary on Windows
#58Earlier quoted context omitted.
Maybe "zig std is a wrapper rather than a rewrite" was the slip and what's written is the opposite of the idea? I wouldn't call zig's std "a wrapper" in this case where it implements the functionality without the C standard library? Had it called something in the C library, then I'd call it a wrapper.
Yeah my choice of words wasn't great. It seams as if the zig std acts as a macro rather than a wrapper. That could just be the aggressive optimization though
std/debug.zig:
pub fn print(comptime fmt: []const u8, args: anytype) void {
const held = stderr_mutex.acquire();
defer held.release();
const stderr = io.getStdErr().writer();
nosuspend stderr.print(fmt, args) catch return;
}
io/writer.zig: pub fn print(self: Self, comptime format: []const u8, args: anytype) Error!void {
return std.fmt.format(self, format, args);
}
std/fmt.zig: pub fn format(
writer: anytype,
comptime fmt: []const u8,
args: anytype,
) !void {
...
It's all based on the language features and the actual implementations of zig's standard library code, and at least I don't see anything "wrapped" there, and nothing what C++, C or asm programmers understand as "a macro".Re: Show HN: Tiny 1k Rust binary on Windows
#59Note that a typical "Hello World" executable written in C does not contain any code capable of actually printing anything. It links to libc shipped with the operating system. That is about 30MB of code that C executables get for free. You can link libc statically and dead-code-eliminate everything except print. That's what Rust does too, but Rust has fancier machinery for formatting and handling of panics with backtr…
Rant: And below libc is probably X or Wayland which tells the kernel where to put pixels. And below that is the kernel and graphics driver which figures out how to do that and communicates it to the GPU. And below that is the actual GPU which figures out how to modulate an array of pixels into an HDMI signal. When do we stop quibbling about the size of binaries? It’s pointless to point out that small code relies on o…
In your example, both the C bin and Rust bin are using X, GPU, etcetc - so they warrant no distinction. So what is different? What is included in the Rust binary that isn't in the C? Because that's what is being tested in these types of comparisons.
This difference may be because some language included inefficient instructions - has bloated includes, etc. Or it could be because you're comparing Apples to Oranges, eg one ships with libc in the binary, and one dynamically links to it.
Re: Show HN: Tiny 1k Rust binary on Windows
#60Earlier quoted context omitted.
Rant: And below libc is probably X or Wayland which tells the kernel where to put pixels. And below that is the kernel and graphics driver which figures out how to do that and communicates it to the GPU. And below that is the actual GPU which figures out how to modulate an array of pixels into an HDMI signal. When do we stop quibbling about the size of binaries? It’s pointless to point out that small code relies on o…
The entire exercise is an attempt to compare apples to apples. In your example, both the C bin and Rust bin are using X, GPU, etcetc - so they warrant no distinction. So what is different? What is included in the Rust binary that isn't in the C? Because that's what is being tested in these types of comparisons. This difference may be because some language included inefficient instructions - has bloated includes, etc.…
Again: it was just a rant.