For static linking, we synthesize __rela_iplt_start and __rela_iplt_end symbols which point to the beginning and ending of .rela.iplt. If .rela.iplt is discarded after that, then the symbols get bogus section index 0xffff. If that happens, no one really uses the symbols, so the symbols' section value doesn't matter, but it should at least be a sane value (0xffff is a reserved value).
We've been investigating an issue with lld 6.0 in upcoming FreeBSD 12.0 which turns out to be this. https://bugs.freebsd.org/233397
From the FreeBSD PR, ld.bfd and gold pick different arbitrary sections for Ndx for these symbols: Linking with gold 1.15 (binutils 2.30): nuc% readelf -s a.out | grep iplt 1033: 000000000048b068 0 NOTYPE LOCAL HIDDEN 8 __rela_iplt_start 1034: 000000000048b068 0 NOTYPE LOCAL HIDDEN 8 __rela_iplt_end [ 8] .tdata PROGBITS 000000000048b070 0008a070 0000000000001800 0000000000000000 WAT 0 0 16 with ld.bfd 2.30 nuc% readelf -s a.out | grep iplt 1032: 00000000004001c0 0 NOTYPE LOCAL DEFAULT 1 __rela_iplt_end 1034: 00000000004001c0 0 NOTYPE LOCAL DEFAULT 1 __rela_iplt_start [ 1] .note.tag NOTE 0000000000400190 00000190 0000000000000030 0000000000000000 A 0 0 4
This is tricky. I have tried several approaches: * Leave __rela_iplt_start undefined if .rela.plt (IPLT) is empty. This should work as the two implementations I know use weak references: // freebsd/src/lib/csu/common/ignore_init.c extern const Elf_Rela __rela_iplt_start[] __weak_symbol __hidden; extern const Elf_Rela __rela_iplt_end[] __weak_symbol __hidden; #include "reloc.c" static void process_irelocs(void) { const Elf_Rela *r; for (r = &__rela_iplt_start[0]; r < &__rela_iplt_end[0]; r++) crt1_handle_rela(r); } // glibc/csu/libc-start.c static void apply_irel (void) { # ifdef IREL /* We use weak references for these so that we'll still work with a linker that doesn't define them. Such a linker doesn't support IFUNC at all and so uses won't work, but a statically-linked program that doesn't use any IFUNC symbols won't have a problem. */ extern const IREL_T IPLT_START[] __attribute__ ((weak)); extern const IREL_T IPLT_END[] __attribute__ ((weak)); for (const IREL_T *ipltent = IPLT_START; ipltent < IPLT_END; ++ipltent) IREL (ipltent); # endif } #endif I've seen a weird glibc R_X86_64_GOTPCRELX relocation error. Using 0 is not as good as using an arbitrary section as the distance between the section and the relocation site is smaller. In lld/ELF/Writer.cpp finalizeSections, there is some nuance when the following processes are reordered: * addRelIpltSymbols * forEachRelSec(scanRelocations<ELFT>); * In.Iplt->addSymbols(); * ... * https://reviews.llvm.org/D54985 [ELF] Keep empty In.RelaIplt so that __rela_iplt_{start,end} have valid st_shndx This requires a change in llvm-readobj as otherwise it would complain .rela.plt is not in any segment --- c/tools/llvm-readobj/ELFDumper.cpp +++ i/tools/llvm-readobj/ELFDumper.cpp @@ -1489,7 +1489,8 @@ void ELFDumper<ELFT>::parseDynamicTable( const Elf_Phdr &Phdr = **I; uint64_t Delta = VAddr - Phdr.p_vaddr; if (Delta >= Phdr.p_filesz) - report_fatal_error("Virtual address is not in any segment"); + return nullptr; After that, `ninja check-lld-elf` reports: Expected Passes : 1113 Unsupported Tests : 8 Unexpected Failures: 271 This place also needs patching: PltRelSec = findNotEmptySectionByAddress(Obj, *DtJmpRel); if (!PltRelSec) report_fatal_error("There is no not empty RELPLT section at 0x" + Twine::utohexstr(*DtJmpRel));
The first option (leaving them undefined in the absence of ifuncs) is my preference.
Maybe we can scan all symbols to make sure that there is at least one ifunc symbol before adding __rela_iplt_{start,end} symbols.
Fixed by https://reviews.llvm.org/D56623