On Nov 29, 2006, at 4:19 AM, Andrew Haley wrote:
Perry Smith writes:
I wrote a class that switches the stack to a new area. This is for
the power PC.
In the text below, I'll use main, testit, and newStack. main is the
main program, testit is a function that main calls, and newStack is
the method that switches the stack to the new space. main calls
testit which calls s.newStack. (s is an instance of the class that
switches the stack).
The purpose of separating main and testit is so I can verify that
returning from testit works properly.
newStack gets the current value of r1 (the stack pointer) and copies
the last two stack frames (which would be the stack frame for testit
and newStack) to the top of some allocated memory. It alters r1(0)
(the previous stack value for newStack) in the new memory to point to
the address of testit's new stack frame. It sets r1 up to the base
of this new area and returns.
OK, before we go any further. Did you write and test DWARF unwinder
information for newStack?
No, I did not. I thought it would be too big a task and I'm willing
to put a try/catch
after the stack has been changed so the unwind does not need to go
through
this. This may be naive. (See more below).
With g++ and no optimization, this works. When newStack returns,
it consumes its stack frame in the new memory leaving only testit's
new stack frame and r1 pointing to the base of the new stack from
for testit. When testit returns, it loads r1 with r1(0) and
returns. This properly puts r1 back to main's stack frame.
If I put -O3, then at the return of testit, instead of loading r1
with r1(0), just adds in the size of the stack frame (and assumes
that r1 has not been munged with). I presume this is faster. I
know that xlc does the same thing. As a result, when we return
back to main, the stack pointer is off in the weeds somewhere.
I get the feeling I'm not understanding something here. As long as
newStack is correct and handles all registers according to the ABI,
there shouldn't be any trouble.
I'm sure you understand this better than I do. Can you point me to
the info
needed for the DWARF unwinder you mention above? That may educate me
more.
It still seems I am going to have problems so I will try and repeat
the symptom:
The code generated to return from a function can have two forms.
Logically, it is
a three step process. Pick up the return address which is located at
r1(8) (assuming
a 32 bit system) into a register (like r0), replace r1 with r1(0)
which moves r1 to
point to the previous stack frame, and then branch to what was at r1(8).
But in optimized code, the compiler does not load r1 with r1(0). It
assumes that r1
has not changed, and it knows the size of the stack frame, it just
adds the size of the
stack frame to r1. This will be the same address if r1 has not been
changed.
It seems like (but I may be wrong), even with the DWARF unwinder
information, the
compiler will still produce the code that adds the size of the stack
from to r1 to get
r1 to point to the previous stack frame instead of loading r1 with r1
(0).
Am I making sense?
Perry Smith ( pedz@xxxxxxxxxxxxxxxx )
Ease Software, Inc. ( http://www.easesoftware.com )
Low cost SATA Disk Systems for IBMs p5, pSeries, and RS/6000 AIX systems