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)
{
bool pic_reg_used;
struct ix86_frame frame;
HOST_WIDE_INT allocate;
+ int gen_frame_pointer = frame_pointer_needed;
ix86_finalize_stack_realign_flags ();
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. */
/* 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;
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)
{
/* 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 }
};
--- /dev/null
+/* 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();
+}