Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -46,6 +46,7 @@ R_PPC_OPD, R_PPC_PLT_OPD, R_PPC_TOC, + R_X86_REX_RELAX_GOT_PC, R_RELAX_TLS_GD_TO_IE, R_RELAX_TLS_GD_TO_IE_PC, R_RELAX_TLS_GD_TO_LE, Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -222,6 +222,7 @@ return SymVA - P; } case R_PC: + case R_X86_REX_RELAX_GOT_PC: return Body.getVA(A) - P; case R_PAGE_PC: return getAArch64Page(Body.getVA(A)) - getAArch64Page(P); @@ -312,6 +313,13 @@ write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) } + if (Expr == R_X86_REX_RELAX_GOT_PC) { + if (SymVA + 0x80000000 > 0xFFFFFFFF) + fatal("R_X86_64_REX_GOTPCRELX relaxation overflow"); + BufLoc[-2] = 0x8d; + Type = R_X86_64_PC32; + } + Target->relocateOne(BufLoc, Type, SymVA); } } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -117,6 +117,9 @@ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + +private: + bool canRelaxGotPCRel(const SymbolBody &S) const; }; class PPCTargetInfo final : public TargetInfo { @@ -502,6 +505,14 @@ TlsGdToLeSkip = 2; } +bool X86_64TargetInfo::canRelaxGotPCRel(const SymbolBody &S) const { + if (S.isUndefined() || S.isPreemptible()) + return false; + if (S.isGnuIFunc()) + return false; + return (S.getName() != "_DYNAMIC"); +} + RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { switch (Type) { default: @@ -522,9 +533,10 @@ return R_PC; case R_X86_64_GOT32: return R_GOT_FROM_END; + case R_X86_64_REX_GOTPCRELX: + return canRelaxGotPCRel(S) ? R_X86_REX_RELAX_GOT_PC : R_GOT_PC; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTTPOFF: return R_GOT_PC; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -433,6 +433,16 @@ return 0; } +template +static bool handleRelaxation(uint32_t Type, SymbolBody &Body, + InputSectionBase &C, uintX_t Offset, + uintX_t Addend, RelExpr Expr) { + if (Expr != R_X86_REX_RELAX_GOT_PC) + return false; + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + return true; +} + // True if non-preemptable symbol always has the same value regardless of where // the DSO is loaded. template static bool isAbsolute(const SymbolBody &Body) { @@ -460,7 +470,7 @@ if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE || E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || - E == R_TLSGD || E == R_PPC_PLT_OPD) + E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_X86_REX_RELAX_GOT_PC) return true; // These never do, except if the entire file is position dependent or if @@ -675,6 +685,9 @@ continue; } + if (handleRelaxation(Type, Body, C, Offset, Addend, Expr)) + continue; + if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) || !Body.isPreemptible()) { // If the relocation points to something in the file, we can process it. 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 -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -relax-relocations -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: 0x20B8 R_X86_64_RELATIVE - 0x2000 +# RELOC-NEXT: 0x20A8 R_X86_64_GLOB_DAT dsofoo 0x0 +# RELOC-NEXT: 0x20B0 R_X86_64_GLOB_DAT foo 0x0 +# RELOC-NEXT: 0x20A0 R_X86_64_GLOB_DAT und 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 +# 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,57 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -relax-relocations -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 relocations. +# RELOC: Relocations [ +# RELOC: ] + +# 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 da 0f 00 00 movq 4058(%rip), %rax +# DISASM-NEXT: 11026: 48 8b 05 d3 0f 00 00 movq 4051(%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