mold
mold copied to clipboard
More options to link the smallest dynamic linked elf binary as possible
I've been trying to use mold for a corner use case, where I need to link the smallest dynamic linked RISC-V 64GC ELF binary as possible, because in this use case every stored byte would cost money, so I want to link the smallest ELF binary I possible can. Such uses cases are also useful in 4kb demoscene competitions for example. So far I've come with the following link options:
First my C program test case small.c is:
#include <stdio.h>
#include <stdlib.h>
__attribute__((noreturn,externally_visible,naked)) void _start(void) {
asm volatile(".option push; .option norelax; la gp, __global_pointer$; .option pop;");
puts("hello\n");
exit(0);
}
In my test case I need to call dynamic linked shared libraries, so using exit and puts calls is intended.
Then I compile with:
riscv64-linux-gnu-gcc small.c -o small -march=rv64gc -Os \
-flto=auto -ffunction-sections -fdata-sections \
-mno-plt -fno-plt -fpie -pie -nostartfiles \
-B/usr/lib/mold \
-Wl,-O1,-gc-sections,--as-needed,--no-eh-frame-hdr,--build-id=none,--hash-style=gnu,--spare-dynamic-tags=0 \
-z norelro -z noseparate-code -z lazy -s
riscv64-linux-gnu-strip \
--remove-section=.comment \
--remove-section=.gnu.hash \
--remove-section=.gnu.version \
small
sstrip small
wc -c small
1160 small
In the end I got an ELF with 1160 bytes and 392 bytes after compressing with xz (I will store compressed ELF binaries in my use case), this is the smallest that I could create with GCC 12.2.0 + mold 1.9.0, matching the same I could with GCC 12.2.0 + ld 2.39. Note that I've disabled use of PLT by using -mno-plt -fno-plt -fpie -pie, as it seems to generate smaller files.
The above shows all flags that I've experimented with that did shrink my ELF binary. My request is that I wish mold had the options to strip ELF sections such as .comment, .gnu.hash, .gnu.version and to remove the end of the elf file, like sstrip tool does, so I could do all in mold.
Also as a curiosity, does anyone have any tips or flag ideas on how I could use mold to generate even smaller dynamic linked ELF binaries?
As reference, there are many ideas on how to link minimal ELF files in the following posts, maybe some are applicable to mold? https://github.com/faemiyah/dnload https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html https://nathanotterness.com/2021/10/tiny_elf_modernized.html
I wonder if https://github.com/rui314/mold/issues/466 ever gets implemented, would it generate smaller elf binaries?
I can add the --hash-style=none option for use cases like yours to negate previous --hash-style options, so that you can eliminate .gnu.hash or .hash from your library.
We can't simply strip .gnu.version because it affects correctness. Dynamic symbol resolution uses that table, and removing that section could results in resolving some dynamic symbols to be resolved to wrong ones. So, we can't generally do this in a safe manner.
We always copy input files' .comment to the output and also add our own string to that section. I believe always doing it is desirable given that the section is not a memory-mapped one. You can always use strip to remove the section.
Would be nice to have the --hash-style=none option.
I was also missing this option this I can pass to ld but not to mold:
-Ttext-segment=org
When creating an ELF executable, it will set the address of the first byte of the text segment.
Using this option I am able to choose a specific text segment that later xz tool is able compress more the ELF binary.
I was also thinking in an option like --no-section-headers, to remove the section headers table. From what I've researched section header table is not necessary to run the ELF, however when removed many tools won't be able to work with the ELF (gdb, objdump, readelf, etc), not even strip will work I think, so it wouldn't make sense to add this if there is no way to remove .comment within mold.
sstrip's -z options appears to break mold linked arm binaries, some segfault. When they're bfd linked they work.
See https://github.com/BR903/ELFkickers/blob/master/sstrip/sstrip.c#L172
What -z does may be invalid and non-working binaries can be expected, or there something mold can do about it?
Just truncating an ELF file to remove trailing null bytes doesn't seem like a safe optimisation. It's generally not supposed to work.
Thought so, thanks ;)