OSDN Git Service

2009-10-12 Stefan Dösinger <stefan@codeweavers.com>
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Oct 2009 16:36:37 +0000 (16:36 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Oct 2009 16:36:37 +0000 (16:36 +0000)
* config/i386/i386.md (vswapmov): New.
* config/i386/i386.c (ix86_handle_fndecl_attribute): New.
(ix86_function_ms_hook_prologue): New.
(ix86_expand_prologue): Handle ms_hook_prologue attribute.
* configure.ac: Test for swap suffix support in as.
* configure: Rebuild.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152670 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/configure.ac
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/ms_hook_prologue.c [new file with mode: 0644]

index b79f323..0714158 100644 (file)
@@ -1,3 +1,12 @@
+2009-10-12  Stefan Dösinger  <stefan@codeweavers.com>
+        
+       * config/i386/i386.md (vswapmov): New.
+       * config/i386/i386.c (ix86_handle_fndecl_attribute): New.
+       (ix86_function_ms_hook_prologue): New.
+       (ix86_expand_prologue): Handle ms_hook_prologue attribute.
+       * configure.ac: Test for swap suffix support in as.
+       * configure: Rebuild.
+
 2009-10-12  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/41680
index b5bb6a0..73913b8 100644 (file)
@@ -4774,6 +4774,25 @@ ix86_function_type_abi (const_tree fntype)
   return ix86_abi;
 }
 
+static bool
+ix86_function_ms_hook_prologue (const_tree fntype)
+{
+  if (!TARGET_64BIT)
+    {
+      if (lookup_attribute ("ms_hook_prologue", DECL_ATTRIBUTES (fntype)))
+        {
+          if (decl_function_context (fntype) != NULL_TREE)
+          {
+            error_at (DECL_SOURCE_LOCATION (fntype),
+                "ms_hook_prologue is not compatible with nested function");
+          }
+
+          return true;
+        }
+    }
+  return false;
+}
+
 static enum calling_abi
 ix86_function_abi (const_tree fndecl)
 {
@@ -8295,6 +8314,7 @@ ix86_expand_prologue (void)
   bool pic_reg_used;
   struct ix86_frame frame;
   HOST_WIDE_INT allocate;
+  int gen_frame_pointer = frame_pointer_needed;
 
   ix86_finalize_stack_realign_flags ();
 
@@ -8307,6 +8327,46 @@ ix86_expand_prologue (void)
 
   ix86_compute_frame_layout (&frame);
 
+  if (ix86_function_ms_hook_prologue (current_function_decl))
+    {
+      rtx push, mov;
+
+      /* Make sure the function starts with
+         8b ff     movl.s %edi,%edi
+         55        push   %ebp
+         8b ec     movl.s %esp,%ebp
+
+         This matches the hookable function prologue in Win32 API functions in Microsoft Windows
+         XP Service Pack 2 and newer. Wine uses this to enable Windows apps to hook the Win32 API
+         functions provided by Wine */
+      insn = emit_insn (gen_vswapmov (gen_rtx_REG (SImode, DI_REG), gen_rtx_REG (SImode, DI_REG)));
+      push = emit_insn (gen_push (hard_frame_pointer_rtx));
+      mov = emit_insn (gen_vswapmov (hard_frame_pointer_rtx, stack_pointer_rtx));
+
+      if (frame_pointer_needed && !(crtl->drap_reg && crtl->stack_realign_needed))
+        {
+          /* The push %ebp and movl.s %esp, %ebp already set up the frame pointer. No need to do
+             this again. */
+          gen_frame_pointer = 0;
+          RTX_FRAME_RELATED_P (push) = 1;
+          RTX_FRAME_RELATED_P (mov) = 1;
+          if (ix86_cfa_state->reg == stack_pointer_rtx)
+            {
+              ix86_cfa_state->reg = hard_frame_pointer_rtx;
+            }
+        }
+      else
+        {
+          /* If the frame pointer is not needed, pop %ebp again. This could be optimized for cases where
+             ebp needs to be backed up for some other reason.
+
+             If stack realignment is needed, pop the base pointer again, align the stack, and later
+             regenerate the frame pointer setup. The frame pointer generated by the hook prologue
+             is not aligned, so it can't be used */
+          insn = emit_insn ((*ix86_gen_pop1) (hard_frame_pointer_rtx));
+        }
+    }
+
   /* The first insn of a function that accepts its static chain on the
      stack is to push the register that would be filled in by a direct
      call.  This insn will be skipped by the trampoline.  */
@@ -8378,7 +8438,7 @@ ix86_expand_prologue (void)
   /* Note: AT&T enter does NOT have reversed args.  Enter is probably
      slower on all targets.  Also sdb doesn't like it.  */
 
-  if (frame_pointer_needed)
+  if (gen_frame_pointer)
     {
       insn = emit_insn (gen_push (hard_frame_pointer_rtx));
       RTX_FRAME_RELATED_P (insn) = 1;
@@ -26470,6 +26530,35 @@ ix86_handle_struct_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+#include <signal.h>
+
+static tree
+ix86_handle_fndecl_attribute (tree *node, tree name,
+                              tree args ATTRIBUTE_UNUSED,
+                              int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+               name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (TARGET_64BIT)
+    {
+      warning (OPT_Wattributes, "%qE attribute only available for 32-bit",
+               name);
+      return NULL_TREE;
+    }
+
+#ifndef HAVE_AS_IX86_SWAP
+  sorry ("ms_hook_prologue attribute needs assembler swap suffix support");
+#endif
+
+    return NULL_TREE;
+}
+
 static bool
 ix86_ms_bitfield_layout_p (const_tree record_type)
 {
@@ -29512,6 +29601,7 @@ static const struct attribute_spec ix86_attribute_table[] =
   /* ms_abi and sysv_abi calling convention function attributes.  */
   { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
   { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+  { "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute },
   /* End element.  */
   { NULL,        0, 0, false, false, false, NULL }
 };
index 22ea39c..3fa938e 100644 (file)
    (UNSPECV_RDTSC              18)
    (UNSPECV_RDTSCP             19)
    (UNSPECV_RDPMC              20)
+   (UNSPECV_VSWAPMOV   21)
   ])
 
 ;; Constants to represent pcomtrue/pcomfalse variants
    (set_attr "length_immediate" "0")
    (set_attr "modrm" "0")])
 
+(define_insn "vswapmov"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (match_operand:SI 1 "register_operand" "r"))
+   (unspec_volatile [(const_int 0)] UNSPECV_VSWAPMOV)]
+  ""
+  "movl.s\t{%1, %0|%0, %1}"
+  [(set_attr "length" "2")
+   (set_attr "length_immediate" "0")
+   (set_attr "modrm" "0")])
+
 ;; Pad to 16-byte boundary, max skip in op0.  Used to avoid
 ;; branch prediction penalty for the third jump in a 16-byte
 ;; block on K8.
index 7947d28..dd3b7e8 100644 (file)
@@ -3047,6 +3047,12 @@ foo:     nop
       [AC_DEFINE(HAVE_AS_IX86_SAHF, 1,
         [Define if your assembler supports the sahf mnemonic.])])
 
+    gcc_GAS_CHECK_FEATURE([swap suffix],
+      gcc_cv_as_ix86_swap,,,
+      [movl.s %esp, %ebp],,
+      [AC_DEFINE(HAVE_AS_IX86_SWAP, 1,
+        [Define if your assembler supports the swap suffix.])])
+
     gcc_GAS_CHECK_FEATURE([different section symbol subtraction],
       gcc_cv_as_ix86_diff_sect_delta,,,
       [.section .rodata
index 6f09555..da886a3 100644 (file)
@@ -2679,6 +2679,14 @@ when targeting Windows.  On all other systems, the default is the AMD ABI.
 
 Note, This feature is currently sorried out for Windows targets trying to
 
+@item ms_hook_prologue
+@cindex @code{ms_hook_prologue} attribute
+
+On 32 bit i[34567]86-*-* targets, you can use this function attribute to make
+gcc generate the "hot-patching" function prologue used in Win32 API
+functions in Microsoft Windows XP Service Pack 2 and newer. This requires
+support for the swap suffix in the assembler. (GNU Binutils 2.19.51 or later)
+
 @item naked
 @cindex function without a prologue/epilogue code
 Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate that
index 0c03606..07c5ef5 100644 (file)
@@ -1,3 +1,7 @@
+2009-10-12  Stefan Dösinger  <stefan@codeweavers.com>
+
+       * gcc.target/i386/ms_hook_prologue.c: New testcase.
+
 2009-10-12  Michael Matz  <matz@suse.de>
 
        * gcc.dg/plugin/one_time_plugin.c: Update test to use the cfg
diff --git a/gcc/testsuite/gcc.target/i386/ms_hook_prologue.c b/gcc/testsuite/gcc.target/i386/ms_hook_prologue.c
new file mode 100644 (file)
index 0000000..19438e7
--- /dev/null
@@ -0,0 +1,29 @@
+/* Test that the ms_hook_prologue attribute generates the correct code.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -fomit-frame-pointer" } */
+
+int __attribute__ ((__ms_hook_prologue__)) foo ()
+{
+  unsigned char *ptr = (unsigned char *) foo;
+
+  /* The NOP mov must not be optimized away by optimizations.
+     The push %ebp, mov %esp, %ebp must not be removed by
+     -fomit-frame-pointer */
+
+  /* movl.s %edi, %edi */
+  if(*ptr++ != 0x8b) return 1;
+  if(*ptr++ != 0xff) return 1;
+  /* push %ebp */
+  if(*ptr++ != 0x55) return 1;
+  /* movl.s %esp, %ebp */
+  if(*ptr++ != 0x8b) return 1;
+  if(*ptr++ != 0xec) return 1;
+  return 0;
+}
+
+int main ()
+{
+  return foo();
+}