OSDN Git Service

Cleanup 32-bit ms_hook code.
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 6d676b2..a77014c 100644 (file)
@@ -2201,6 +2201,14 @@ static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
   "bdver1"
 };
 \f
+/* Return true if a red-zone is in use.  */
+
+static inline bool
+ix86_using_red_zone (void)
+{
+  return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
+}
+
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
@@ -5109,17 +5117,15 @@ ix86_function_type_abi (const_tree fntype)
 }
 
 static bool
-ix86_function_ms_hook_prologue (const_tree fntype)
+ix86_function_ms_hook_prologue (const_tree fn)
 {
-  if (fntype && lookup_attribute ("ms_hook_prologue", DECL_ATTRIBUTES (fntype)))
+  if (fn && lookup_attribute ("ms_hook_prologue", DECL_ATTRIBUTES (fn)))
     {
-      if (decl_function_context (fntype) != NULL_TREE)
-      {
-       error_at (DECL_SOURCE_LOCATION (fntype),
-           "ms_hook_prologue is not compatible with nested function");
-      }
-
-      return true;
+      if (decl_function_context (fn) != NULL_TREE)
+       error_at (DECL_SOURCE_LOCATION (fn),
+                 "ms_hook_prologue is not compatible with nested function");
+      else
+        return true;
     }
   return false;
 }
@@ -5161,18 +5167,23 @@ ix86_asm_output_function_label (FILE *asm_out_file, const char *fname,
 
   ASM_OUTPUT_LABEL (asm_out_file, fname);
 
-  /* Output magic byte marker, if hot-patch attribute is set.
-     For x86 case frame-pointer prologue will be emitted in
-     expand_prologue.  */
+  /* Output magic byte marker, if hot-patch attribute is set.  */
   if (is_ms_hook)
     {
       if (TARGET_64BIT)
-       /* leaq [%rsp + 0], %rsp  */
-       asm_fprintf (asm_out_file, ASM_BYTE
-                    "0x48, 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00\n");
+       {
+         /* leaq [%rsp + 0], %rsp  */
+         asm_fprintf (asm_out_file, ASM_BYTE
+                      "0x48, 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00\n");
+       }
       else
-        /* movl.s %edi, %edi.  */
-       asm_fprintf (asm_out_file, ASM_BYTE "0x8b, 0xff\n");
+       {
+          /* movl.s %edi, %edi
+            push   %ebp
+            movl.s %esp, %ebp */
+         asm_fprintf (asm_out_file, ASM_BYTE
+                      "0x8b, 0xff, 0x55, 0x8b, 0xec\n");
+       }
     }
 }
 
@@ -8459,7 +8470,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
       || (TARGET_64BIT && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000))
     frame->save_regs_using_mov = false;
 
-  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE
+  if (ix86_using_red_zone ()
       && current_function_sp_is_unchanging
       && current_function_is_leaf
       && !ix86_current_function_calls_tls_descriptor)
@@ -8542,8 +8553,7 @@ static GTY(()) rtx queued_cfa_restores;
 static void
 ix86_add_cfa_restore_note (rtx insn, rtx reg, HOST_WIDE_INT red_offset)
 {
-  if (TARGET_RED_ZONE
-      && !TARGET_64BIT_MS_ABI
+  if (ix86_using_red_zone ()
       && red_offset + RED_ZONE_SIZE >= 0
       && crtl->args.pops_args < 65536)
     return;
@@ -9193,7 +9203,8 @@ ix86_expand_prologue (void)
   bool pic_reg_used;
   struct ix86_frame frame;
   HOST_WIDE_INT allocate;
-  int gen_frame_pointer = frame_pointer_needed;
+  bool gen_frame_pointer = frame_pointer_needed;
+  bool int_registers_saved = false;
 
   ix86_finalize_stack_realign_flags ();
 
@@ -9208,51 +9219,78 @@ ix86_expand_prologue (void)
 
   if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
     {
-      rtx push, mov;
+      /* We should have already generated an error for any use of
+         ms_hook on a nested function.  */
+      gcc_checking_assert (!ix86_static_chain_on_stack);
 
       /* Check if profiling is active and we shall use profiling before
          prologue variant. If so sorry.  */
       if (crtl->profile && flag_fentry != 0)
         sorry ("ms_hook_prologue attribute isn't compatible with -mfentry for 32-bit");
 
-      /* Make sure the function starts with
-        8b ff     movl.s %edi,%edi (emited by ix86_asm_output_function_label)
+      /* In ix86_asm_output_function_label we emitted:
+        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.  */
-      push = emit_insn (gen_push (hard_frame_pointer_rtx));
-      mov = emit_insn (gen_vswapmov (hard_frame_pointer_rtx,
-                                    stack_pointer_rtx));
+        functions provided by Wine.
+
+        What that means is that we've already set up the frame pointer.  */
 
-      if (frame_pointer_needed && !(crtl->drap_reg
-                                   && crtl->stack_realign_needed))
+      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 push, mov;
+
+         /* We've decided to use the frame pointer already set up.
+            Describe this to the unwinder by pretending that both
+            push and mov insns happen right here.
+
+            Putting the unwind info here at the end of the ms_hook
+            is done so that we can make absolutely certain we get
+            the required byte sequence at the start of the function,
+            rather than relying on an assembler that can produce
+            the exact encoding required.
+
+            However it does mean (in the unpatched case) that we have
+            a 1 insn window where the asynchronous unwind info is
+            incorrect.  However, if we placed the unwind info at
+            its correct location we would have incorrect unwind info
+            in the patched case.  Which is probably all moot since
+            I don't expect Wine generates dwarf2 unwind info for the
+            system libraries that use this feature.  */
+
+         insn = emit_insn (gen_blockage ());
+
+         push = gen_push (hard_frame_pointer_rtx);
+         mov = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+                            stack_pointer_rtx);
          RTX_FRAME_RELATED_P (push) = 1;
          RTX_FRAME_RELATED_P (mov) = 1;
+
+         RTX_FRAME_RELATED_P (insn) = 1;
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                       gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, push, mov)));
+
          if (ix86_cfa_state->reg == stack_pointer_rtx)
            ix86_cfa_state->reg = hard_frame_pointer_rtx;
+         gen_frame_pointer = false;
        }
       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 frame pointer is not needed so pop %ebp again.
+            This leaves us with a pristine state.  */
+         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.  */
-  if (ix86_static_chain_on_stack)
+  else if (ix86_static_chain_on_stack)
     {
       rtx t;
 
@@ -9347,7 +9385,10 @@ ix86_expand_prologue (void)
   allocate = frame.to_allocate + frame.nsseregs * 16 + frame.padding0;
 
   if (!frame.save_regs_using_mov)
-    ix86_emit_save_regs ();
+    {
+      ix86_emit_save_regs ();
+      int_registers_saved = true;
+    }
   else
     allocate += frame.nregs * UNITS_PER_WORD;
 
@@ -9356,7 +9397,7 @@ ix86_expand_prologue (void)
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
     {
       /* We expect the registers to be saved when probes are used.  */
-      gcc_assert (!frame.save_regs_using_mov);
+      gcc_assert (int_registers_saved);
 
       if (STACK_CHECK_MOVING_SP)
        {
@@ -9382,13 +9423,17 @@ ix86_expand_prologue (void)
      avoid doing this if I am going to have to probe the stack since
      at least on x86_64 the stack probe can turn into a call that clobbers
      a red zone location */
-  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE && frame.save_regs_using_mov
+  if (!int_registers_saved
+      && ix86_using_red_zone ()
       && (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT))
-    ix86_emit_save_regs_using_mov ((frame_pointer_needed
-                                    && !crtl->stack_realign_needed)
-                                   ? hard_frame_pointer_rtx
-                                  : stack_pointer_rtx,
-                                  -frame.nregs * UNITS_PER_WORD);
+    {
+      ix86_emit_save_regs_using_mov ((frame_pointer_needed
+                                     && !crtl->stack_realign_needed)
+                                     ? hard_frame_pointer_rtx
+                                    : stack_pointer_rtx,
+                                    -frame.nregs * UNITS_PER_WORD);
+      int_registers_saved = true;
+    }
 
   if (allocate == 0)
     ;
@@ -9439,9 +9484,7 @@ ix86_expand_prologue (void)
        }
     }
 
-  if (frame.save_regs_using_mov
-      && !(!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE
-         && (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)))
+  if (!int_registers_saved)
     {
       if (!frame_pointer_needed
          || !(frame.to_allocate + frame.padding0)
@@ -25768,7 +25811,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
   rtx result;
 
   gcc_assert (reload_completed);
-  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE)
+  if (ix86_using_red_zone ())
     {
       result = gen_rtx_MEM (mode,
                            gen_rtx_PLUS (Pmode,
@@ -25776,7 +25819,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
                                          GEN_INT (-RED_ZONE_SIZE)));
       emit_move_insn (result, operand);
     }
-  else if ((TARGET_64BIT_MS_ABI || !TARGET_RED_ZONE) && TARGET_64BIT)
+  else if (TARGET_64BIT)
     {
       switch (mode)
        {
@@ -25843,7 +25886,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
 void
 ix86_free_from_memory (enum machine_mode mode)
 {
-  if (!TARGET_RED_ZONE || TARGET_64BIT_MS_ABI)
+  if (!ix86_using_red_zone ())
     {
       int size;
 
@@ -26997,23 +27040,16 @@ ix86_handle_fndecl_attribute (tree *node, tree name,
       warning (OPT_Wattributes, "%qE attribute only applies to functions",
                name);
       *no_add_attrs = true;
-      return NULL_TREE;
     }
-
-#ifndef HAVE_AS_IX86_SWAP
-  if (!TARGET_64BIT)
-    sorry ("ms_hook_prologue attribute needs assembler swap suffix support");
-#endif
-
-    return NULL_TREE;
+  return NULL_TREE;
 }
 
 static bool
 ix86_ms_bitfield_layout_p (const_tree record_type)
 {
-  return (TARGET_MS_BITFIELD_LAYOUT &&
-         !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
-    || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
+  return ((TARGET_MS_BITFIELD_LAYOUT
+          && !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
+          || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type)));
 }
 
 /* Returns an expression indicating where the this parameter is