Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -274,6 +274,9 @@ if (Config->EMachine == EM_MIPS) PairedLoc = findMipsPairedReloc(Buf, &RI, Rels.end()); + if (Target->doRelax(Type, Body, AddrLoc, SymVA, BufLoc)) + continue; + if (Target->needsPlt(Type, Body)) { SymVA = Body.getPltVA() + A; } else if (Target->needsGot(Type, Body)) { Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -67,6 +67,10 @@ uint8_t *PairedLoc = nullptr) const = 0; virtual bool isGotRelative(uint32_t Type) const; bool canRelaxTls(uint32_t Type, const SymbolBody *S) const; + virtual uint32_t getRelaxed(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const; + virtual bool doRelax(uint32_t Type, const SymbolBody &S, uint64_t P, + uint64_t SA, uint8_t *Loc) const; template bool needsCopyRel(uint32_t Type, const SymbolBody &S) const; size_t relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -109,6 +109,8 @@ class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); + bool doRelax(uint32_t Type, const SymbolBody &S, uint64_t P, uint64_t SA, + uint8_t *Loc) const override; uint32_t getTlsGotRel(uint32_t Type) const override; bool pointsToLocalDynamicGotEntry(uint32_t Type) const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; @@ -128,6 +130,8 @@ uint8_t *PairedLoc = nullptr) const override; bool isRelRelative(uint32_t Type) const override; bool isSizeRel(uint32_t Type) const override; + uint32_t getRelaxed(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA) const override; @@ -270,6 +274,11 @@ return false; } +uint32_t TargetInfo::getRelaxed(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + return Type; +} + uint64_t TargetInfo::getVAStart() const { return Config->Pic ? 0 : VAStart; } bool TargetInfo::needsCopyRelImpl(uint32_t Type) const { return false; } @@ -283,6 +292,11 @@ return SS->Sym.getType() == STT_OBJECT; } +bool TargetInfo::doRelax(uint32_t Type, const SymbolBody &S, uint64_t P, + uint64_t SA, uint8_t *Loc) const { + return false; +} + template bool TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { return mayNeedCopy(S) && needsCopyRelImpl(Type); @@ -914,6 +928,32 @@ return 1; } +uint32_t X86_64TargetInfo::getRelaxed(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + if (Type != R_X86_64_GOTPCREL) + return Type; + if (Loc[-2] != 0x8b || S.isPreemptible()) + return Type; + if (S.isGnuIfunc()) + return Type; + if (S.getName() == "_DYNAMIC") + return Type; + return R_X86_64_PC32; +} + +bool X86_64TargetInfo::doRelax(uint32_t Type, const SymbolBody &S, uint64_t P, + uint64_t SA, uint8_t *Loc) const { + if (getRelaxed(Type, S, Loc) == Type) + return false; + + if (SA - P + 0x80000000 > 0xFFFFFFFF) + error("R_X86_64_GOTPCREL relaxation overflow"); + + Loc[-2] = 0x8d; + write32le(Loc, SA - P); + return true; +} + void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA, uint8_t *PairedLoc) const { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -401,6 +401,9 @@ continue; } + const uint8_t *Data = C.getSectionData().data(); + Type = Target->getRelaxed(Type, Body, Data + RI.r_offset); + // If a relocation needs GOT, we create a GOT slot for the symbol. if (Target->needsGot(Type, Body)) { if (Body.isInGot()) 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,61 @@ +# REQUIRES: x86 +# 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: 0x20B8 R_X86_64_RELATIVE - 0x2000 +# 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 +# DISASM-NEXT: 103a: 48 8b 05 77 10 00 00 movq 4215(%rip), %rax +# DISASM-NEXT: 1041: 48 8b 05 70 10 00 00 movq 4208(%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 + movq _DYNAMIC@GOTPCREL(%rip), %rax + movq _DYNAMIC@GOTPCREL(%rip), %rax Index: test/ELF/gotpc-relax.s =================================================================== --- test/ELF/gotpc-relax.s +++ test/ELF/gotpc-relax.s @@ -0,0 +1,58 @@ +# REQUIRES: x86 +# 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