forked from OSchip/llvm-project
[ELF] - Stop producing broken output for R_386_GOT32[X] relocations.
Previously we silently produced broken output for R_386_GOT32X/R_386_GOT32 relocations if they were used to compute the address of the symbol’s global offset table entry without base register when position-independent code is disabled. Situation happened because of recent ABI changes. Released ABI mentions that R_386_GOT32X can be calculated in a two different ways (so we did not follow ABI here before this patch), but draft ABI also mentions R_386_GOT32 relocation here. We should use the same calculations for both relocations. Problem is that we always calculated them as G + A - GOT (offset from end of GOT), but for case when PIC is disabled, according to i386 ABI calculation should be G + A, what should produce just an address in GOT finally. ABI: https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-draft.pdf (p36, p60). llvm-svn: 299812
This commit is contained in:
parent
3d941bc696
commit
e7bf968803
|
@ -561,7 +561,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
|||
Addend += Target->getImplicitAddend(BufLoc, Type);
|
||||
|
||||
SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel);
|
||||
RelExpr Expr = Target->getRelExpr(Type, Sym);
|
||||
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
|
||||
if (Expr == R_NONE)
|
||||
continue;
|
||||
if (Expr != R_ABS) {
|
||||
|
|
|
@ -851,7 +851,8 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
|
|||
if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
|
||||
reportUndefined<ELFT>(Body, Sec, Rel.r_offset);
|
||||
|
||||
RelExpr Expr = Target->getRelExpr(Type, Body);
|
||||
RelExpr Expr =
|
||||
Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset);
|
||||
|
||||
// Ignore "hint" relocations because they are only markers for relaxation.
|
||||
if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
|
||||
|
|
|
@ -59,7 +59,7 @@ TargetInfo *Target;
|
|||
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
|
||||
static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
|
||||
|
||||
template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
|
||||
template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
|
||||
for (InputSectionBase *D : InputSections) {
|
||||
auto *IS = dyn_cast_or_null<InputSection>(D);
|
||||
if (!IS || !IS->OutSec)
|
||||
|
@ -72,7 +72,7 @@ template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static std::string getErrorLocation(uint8_t *Loc) {
|
||||
static std::string getErrorLocation(const uint8_t *Loc) {
|
||||
switch (Config->EKind) {
|
||||
case ELF32LEKind:
|
||||
return getErrorLoc<ELF32LE>(Loc);
|
||||
|
@ -119,7 +119,8 @@ namespace {
|
|||
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;
|
||||
|
@ -143,7 +144,8 @@ public:
|
|||
template <class ELFT> 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 isTlsInitialExecRel(uint32_t Type) const override;
|
||||
|
@ -171,13 +173,15 @@ class PPCTargetInfo final : public TargetInfo {
|
|||
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 GotPltEntryAddr, uint64_t PltEntryAddr,
|
||||
int32_t Index, unsigned RelOff) const override;
|
||||
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
||||
|
@ -186,7 +190,8 @@ public:
|
|||
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;
|
||||
|
@ -206,13 +211,15 @@ class AMDGPUTargetInfo final : public TargetInfo {
|
|||
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;
|
||||
|
@ -233,7 +240,8 @@ public:
|
|||
template <class ELFT> 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;
|
||||
|
@ -353,7 +361,8 @@ X86TargetInfo::X86TargetInfo() {
|
|||
TrapInstr = 0xcccccccc;
|
||||
}
|
||||
|
||||
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
|
||||
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
|
||||
const uint8_t *Loc) const {
|
||||
switch (Type) {
|
||||
case R_386_8:
|
||||
case R_386_16:
|
||||
|
@ -376,6 +385,24 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
|
|||
return R_GOT;
|
||||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
// These relocations can be calculated in two different ways.
|
||||
// Usual calculation is G + A - GOT what means an offset in GOT table
|
||||
// (R_GOT_FROM_END). When instruction pointed by relocation has no base
|
||||
// register, then relocations can be used when PIC code is disabled. In that
|
||||
// case calculation is G + A, it resolves to an address of entry in GOT
|
||||
// (R_GOT) and not an offset.
|
||||
//
|
||||
// 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)
|
||||
if ((Loc[-1] & 0xc7) != 0x5)
|
||||
return R_GOT_FROM_END;
|
||||
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;
|
||||
case R_386_TLS_GOTIE:
|
||||
return R_GOT_FROM_END;
|
||||
case R_386_GOTOFF:
|
||||
|
@ -654,8 +681,8 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
|
||||
const SymbolBody &S) const {
|
||||
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
|
||||
const uint8_t *Loc) const {
|
||||
switch (Type) {
|
||||
case R_X86_64_8:
|
||||
case R_X86_64_16:
|
||||
|
@ -1093,7 +1120,8 @@ void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
|||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -1142,7 +1170,8 @@ uint64_t getPPC64TocBase() {
|
|||
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;
|
||||
|
@ -1290,8 +1319,8 @@ AArch64TargetInfo::AArch64TargetInfo() {
|
|||
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;
|
||||
|
@ -1634,7 +1663,8 @@ void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
|||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -1671,7 +1701,8 @@ ARMTargetInfo::ARMTargetInfo() {
|
|||
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;
|
||||
|
@ -2065,8 +2096,8 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
|
||||
const SymbolBody &S) const {
|
||||
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
|
||||
const uint8_t *Loc) const {
|
||||
// See comment in the calculateMipsRelChain.
|
||||
if (ELFT::Is64Bits || Config->MipsN32Abi)
|
||||
Type &= 0xff;
|
||||
|
|
|
@ -53,7 +53,8 @@ public:
|
|||
// 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();
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,23 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: llvm-objdump -section-headers -d %t | FileCheck %s
|
||||
|
||||
## We have R_386_GOT32 relocation here.
|
||||
.globl foo
|
||||
.type foo, @function
|
||||
foo:
|
||||
nop
|
||||
|
||||
_start:
|
||||
movl foo@GOT, %ebx
|
||||
|
||||
## 73728 == 0x12000 == ADDR(.got)
|
||||
# CHECK: _start:
|
||||
# CHECK-NEXT: 11001: 8b 1d {{.*}} movl 73728, %ebx
|
||||
# CHECK: Sections:
|
||||
# CHECK: Name Size Address
|
||||
# CHECK: .got 00000004 0000000000012000
|
||||
|
||||
# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
# ERR: relocation R_386_GOT32 against 'foo' without base register can not be used when PIC enabled
|
|
@ -0,0 +1,47 @@
|
|||
# REQUIRES: x86
|
||||
|
||||
## i386-got32x-baseless.elf is a file produced using GNU as v.2.27
|
||||
## using following code and command line:
|
||||
## (as --32 -o base.o base.s)
|
||||
##
|
||||
## .text
|
||||
## .globl foo
|
||||
## .type foo, @function
|
||||
## foo:
|
||||
## nop
|
||||
##
|
||||
## _start:
|
||||
## movl foo@GOT, %eax
|
||||
## movl foo@GOT, %ebx
|
||||
## movl foo@GOT(%eax), %eax
|
||||
## movl foo@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.
|
||||
##
|
||||
# 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 'foo' without base register can not be used when PIC enabled
|
||||
# ERR: relocation R_386_GOT32X against 'foo' without base register can not be used when PIC enabled
|
Loading…
Reference in New Issue