[lld] r270705 - [ELF] - Implemented optimization for R_X86_64_GOTPCREL relocation.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Wed May 25 07:31:38 PDT 2016


Author: grimar
Date: Wed May 25 09:31:37 2016
New Revision: 270705

URL: http://llvm.org/viewvc/llvm-project?rev=270705&view=rev
Log:
[ELF] - Implemented optimization for R_X86_64_GOTPCREL relocation.

System V Application Binary Interface AMD64 Architecture Processor Supplement Draft Version 0.99.8 
(https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r249.pdf, B.2 "B.2 Optimize GOTPCRELX Relocations")
introduces possible relaxations for R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX.

That patch implements the next relaxation: 
mov foo at GOTPCREL(%rip), %reg => lea foo(%rip), %reg
and also opens door for implementing all other ones.

Implementation was suggested by Rafael Ávila de Espíndola with few additions and testcases by myself.

Differential revision: http://reviews.llvm.org/D15779

Added:
    lld/trunk/test/ELF/Inputs/gotpc-relax-und-dso.s
    lld/trunk/test/ELF/gotpc-relax-und-dso.s
    lld/trunk/test/ELF/gotpc-relax.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    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=270705&r1=270704&r2=270705&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed May 25 09:31:37 2016
@@ -250,6 +250,7 @@ getSymVA(uint32_t Type, typename ELFT::u
     return SymVA - P;
   }
   case R_PC:
+  case R_RELAX_GOT_PC:
     return Body.getVA<ELFT>(A) - P;
   case R_PAGE_PC:
     return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
@@ -318,6 +319,9 @@ void InputSectionBase<ELFT>::relocate(ui
         getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, BufLoc, *File, Expr));
 
     switch (Expr) {
+    case R_RELAX_GOT_PC:
+      Target->relaxGot(BufLoc, SymVA);
+      break;
     case R_RELAX_TLS_IE_TO_LE:
       Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
       break;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=270705&r1=270704&r2=270705&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed May 25 09:31:37 2016
@@ -227,7 +227,8 @@ static bool needsPlt(RelExpr Expr) {
 // True if this expression is of the form Sym - X, where X is a position in the
 // file (PC, or GOT for example).
 static bool isRelExpr(RelExpr Expr) {
-  return Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC;
+  return Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC ||
+         Expr == R_RELAX_GOT_PC;
 }
 
 template <class ELFT>
@@ -343,14 +344,19 @@ template <class ELFT> static void addCop
 
 template <class ELFT>
 static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
-                          bool IsWrite, RelExpr Expr, uint32_t Type) {
+                          bool IsWrite, RelExpr Expr, uint32_t Type,
+                          const uint8_t *Data, typename ELFT::uint Offset) {
   if (Target->needsThunk(Type, File, Body))
     return R_THUNK;
   bool Preemptible = Body.isPreemptible();
-  if (Body.isGnuIFunc())
+  if (Body.isGnuIFunc()) {
     Expr = toPlt(Expr);
-  else if (needsPlt(Expr) && !Preemptible)
-    Expr = fromPlt(Expr);
+  } else if (!Preemptible) {
+    if (needsPlt(Expr))
+      Expr = fromPlt(Expr);
+    if (Expr == R_GOT_PC && Target->canRelaxGot(Type, Data, Offset))
+      Expr = R_RELAX_GOT_PC;
+  }
 
   if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))
     return Expr;
@@ -480,7 +486,7 @@ static void scanRelocs(InputSectionBase<
       continue;
 
     bool Preemptible = Body.isPreemptible();
-    Expr = adjustExpr(File, Body, IsWrite, Expr, Type);
+    Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf, Offset);
     if (HasError)
       continue;
 

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=270705&r1=270704&r2=270705&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Wed May 25 09:31:37 2016
@@ -38,6 +38,7 @@ enum RelExpr {
   R_PPC_OPD,
   R_PPC_PLT_OPD,
   R_PPC_TOC,
+  R_RELAX_GOT_PC,
   R_RELAX_TLS_GD_TO_IE,
   R_RELAX_TLS_GD_TO_LE,
   R_RELAX_TLS_IE_TO_LE,

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=270705&r1=270704&r2=270705&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Wed May 25 09:31:37 2016
@@ -113,6 +113,9 @@ public:
                 int32_t Index, unsigned RelOff) const override;
   void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
 
+  bool canRelaxGot(uint32_t Type, const uint8_t *Data,
+                   uint64_t Offset) const override;
+  void relaxGot(uint8_t *Loc, uint64_t Val) const override;
   void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   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;
@@ -232,6 +235,15 @@ bool TargetInfo::isTlsGlobalDynamicRel(u
   return false;
 }
 
+bool TargetInfo::canRelaxGot(uint32_t Type, const uint8_t *Data,
+                             uint64_t Offset) const {
+  return false;
+}
+
+void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
 void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
                                 uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
@@ -724,6 +736,21 @@ void X86_64TargetInfo::relocateOne(uint8
   }
 }
 
+bool X86_64TargetInfo::canRelaxGot(uint32_t Type, const uint8_t *Data,
+                                   uint64_t Offset) const {
+  if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
+    return false;
+
+  // Converting mov foo at GOTPCREL(%rip), %reg to lea foo(%rip), %reg
+  // is the only supported relaxation for now.
+  return (Offset >= 2 && Data[Offset - 2] == 0x8b);
+}
+
+void X86_64TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  Loc[-2] = 0x8d;
+  relocateOne(Loc, R_X86_64_PC32, Val);
+}
+
 // Relocation masks following the #lo(value), #hi(value), #ha(value),
 // #higher(value), #highera(value), #highest(value), and #highesta(value)
 // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=270705&r1=270704&r2=270705&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Wed May 25 09:31:37 2016
@@ -88,6 +88,9 @@ public:
 
   uint32_t ThunkSize = 0;
 
+  virtual bool canRelaxGot(uint32_t Type, const uint8_t *Data,
+                           uint64_t Offset) const;
+  virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
   virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
   virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
   virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;

Added: lld/trunk/test/ELF/Inputs/gotpc-relax-und-dso.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/gotpc-relax-und-dso.s?rev=270705&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/gotpc-relax-und-dso.s (added)
+++ lld/trunk/test/ELF/Inputs/gotpc-relax-und-dso.s Wed May 25 09:31:37 2016
@@ -0,0 +1,4 @@
+.globl dsofoo
+.type dsofoo, @function
+dsofoo:
+ nop

Added: lld/trunk/test/ELF/gotpc-relax-und-dso.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gotpc-relax-und-dso.s?rev=270705&view=auto
==============================================================================
--- lld/trunk/test/ELF/gotpc-relax-und-dso.s (added)
+++ lld/trunk/test/ELF/gotpc-relax-und-dso.s Wed May 25 09:31:37 2016
@@ -0,0 +1,72 @@
+# 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:     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: 8b 05 60 10 00 00       movl    4192(%rip), %eax
+# DISASM-NEXT:    1040: 8b 05 5a 10 00 00       movl    4186(%rip), %eax
+# DISASM-NEXT:    1046: 8b 05 5c 10 00 00       movl    4188(%rip), %eax
+# DISASM-NEXT:    104c: 8b 05 56 10 00 00       movl    4182(%rip), %eax
+# DISASM-NEXT:    1052: 8d 05 a9 ff ff ff       leal    -87(%rip), %eax
+# DISASM-NEXT:    1058: 8d 05 a3 ff ff ff       leal    -93(%rip), %eax
+# DISASM-NEXT:    105e: 8b 05 4c 10 00 00       movl    4172(%rip), %eax
+# DISASM-NEXT:    1064: 8b 05 46 10 00 00       movl    4166(%rip), %eax
+
+.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 at GOTPCREL(%rip), %rax
+ movq und at GOTPCREL(%rip), %rax
+ movq dsofoo at GOTPCREL(%rip), %rax
+ movq dsofoo at GOTPCREL(%rip), %rax
+ movq hid at GOTPCREL(%rip), %rax
+ movq hid at GOTPCREL(%rip), %rax
+ movq foo at GOTPCREL(%rip), %rax
+ movq foo at GOTPCREL(%rip), %rax
+ movl und at GOTPCREL(%rip), %eax
+ movl und at GOTPCREL(%rip), %eax
+ movl dsofoo at GOTPCREL(%rip), %eax
+ movl dsofoo at GOTPCREL(%rip), %eax
+ movl hid at GOTPCREL(%rip), %eax
+ movl hid at GOTPCREL(%rip), %eax
+ movl foo at GOTPCREL(%rip), %eax
+ movl foo at GOTPCREL(%rip), %eax

Added: lld/trunk/test/ELF/gotpc-relax.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gotpc-relax.s?rev=270705&view=auto
==============================================================================
--- lld/trunk/test/ELF/gotpc-relax.s (added)
+++ lld/trunk/test/ELF/gotpc-relax.s Wed May 25 09:31:37 2016
@@ -0,0 +1,76 @@
+# 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
+# DISASM-NEXT: 1102d: 8d 05 cd ff ff ff    leal -51(%rip), %eax
+# DISASM-NEXT: 11033: 8d 05 c7 ff ff ff    leal -57(%rip), %eax
+# DISASM-NEXT: 11039: 8d 05 c2 ff ff ff    leal -62(%rip), %eax
+# DISASM-NEXT: 1103f: 8d 05 bc ff ff ff    leal -68(%rip), %eax
+# DISASM-NEXT: 11045: 8b 05 b5 0f 00 00    movl 4021(%rip), %eax
+# DISASM-NEXT: 1104b: 8b 05 af 0f 00 00    movl 4015(%rip), %eax
+# DISASM-NEXT: 11051: ff 15 b1 0f 00 00    callq *4017(%rip)
+# DISASM-NEXT: 11057: ff 25 a3 0f 00 00    jmpq *4003(%rip)
+
+.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 at GOTPCREL(%rip), %rax
+ movq foo at GOTPCREL(%rip), %rax
+ movq hid at GOTPCREL(%rip), %rax
+ movq hid at GOTPCREL(%rip), %rax
+ movq ifunc at GOTPCREL(%rip), %rax
+ movq ifunc at GOTPCREL(%rip), %rax
+ movl foo at GOTPCREL(%rip), %eax
+ movl foo at GOTPCREL(%rip), %eax
+ movl hid at GOTPCREL(%rip), %eax
+ movl hid at GOTPCREL(%rip), %eax
+ movl ifunc at GOTPCREL(%rip), %eax
+ movl ifunc at GOTPCREL(%rip), %eax
+
+## We check few other possible instructions
+## to see that they are not "relaxed" by mistake to lea.
+ call *foo at GOTPCREL(%rip)
+ jmp *ifunc at GOTPCREL(%rip)




More information about the llvm-commits mailing list