ELF defines two relocation formats, REL and RELA. REL uses implicit addends, saving space compared to RELA's explicit addend field. However, REL is often inadequate for static code relocations because the instruction to be modified (commonly 4 bytes on RISC architectures) limits the available space for the addend. GNU assembler generates RELA static relocations for most ports and generates REL for very few ones (AArch32, BPF, M32R, MIPS o32). However, using RELA can be unnecessarily bulky for data and debug sections where the constraints on addend size don't apply. I propose that we add an assembler option `-Wa,--implicit-addends-for-data` to allow non-code sections to use implicit addends to save space. In a clang -O0 -g -gpubnames build, using REL for non-code sections (sections without the SHF_EXECINSTR flag) decreased relocation size by 27.1% and the .o file size by 6.4%. Using CREL (`clang -Wa,--crel,--implicit-addends-for-data`) decreased the .o file size by 21.6%! ``` |reloc size | .o size ---------+-----------+------------ RELA | 550519056 | 2339938120 REL data | 401209104 | 2190607000 -Wa,--implicit-addends-for-data CREL | 44865612 | 1834284744 -Wa,--crel,--implicit-addends-for-data ``` ``` # https://github.com/MaskRay/llvm-project/tree/demo-crel clang -fuse-ld=lld -Wa,--implicit-addends-for-data a.c -o a ``` The saving is less pronounced in a non-debug -O3 build (2.3% .o file size) due to relatively fewer data relocations. ``` |reloc size | .o size ---------+-----------+----------- RELA | 28235664 | 136014800 REL data | 25081480 | 132847952 CREL | 3812677 | 111591872 -Wa,--implicit-addends-for-data CREL | 3482387 | 111261704 -Wa,--crel,--implicit-addends-for-data ``` --- Technically, data sections can have static code relocations because assemblers don't reject `.data; call foo`. Since we are adding an opt-in assembler option, we can rely on the user to do the right thing and only use data directives. For a custom section, `sec->use_rela_p` is at a location matching the following stack trace. ``` perform_an_assembly_pass read_a_source_file obj_elf_section change_section subseg_force_new subseg_get bfd_make_section_anyway bfd_make_section_anyway_with_flags bfd_section_init _bfd_elf_new_section_hook ``` _bfd_elf_new_section_hook sets `sec->use_rela_p = bed->default_use_rela_p;` --- The GNU ld support for REL data relocations seems good, but .eh_frame needs to be fixed. ``` # clang is patched with my user branch mentioned by https://maskray.me/blog/2024-03-09-a-compact-relocation-format-for-elf#relleb-for-dynamic-relocations % fclang -Wa,--implicit-addends-for-data a.c b.c -fuse-ld=bfd -o a /usr/bin/ld.bfd: .eh_frame_hdr refers to overlapping FDEs /usr/bin/ld.bfd: final link failed: bad value clang: error: linker command failed with exit code 1 (use -v to see invocation) % fclang -Wa,--implicit-addends-for-data a.c b.c -fuse-ld=bfd -o a -fno-asynchronous-unwind-tables % ./a hello h 0x5633b227e020 0x5633b227e028 % fclang -Wa,--implicit-addends-for-data a.c b.c -fuse-ld=bfd -o a -fno-asynchronous-unwind-tables -static --target=aarch64-linux-gnu % ./a hello h 0x490050 0x490058 ```