]> granicus.if.org Git - llvm/commitdiff
CFI-icall on Thumb
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Thu, 8 Dec 2016 00:32:26 +0000 (00:32 +0000)
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Thu, 8 Dec 2016 00:32:26 +0000 (00:32 +0000)
Replace @progbits in the section directive with %progbits, because "@" starts a comment on arm/thumb.
Use b.w branch instruction.
Use .thumb_function and .thumb_set for proper arm/thumb interwork. This way jumptable entry addresses on thumb have bit 0 set (correctly). This does not affect CFI check math, because the address of the jumptable start also has that bit set.

This does not work on thumbv5, because it does not support b.w, and the linker would not insert a veneer (trampoline?) to extend the range of b.n. We may need to do full-range plt-style jumptables on thumbv54, which are 12 bytes per entry. Another option is "push lr; bl; pop pc" (4 bytes) but that needs unwinding instructions, etc.

Differential Revision: https://reviews.llvm.org/D27499

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289008 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/LowerTypeTests.cpp
test/Transforms/LowerTypeTests/function.ll

index 421c8284edb6fb1a5628f58699290ac785ba5273..753eb4c31e7520b90bac284d994f3529cd703922 100644 (file)
@@ -683,6 +683,7 @@ unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
     case Triple::x86_64:
       return kX86JumpTableEntrySize;
     case Triple::arm:
+    case Triple::thumb:
     case Triple::aarch64:
       return kARMJumpTableEntrySize;
     default:
@@ -730,6 +731,8 @@ void LowerTypeTestsModule::createJumpTableEntry(raw_ostream &OS, Function *Dest,
     OS << "int3\nint3\nint3\n";
   } else if (Arch == Triple::arm || Arch == Triple::aarch64) {
     OS << "b " << Name << "\n";
+  } else if (Arch == Triple::thumb) {
+    OS << "b.w " << Name << "\n";
   } else {
     report_fatal_error("Unsupported architecture for jump tables");
   }
@@ -754,8 +757,13 @@ void LowerTypeTestsModule::createJumpTableAlias(raw_ostream &OS, Function *Dest,
   else if (!Dest->hasLocalLinkage())
     OS << ".globl " << Name << "\n";
   OS << ".type " << Name << ", function\n";
-  OS << Name << " = " << JumpTable->getName() << " + "
-     << (getJumpTableEntrySize() * Distance) << "\n";
+  if (Arch == Triple::thumb) {
+    OS << ".thumb_set " << Name << ", " << JumpTable->getName() << " + "
+       << (getJumpTableEntrySize() * Distance) << "\n";
+  } else {
+    OS << Name << " = " << JumpTable->getName() << " + "
+       << (getJumpTableEntrySize() * Distance) << "\n";
+  }
   OS << ".size " << Name << ", " << getJumpTableEntrySize() << "\n";
 }
 
@@ -768,7 +776,7 @@ Type *LowerTypeTestsModule::getJumpTableEntryType() {
 void LowerTypeTestsModule::buildBitSetsFromFunctions(
     ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalTypeMember *> Functions) {
   if (Arch == Triple::x86 || Arch == Triple::x86_64 || Arch == Triple::arm ||
-      Arch == Triple::aarch64)
+      Arch == Triple::thumb || Arch == Triple::aarch64)
     buildBitSetsFromFunctionsNative(TypeIds, Functions);
   else if (Arch == Triple::wasm32 || Arch == Triple::wasm64)
     buildBitSetsFromFunctionsWASM(TypeIds, Functions);
@@ -990,10 +998,12 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
   // FIXME: this magic section name seems to do the trick.
   AsmOS << ".section " << (ObjectFormat == Triple::MachO
                                ? "__TEXT,__text,regular,pure_instructions"
-                               : ".text.cfi, \"ax\", @progbits")
+                               : ".text.cfi, \"ax\", %progbits")
         << "\n";
   // Align the whole table by entry size.
   AsmOS << ".balign " << EntrySize << "\n";
+  if (Arch == Triple::thumb)
+    AsmOS << ".thumb_func\n";
   AsmOS << JumpTable->getName() << ":\n";
   for (unsigned I = 0; I != Functions.size(); ++I)
     createJumpTableEntry(AsmOS, cast<Function>(Functions[I]->getGlobal()), I);
index 7b7a6af320aa9a04da80eeca7d8914bb6ad2765e..effe76959038f129575c168112f31c159ffd7cf3 100644 (file)
@@ -1,7 +1,8 @@
-; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefix=X86 %s
-; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X86 %s
-; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck --check-prefix=ARM %s
-; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefix=ARM %s
+; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,NATIVE %s
+; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,NATIVE %s
+; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck --check-prefixes=ARM,NATIVE %s
+; RUN: opt -S -lowertypetests -mtriple=thumb-unknown-linux-gnu < %s | FileCheck --check-prefixes=THUMB,NATIVE %s
+; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefixes=ARM,NATIVE %s
 ; RUN: opt -S -lowertypetests -mtriple=wasm32-unknown-unknown < %s | FileCheck --check-prefix=WASM32 %s
 
 ; Tests that we correctly handle bitsets containing 2 or more functions.
@@ -15,7 +16,7 @@ target datalayout = "e-p:64:64"
 ; X86-NEXT: module asm ".type g, function"
 ; X86-NEXT: module asm "g = .cfi.jumptable + 8"
 ; X86-NEXT: module asm ".size g, 8"
-; X86-NEXT: module asm ".section .text.cfi, \22ax\22, @progbits"
+; X86-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits"
 ; X86-NEXT: module asm ".balign 8"
 ; X86-NEXT: module asm ".cfi.jumptable:"
 ; X86-NEXT: module asm "jmp f.cfi@plt"
@@ -34,30 +35,43 @@ target datalayout = "e-p:64:64"
 ; ARM-NEXT: module asm ".type g, function"
 ; ARM-NEXT: module asm "g = .cfi.jumptable + 4"
 ; ARM-NEXT: module asm ".size g, 4"
-; ARM-NEXT: module asm ".section .text.cfi, \22ax\22, @progbits"
+; ARM-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits"
 ; ARM-NEXT: module asm ".balign 4"
 ; ARM-NEXT: module asm ".cfi.jumptable:"
 ; ARM-NEXT: module asm "b f.cfi"
 ; ARM-NEXT: module asm "b g.cfi"
 
+; THUMB:      module asm ".globl f"
+; THUMB-NEXT: module asm ".type f, function"
+; THUMB-NEXT: module asm ".thumb_set f, .cfi.jumptable + 0"
+; THUMB-NEXT: module asm ".size f, 4"
+; THUMB-NEXT: module asm ".type g, function"
+; THUMB-NEXT: module asm ".thumb_set g, .cfi.jumptable + 4"
+; THUMB-NEXT: module asm ".size g, 4"
+; THUMB-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits"
+; THUMB-NEXT: module asm ".balign 4"
+; THUMB-NEXT: module asm ".thumb_func"
+; THUMB-NEXT: module asm ".cfi.jumptable:"
+; THUMB-NEXT: module asm "b.w f.cfi"
+; THUMB-NEXT: module asm "b.w g.cfi"
+
+
 ; X86: @.cfi.jumptable = external hidden constant [2 x [8 x i8]]
 ; ARM: @.cfi.jumptable = external hidden constant [2 x [4 x i8]]
+; THUMB: @.cfi.jumptable = external hidden constant [2 x [4 x i8]]
 
 ; WASM32: private constant [0 x i8] zeroinitializer
 @0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
 
-; X86: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata"
-; ARM: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata"
+; NATIVE: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata"
 
-; X86: define internal void @f.cfi()
-; ARM: define internal void @f.cfi()
+; NATIVE: define internal void @f.cfi()
 ; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]]
 define void @f() !type !0 {
   ret void
 }
 
-; X86: define internal void @g.cfi()
-; ARM: define internal void @g.cfi()
+; NATIVE: define internal void @g.cfi()
 ; WASM32: define internal void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
 define internal void @g() !type !0 {
   ret void
@@ -76,10 +90,8 @@ define i1 @foo(i8* %p) {
   ret i1 %x
 }
 
-; X86: declare void @f()
-; ARM: declare void @f()
-; X86: declare hidden void @g()
-; ARM: declare hidden void @g()
+; NATIVE: declare void @f()
+; NATIVE: declare hidden void @g()
 
 ; WASM32: ![[I0]] = !{i64 1}
 ; WASM32: ![[I1]] = !{i64 2}