The smallest C++ binary
28 points by weineng
28 points by weineng
Why even use a C compiler if all we're writing is assembly?
it's just a fun exercise :)
It's a very fun exercise!
I collected a list of "smallest" executables with slightly differing constraints here: https://www.muppetlabs.com/~breadbox/software/tiny/return42.html -- but I didn't think to include one with the constraint of having to use gcc to produce the binary. I like it -- although as @sammko points out here, you can use the -oformat=binary linker flag to devolve the constraint more or less completely.
The assembly is a really good place to start. I have a 231 byte hello world binary compiled from this: https://github.com/Cons-Cat/libCat/blob/main/examples%2Fhello.cpp
I started there from a similar tutorial a few years ago, and then factored the code out better and incrementally built up a lot of technology around it while keeping the overhead in the simple case as low as possible. I even have a CI test to ensure it stays at 231 bytes because that matters to me.
EDIT: Oops I somehow left an unneeded include in there. Gotta fix that.
Agreed. But it still has some nice C-only tricks and without some asm the picture would've been incomplete.
Indeed, there is a 45B binary here. Surely it is possible to encode that in assembly (just a sequence of db's in the extreme) and get gcc to assemble that back into the 45B "raw" file. It will coincidentally be an ELF, but gcc doesn't need to know. This would satisfy the OPs rules?
It would cease to be a "C binary" though, for most reasonable definitions of that term.
I think the answer depends by compiler. I'm not sure resorting to non-C code which some C compilers happen to accept counts though 😉
There’s an intermediate stage between the C++ program that calls exit(3) and the assembler call to SYS_exit: as you can tell from the manual section number, exit(3) is a library function that pulls in loads of libc (the atexit(3) machinery amongst other stuff). The standard way to call the raw exit system call is _exit(2), and if you put that in _start() and statically link then you should get something reasonably small. You can reduce the size of the compiler invocation and the source code by writing in C instead of C++.