This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PING [RFC] Fix MIPS frame prologue scan problem


Pierre,

>   I didn't get any answer on the question I raised 
> on the bottom of my answer to your comments.
> 
>   I just summarize here:
> 1) It's true that my pot might not be ABI complaint, but I saw
> several other assembly code that use the same approach (it might
> be really old assembler)
> 2) The current code in mips-tdep.c should either 
> handle the 
>   add $s8, $sp, LOCALSIZE
> in a way similar to what I propose or
> otherwise at least complain about non-ABI code, no?

 Thanks for the reminder and apologies to have lost your case.  See 
further comments below.

> > > >   I am trying to extend the Free Pascal compiler to support
> > > > MIPS architecture.
> > > >
> > > >   From what I read so far, register $s8 (register number 30) can be
> used
> > > as
> > > > a frame register,
> > > > but when I set $s8 to the value of the stack pointer ($sp, register
> > number
> > > > 29)
> > > > I get all my locals and parameter of functions wrong.
> > > >
> > > >   I traced it down to the fact that GDB seems to use a
> > > > 'virtual' frame pointer register called $fp,
> > > > but which is miscalculated in my case.
> > > >
> > > >   In GCC generated code, $s8 register gets the same value as
> > > > $sp register, so that this problem does not show up in that case,
> > > > but for me, if I have a prologue that reserves 80 bytes,
> > > > I will typically get
> > > >
> > > >   # Reserve 80 bytes for locals and area for called function
> parameters
> > > >   addi $sp,$sp,-80
> > > >   # Save $ra and $s8 registers, there could be others...
> > > >   sw    $ra,44($sp)
> > > >   sw   $s8,40($sp)
> > > >   # Set $s8 to function entry value of $sp
> > > >   addi $s8,$sp,80
> > > >
> > > >   Analysis of first instruction leads to setting of
> > > > frame_offset to 80.
> > > >
> > > >   The problem is that when the last instruction
> > > > is analyzed by mips32_scan_prologue,
> > > > it switches the frame_reg from $sp to $s8,
> > > > but does not modify frame_offset value.
> > > >   This leads to a frame pointer $fp
> > > > being computed as $s8 + frame_offset
> > > > which is equal to $sp + 2*frame_offset.
> > > >   Thus all my locals are wrong :(
> > > >
> > > >   Substraction of the constant in the last addi instruction (low_word)
> > > > to frame_offset seems to cure my problem.
> > >
> > >  Well, to put it short, you're not supposed to do that if you want to
> > > follow the MIPS ABI.  The MIPS processor has no hardware stack and the
> > > software implementation of the stack has been made such that there is
> > > generally no need to arrange for a hard frame pointer (in a register
> > > separate from the stack pointer), except where dynamic stack allocation
> > > is used (alloca in C terms).
> > 
> >   I tried to read several MIPS documents,
> > and the message was not that clear to me...

 I agree documentation appears ambiguous, for example SGI's "MIPSpro 
Assembly Language Programmer's Guide" (doc #007-2418-004) refers to the 
"virtual frame pointer ($fp)" as the incoming value of $sp.  However I 
still think the MIPS psABI document referred below is the normative 
standard.

> > >  Therefore the right place to look for how the hard frame pointer has
> been
> > > specified is the "Dynamic Allocation of Stack Space" section in Chapter
> 3
> > > "Machine Interface" of the MIPS psABI document:
> > >
> > > "When a function requires dynamically allocated stack space it manifests
> a
> > > frame pointer on entry to the function.  The frame pointer is kept in a
> > > callee-saved register so that it is not changed across subsequent
> function
> > > calls.  Dynamic stack allocation requires the following steps.
> > >
> > >  1. On function entry, the function adjusts the stack pointer by the
> size
> > >     of the static stack frame.  The frame pointer is then set to this
> > >     initial sp value and is used for referencing the static elements
> > >     within the stack frame, performing the normal function of the stack
> > >     pointer."
> > >
> > >  So in fact both GCC and GDB are correct, you're not supposed to add a
> > > constant to the stack pointer when calculating the value of the frame
> > > pointer -- it is supposed to hold the value of the stack pointer *after*
> > > the frame has been allocated (in other words any frame offsets are
> > > non-negative).
> > 
> >   Our current problem is that we don't yet knoow the
> > stacksize that we need for the function while we generate
> > its code, so that using a frame pointer at previous value of stack pointer
> > makes this
> > really easier for now.

 NB the use of the frame pointer at the incoming value of $sp does not 
seem to help you as the local stack variables are meant to be allocated 
first (toward the bottom of the stack), followed by the incoming register 
save area and finally the argument build area.  See Figure 3-21 in the 
MIPS psABI document.  And you need to know the offset from the frame 
pointer register to save the incoming registers that happens first in the 
function prologue.

 However this simple program:

$ cat alloca.c
#include <alloca.h>

extern int bar(void *, int *);

int foo(unsigned int i)
{
	int v;

	return bar(alloca(i), &v);
}
$

is compiled to this by GCC (I've stripped some less relevant bits for 
brevity):

	.text
	.align	2
	.globl	foo
	.ent	foo
	.type	foo, @function
foo:
	.frame	$fp,40,$31		# vars= 8, regs= 2/0, args= 16, gp= 8
	.mask	0xc0000000,-4
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	addiu	$4,$4,14
	srl	$2,$4,3
	addiu	$sp,$sp,-40
	sll	$2,$2,3
	sw	$31,36($sp)
	sw	$fp,32($sp)
	move	$fp,$sp
	subu	$sp,$sp,$2
	addiu	$4,$sp,16
	jal	bar
	addiu	$5,$fp,24

	move	$sp,$fp
	lw	$31,36($sp)
	lw	$fp,32($sp)
	j	$31
	addiu	$sp,$sp,40

	.set	macro
	.set	reorder
	.end	foo
	.size	foo, .-foo

so this does not really follow the standard referred above, as v (at $fp + 
24) is clearly allocated farther from the bottom of the stack than the 
incoming register save area (from $fp + 32 on).

 And then the stack layout used in code above is hardwired in the 
implementation of the MIPS16 SAVE instruction, so I think this means 
you're essentially free to pick your choice.

> > >  You need to adjust your code generated (BTW, note that the
> > > convention assumed by the ABI is to use non-trapping arithmetic; I'm
> > Is this the difference between
> >   ADDI and ADDIU?
> > I thought it was only a signed/unsigned difference,
> > Do that mean that you never generate any exception if you use the U
> version?

 Correct, the use of signed/unsigned reference in the context of additive 
operations (ADDI/ADD/SUB and likewise the doubleword variants) is a bit of 
a misnomer.  The only difference between each pair of signed/unsigned 
operations is that the former takes an overflow exception on a signed 
overflow and the latter does not.  The result computed is otherwise the 
same for both operations in each pair.

> > I am really new to MIPS assembly...

 Well, I suggest a MIPS assembly book first then, getting a grasp on the 
dialect purely from technical specs may be quite a challenge.  Especially 
for such a long-lived architecure with its all twists and quirks 
accumulated over the years.  Dominic Sweetman's "See MIPS Run" (ISBN: 
0-12-088421-6) is one I can recommend, and it covers much more than lone 
MIPS assembly programming.

 Although for some reason the hard frame pointer usage consideration in 
Section 11.2.9 there also builds on the approach outlined in the SGI 
document referred above.  I don't know why, I have never seen a piece of 
code doing anything like this and there is no hard example of such code in 
either text either, although there are many assembly pieces using $sp only 
quoted.

> > > assuming that you deliberately want to trap on overflows to detect the
> > > stack pointer crossing the user/kernel segment boundary, right?).
> >   Not really as explained above ...

 Ack.

> > >  NB I suggest that you get real debug information generated as well; it
> > > can be stabs if DWARF-2 is too difficult to start with.  The heuristic
> > > unwinder is really the last-chance attempt made by GDB to find its way
> > > around, can only be relied on when applied to conservative code and is
> > > best avoided if possible.
> > 
> >   But my problem is really that
> > GDB found my I do generate stabs debugging information,
> > and give parameters and locals
> > offsets relative to frame pointer.

 I'm not sure what you mean -- do you want to say that with stabs debug 
information GDB still uses the heuristic unwinders to examine function 
prologues?  Hmm, I have been to short into MIPS debug internals to have 
ever had a need to use stabs, for me DWARF-2 support has been there since 
forever.  But I realise it may be easier for you to start with this 
simpler debugging format and it's a bit unfortunate that it's not capable 
enough to get away without the heuristic unwinders, as they are overall 
quite fragile.

> > But in mips32_scan_prologue,
> > the first
> >   ADDI $s8,$sp,LocalSize
> > instruction,
> >   interpreted it in mips32_scan_prologue function
> > but ended up with a wrong position of my
> > non-ABI standard frame pointer
> > because it changed frame pointer register from sp to s8 register,
> > but kept frame_offset value as set by the
> >   SUBI $sp, $sp, LocalSize
> > instruction
> >   analyzed before.
> > 
> >   Thus GDB wrongly ends up with a
> > frame pointer located a
> >   value of $s8 register (as from ADDI instruction analysis)
> > + LocalSize (from SUBI instruction)
> > 
> >   This means that of
> >   $sp is say at address addr
> >   $s8  is at addr +LocalSize
> > and the virtual frame pointer
> >   $fp at  $s8 + LocalSize = addr + 2 * LocalSize
> > 
> > 
> >   This means that it would be better to remove
> > analysis of the ADDI $s8, $sp, LocalSize
> > than to leave the current behavior.
> > 
> >   I think that we should either use my proposed patch,
> > or completely remove the analysis of this ADDI $s8, $sp, LocalSize...

 Given the ambiguities noted above and following the principle of being 
liberal as to what to accept I agree your proposal makes sense.  I am 
fairly sure though that in the presence of a hard frame pointer ($fp) it 
is that value we should rely on as it's there for a reason.

 I'll get back to you shortly, sorry for the delay and thanks for 
persistence.

  Maciej


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]