The current Nios II prologue/epilogue code has a bug where the frame pointer points to the start of the register save area, rather than the frame slot where FP is saved (as specified the Nios II ABI).
This was only discovered relatively recently, as dwarf-based unwinding is used most of the time, plus nios2 GDB's prologue analyzer is capable of determining where FP is stored. Still this needs to fixed to be conformant to the ABI. Tested (both the compiler and gdb) and applied to trunk. Chung-Lin 2014-03-11 Chung-Lin Tang <clt...@codesourcery.com> * config/nios2/nios2.c (machine_function): Add fp_save_offset field. (nios2_compute_frame_layout): Add calculation of cfun->machine->fp_save_offset. (nios2_expand_prologue): Correct setting of frame pointer register in prologue. (nios2_expand_epilogue): Update recovery of stack pointer from frame pointer accordingly. (nios2_initial_elimination_offset): Update calculation of offset for eliminating to HARD_FRAME_POINTER_REGNUM.
Index: config/nios2/nios2.c =================================================================== --- config/nios2/nios2.c (revision 208471) +++ config/nios2/nios2.c (working copy) @@ -81,8 +81,10 @@ struct GTY (()) machine_function int args_size; /* Number of bytes needed to store registers in frame. */ int save_reg_size; - /* Offset from new stack pointer to store registers. */ + /* Offset from new stack pointer to store registers. */ int save_regs_offset; + /* Offset from save_regs_offset to store frame pointer register. */ + int fp_save_offset; /* != 0 if frame layout already calculated. */ int initialized; }; @@ -390,6 +392,17 @@ nios2_compute_frame_layout (void) } } + cfun->machine->fp_save_offset = 0; + if (save_mask & (1 << HARD_FRAME_POINTER_REGNUM)) + { + int fp_save_offset = 0; + for (regno = 0; regno < HARD_FRAME_POINTER_REGNUM; regno++) + if (save_mask & (1 << regno)) + fp_save_offset += 4; + + cfun->machine->fp_save_offset = fp_save_offset; + } + save_reg_size = NIOS2_STACK_ALIGN (save_reg_size); total_size += save_reg_size; total_size += NIOS2_STACK_ALIGN (crtl->args.pretend_args_size); @@ -450,8 +463,8 @@ nios2_expand_prologue (void) { unsigned int regno; int total_frame_size, save_offset; - int sp_offset; /* offset from base_reg to final stack value. */ - int fp_offset; /* offset from base_reg to final fp value. */ + int sp_offset; /* offset from base_reg to final stack value. */ + int save_regs_base; /* offset from base_reg to register save area. */ rtx insn; total_frame_size = nios2_compute_frame_layout (); @@ -468,8 +481,7 @@ nios2_expand_prologue (void) gen_int_mode (cfun->machine->save_regs_offset - total_frame_size, Pmode))); RTX_FRAME_RELATED_P (insn) = 1; - - fp_offset = 0; + save_regs_base = 0; sp_offset = -cfun->machine->save_regs_offset; } else if (total_frame_size) @@ -478,16 +490,16 @@ nios2_expand_prologue (void) gen_int_mode (-total_frame_size, Pmode))); RTX_FRAME_RELATED_P (insn) = 1; - fp_offset = cfun->machine->save_regs_offset; + save_regs_base = cfun->machine->save_regs_offset; sp_offset = 0; } else - fp_offset = sp_offset = 0; + save_regs_base = sp_offset = 0; if (crtl->limit_stack) nios2_emit_stack_limit_check (); - save_offset = fp_offset + cfun->machine->save_reg_size; + save_offset = save_regs_base + cfun->machine->save_reg_size; for (regno = LAST_GP_REG; regno > 0; regno--) if (cfun->machine->save_mask & (1 << regno)) @@ -498,9 +510,10 @@ nios2_expand_prologue (void) if (frame_pointer_needed) { + int fp_save_offset = save_regs_base + cfun->machine->fp_save_offset; insn = emit_insn (gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx, - gen_int_mode (fp_offset, Pmode))); + gen_int_mode (fp_save_offset, Pmode))); RTX_FRAME_RELATED_P (insn) = 1; } @@ -555,7 +568,9 @@ nios2_expand_epilogue (bool sibcall_p) if (frame_pointer_needed) { /* Recover the stack pointer. */ - insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); + insn = emit_insn (gen_add3_insn + (stack_pointer_rtx, hard_frame_pointer_rtx, + gen_int_mode (-cfun->machine->fp_save_offset, Pmode))); cfa_adj = plus_constant (Pmode, stack_pointer_rtx, (total_frame_size - cfun->machine->save_regs_offset)); @@ -772,7 +787,8 @@ nios2_initial_elimination_offset (int from, int to /* If we are asked for the frame pointer offset, then adjust OFFSET by the offset from the frame pointer to the stack pointer. */ if (to == HARD_FRAME_POINTER_REGNUM) - offset -= cfun->machine->save_regs_offset; + offset -= (cfun->machine->save_regs_offset + + cfun->machine->fp_save_offset); return offset; }