Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -471,7 +471,7 @@ Addend += Target->getImplicitAddend(BufLoc, Type); SymbolBody &Sym = this->getFile()->getRelocTargetSym(Rel); - RelExpr Expr = Target->getRelExpr(Type, Sym); + RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; if (Expr != R_ABS) { Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -688,7 +688,7 @@ if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) reportUndefined(Body, C, RI.r_offset); - RelExpr Expr = Target->getRelExpr(Type, Body); + RelExpr Expr = Target->getRelExpr(Type, Body, Buf + RI.r_offset); // Ignore "hint" relocations because they are only markers for relaxation. if (isRelExprOneOf(Expr)) Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -54,7 +54,8 @@ // targeting S. virtual bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const; - virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0; + virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const = 0; virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0; virtual ~TargetInfo(); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -119,7 +119,8 @@ class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; @@ -144,7 +145,8 @@ template class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; bool isTlsGlobalDynamicRel(uint32_t Type) const override; @@ -173,13 +175,15 @@ public: PPCTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; @@ -188,7 +192,8 @@ class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; @@ -208,13 +213,15 @@ public: AMDGPUTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; }; class ARMTargetInfo final : public TargetInfo { public: ARMTargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; @@ -236,7 +243,8 @@ template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; @@ -357,7 +365,28 @@ TlsGdRelaxSkip = 2; } -RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { +RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + // R_386_GOT32X can be calculated in a two different ways. Usually it resolves + // to an offset in GOT table, but when instruction pointed by relocation has + // no base register, this relocation can be used when PIC code is disabled. In + // that case it resolves to address of entry in GOT. + if (Type == R_386_GOT32X) { + // To check that instruction has no base register we scan ModR/M byte. + // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" + // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ + // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) + uint8_t ModRM = Loc[-1]; + if ((ModRM & 0xc7) == 0x5) { // Has no base register. + if (Config->pic()) + error(toString(S.File) + ": relocation " + toString(Type) + + " against '" + S.getName() + + "' without base register can not be used when PIC enabled"); + return R_GOT; + } + return R_GOT_FROM_END; + } + switch (Type) { case R_386_8: case R_386_16: @@ -379,7 +408,6 @@ case R_386_TLS_IE: return R_GOT; case R_386_GOT32: - case R_386_GOT32X: case R_386_TLS_GOTIE: return R_GOT_FROM_END; case R_386_GOTOFF: @@ -650,8 +678,8 @@ } template -RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, - const SymbolBody &S) const { +RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { case R_X86_64_8: case R_X86_64_16: @@ -1090,7 +1118,8 @@ } } -RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { +RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { case R_PPC_REL24: case R_PPC_REL32: @@ -1139,7 +1168,8 @@ return TocVA + PPC64TocOffset; } -RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { +RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { default: return R_ABS; @@ -1287,8 +1317,8 @@ TcbSize = 16; } -RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, - const SymbolBody &S) const { +RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { default: return R_ABS; @@ -1629,7 +1659,8 @@ } } -RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { +RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_ABS64: @@ -1666,7 +1697,8 @@ NeedsThunks = true; } -RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { +RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { switch (Type) { default: return R_ABS; @@ -2064,8 +2096,8 @@ } template -RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, - const SymbolBody &S) const { +RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; Index: test/ELF/got32x-i386.s =================================================================== --- test/ELF/got32x-i386.s +++ test/ELF/got32x-i386.s @@ -0,0 +1,50 @@ +# REQUIRES: x86 + +## i386-got32x-baseless.elf is a file produced using GNU as v.2.27 +## using following code: +## +## .text +## .type ifunc STT_GNU_IFUNC +## .globl ifunc +## .type ifunc, @function +## ifunc: +## ret +## +## _start: +## movl ifunc@GOT, %eax +## movl ifunc@GOT, %ebx +## movl ifunc@GOT(%eax), %eax +## movl ifunc@GOT(%ebx), %eax +## +## Result file contains four R_386_GOT32X relocations. Generated code +## is also a four mov instructions. And first two has no base register: +## <_start>: +## 1: 8b 05 00 00 00 00 mov 0x0,%eax +## 7: 8b 1d 00 00 00 00 mov 0x0,%ebx +## d: 8b 80 00 00 00 00 mov 0x0(%eax),%eax +## 13: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax +## +## R_386_GOT32X is computed as G + A - GOT, but if it used without base +## register, it should be calculated as G + A. Using without base register +## is only allowed for non-PIC code. +## +## STT_GNU_IFUNC was used specially because R_386_GOT32X can be optimized +## by linker. Optimization is not applicable if it is used against +## STT_GNU_IFUNC symbol. + +# RUN: ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 +# RUN: llvm-objdump -section-headers -d %t1 | FileCheck %s + +## 73728 == 0x12000 == ADDR(.got) +# CHECK: _start: +# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 73728, %eax +# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 73728, %ebx +# CHECK-NEXT: 1100d: 8b 80 {{.*}} movl -4(%eax), %eax +# CHECK-NEXT: 11013: 8b 83 {{.*}} movl -4(%ebx), %eax +# CHECK: Sections: +# CHECK: Name Size Address +# CHECK: .got 00000004 0000000000012000 + +# RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERR +# ERR: relocation R_386_GOT32X against 'ifunc' without base register can not be used when PIC enabled