From afd2c302c6f4377ed46d809744115e67d363d997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Mon, 12 Oct 2009 16:36:37 +0000 Subject: [PATCH] i386.md (vswapmov): New. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2009-10-12 Stefan Dösinger * 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. From-SVN: r152670 --- gcc/ChangeLog | 9 ++ gcc/config/i386/i386.c | 92 ++++++++++++++++++- gcc/config/i386/i386.md | 11 +++ gcc/configure.ac | 6 ++ gcc/doc/extend.texi | 8 ++ gcc/testsuite/ChangeLog | 4 + .../gcc.target/i386/ms_hook_prologue.c | 29 ++++++ 7 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/ms_hook_prologue.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b79f323a11e..0714158ea99 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2009-10-12 Stefan Dösinger + + * 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 PR target/41680 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index b5bb6a0352f..73913b8376d 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -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 + +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 } }; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 22ea39cf79b..3fa938ea3bb 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -241,6 +241,7 @@ (UNSPECV_RDTSC 18) (UNSPECV_RDTSCP 19) (UNSPECV_RDPMC 20) + (UNSPECV_VSWAPMOV 21) ]) ;; Constants to represent pcomtrue/pcomfalse variants @@ -14893,6 +14894,16 @@ (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. diff --git a/gcc/configure.ac b/gcc/configure.ac index 7947d285629..dd3b7e890d2 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -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 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6f0955577c3..da886a30f11 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0c0360679e6..07c5ef5c442 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-10-12 Stefan Dösinger + + * gcc.target/i386/ms_hook_prologue.c: New testcase. + 2009-10-12 Michael Matz * 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 index 00000000000..19438e7583f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/ms_hook_prologue.c @@ -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(); +}