Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1024,6 +1024,20 @@ Entries.push_back({Tag, [=] { return Sym->getVA(); }}); } +// RelaIplt section is used to store IRelative relocations and usually +// immediately follows RelaPlt section in the same output section .rel[a].plt. +// At the same time any of these sections can be empty in case there is no +// corresponding relocations in output. Function is used to find the first +// non-empty input section with relocations in .rel[a].plt if any exist. +static RelocationBaseSection *findFirstRelPltSection() { + if (InX::RelaPlt->getParent() && !InX::RelaPlt->empty()) + return InX::RelaPlt; + if (InX::RelaIplt->Name == InX::RelaPlt->Name && InX::RelaIplt->getParent() && + !InX::RelaIplt->empty()) + return InX::RelaIplt; + return nullptr; +} + // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalizeContents() { if (this->Size) @@ -1081,20 +1095,27 @@ addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } - if (InX::RelaPlt->getParent() && !InX::RelaPlt->empty()) { - addInSec(DT_JMPREL, InX::RelaPlt); - addSize(DT_PLTRELSZ, InX::RelaPlt->getParent()); - switch (Config->EMachine) { - case EM_MIPS: - addInSec(DT_MIPS_PLTGOT, InX::GotPlt); - break; - case EM_SPARCV9: - addInSec(DT_PLTGOT, InX::Plt); - break; - default: - addInSec(DT_PLTGOT, InX::GotPlt); - break; - } + + // Here we want to emit dynamic tags relative to PLT relocations. + // If .rel[a].plt section is empty, no tags will be created. + RelocationBaseSection *RelPltSec = findFirstRelPltSection(); + if (RelPltSec) { + addInSec(DT_JMPREL, RelPltSec); + addSize(DT_PLTRELSZ, RelPltSec->getParent()); + + InputSection *PltSec; + if (Config->EMachine == EM_SPARCV9) + PltSec = InX::Plt; + else if (RelPltSec == InX::RelaPlt) + PltSec = InX::GotPlt; + else + PltSec = InX::IgotPlt; + + if (Config->EMachine == EM_MIPS) + addInSec(DT_MIPS_PLTGOT, PltSec); + else + addInSec(DT_PLTGOT, PltSec); + addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); } Index: test/ELF/gnu-ifunc-dyntags.s =================================================================== --- test/ELF/gnu-ifunc-dyntags.s +++ test/ELF/gnu-ifunc-dyntags.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -pie %t.o -o %tout +# RUN: llvm-objdump -section-headers %tout | FileCheck %s +# RUN: llvm-readobj -dynamic-table -r %tout | FileCheck %s --check-prefix=TAGS + +## Check we produce DT_PLTREL/DT_JMPREL/DT_PLTGOT and DT_PLTRELSZ tags +## when there are no other relocations except R_*_IRELATIVE. + +# CHECK: Name Size Address +# CHECK: .rela.plt 00000030 0000000000000210 +# CHECK: .got.plt 00000010 0000000000002000 + +# TAGS: Relocations [ +# TAGS-NEXT: Section {{.*}} .rela.plt { +# TAGS-NEXT: R_X86_64_IRELATIVE +# TAGS-NEXT: R_X86_64_IRELATIVE +# TAGS-NEXT: } +# TAGS-NEXT: ] + +# TAGS: Tag Type Name/Value +# TAGS: 0x0000000000000017 JMPREL 0x210 +# TAGS: 0x0000000000000002 PLTRELSZ 48 +# TAGS: 0x0000000000000003 PLTGOT 0x2000 +# TAGS: 0x0000000000000014 PLTREL RELA + +.text +.type foo STT_GNU_IFUNC +.globl foo +foo: + ret + +.type bar STT_GNU_IFUNC +.globl bar +bar: + ret + +.globl _start +_start: + call foo + call bar