From 9ff352cb602d5dd68bcd7bf2ba4711c8568271a9 Mon Sep 17 00:00:00 2001
From: George Rimar <grimar@accesssoftek.com>
Date: Tue, 20 Feb 2018 10:17:57 +0000
Subject: [PATCH] [llvm-mc] - Produce R_X86_64_PLT32 for "call/jmp foo".

For instructions like call foo and jmp foo patch changes
relocation produced from R_X86_64_PC32 to R_X86_64_PLT32.
Relocation can be used as a marker for 32-bit PC-relative branches.
Linker will reduce PLT32 relocation to PC32 if function is defined locally.

Differential revision: https://reviews.llvm.org/D43383

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@325569 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp |  3 ++
 .../X86/MCTargetDesc/X86ELFObjectWriter.cpp   |  3 ++
 lib/Target/X86/MCTargetDesc/X86FixupKinds.h   |  1 +
 .../X86/MCTargetDesc/X86MCCodeEmitter.cpp     | 32 +++++++++++++++++--
 .../X86/MCTargetDesc/X86MachObjectWriter.cpp  |  1 +
 .../MCTargetDesc/X86WinCOFFObjectWriter.cpp   |  1 +
 test/CodeGen/X86/cmp.ll                       |  2 +-
 test/CodeGen/X86/fma.ll                       |  8 ++---
 test/MC/ELF/basic-elf-64.s                    | 18 ++++++-----
 test/MC/ELF/ifunc-reloc.s                     |  2 +-
 test/MC/ELF/weak-diff.s                       |  2 +-
 test/MC/ELF/weak-relocation.s                 |  2 +-
 test/MC/ELF/weakref-reloc.s                   |  2 +-
 13 files changed, 58 insertions(+), 19 deletions(-)

diff --git a/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index 34db5918926..b301722b535 100644
--- a/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -46,6 +46,7 @@ static unsigned getFixupKindLog2Size(unsigned Kind) {
   case X86::reloc_signed_4byte:
   case X86::reloc_signed_4byte_relax:
   case X86::reloc_global_offset_table:
+  case X86::reloc_branch_4byte_pcrel:
   case FK_SecRel_4:
   case FK_Data_4:
     return 2;
@@ -95,6 +96,7 @@ public:
         {"reloc_signed_4byte_relax", 0, 32, 0},
         {"reloc_global_offset_table", 0, 32, 0},
         {"reloc_global_offset_table8", 0, 64, 0},
+        {"reloc_branch_4byte_pcrel", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
     };
 
     if (Kind < FirstTargetFixupKind)
@@ -102,6 +104,7 @@ public:
 
     assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
            "Invalid kind!");
+    assert(Infos[Kind - FirstTargetFixupKind].Name && "Empty fixup name!");
     return Infos[Kind - FirstTargetFixupKind];
   }
 
diff --git a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
index 4cdbae4d0d9..2ecbb80cd06 100644
--- a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
@@ -75,6 +75,9 @@ static X86_64RelType getType64(unsigned Kind,
   case X86::reloc_riprel_4byte_relax_rex:
   case X86::reloc_riprel_4byte_movq_load:
     return RT64_32;
+  case X86::reloc_branch_4byte_pcrel:
+    Modifier = MCSymbolRefExpr::VK_PLT;
+    return RT64_32;
   case FK_PCRel_2:
   case FK_Data_2:
     return RT64_16;
diff --git a/lib/Target/X86/MCTargetDesc/X86FixupKinds.h b/lib/Target/X86/MCTargetDesc/X86FixupKinds.h
index dfdc9ec29ae..3c04b13e002 100644
--- a/lib/Target/X86/MCTargetDesc/X86FixupKinds.h
+++ b/lib/Target/X86/MCTargetDesc/X86FixupKinds.h
@@ -30,6 +30,7 @@ enum Fixups {
                                              // of the instruction. Used only
                                              // for _GLOBAL_OFFSET_TABLE_.
   reloc_global_offset_table8,                // 64-bit variant.
+  reloc_branch_4byte_pcrel,                  // 32-bit PC relative branch.
   // Marker
   LastTargetFixupKind,
   NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 4ddc1f0ba42..608dc4acb04 100644
--- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -152,6 +152,8 @@ public:
 
   uint8_t DetermineREXPrefix(const MCInst &MI, uint64_t TSFlags,
                              int MemOperand, const MCInstrDesc &Desc) const;
+
+  bool isPCRel32Branch(const MCInst &MI) const;
 };
 
 } // end anonymous namespace
@@ -276,6 +278,22 @@ static bool HasSecRelSymbolRef(const MCExpr *Expr) {
   return false;
 }
 
+bool X86MCCodeEmitter::isPCRel32Branch(const MCInst &MI) const {
+  unsigned Opcode = MI.getOpcode();
+  const MCInstrDesc &Desc = MCII.get(Opcode);
+  if ((Opcode != X86::CALL64pcrel32 && Opcode != X86::JMP_4) ||
+      getImmFixupKind(Desc.TSFlags) != FK_PCRel_4)
+    return false;
+
+  unsigned CurOp = X86II::getOperandBias(Desc);
+  const MCOperand &Op = MI.getOperand(CurOp);
+  if (!Op.isExpr())
+    return false;
+
+  const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Op.getExpr());
+  return Ref && Ref->getKind() == MCSymbolRefExpr::VK_None;
+}
+
 void X86MCCodeEmitter::
 EmitImmediate(const MCOperand &DispOp, SMLoc Loc, unsigned Size,
               MCFixupKind FixupKind, unsigned &CurByte, raw_ostream &OS,
@@ -331,7 +349,8 @@ EmitImmediate(const MCOperand &DispOp, SMLoc Loc, unsigned Size,
       FixupKind == MCFixupKind(X86::reloc_riprel_4byte) ||
       FixupKind == MCFixupKind(X86::reloc_riprel_4byte_movq_load) ||
       FixupKind == MCFixupKind(X86::reloc_riprel_4byte_relax) ||
-      FixupKind == MCFixupKind(X86::reloc_riprel_4byte_relax_rex))
+      FixupKind == MCFixupKind(X86::reloc_riprel_4byte_relax_rex) ||
+      FixupKind == MCFixupKind(X86::reloc_branch_4byte_pcrel))
     ImmOffset -= 4;
   if (FixupKind == FK_PCRel_2)
     ImmOffset -= 2;
@@ -1287,9 +1306,18 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
     EmitByte(BaseOpcode, CurByte, OS);
     break;
   }
-  case X86II::RawFrm:
+  case X86II::RawFrm: {
     EmitByte(BaseOpcode, CurByte, OS);
+
+    if (!is64BitMode(STI) || !isPCRel32Branch(MI))
+      break;
+
+    const MCOperand &Op = MI.getOperand(CurOp++);
+    EmitImmediate(Op, MI.getLoc(), X86II::getSizeOfImm(TSFlags),
+                  MCFixupKind(X86::reloc_branch_4byte_pcrel), CurByte, OS,
+                  Fixups);
     break;
+  }
   case X86II::RawFrmMemOffs:
     // Emit segment override opcode prefix as needed.
     EmitSegmentOverridePrefix(CurByte, 1, MI, OS);
diff --git a/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp
index 965f7de809b..22773e64409 100644
--- a/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp
@@ -94,6 +94,7 @@ static unsigned getFixupKindLog2Size(unsigned Kind) {
   case X86::reloc_riprel_4byte_movq_load:
   case X86::reloc_signed_4byte:
   case X86::reloc_signed_4byte_relax:
+  case X86::reloc_branch_4byte_pcrel:
   case FK_Data_4: return 2;
   case FK_Data_8: return 3;
   }
diff --git a/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp
index 5139bb46b56..291056e3526 100644
--- a/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp
@@ -62,6 +62,7 @@ unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx,
     case X86::reloc_riprel_4byte_movq_load:
     case X86::reloc_riprel_4byte_relax:
     case X86::reloc_riprel_4byte_relax_rex:
+    case X86::reloc_branch_4byte_pcrel:
       return COFF::IMAGE_REL_AMD64_REL32;
     case FK_Data_4:
     case X86::reloc_signed_4byte:
diff --git a/test/CodeGen/X86/cmp.ll b/test/CodeGen/X86/cmp.ll
index 1ab8421638d..244e651e182 100644
--- a/test/CodeGen/X86/cmp.ll
+++ b/test/CodeGen/X86/cmp.ll
@@ -240,7 +240,7 @@ define i32 @test12() ssp uwtable {
 ; CHECK-NEXT:    pushq %rax # encoding: [0x50]
 ; CHECK-NEXT:    .cfi_def_cfa_offset 16
 ; CHECK-NEXT:    callq test12b # encoding: [0xe8,A,A,A,A]
-; CHECK-NEXT:    # fixup A - offset: 1, value: test12b-4, kind: FK_PCRel_4
+; CHECK-NEXT:    # fixup A - offset: 1, value: test12b-4, kind: reloc_branch_4byte_pcrel
 ; CHECK-NEXT:    testb %al, %al # encoding: [0x84,0xc0]
 ; CHECK-NEXT:    je .LBB12_2 # encoding: [0x74,A]
 ; CHECK-NEXT:    # fixup A - offset: 1, value: .LBB12_2-1, kind: FK_PCRel_1
diff --git a/test/CodeGen/X86/fma.ll b/test/CodeGen/X86/fma.ll
index 611f707d64c..2c919e3ebc9 100644
--- a/test/CodeGen/X86/fma.ll
+++ b/test/CodeGen/X86/fma.ll
@@ -137,7 +137,7 @@ define x86_fp80 @test_f80(x86_fp80 %a, x86_fp80 %b, x86_fp80 %c) #0 {
 ; FMA64-NEXT:    fstpt {{[0-9]+}}(%rsp) ## encoding: [0xdb,0x7c,0x24,0x10]
 ; FMA64-NEXT:    fstpt (%rsp) ## encoding: [0xdb,0x3c,0x24]
 ; FMA64-NEXT:    callq _fmal ## encoding: [0xe8,A,A,A,A]
-; FMA64-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: FK_PCRel_4
+; FMA64-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: reloc_branch_4byte_pcrel
 ; FMA64-NEXT:    addq $56, %rsp ## encoding: [0x48,0x83,0xc4,0x38]
 ; FMA64-NEXT:    retq ## encoding: [0xc3]
 ;
@@ -151,7 +151,7 @@ define x86_fp80 @test_f80(x86_fp80 %a, x86_fp80 %b, x86_fp80 %c) #0 {
 ; FMACALL64-NEXT:    fstpt {{[0-9]+}}(%rsp) ## encoding: [0xdb,0x7c,0x24,0x10]
 ; FMACALL64-NEXT:    fstpt (%rsp) ## encoding: [0xdb,0x3c,0x24]
 ; FMACALL64-NEXT:    callq _fmal ## encoding: [0xe8,A,A,A,A]
-; FMACALL64-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: FK_PCRel_4
+; FMACALL64-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: reloc_branch_4byte_pcrel
 ; FMACALL64-NEXT:    addq $56, %rsp ## encoding: [0x48,0x83,0xc4,0x38]
 ; FMACALL64-NEXT:    retq ## encoding: [0xc3]
 ;
@@ -165,7 +165,7 @@ define x86_fp80 @test_f80(x86_fp80 %a, x86_fp80 %b, x86_fp80 %c) #0 {
 ; AVX512-NEXT:    fstpt {{[0-9]+}}(%rsp) ## encoding: [0xdb,0x7c,0x24,0x10]
 ; AVX512-NEXT:    fstpt (%rsp) ## encoding: [0xdb,0x3c,0x24]
 ; AVX512-NEXT:    callq _fmal ## encoding: [0xe8,A,A,A,A]
-; AVX512-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: FK_PCRel_4
+; AVX512-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: reloc_branch_4byte_pcrel
 ; AVX512-NEXT:    addq $56, %rsp ## encoding: [0x48,0x83,0xc4,0x38]
 ; AVX512-NEXT:    retq ## encoding: [0xc3]
 ;
@@ -179,7 +179,7 @@ define x86_fp80 @test_f80(x86_fp80 %a, x86_fp80 %b, x86_fp80 %c) #0 {
 ; AVX512VL-NEXT:    fstpt {{[0-9]+}}(%rsp) ## encoding: [0xdb,0x7c,0x24,0x10]
 ; AVX512VL-NEXT:    fstpt (%rsp) ## encoding: [0xdb,0x3c,0x24]
 ; AVX512VL-NEXT:    callq _fmal ## encoding: [0xe8,A,A,A,A]
-; AVX512VL-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: FK_PCRel_4
+; AVX512VL-NEXT:    ## fixup A - offset: 1, value: _fmal-4, kind: reloc_branch_4byte_pcrel
 ; AVX512VL-NEXT:    addq $56, %rsp ## encoding: [0x48,0x83,0xc4,0x38]
 ; AVX512VL-NEXT:    retq ## encoding: [0xc3]
 entry:
diff --git a/test/MC/ELF/basic-elf-64.s b/test/MC/ELF/basic-elf-64.s
index 01f020bd64b..ae0903ec8cd 100644
--- a/test/MC/ELF/basic-elf-64.s
+++ b/test/MC/ELF/basic-elf-64.s
@@ -13,6 +13,7 @@ main:                                   # @main
 	callq	puts
 	xorl	%eax, %eax
 	addq	$8, %rsp
+    call foo@GOTPCREL
 	ret
 .Ltmp0:
 	.size	main, .Ltmp0-main
@@ -44,14 +45,15 @@ main:                                   # @main
 
 // CHECK:     Name: .rela.text
 
-// CHECK: Relocations [
-// CHECK:   Section {{.*}} .rela.text {
-// CHECK:     0x5  R_X86_64_32   .rodata.str1.1 0x0
-// CHECK:     0xA  R_X86_64_PC32 puts           0xFFFFFFFFFFFFFFFC
-// CHECK:     0xF  R_X86_64_32   .rodata.str1.1 0x6
-// CHECK:     0x14 R_X86_64_PC32 puts           0xFFFFFFFFFFFFFFFC
-// CHECK:   }
-// CHECK: ]
+// CHECK:      Relocations [
+// CHECK:        Section {{.*}} .rela.text {
+// CHECK-NEXT:     0x5  R_X86_64_32   .rodata.str1.1 0x0
+// CHECK-NEXT:     0xA  R_X86_64_PLT32 puts           0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0xF  R_X86_64_32   .rodata.str1.1 0x6
+// CHECK-NEXT:     0x14 R_X86_64_PLT32 puts           0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0x1F R_X86_64_GOTPCREL foo 0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
 
 // CHECK:   Symbol {
 // CHECK:     Binding: Local
diff --git a/test/MC/ELF/ifunc-reloc.s b/test/MC/ELF/ifunc-reloc.s
index 6f1d79b22c4..b4917371b0f 100644
--- a/test/MC/ELF/ifunc-reloc.s
+++ b/test/MC/ELF/ifunc-reloc.s
@@ -11,6 +11,6 @@ alias:
 
 // CHECK: Relocations [
 // CHECK-NEXT:   Section {{.*}} .rela.text {
-// CHECK-NEXT:     0x1 R_X86_64_PC32 sym 0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0x1 R_X86_64_PLT32 sym 0xFFFFFFFFFFFFFFFC
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
diff --git a/test/MC/ELF/weak-diff.s b/test/MC/ELF/weak-diff.s
index ded89b8f833..9785a2befb1 100644
--- a/test/MC/ELF/weak-diff.s
+++ b/test/MC/ELF/weak-diff.s
@@ -2,7 +2,7 @@
 
 // CHECK:      Relocations [
 // CHECK-NEXT:   Section ({{.*}}) .rela.text {
-// CHECK-NEXT:     0x1D R_X86_64_PC32 f2 0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0x1D R_X86_64_PLT32 f2 0xFFFFFFFFFFFFFFFC
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
 
diff --git a/test/MC/ELF/weak-relocation.s b/test/MC/ELF/weak-relocation.s
index 19153aa50da..defaf4e6a38 100644
--- a/test/MC/ELF/weak-relocation.s
+++ b/test/MC/ELF/weak-relocation.s
@@ -9,6 +9,6 @@ bar:
 
 // CHECK:      Relocations [
 // CHECK-NEXT:   Section ({{[0-9]+}}) .rela.text {
-// CHECK-NEXT:     0x1 R_X86_64_PC32 foo 0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0x1 R_X86_64_PLT32 foo 0xFFFFFFFFFFFFFFFC
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
diff --git a/test/MC/ELF/weakref-reloc.s b/test/MC/ELF/weakref-reloc.s
index baf80060c43..997aea0477a 100644
--- a/test/MC/ELF/weakref-reloc.s
+++ b/test/MC/ELF/weakref-reloc.s
@@ -9,6 +9,6 @@
 // CHECK:      Relocations [
 // CHECK-NEXT:   Section ({{[0-9]+}}) {{[^ ]+}} {
 // CHECK-NEXT:     0x1 R_X86_64_PLT32 zed 0xFFFFFFFFFFFFFFFC
-// CHECK-NEXT:     0x6 R_X86_64_PC32 foo 0xFFFFFFFFFFFFFFFC
+// CHECK-NEXT:     0x6 R_X86_64_PLT32 foo 0xFFFFFFFFFFFFFFFC
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
-- 
2.18.0

