Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More options to link the smallest dynamic linked elf binary as possible #971

Open
edubart opened this issue Jan 21, 2023 · 5 comments
Open

Comments

@edubart
Copy link

edubart commented Jan 21, 2023

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 #466 ever gets implemented, would it generate smaller elf binaries?

@rui314
Copy link
Owner

rui314 commented Jan 21, 2023

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.

@edubart
Copy link
Author

edubart commented Jan 22, 2023

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.

@dhewg
Copy link

dhewg commented Jan 28, 2023

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?

@rui314
Copy link
Owner

rui314 commented Jan 28, 2023

Just truncating an ELF file to remove trailing null bytes doesn't seem like a safe optimisation. It's generally not supposed to work.

@dhewg
Copy link

dhewg commented Jan 28, 2023

Thought so, thanks ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants