[lld] r270721 - [ELF] - Added support for jmp/call relaxations when R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX are used.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Wed May 25 09:51:12 PDT 2016


Author: grimar
Date: Wed May 25 11:51:08 2016
New Revision: 270721

URL: http://llvm.org/viewvc/llvm-project?rev=270721&view=rev
Log:
[ELF] - Added support for jmp/call relaxations when R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX are used.

D15779 introduced basic approach to support new relaxations.
This patch implements relaxations for jmp and call instructions,
described in 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")

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

Modified:
    lld/trunk/ELF/Target.cpp
    lld/trunk/test/ELF/gotpc-relax.s

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=270721&r1=270720&r2=270721&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Wed May 25 11:51:08 2016
@@ -740,14 +740,42 @@ bool X86_64TargetInfo::canRelaxGot(uint3
                                    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);
+  const uint8_t Op = Data[Offset - 2];
+  const uint8_t ModRm = Data[Offset - 1];
+  // Relax mov.
+  if (Op == 0x8b)
+    return true;
+  // Relax call and jmp.
+  return Op == 0xff && (ModRm == 0x15 || ModRm == 0x25);
 }
 
 void X86_64TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
-  Loc[-2] = 0x8d;
+  const uint8_t Op = Loc[-2];
+  const uint8_t ModRm = Loc[-1];
+
+  // Convert mov foo at GOTPCREL(%rip), %reg to lea foo(%rip), %reg.
+  if (Op == 0x8b) {
+    *(Loc - 2) = 0x8d;
+    relocateOne(Loc, R_X86_64_PC32, Val);
+    return;
+  }
+
+  assert(Op == 0xff);
+  if (ModRm == 0x15) {
+    // ABI says we can convert call *foo at GOTPCREL(%rip) to nop call foo.
+    // Instead we convert to addr32 call foo, where addr32 is instruction
+    // prefix. That makes result expression to be a single instruction.
+    *(Loc - 2) = 0x67; // addr32 prefix
+    *(Loc - 1) = 0xe8; // call
+  } else {
+    assert(ModRm == 0x25);
+    // Convert jmp *foo at GOTPCREL(%rip) to jmp foo nop.
+    // jmp doesn't return, so it is fine to use nop here, it is just a stub.
+    *(Loc - 2) = 0xe9; // jmp
+    *(Loc + 3) = 0x90; // nop
+    Loc -= 1;
+    Val += 1;
+  }
   relocateOne(Loc, R_X86_64_PC32, Val);
 }
 

Modified: lld/trunk/test/ELF/gotpc-relax.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gotpc-relax.s?rev=270721&r1=270720&r2=270721&view=diff
==============================================================================
--- lld/trunk/test/ELF/gotpc-relax.s (original)
+++ lld/trunk/test/ELF/gotpc-relax.s Wed May 25 11:51:08 2016
@@ -32,8 +32,22 @@
 # 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)
+# DISASM-NEXT: 11051: 67 e8 a9 ff ff ff    callq -87 <foo>
+# DISASM-NEXT: 11057: 67 e8 a3 ff ff ff    callq -93 <foo>
+# DISASM-NEXT: 1105d: 67 e8 9e ff ff ff    callq -98 <hid>
+# DISASM-NEXT: 11063: 67 e8 98 ff ff ff    callq -104 <hid>
+# DISASM-NEXT: 11069: ff 15 91 0f 00 00    callq *3985(%rip)
+# DISASM-NEXT: 1106f: ff 15 8b 0f 00 00    callq *3979(%rip)
+# DISASM-NEXT: 11075: e9 86 ff ff ff       jmp   -122 <foo>
+# DISASM-NEXT: 1107a: 90                   nop
+# DISASM-NEXT: 1107b: e9 80 ff ff ff       jmp   -128 <foo>
+# DISASM-NEXT: 11080: 90                   nop
+# DISASM-NEXT: 11081: e9 7b ff ff ff       jmp   -133 <hid>
+# DISASM-NEXT: 11086: 90                   nop
+# DISASM-NEXT: 11087: e9 75 ff ff ff       jmp   -139 <hid>
+# DISASM-NEXT: 1108c: 90                   nop
+# DISASM-NEXT: 1108d: ff 25 6d 0f 00 00    jmpq  *3949(%rip)
+# DISASM-NEXT: 11093: ff 25 67 0f 00 00    jmpq  *3943(%rip)
 
 .text
 .globl foo
@@ -70,7 +84,15 @@ _start:
  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)
+ call *foo at GOTPCREL(%rip)
+ call *hid at GOTPCREL(%rip)
+ call *hid at GOTPCREL(%rip)
+ call *ifunc at GOTPCREL(%rip)
+ call *ifunc at GOTPCREL(%rip)
+ jmp *foo at GOTPCREL(%rip)
+ jmp *foo at GOTPCREL(%rip)
+ jmp *hid at GOTPCREL(%rip)
+ jmp *hid at GOTPCREL(%rip)
+ jmp *ifunc at GOTPCREL(%rip)
  jmp *ifunc at GOTPCREL(%rip)




More information about the llvm-commits mailing list