(This proposal is part of the CREL work, but this feature can be used standalone for SHT_REL with existing lld. I encourage that you comment on the CREL proposal as well!)
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).
Many GNU ld ports don’t support REL.
lld supports REL for all ports.
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. My compact relocation format branch https://github.com/MaskRay/llvm-project/tree/demo-crel contains an implementation along with -Wa,--crel
support.
- When CREL (compact relocation) is not enabled,
SHT_REL
is selected. - When CREL is enabled, CREL with the
addend_bit==0
mode is selected.
Let’s explore data relocations in a .debug_str_offsets
section.
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
...
Here are the number of bytes to encode one relocation:
- Elf64_Rela: 24
- Elf64_Rel: 16
- CREL: 1 (all but the first). Yes, one byte to encode the delta offset and signal that type/symbol index do not change.
Using implicit addends primarily benefits debug sections such as .debug_str_offsets, .debug_names, .debug_addr, .debug_line
, but also data sections such as .eh_frame, .data., .data.rel.ro, .init_array
.
In a -O0 -g -gpubnames build, using REL for non-code sections decreased relocation size by 27.1% and the .o file size by 6.4%.
Using CREL (-Wa,--crel,--implicit-addends-for-data
) decreases the .o file size by 21.6%!
|reloc size | .o size
-------+-----------+------------
RELA |550519056 | 2339938120
REL |401209104 | 2190607000
CREL | 44865612 | 1834284744
# https://github.com/MaskRay/llvm-project/tree/demo-crel
clang -fuse-ld=lld -Wa,--implicit-addends-for-data a.c -o a
clang -Wa,--implicit-addends-for-data
generated relocatable files can be linked with lld, which supports REL for all targets.
However, many GNU ld ports don’t support REL (many do not define elf_backend_may_use_rel_p
, or the support may be incomplete).
% clang -Wa,--crel,--implicit-addends-for-data a.c b.c -fuse-ld=bfd
/usr/bin/ld.bfd: unknown architecture of input file `/tmp/a-10a324.o' is incompatible with i386:x86-64 output
/usr/bin/ld.bfd: unknown architecture of input file `/tmp/b-dde44a.o' is incompatible with i386:x86-64 output
/usr/bin/ld.bfd: error in /tmp/a-10a324.o(.eh_frame); no .eh_frame_hdr table will be created
/usr/bin/ld.bfd: error in /tmp/b-dde44a.o(.eh_frame); no .eh_frame_hdr table will be created
clang: error: linker command failed with exit code 1 (use -v to see invocation)
binutils feature request: 31567 – gas/ld: Implicit addends for non-code sections