]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/45807 (Lying eh_frame r2 save info causes crashes with static libgcc_eh...
authorAlan Modra <amodra@gmail.com>
Wed, 17 Nov 2010 06:09:53 +0000 (16:39 +1030)
committerAlan Modra <amodra@gcc.gnu.org>
Wed, 17 Nov 2010 06:09:53 +0000 (16:39 +1030)
PR target/45807
Backport r164685,r164825,r165101
* config/rs6000/aix.h (SETUP_FRAME_ADDRESSES): Delete.
* config/rs6000/linux64.h (SETUP_FRAME_ADDRESSES): Delete.
* config/rs6000/rs6000-protos.h (rs6000_aix_emit_builtin_unwind_init):
Delete.
* config/rs6000/rs6000.c (rs6000_aix_emit_builtin_unwind_init): Delete.
(rs6000_emit_prologue): Don't just create frame save info for r2,
actually save r2.

From-SVN: r166857

gcc/ChangeLog
gcc/config/rs6000/aix.h
gcc/config/rs6000/linux64.h
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c

index 58f9160f01d17a5b30e8317c5c209bfa8894bcc3..3602b6c4e96d81742e4e0cabfd9fe19413eccd58 100644 (file)
@@ -1,3 +1,14 @@
+2010-11-17  Alan Modra  <amodra@gmail.com>
+
+       PR target/45807
+       * config/rs6000/aix.h (SETUP_FRAME_ADDRESSES): Delete.
+       * config/rs6000/linux64.h (SETUP_FRAME_ADDRESSES): Delete.
+       * config/rs6000/rs6000-protos.h (rs6000_aix_emit_builtin_unwind_init):
+       Delete.
+       * config/rs6000/rs6000.c (rs6000_aix_emit_builtin_unwind_init): Delete.
+       (rs6000_emit_prologue): Don't just create frame save info for r2,
+       actually save r2.
+
 2010-11-17  Alan Modra  <amodra@gmail.com>
 
        PR target/44266
index ec7add4c2e64242bd5a1a46f77107a29451a2324..758c72b327200e62c446e28f51cae47ef35457d9 100644 (file)
 /* And similarly for general purpose registers.  */
 #define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32)
 
-/* __throw will restore its own return address to be the same as the
-   return address of the function that the throw is being made to.
-   This is unfortunate, because we want to check the original
-   return address to see if we need to restore the TOC.
-   So we have to squirrel it away with this.  */
-#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
-
 /* If the current unwind info (FS) does not contain explicit info
    saving R2, then we have to do a minor amount of code reading to
    figure out if it was saved.  The big problem here is that the
index da7bca3037c23fcf9fbd21c59eee5f89b12ef80d..305647e1807a3d417f309cd8b7d563a49a3e8ad1 100644 (file)
@@ -273,14 +273,6 @@ extern int dot_symbols;
 #define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
   (!(FIRST) ? upward : FUNCTION_ARG_PADDING (MODE, TYPE))
 
-/* __throw will restore its own return address to be the same as the
-   return address of the function that the throw is being made to.
-   This is unfortunate, because we want to check the original
-   return address to see if we need to restore the TOC.
-   So we have to squirrel it away with this.  */
-#define SETUP_FRAME_ADDRESSES() \
-  do { if (TARGET_64BIT) rs6000_aix_emit_builtin_unwind_init (); } while (0)
-
 /* Override svr4.h  */
 #undef MD_EXEC_PREFIX
 #undef MD_STARTFILE_PREFIX
index 14b5496a2f836f70007599ba512896e188f9bc24..3c24dfcc73dce406383a0cfc59fc341f7d723832 100644 (file)
@@ -167,7 +167,6 @@ extern int rs6000_trampoline_size (void);
 extern alias_set_type get_TOC_alias_set (void);
 extern void rs6000_emit_prologue (void);
 extern void rs6000_emit_load_toc_table (int);
-extern void rs6000_aix_emit_builtin_unwind_init (void);
 extern unsigned int rs6000_dbx_register_number (unsigned int);
 extern void rs6000_emit_epilogue (int);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
index 9545d3e3da388b6ce77bd602c61c9362baccb5f6..01e6d7167ec6bf6dab08101db4ef4f098f148b5c 100644 (file)
@@ -17970,42 +17970,6 @@ rs6000_aix_asm_output_dwarf_table_ref (char * frame_table_label)
   fprintf (asm_out_file, "\t.ref %s\n",
           TARGET_STRIP_NAME_ENCODING (frame_table_label));
 }
-
-/* If _Unwind_* has been called from within the same module,
-   toc register is not guaranteed to be saved to 40(1) on function
-   entry.  Save it there in that case.  */
-
-void
-rs6000_aix_emit_builtin_unwind_init (void)
-{
-  rtx mem;
-  rtx stack_top = gen_reg_rtx (Pmode);
-  rtx opcode_addr = gen_reg_rtx (Pmode);
-  rtx opcode = gen_reg_rtx (SImode);
-  rtx tocompare = gen_reg_rtx (SImode);
-  rtx no_toc_save_needed = gen_label_rtx ();
-
-  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
-  emit_move_insn (stack_top, mem);
-
-  mem = gen_frame_mem (Pmode,
-                      gen_rtx_PLUS (Pmode, stack_top,
-                                    GEN_INT (2 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (opcode_addr, mem);
-  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
-  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
-                                          : 0xE8410028, SImode));
-
-  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
-                          SImode, NULL_RTX, NULL_RTX,
-                          no_toc_save_needed, -1);
-
-  mem = gen_frame_mem (Pmode,
-                      gen_rtx_PLUS (Pmode, stack_top,
-                                    GEN_INT (5 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
-  emit_label (no_toc_save_needed);
-}
 \f
 /* This ties together stack memory (MEM with an alias set of frame_alias_set)
    and the change to the stack pointer.  */
@@ -19154,22 +19118,6 @@ rs6000_emit_prologue (void)
     {
       unsigned int i, regno;
 
-      /* In AIX ABI we need to pretend we save r2 here.  */
-      if (TARGET_AIX)
-       {
-         rtx addr, reg, mem;
-
-         reg = gen_rtx_REG (reg_mode, 2);
-         addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (sp_offset + 5 * reg_size));
-         mem = gen_frame_mem (reg_mode, addr);
-
-         insn = emit_move_insn (mem, reg);
-         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                               NULL_RTX, NULL_RTX);
-         PATTERN (insn) = gen_blockage ();
-       }
-
       for (i = 0; ; ++i)
        {
          regno = EH_RETURN_DATA_REGNO (i);
@@ -19183,6 +19131,51 @@ rs6000_emit_prologue (void)
        }
     }
 
+  /* In AIX ABI we need to make sure r2 is really saved.  */
+  if (TARGET_AIX && crtl->calls_eh_return)
+    {
+      rtx tmp_reg, tmp_reg_si, hi, lo, compare_result, toc_save_done, jump;
+      long toc_restore_insn;
+
+      gcc_assert (frame_reg_rtx == frame_ptr_rtx
+                 || frame_reg_rtx == sp_reg_rtx);
+      tmp_reg = gen_rtx_REG (Pmode, 11);
+      tmp_reg_si = gen_rtx_REG (SImode, 11);
+      if (using_static_chain_p)
+       emit_move_insn (gen_rtx_REG (Pmode, 0), tmp_reg);
+      gcc_assert (saving_GPRs_inline && saving_FPRs_inline);
+      emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, LR_REGNO));
+      /* Peek at instruction to which this function returns.  If it's
+        restoring r2, then we know we've already saved r2.  We can't
+        unconditionally save r2 because the value we have will already
+        be updated if we arrived at this function via a plt call or
+        toc adjusting stub.  */
+      emit_move_insn (tmp_reg_si, gen_rtx_MEM (SImode, tmp_reg));
+      toc_restore_insn = TARGET_32BIT ? 0x80410014 : 0xE8410028;
+      hi = gen_int_mode (toc_restore_insn & ~0xffff, SImode);
+      emit_insn (gen_xorsi3 (tmp_reg_si, tmp_reg_si, hi));
+      compare_result = gen_rtx_REG (CCUNSmode, CR0_REGNO);
+      validate_condition_mode (EQ, CCUNSmode);
+      lo = gen_int_mode (toc_restore_insn & 0xffff, SImode);
+      emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+                             gen_rtx_COMPARE (CCUNSmode, tmp_reg_si, lo)));
+      toc_save_done = gen_label_rtx ();
+      jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                                  gen_rtx_EQ (VOIDmode, compare_result,
+                                              const0_rtx),
+                                  gen_rtx_LABEL_REF (VOIDmode, toc_save_done),
+                                  pc_rtx);
+      jump = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, jump));
+      JUMP_LABEL (jump) = toc_save_done;
+      LABEL_NUSES (toc_save_done) += 1;
+
+      emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2,
+                      sp_offset + 5 * reg_size, info->total_size);
+      emit_label (toc_save_done);
+      if (using_static_chain_p)
+       emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
+    }
+
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {