Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -195,7 +195,7 @@ if (Config->EMachine == EM_MIPS && (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)) SymVA += File->getMipsGp0(); - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, Body, findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); continue; } @@ -211,7 +211,7 @@ uintX_t SymVA = getSymVA(*Body); if (Target->relocNeedsPlt(Type, *Body)) { SymVA = Out::Plt->getEntryAddr(*Body); - } else if (Target->relocNeedsGot(Type, *Body)) { + } else if (Target->relocNeedsGot(Type, *Body, Buf, Offset)) { SymVA = Out::Got->getEntryAddr(*Body); if (Body->isTls()) Type = Target->getTlsGotReloc(Type); @@ -233,8 +233,9 @@ SymVA = getMipsGpAddr() - AddrLoc + 4; } uintX_t Size = getSymSize(*Body); + uint8_t *MP = findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs); Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, - findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); + Body, MP); } } Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -56,7 +56,6 @@ virtual void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const = 0; - // Returns true if a relocation is just a hint for linker to make for example // some code optimization. Such relocations should not be handled as a regular // ones and lead to dynamic relocation creation etc. @@ -67,14 +66,17 @@ // need not be fixed up if an image is loaded to a different address than // the link-time address. So we don't have to emit a relocation for the // dynamic linker if isRelRelative returns true. - virtual bool isRelRelative(uint32_t Type) const; - + virtual bool isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const; virtual bool isSizeReloc(uint32_t Type) const; virtual bool relocNeedsDynRelative(unsigned Type) const { return false; } - virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; + virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D = nullptr, + uint64_t Off = 0) const = 0; virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, + const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const = 0; virtual bool isGotRelative(uint32_t Type) const; virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S) const; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -97,10 +97,11 @@ unsigned RelOff) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsDynRelative(unsigned Type) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, @@ -131,12 +132,14 @@ uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + bool isRelRelative(uint32_t Type, const SymbolBody *S, const uint8_t *D, + uint64_t Off) const override; bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; bool isSizeReloc(uint32_t Type) const override; unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, @@ -152,6 +155,9 @@ uint64_t SA) const; void relocateTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, uint64_t SA) const; + bool canOptimizeGotPcRel(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const; + inline void optimizeGotPcRel(uint8_t *D) const; }; class PPCTargetInfo final : public TargetInfo { @@ -163,12 +169,14 @@ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + bool isRelRelative(uint32_t Type, const SymbolBody *S, const uint8_t *D, + uint64_t Off) const override; }; class PPC64TargetInfo final : public TargetInfo { @@ -180,12 +188,14 @@ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + bool isRelRelative(uint32_t Type, const SymbolBody *S, const uint8_t *D, + uint64_t Off) const override; }; class AArch64TargetInfo final : public TargetInfo { @@ -201,10 +211,11 @@ unsigned getTlsGotReloc(unsigned Type = -1) const override; bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; }; @@ -217,10 +228,11 @@ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; }; @@ -235,13 +247,15 @@ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S, const uint8_t *D, + uint64_t Off) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, + uint64_t SA, uint64_t ZA = 0, const SymbolBody *S = nullptr, uint8_t *PairedLoc = nullptr) const override; bool isHintReloc(uint32_t Type) const override; - bool isRelRelative(uint32_t Type) const override; + bool isRelRelative(uint32_t Type, const SymbolBody *S, const uint8_t *D, + uint64_t Off) const override; }; } // anonymous namespace @@ -288,7 +302,10 @@ bool TargetInfo::isHintReloc(uint32_t Type) const { return false; } -bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } +bool TargetInfo::isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const { + return true; +} bool TargetInfo::isSizeReloc(uint32_t Type) const { return false; } @@ -398,7 +415,8 @@ return false; } -bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { +bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { if (S.isTls() && Type == R_386_TLS_GD) return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true); if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE) @@ -421,7 +439,7 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { + const SymbolBody *S, uint8_t *PairedLoc) const { switch (Type) { case R_386_32: add32le(Loc, SA); @@ -670,11 +688,37 @@ return false; } -bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { +// System V Application Binary Interface AMD64 Architecture Processor Supplement +// Draft Version 0.99.8 introduces possible relaxations for GOTPCRELX +// Relocations. +// R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX should be generated instead of +// R_X86_64_GOTPCREL for places where relaxation is possible. +// At the same time nothing stops us from using it right now for +// R_X86_64_GOTPCREL if we perform additional check of instructions. Both gold +// and bfd do the same. +bool X86_64TargetInfo::canOptimizeGotPcRel(uint32_t Type, const SymbolBody &S, + const uint8_t *D, + uint64_t Off) const { + if (Type != R_X86_64_GOTPCREL || Off <= 2 || isGnuIFunc(S)) + return false; + if (Off == (uint64_t)-1) + Off = 0; + if (D[Off - 2] != 0x8b) + return false; + return !canBePreempted(&S, true); +} + +// Converting mov -> lea. +void X86_64TargetInfo::optimizeGotPcRel(uint8_t *D) const { D[-2] = 0x8d; } + +bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { if (Type == R_X86_64_TLSGD) return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true); if (Type == R_X86_64_GOTTPOFF) return !isTlsOptimized(Type, &S); + if (canOptimizeGotPcRel(Type, S, D, Off)) + return false; return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S); } @@ -724,7 +768,8 @@ } } -bool X86_64TargetInfo::isRelRelative(uint32_t Type) const { +bool X86_64TargetInfo::isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const { switch (Type) { default: return false; @@ -736,6 +781,8 @@ case R_X86_64_PC64: case R_X86_64_PLT32: return true; + case R_X86_64_GOTPCREL: + return S && canOptimizeGotPcRel(Type, *S, D, Off); } } @@ -884,6 +931,7 @@ void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, + const SymbolBody *S, uint8_t *PairedLoc) const { switch (Type) { case R_X86_64_32: @@ -904,6 +952,10 @@ write64le(Loc, SA); break; case R_X86_64_GOTPCREL: + if (S && canOptimizeGotPcRel(Type, *S, Loc, (uint64_t)-1)) + optimizeGotPcRel(Loc); + write32le(Loc, SA - P); + break; case R_X86_64_PC32: case R_X86_64_PLT32: case R_X86_64_TLSGD: @@ -945,22 +997,25 @@ PPCTargetInfo::PPCTargetInfo() {} void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} + uint64_t PltEntryAddr) const {} void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const {} -bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { + uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const {} +bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { return false; } bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { return false; } -bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; } +bool PPCTargetInfo::isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const { + return false; +} void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { + const SymbolBody *S, uint8_t *PairedLoc) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, applyPPCHa(SA)); @@ -1036,7 +1091,8 @@ write32be(Buf + 28, 0x4e800420); // bctr } -bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { +bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { if (relocNeedsPlt(Type, S)) return true; @@ -1057,7 +1113,8 @@ return Type == R_PPC64_REL24 && canBePreempted(&S, false); } -bool PPC64TargetInfo::isRelRelative(uint32_t Type) const { +bool PPC64TargetInfo::isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const { switch (Type) { default: return true; @@ -1069,6 +1126,7 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, + const SymbolBody *S, uint8_t *PairedLoc) const { uint64_t TB = getPPC64TocBase(); @@ -1287,8 +1345,8 @@ } } -bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, - const SymbolBody &S) const { +bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { switch (Type) { case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: @@ -1331,7 +1389,8 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, - uint64_t ZA, uint8_t *PairedLoc) const { + uint64_t ZA, const SymbolBody *S, + uint8_t *PairedLoc) const { switch (Type) { case R_AARCH64_ABS16: checkIntUInt<16>(SA, Type); @@ -1443,7 +1502,8 @@ llvm_unreachable("not implemented"); } -bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { +bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { return false; } @@ -1457,6 +1517,7 @@ // That's why the AMDGPU port works without implementing this function. void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, + const SymbolBody *S, uint8_t *PairedLoc) const { llvm_unreachable("not implemented"); } @@ -1487,8 +1548,9 @@ template void MipsTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} template -void MipsTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} +void MipsTargetInfo::writePltZeroEntry(uint8_t *Buf, + uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {} template void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, @@ -1496,8 +1558,8 @@ unsigned RelOff) const {} template -bool MipsTargetInfo::relocNeedsGot(uint32_t Type, - const SymbolBody &S) const { +bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S, + const uint8_t *D, uint64_t Off) const { return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16; } @@ -1524,7 +1586,8 @@ template void MipsTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, - uint64_t ZA, uint8_t *PairedLoc) const { + uint64_t ZA, const SymbolBody *S, + uint8_t *PairedLoc) const { const endianness E = ELFT::TargetEndianness; switch (Type) { case R_MIPS_32: @@ -1610,7 +1673,8 @@ } template -bool MipsTargetInfo::isRelRelative(uint32_t Type) const { +bool MipsTargetInfo::isRelRelative(uint32_t Type, const SymbolBody *S, + const uint8_t *D, uint64_t Off) const { switch (Type) { default: return false; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -259,6 +259,8 @@ bool NeedsGot = false; bool NeedsPlt = false; + const uint8_t *D = C.getSectionData().data(); + uint64_t Off = RI.r_offset; if (Body) { if (auto *E = dyn_cast>(Body)) { if (E->NeedsCopy) @@ -272,7 +274,7 @@ continue; Out::Plt->addEntry(Body); } - NeedsGot = Target->relocNeedsGot(Type, *Body); + NeedsGot = Target->relocNeedsGot(Type, *Body, D, Off); if (NeedsGot) { if (NeedsPlt && Target->supportsLazyRelocations()) { Out::GotPlt->addEntry(Body); @@ -314,8 +316,8 @@ // a relocation from an object file, but some relocations need no // load-time fixup when the final target is known. Skip such relocation. bool CBP = canBePreempted(Body, NeedsGot); - bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeReloc(Type) || - !Config->Shared; + bool NoDynrel = Target->isRelRelative(Type, Body, D, Off) || + Target->isSizeReloc(Type) || !Config->Shared; if (!CBP && NoDynrel) continue; Index: test/ELF/Inputs/gotpc-relax-und-dso.s =================================================================== --- test/ELF/Inputs/gotpc-relax-und-dso.s +++ test/ELF/Inputs/gotpc-relax-und-dso.s @@ -0,0 +1,4 @@ +.globl dsofoo +.type dsofoo, @function +dsofoo: + nop Index: test/ELF/gotpc-relax-und-dso.s =================================================================== --- test/ELF/gotpc-relax-und-dso.s +++ test/ELF/gotpc-relax-und-dso.s @@ -0,0 +1,55 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gotpc-relax-und-dso.s -o %tdso.o +// RUN: ld.lld -shared %tdso.o -o %t.so +// RUN: ld.lld -shared %t.o %t.so -o %tout +// RUN: llvm-readobj -r -s %tout | FileCheck --check-prefix=RELOC %s +// RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s + +// RELOC: Relocations [ +// RELOC-NEXT: Section ({{.*}}) .rela.dyn { +// RELOC-NEXT: 0x20A0 R_X86_64_GLOB_DAT und 0x0 +// RELOC-NEXT: 0x20A8 R_X86_64_GLOB_DAT dsofoo 0x0 +// RELOC-NEXT: 0x20B0 R_X86_64_GLOB_DAT foo 0x0 +// RELOC-NEXT: } +// RELOC-NEXT: ] + +// 0x101e + 7 - 36 = 0x1001 +// 0x1025 + 7 - 43 = 0x1001 +// DISASM: Disassembly of section .text: +// DISASM-NEXT: foo: +// DISASM-NEXT: 1000: 90 nop +// DISASM: hid: +// DISASM-NEXT: 1001: 90 nop +// DISASM: _start: +// DISASM-NEXT: 1002: 48 8b 05 97 10 00 00 movq 4247(%rip), %rax +// DISASM-NEXT: 1009: 48 8b 05 90 10 00 00 movq 4240(%rip), %rax +// DISASM-NEXT: 1010: 48 8b 05 91 10 00 00 movq 4241(%rip), %rax +// DISASM-NEXT: 1017: 48 8b 05 8a 10 00 00 movq 4234(%rip), %rax +// DISASM-NEXT: 101e: 48 8d 05 dc ff ff ff leaq -36(%rip), %rax +// DISASM-NEXT: 1025: 48 8d 05 d5 ff ff ff leaq -43(%rip), %rax +// DISASM-NEXT: 102c: 48 8b 05 7d 10 00 00 movq 4221(%rip), %rax +// DISASM-NEXT: 1033: 48 8b 05 76 10 00 00 movq 4214(%rip), %rax + +.text +.globl foo +.type foo, @function +foo: + nop + +.globl hid +.hidden hid +.type hid, @function +hid: + nop + +.globl _start +.type _start, @function +_start: + movq und@GOTPCREL(%rip), %rax + movq und@GOTPCREL(%rip), %rax + movq dsofoo@GOTPCREL(%rip), %rax + movq dsofoo@GOTPCREL(%rip), %rax + movq hid@GOTPCREL(%rip), %rax + movq hid@GOTPCREL(%rip), %rax + movq foo@GOTPCREL(%rip), %rax + movq foo@GOTPCREL(%rip), %rax Index: test/ELF/gotpc-relax.s =================================================================== --- test/ELF/gotpc-relax.s +++ test/ELF/gotpc-relax.s @@ -0,0 +1,57 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t1 +// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOC %s +// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s + +// There is no R_X86_64_GLOB_DAT relocations. +// RELOC: Relocations [ +// RELOC-NEXT: Section ({{.*}}) .rela.plt { +// RELOC-NOT: R_X86_64_GLOB_DAT + +// 0x11003 + 7 - 10 = 0x11000 +// 0x1100a + 7 - 17 = 0x11000 +// 0x11011 + 7 - 23 = 0x11001 +// 0x11018 + 7 - 30 = 0x11001 +// DISASM: Disassembly of section .text: +// DISASM-NEXT: foo: +// DISASM-NEXT: 11000: 90 nop +// DISASM: hid: +// DISASM-NEXT: 11001: 90 nop +// DISASM: ifunc: +// DISASM-NEXT: 11002: c3 retq +// DISASM: _start: +// DISASM-NEXT: 11003: 48 8d 05 f6 ff ff ff leaq -10(%rip), %rax +// DISASM-NEXT: 1100a: 48 8d 05 ef ff ff ff leaq -17(%rip), %rax +// DISASM-NEXT: 11011: 48 8d 05 e9 ff ff ff leaq -23(%rip), %rax +// DISASM-NEXT: 11018: 48 8d 05 e2 ff ff ff leaq -30(%rip), %rax +// DISASM-NEXT: 1101f: 48 8b 05 1a 00 00 00 movq 26(%rip), %rax +// DISASM-NEXT: 11026: 48 8b 05 13 00 00 00 movq 19(%rip), %rax + +.text +.globl foo +.type foo, @function +foo: + nop + +.globl hid +.hidden hid +.type hid, @function +hid: + nop + +.text +.type ifunc STT_GNU_IFUNC +.globl ifunc +.type ifunc, @function +ifunc: + ret + +.globl _start +.type _start, @function +_start: + movq foo@GOTPCREL(%rip), %rax + movq foo@GOTPCREL(%rip), %rax + movq hid@GOTPCREL(%rip), %rax + movq hid@GOTPCREL(%rip), %rax + movq ifunc@GOTPCREL(%rip), %rax + movq ifunc@GOTPCREL(%rip), %rax