Argument pointers, dwarf and prologue analysis

Randolph Chung
2005-11-21T05:50:54Z

Here's another interesting bit from HPPA's abi -- on 64-bit, the HPPA
ABI uses an "argument pointer" (r29) that points inside the stack frame
for storing various things. The argument pointer is set by the caller,
and is *not* a call preserved register. Moreover, in gcc, in the callee
frame, the compiler will compute an offset to r29, and use that to store
the arguments. For example:

foo
.PROC
.CALLINFO FRAME=80,NO_CALLS,SAVE_SP,ENTRY_GR=3
.ENTRY
copy %r3,%r1
copy %r30,%r3
std,ma %r1,80(%r30)
std %r3,-8(%r30)
ldo -64(%r29),%r20
stw %r26,4(%r20)
stw %r25,12(%r20)
stw %r24,20(%r20)
[...]

Here, r20 is a scratch register (also not call preserved). r26, r25, r24
are the first three arguments to the function.

Based on the above code, the dwarf debug info emitted describes the
arguments using DW_OP_breg20 {4,12,20}

This causes obvious problems when trying to retrieve arguments from
outer frames, for example:

int foo(int a, int b, int c, int d, int e, int f, int g, int h)
{
return a+b+c+d+e+f+g+h;
}

int bar(int a, int b, int c, int d, int e, int f, int g, int h)
{
return foo(a+1, b+1, c+1, d+1, e+1, f+1, g+1, h+1);
}

int main(int argc, char **argv)
{
return bar(1,2,3,4,5,6,7,8);
}

in foo, the arguments to bar are incorrectly read because r20 may have
been clobbered and cannot be recovered (currently).

Possibly, gcc should be changed to generate code that stores arguments
based on a call preserved register, but in talking with Dave Anglin, it
seems this is not so straightforward. He also suggested another idea:

In fact, r20 above can be determined by looking at the caller frame (bar
in the example). A few insn before the call to foo, you will find:

ldo -48(%r30),%r29
copy %r27,%r4
b,l foo,%r2

r30 is the stack pointer. So, theoretically, one could find the return
pointer of the current frame, look at a few insns before that point,
determine the offset from the frame base of the current frame, then
adjust that based on the ldo insn in the prologue in the current frame
to get the value of r20, and store that value in the frame cache. Then,
the dwarf evaluation will be able to read the argument values from the
correct location. Whew!

Before I go and try to implement this mess, I would like to get some
feedback about whether this seems to be a good solution. Are there
better ways to do this? Can we simply make gcc emit a few more dwarf ops
to describe all the offsets and pointers that are involved?

Comments much appreciated :)
randolph
--
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports