]> granicus.if.org Git - clang/commitdiff
[Attr] Add support for the `ms_hook_prologue` attribute.
authorCharles Davis <cdavis5x@gmail.com>
Mon, 8 Aug 2016 21:03:39 +0000 (21:03 +0000)
committerCharles Davis <cdavis5x@gmail.com>
Mon, 8 Aug 2016 21:03:39 +0000 (21:03 +0000)
Summary:
Based on a patch by Michael Mueller.

This attribute specifies that a function can be hooked or patched. This
mechanism was originally devised by Microsoft for hotpatching their
binaries (which they're constantly updating to stay ahead of crackers,
script kiddies, and other ne'er-do-wells on the Internet), but it's now
commonly abused by Windows programs that want to hook API functions. It
is for this reason that this attribute was added to GCC--hence the name,
`ms_hook_prologue`.

Depends on D19908.

Reviewers: rnk, aaron.ballman

Subscribers: cfe-commits

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

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

include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
lib/CodeGen/TargetInfo.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/function-attributes.c
test/Sema/attr-ms-hook-prologue-wrong-arch.c [new file with mode: 0644]
test/Sema/attr-ms-hook-prologue.c [new file with mode: 0644]

index 7da1efe5ff4054b169d46fd2a59326f7af1b3504..49a3273b77f321e51b1c4677515abae9f1683751 100644 (file)
@@ -257,6 +257,7 @@ def TargetMips : TargetArch<["mips", "mipsel"]>;
 def TargetMSP430 : TargetArch<["msp430"]>;
 def TargetX86 : TargetArch<["x86"]>;
 def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
+def TargetWindowsArches : TargetArch<["x86", "x86_64", "arm", "thumb"]>;
 def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
   let OSes = ["Win32"];
 }
@@ -2069,6 +2070,12 @@ def TypeTagForDatatype : InheritableAttr {
 
 // Microsoft-related attributes
 
+def MSHookPrologue : InheritableAttr, TargetSpecificAttr<TargetWindowsArches> {
+  let Spellings = [GCC<"ms_hook_prologue">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [MSHookPrologueDocs];
+}
+
 def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
   let Spellings = [Declspec<"novtable">];
   let Subjects = SubjectList<[CXXRecord]>;
index 9b1ddca05a5d247058007a3182908f86a810fc11..4a78f53754fc4a9c61cc18594e1a9b04ca92861d 100644 (file)
@@ -548,6 +548,22 @@ Query for this feature with ``__has_attribute(objc_method_family)``.
   }];
 }
 
+def MSHookPrologueDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``ms_hook_prologue`` attribute marks a function as "hotpatchable" according
+to conventions used on Windows. Specifically, enough space will be ensured
+in the prologue for a short jump, and an architecturally dependently sized
+patch space will be reserved prior to the entry point. See the documentation
+for the `/HOTPATCH`_ switch on MSDN.
+
+This attribute cannot be used in conjunction with the ``naked``,
+``always_inline``, or ``__forceinline`` attributes.
+
+.. _`/HOTPATCH`: https://msdn.microsoft.com/en-us/library/ms173507.aspx
+  }];
+}
+
 def NoDebugDocs : Documentation {
   let Category = DocCatVariable;
   let Content = [{
index fa1b58ddd52190935a5cc8da7b49e0611f7af89e..1e8ac6399316da04b2032bcf89e7a81a40a080cd 100644 (file)
@@ -1779,6 +1779,10 @@ void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
       llvm::Function *Fn = cast<llvm::Function>(GV);
       Fn->setCallingConv(llvm::CallingConv::X86_INTR);
     }
+    if (FD->hasAttr<MSHookPrologueAttr>()) {
+      llvm::Function *Fn = cast<llvm::Function>(GV);
+      Fn->addFnAttr("patchable-function", "ms-hotpatch");
+    }
   }
 }
 
@@ -2109,6 +2113,10 @@ public:
         llvm::Function *Fn = cast<llvm::Function>(GV);
         Fn->setCallingConv(llvm::CallingConv::X86_INTR);
       }
+      if (FD->hasAttr<MSHookPrologueAttr>()) {
+        llvm::Function *Fn = cast<llvm::Function>(GV);
+        Fn->addFnAttr("patchable-function", "ms-hotpatch");
+      }
     }
   }
 };
index d74cebc718c7e40721fabc1028094122d797ce68..5dbe7aa52eaf69b053827176b284f6ce1de1856e 100644 (file)
@@ -1664,15 +1664,6 @@ static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
     D->addAttr(CA);
 }
 
-static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(),
-                                                     Attr.getName()))
-    return;
-
-  D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context,
-                                         Attr.getAttributeSpellingListIndex()));
-}
-
 static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
   if (hasDeclarator(D)) return;
 
@@ -3673,7 +3664,9 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
 static void handleAlwaysInlineAttr(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
   if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(),
-                                                  Attr.getName()))
+                                                  Attr.getName()) ||
+      checkAttrMutualExclusion<MSHookPrologueAttr>(S, D, Attr.getRange(),
+                                                   Attr.getName()))
     return;
 
   if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
@@ -5552,7 +5545,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
     handleHotAttr(S, D, Attr);
     break;
   case AttributeList::AT_Naked:
-    handleNakedAttr(S, D, Attr);
+    handleSimpleAttributeWithExclusions<NakedAttr, DisableTailCallsAttr,
+                                        MSHookPrologueAttr>(S, D, Attr);
     break;
   case AttributeList::AT_NoReturn:
     handleNoReturnAttr(S, D, Attr);
@@ -5780,6 +5774,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
     break;
   case AttributeList::AT_LayoutVersion:
     handleLayoutVersion(S, D, Attr);
+  case AttributeList::AT_MSHookPrologue:
+    handleSimpleAttributeWithExclusions<MSHookPrologueAttr, NakedAttr,
+      AlwaysInlineAttr>(S, D, Attr);
     break;
   case AttributeList::AT_MSNoVTable:
     handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr);
index 8f682a715d73bdef1578911bde85e85a1080e21d..d0374c186601ea888c489b044e7ddb28642afbf7 100644 (file)
@@ -108,11 +108,18 @@ void f20(void) {
   _setjmp(0);
 }
 
+// CHECK-LABEL: define void @f21
+// CHECK: [[HOTPATCH:#[0-9]+]]
+// CHECK: {
+void __attribute__((ms_hook_prologue)) f21(void) {
+}
+
 // CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} }
 // CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} }
 // CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} }
 // CHECK: attributes [[ALIGN]] = { nounwind optsize alignstack=16{{.*}} }
 // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
+// CHECK: attributes [[HOTPATCH]] = { nounwind optsize{{.*}}"patchable-function"="ms-hotpatch"{{.*}} }
 // CHECK: attributes [[NR]] = { noreturn optsize }
 // CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone }
 // CHECK: attributes [[RT_CALL]] = { optsize returns_twice }
diff --git a/test/Sema/attr-ms-hook-prologue-wrong-arch.c b/test/Sema/attr-ms-hook-prologue-wrong-arch.c
new file mode 100644 (file)
index 0000000..cd4b591
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple s390x-unknown-linux -fms-extensions -fsyntax-only -verify %s
+
+// expected-warning@+1{{unknown attribute 'ms_hook_prologue' ignored}}
+int __attribute__((ms_hook_prologue)) foo(int a, int b) {
+  return a+b;
+}
diff --git a/test/Sema/attr-ms-hook-prologue.c b/test/Sema/attr-ms-hook-prologue.c
new file mode 100644 (file)
index 0000000..5417f4a
--- /dev/null
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple i386-pc-linux -fms-extensions -fsyntax-only -verify %s
+
+int __attribute__((ms_hook_prologue)) foo(int a, int b) {
+  return a+b;
+}
+
+// expected-note@+2{{conflicting attribute is here}}
+// expected-error@+1{{'naked' and 'ms_hook_prologue' attributes are not compatible}}
+__declspec(naked) int __attribute__((ms_hook_prologue)) bar(int a, int b) {
+}
+
+// expected-note@+2{{conflicting attribute is here}}
+// expected-error@+1{{'__forceinline' and 'ms_hook_prologue' attributes are not compatible}}
+__forceinline int __attribute__((ms_hook_prologue)) baz(int a, int b) {
+  return a-b;
+}
+
+// expected-warning@+1{{'ms_hook_prologue' attribute only applies to functions}}
+int x __attribute__((ms_hook_prologue));
+
+// expected-error@+1{{'ms_hook_prologue' attribute takes no arguments}}
+int f(int a, int b) __attribute__((ms_hook_prologue(2)));