[lld] r299812 - [ELF] - Stop producing broken output for R_386_GOT32[X] relocations.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 7 23:14:15 PDT 2017


Author: grimar
Date: Sat Apr  8 01:14:14 2017
New Revision: 299812

URL: http://llvm.org/viewvc/llvm-project?rev=299812&view=rev
Log:
[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).

Added:
    lld/trunk/test/ELF/Inputs/i386-got32x-baseless.elf   (with props)
    lld/trunk/test/ELF/got32-i386.s
    lld/trunk/test/ELF/got32x-i386.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=299812&r1=299811&r2=299812&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Sat Apr  8 01:14:14 2017
@@ -561,7 +561,7 @@ void InputSection::relocateNonAlloc(uint
       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) {

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=299812&r1=299811&r2=299812&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Sat Apr  8 01:14:14 2017
@@ -851,7 +851,8 @@ static void scanRelocs(InputSectionBase
     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))

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=299812&r1=299811&r2=299812&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Sat Apr  8 01:14:14 2017
@@ -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
   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 Targe
 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 Ta
 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
     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<E
 }
 
 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
   }
 }
 
-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
   }
 }
 
-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<ELF
 }
 
 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;

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=299812&r1=299811&r2=299812&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Sat Apr  8 01:14:14 2017
@@ -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();
 

Added: lld/trunk/test/ELF/Inputs/i386-got32x-baseless.elf
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/i386-got32x-baseless.elf?rev=299812&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lld/trunk/test/ELF/Inputs/i386-got32x-baseless.elf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: lld/trunk/test/ELF/got32-i386.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/got32-i386.s?rev=299812&view=auto
==============================================================================
--- lld/trunk/test/ELF/got32-i386.s (added)
+++ lld/trunk/test/ELF/got32-i386.s Sat Apr  8 01:14:14 2017
@@ -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 at 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

Added: lld/trunk/test/ELF/got32x-i386.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/got32x-i386.s?rev=299812&view=auto
==============================================================================
--- lld/trunk/test/ELF/got32x-i386.s (added)
+++ lld/trunk/test/ELF/got32x-i386.s Sat Apr  8 01:14:14 2017
@@ -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 at GOT, %eax
+##  movl foo at GOT, %ebx
+##  movl foo at GOT(%eax), %eax
+##  movl foo at 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




More information about the llvm-commits mailing list