Index: gcc/config/i386/i386.c
===================================================================
--- gcc.orig/config/i386/i386.c
+++ gcc/config/i386/i386.c
@@ -8953,6 +8953,8 @@ output_set_got (rtx dest, rtx label ATTR
 	output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops);
       else
 	{
+	  /* For normal functions, this pattern is split, but we can still
+	     get here for thunks.  */
 	  output_asm_insn ("call\t%a2", xops);
 #ifdef DWARF2_UNWIND_INFO
 	  /* The call to next label acts as a push.  */
@@ -9010,12 +9012,6 @@ output_set_got (rtx dest, rtx label ATTR
       get_pc_thunk_name (name, REGNO (dest));
       pic_labels_used |= 1 << REGNO (dest);
 
-#ifdef DWARF2_UNWIND_INFO
-      /* Ensure all queued register saves are flushed before the
-	 call.  */
-      if (dwarf2out_do_frame ())
-	dwarf2out_flush_queued_reg_saves ();
-#endif
       xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
       xops[2] = gen_rtx_MEM (QImode, xops[2]);
       output_asm_insn ("call\t%X2", xops);
@@ -30458,6 +30454,56 @@ ix86_reorg (void)
      with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
   compute_bb_for_insn ();
 
+  /* Split any set_got patterns so that we interact correctly with
+     dwarf2out.  */
+  if (!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+      && flag_pic)
+    {
+      rtx insn, next;
+      for (insn = get_insns (); insn; insn = next)
+	{
+	  rtx pat, label, dest, cst, gotsym, new_insn;
+	  int icode;
+
+	  next = NEXT_INSN (insn);
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  icode = recog_memoized (insn);
+	  if (icode != CODE_FOR_set_got && icode != CODE_FOR_set_got_labelled)
+	    continue;
+
+	  extract_insn (insn);
+	  if (icode == CODE_FOR_set_got)
+	    {
+	      label = gen_label_rtx ();
+	      cst = const0_rtx;
+	    }
+	  else
+	    {
+	      label = recog_data.operand[1];
+	      cst = const1_rtx;
+	    }
+
+	  dest = recog_data.operand[0];
+	  pat = gen_set_got_call (label, cst);
+	  new_insn = emit_insn_before (pat, insn);
+	  RTX_FRAME_RELATED_P (new_insn) = 1;
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (new_insn), 0, 1)) = 1;
+	  gotsym = gen_rtx_SYMBOL_REF (Pmode, GOT_SYMBOL_NAME);
+	  pat = gen_set_got_pop (dest, label);
+	  new_insn = emit_insn_before (pat, insn);
+	  RTX_FRAME_RELATED_P (new_insn) = 1;
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (new_insn), 0, 1)) = 1;
+	  if (!TARGET_MACHO)
+	    {
+	      pat = gen_set_got_add (dest, gotsym, label);
+	      new_insn = emit_insn_before (pat, insn);
+	    }
+	  delete_insn (insn);
+	}
+    }
+
   if (optimize && optimize_function_for_speed_p (cfun))
     {
       if (TARGET_PAD_SHORT_FUNCTION)
@@ -30475,6 +30521,30 @@ ix86_reorg (void)
     move_or_delete_vzeroupper ();
 }
 
+/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
+   This is called from dwarf2out.c to emit call frame instructions
+   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs.  */
+static void
+i386_dwarf_handle_frame_unspec (rtx pattern ATTRIBUTE_UNUSED,
+				int index ATTRIBUTE_UNUSED)
+{
+  gcc_assert (index == UNSPEC_SET_GOT);
+}
+
+/* Handle the TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES hook.
+   This is called from dwarf2out.c to decide whether all queued
+   register saves should be emitted before INSN.  */
+static bool
+i386_dwarf_flush_queued_register_saves (rtx insn)
+{
+  if (!TARGET_VXWORKS_RTP || !flag_pic)
+    {
+      int icode = recog_memoized (insn);
+      return (icode == CODE_FOR_set_got || icode == CODE_FOR_set_got_labelled);
+    }
+  return false;
+}
+
 /* Return nonzero when QImode register that must be represented via REX prefix
    is used.  */
 bool
@@ -35321,6 +35391,13 @@ ix86_autovectorize_vector_sizes (void)
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL i386_output_dwarf_dtprel
 #endif
 
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC i386_dwarf_handle_frame_unspec
+
+#undef TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES
+#define TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES \
+  i386_dwarf_flush_queued_register_saves
+
 #ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
Index: gcc/config/i386/i386.md
===================================================================
--- gcc.orig/config/i386/i386.md
+++ gcc/config/i386/i386.md
@@ -11797,6 +11797,52 @@
   ""
   "ix86_expand_prologue (); DONE;")
 
+(define_insn "set_got_call"
+  [(unspec [(label_ref (match_operand 0 "" ""))
+	    (match_operand:SI 1 "const_int_operand" "")] UNSPEC_SET_GOT)
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4)))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+{
+  output_asm_insn ("call\t%l0", operands);
+#if TARGET_MACHO
+  /* If this was for an unlabelled set_got instruction, output the Mach-O
+     "canonical" label name ("Lxx$pb") here too.  This is what will be
+     referenced by the Mach-O PIC subsystem.  */
+  if (operands[1] == const0_rtx)
+    ASM_OUTPUT_LABEL (asm_out_file, MACHOPIC_FUNCTION_BASE_NAME);
+#endif
+  targetm.asm_out.internal_label (asm_out_file, "L",
+				  CODE_LABEL_NUMBER (operands[0]));
+  return "";
+}
+  [(set_attr "type" "call")
+   (set_attr "length" "5")])
+
+(define_insn "set_got_pop"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_SET_GOT))
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+  "pop%z0\t%0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "7")])
+
+(define_insn "set_got_add"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec [(match_dup 0)
+		 (match_operand 1 "" "")
+		 (label_ref (match_operand 2 "" ""))] UNSPEC_SET_GOT))
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+  "add%z0\t{%1+[.-%l2], %0|%0, %1+(.-%l2)}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "7")])
+
 (define_insn "set_got"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
Index: gcc/doc/tm.texi
===================================================================
--- gcc.orig/doc/tm.texi
+++ gcc/doc/tm.texi
@@ -3204,6 +3204,10 @@ terminate the stack backtrace.  New port
 @end defmac
 
 @deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (rtx @var{pattern}, int @var{index})
+
+@deftypefn {Target Hook} bool TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES (rtx @var{insn})
+This target hook allows the backend to force dwarf2out to flush queued register saves before an insn when generating unwind information.  It is called with an insn as its argument and should return true if register saves must be flushed.
+@end deftypefn
 This target hook allows the backend to emit frame-related insns that
 contain UNSPECs or UNSPEC_VOLATILEs.  The DWARF 2 call frame debugging
 info engine will invoke it on insns of the form
Index: gcc/dwarf2out.c
===================================================================
--- gcc.orig/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -2972,7 +2972,9 @@ scan_until_barrier (rtx insn, jump_targe
 	}
 
       if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)
-	  || (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END))
+	  || (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
+	  || (targetm.dwarf_flush_queued_register_saves != NULL
+	      && targetm.dwarf_flush_queued_register_saves (insn)))
 	{
 	  cfi_insn = PREV_INSN (insn);
 	  dwarf2out_flush_queued_reg_saves ();
Index: gcc/target.def
===================================================================
--- gcc.orig/target.def
+++ gcc/target.def
@@ -1794,6 +1794,14 @@ DEFHOOK
  "",
  void, (rtx pattern, int index), NULL)
 
+DEFHOOK
+(dwarf_flush_queued_register_saves,
+"This target hook allows the backend to force dwarf2out to flush queued\
+ register saves before an insn when generating unwind information.  It\
+ is called with an insn as its argument and should return true if\
+ register saves must be flushed.",
+ bool, (rtx insn), NULL)
+
 /* ??? Documenting this hook requires a GFDL license grant.  */
 DEFHOOK_UNDOC
 (stdarg_optimize_hook,
