Skip to content

Commit e7bf968

Browse files
author
George Rimar
committed
[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
1 parent 3d941bc commit e7bf968

File tree

7 files changed

+127
-24
lines changed

7 files changed

+127
-24
lines changed

lld/ELF/InputSection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
561561
Addend += Target->getImplicitAddend(BufLoc, Type);
562562

563563
SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel);
564-
RelExpr Expr = Target->getRelExpr(Type, Sym);
564+
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
565565
if (Expr == R_NONE)
566566
continue;
567567
if (Expr != R_ABS) {

lld/ELF/Relocations.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,8 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
851851
if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
852852
reportUndefined<ELFT>(Body, Sec, Rel.r_offset);
853853

854-
RelExpr Expr = Target->getRelExpr(Type, Body);
854+
RelExpr Expr =
855+
Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset);
855856

856857
// Ignore "hint" relocations because they are only markers for relaxation.
857858
if (isRelExprOneOf<R_HINT, R_NONE>(Expr))

lld/ELF/Target.cpp

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ TargetInfo *Target;
5959
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
6060
static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
6161

62-
template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
62+
template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
6363
for (InputSectionBase *D : InputSections) {
6464
auto *IS = dyn_cast_or_null<InputSection>(D);
6565
if (!IS || !IS->OutSec)
@@ -72,7 +72,7 @@ template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
7272
return "";
7373
}
7474

75-
static std::string getErrorLocation(uint8_t *Loc) {
75+
static std::string getErrorLocation(const uint8_t *Loc) {
7676
switch (Config->EKind) {
7777
case ELF32LEKind:
7878
return getErrorLoc<ELF32LE>(Loc);
@@ -119,7 +119,8 @@ namespace {
119119
class X86TargetInfo final : public TargetInfo {
120120
public:
121121
X86TargetInfo();
122-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
122+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
123+
const uint8_t *Loc) const override;
123124
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
124125
void writeGotPltHeader(uint8_t *Buf) const override;
125126
uint32_t getDynRel(uint32_t Type) const override;
@@ -143,7 +144,8 @@ class X86TargetInfo final : public TargetInfo {
143144
template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
144145
public:
145146
X86_64TargetInfo();
146-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
147+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
148+
const uint8_t *Loc) const override;
147149
bool isPicRel(uint32_t Type) const override;
148150
bool isTlsLocalDynamicRel(uint32_t Type) const override;
149151
bool isTlsInitialExecRel(uint32_t Type) const override;
@@ -171,13 +173,15 @@ class PPCTargetInfo final : public TargetInfo {
171173
public:
172174
PPCTargetInfo();
173175
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
174-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
176+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
177+
const uint8_t *Loc) const override;
175178
};
176179

177180
class PPC64TargetInfo final : public TargetInfo {
178181
public:
179182
PPC64TargetInfo();
180-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
183+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
184+
const uint8_t *Loc) const override;
181185
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
182186
int32_t Index, unsigned RelOff) const override;
183187
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@@ -186,7 +190,8 @@ class PPC64TargetInfo final : public TargetInfo {
186190
class AArch64TargetInfo final : public TargetInfo {
187191
public:
188192
AArch64TargetInfo();
189-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
193+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
194+
const uint8_t *Loc) const override;
190195
bool isPicRel(uint32_t Type) const override;
191196
bool isTlsInitialExecRel(uint32_t Type) const override;
192197
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
@@ -206,13 +211,15 @@ class AMDGPUTargetInfo final : public TargetInfo {
206211
public:
207212
AMDGPUTargetInfo();
208213
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
209-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
214+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
215+
const uint8_t *Loc) const override;
210216
};
211217

212218
class ARMTargetInfo final : public TargetInfo {
213219
public:
214220
ARMTargetInfo();
215-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
221+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
222+
const uint8_t *Loc) const override;
216223
bool isPicRel(uint32_t Type) const override;
217224
uint32_t getDynRel(uint32_t Type) const override;
218225
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
@@ -233,7 +240,8 @@ class ARMTargetInfo final : public TargetInfo {
233240
template <class ELFT> class MipsTargetInfo final : public TargetInfo {
234241
public:
235242
MipsTargetInfo();
236-
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
243+
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
244+
const uint8_t *Loc) const override;
237245
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
238246
bool isPicRel(uint32_t Type) const override;
239247
uint32_t getDynRel(uint32_t Type) const override;
@@ -353,7 +361,8 @@ X86TargetInfo::X86TargetInfo() {
353361
TrapInstr = 0xcccccccc;
354362
}
355363

356-
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
364+
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
365+
const uint8_t *Loc) const {
357366
switch (Type) {
358367
case R_386_8:
359368
case R_386_16:
@@ -376,6 +385,24 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
376385
return R_GOT;
377386
case R_386_GOT32:
378387
case R_386_GOT32X:
388+
// These relocations can be calculated in two different ways.
389+
// Usual calculation is G + A - GOT what means an offset in GOT table
390+
// (R_GOT_FROM_END). When instruction pointed by relocation has no base
391+
// register, then relocations can be used when PIC code is disabled. In that
392+
// case calculation is G + A, it resolves to an address of entry in GOT
393+
// (R_GOT) and not an offset.
394+
//
395+
// To check that instruction has no base register we scan ModR/M byte.
396+
// See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
397+
// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
398+
// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
399+
if ((Loc[-1] & 0xc7) != 0x5)
400+
return R_GOT_FROM_END;
401+
if (Config->Pic)
402+
error(toString(S.File) + ": relocation " + toString(Type) + " against '" +
403+
S.getName() +
404+
"' without base register can not be used when PIC enabled");
405+
return R_GOT;
379406
case R_386_TLS_GOTIE:
380407
return R_GOT_FROM_END;
381408
case R_386_GOTOFF:
@@ -654,8 +681,8 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
654681
}
655682

656683
template <class ELFT>
657-
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
658-
const SymbolBody &S) const {
684+
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
685+
const uint8_t *Loc) const {
659686
switch (Type) {
660687
case R_X86_64_8:
661688
case R_X86_64_16:
@@ -1093,7 +1120,8 @@ void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
10931120
}
10941121
}
10951122

1096-
RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
1123+
RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
1124+
const uint8_t *Loc) const {
10971125
switch (Type) {
10981126
case R_PPC_REL24:
10991127
case R_PPC_REL32:
@@ -1142,7 +1170,8 @@ uint64_t getPPC64TocBase() {
11421170
return TocVA + PPC64TocOffset;
11431171
}
11441172

1145-
RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
1173+
RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
1174+
const uint8_t *Loc) const {
11461175
switch (Type) {
11471176
default:
11481177
return R_ABS;
@@ -1290,8 +1319,8 @@ AArch64TargetInfo::AArch64TargetInfo() {
12901319
TcbSize = 16;
12911320
}
12921321

1293-
RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
1294-
const SymbolBody &S) const {
1322+
RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
1323+
const uint8_t *Loc) const {
12951324
switch (Type) {
12961325
default:
12971326
return R_ABS;
@@ -1634,7 +1663,8 @@ void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
16341663
}
16351664
}
16361665

1637-
RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
1666+
RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
1667+
const uint8_t *Loc) const {
16381668
switch (Type) {
16391669
case R_AMDGPU_ABS32:
16401670
case R_AMDGPU_ABS64:
@@ -1671,7 +1701,8 @@ ARMTargetInfo::ARMTargetInfo() {
16711701
NeedsThunks = true;
16721702
}
16731703

1674-
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
1704+
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
1705+
const uint8_t *Loc) const {
16751706
switch (Type) {
16761707
default:
16771708
return R_ABS;
@@ -2065,8 +2096,8 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
20652096
}
20662097

20672098
template <class ELFT>
2068-
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
2069-
const SymbolBody &S) const {
2099+
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
2100+
const uint8_t *Loc) const {
20702101
// See comment in the calculateMipsRelChain.
20712102
if (ELFT::Is64Bits || Config->MipsN32Abi)
20722103
Type &= 0xff;

lld/ELF/Target.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class TargetInfo {
5353
// targeting S.
5454
virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
5555
const InputFile *File, const SymbolBody &S) const;
56-
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
56+
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
57+
const uint8_t *Loc) const = 0;
5758
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
5859
virtual ~TargetInfo();
5960

628 Bytes
Binary file not shown.

lld/test/ELF/got32-i386.s

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
3+
# RUN: ld.lld %t.o -o %t
4+
# RUN: llvm-objdump -section-headers -d %t | FileCheck %s
5+
6+
## We have R_386_GOT32 relocation here.
7+
.globl foo
8+
.type foo, @function
9+
foo:
10+
nop
11+
12+
_start:
13+
movl foo@GOT, %ebx
14+
15+
## 73728 == 0x12000 == ADDR(.got)
16+
# CHECK: _start:
17+
# CHECK-NEXT: 11001: 8b 1d {{.*}} movl 73728, %ebx
18+
# CHECK: Sections:
19+
# CHECK: Name Size Address
20+
# CHECK: .got 00000004 0000000000012000
21+
22+
# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR
23+
# ERR: relocation R_386_GOT32 against 'foo' without base register can not be used when PIC enabled

lld/test/ELF/got32x-i386.s

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# REQUIRES: x86
2+
3+
## i386-got32x-baseless.elf is a file produced using GNU as v.2.27
4+
## using following code and command line:
5+
## (as --32 -o base.o base.s)
6+
##
7+
## .text
8+
## .globl foo
9+
## .type foo, @function
10+
## foo:
11+
## nop
12+
##
13+
## _start:
14+
## movl foo@GOT, %eax
15+
## movl foo@GOT, %ebx
16+
## movl foo@GOT(%eax), %eax
17+
## movl foo@GOT(%ebx), %eax
18+
##
19+
## Result file contains four R_386_GOT32X relocations. Generated code
20+
## is also a four mov instructions. And first two has no base register:
21+
## <_start>:
22+
## 1: 8b 05 00 00 00 00 mov 0x0,%eax
23+
## 7: 8b 1d 00 00 00 00 mov 0x0,%ebx
24+
## d: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
25+
## 13: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax
26+
##
27+
## R_386_GOT32X is computed as G + A - GOT, but if it used without base
28+
## register, it should be calculated as G + A. Using without base register
29+
## is only allowed for non-PIC code.
30+
##
31+
# RUN: ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1
32+
# RUN: llvm-objdump -section-headers -d %t1 | FileCheck %s
33+
34+
## 73728 == 0x12000 == ADDR(.got)
35+
# CHECK: _start:
36+
# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 73728, %eax
37+
# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 73728, %ebx
38+
# CHECK-NEXT: 1100d: 8b 80 {{.*}} movl -4(%eax), %eax
39+
# CHECK-NEXT: 11013: 8b 83 {{.*}} movl -4(%ebx), %eax
40+
# CHECK: Sections:
41+
# CHECK: Name Size Address
42+
# CHECK: .got 00000004 0000000000012000
43+
44+
# RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \
45+
# RUN: FileCheck %s --check-prefix=ERR
46+
# ERR: relocation R_386_GOT32X against 'foo' without base register can not be used when PIC enabled
47+
# ERR: relocation R_386_GOT32X against 'foo' without base register can not be used when PIC enabled

0 commit comments

Comments
 (0)