The following is part of my save C procedures:
save(){
....
int stack_size, stack_bot;
/* stack_bot is the last automatic variables in
this procedure */
if (setjmp(save_state) == 0) {
....
stack_bot = (int) &stack_bot;
....
}
else {
....
}
}
Unix/C gurus, please help me with the following questions:
1. Is it right to assume that the address of the last automatic
variable is the bottom of stack frame ?
2. How come save_state[2], which stores the Stack Pointer for
SunOS 4.x, is far away from the assumed stack bottom ?
Note: save_state[14], which stores the SP for SunOS 3.x, is
very close to the assumed stack bottom.
3. Any major differences in the way of stack frame manipulation
are there between SunOS 3.x and SunOS 4.x ?
4. Any better solutions to save and restore stack frame for
SunOS 4.x ?
Any help with you guys will be greatly appreciated.
--
-Andy Tan
"Stack frame"? There doesn't even have to *be* a stack frame. (Indeed, in
"leaf" functions on modern machines, often there isn't.) What you are doing
is hopelessly unportable.
--
"[Some people] positively *wish* to | Henry Spencer @ U of Toronto Zoology
believe ill of the modern world."-R.Peto| he...@zoo.toronto.edu utzoo!henry
Certainly not. It is not even correct to assume that there IS a stack
as such; some implementations thread activation records together as
linked segments.
>4. Any better solutions to save and restore stack frame for SunOS 4.x ?
Yes -- figure out what it is that your program REALLY needs to be doing
(saving stack frames cannot possibly be an application requirement),
then devise an alternate solution that uses portable techniques.
1. Is it right to assume that the address of the last automatic
variable is the bottom of stack frame ?
it is not right to assume that there is a stack frame, and some
compilers aren't going to put autos in the frame even if a frame
exists since they can be more cheaply handled with registers.
2. How come save_state[2], which stores the Stack Pointer for
SunOS 4.x, is far away from the assumed stack bottom ?
Note: save_state[14], which stores the SP for SunOS 3.x, is
very close to the assumed stack bottom.
on a risc system with register windows some or all of your context
might not even be in memory (if i understand some risc systems' usage
of register windows correctly). every cpu is going to have varying
stack frame format(s), assuming the cpu enforces one at all, and OS
and compiler vendors are more than happy to create oddball parameter
passing and stack frame conventions.
what you appear to be doing is horribly non-portable and might as well
be written in assembly; at least then it will be obvious that it's
non-portable. :-)
--
Help stamp out vi in our lifetime!
Scott Goehring goeh...@gnu.ai.mit.edu
On exile in Indianapolis, IN
If, of course, you have the registers (68K only have so many).
If there's not a stack frame, how are parameters passed to the
function...? And how would you return...?
* every cpu is going to have varying stack frame format(s), assuming the
* cpu enforces one at all, and OS and compiler vendors are more than happy
* to create oddball parameter passing and stack frame conventions.
I didn't think that a CPU ever "enforced" a stack frame; ostensibly one
could ignore the references to "4(fp)" in the manual and do it their own
way.
But a stack frame seems to be the most efficient way of dealing with
calls and returns.
* --
* Help stamp out vi in our lifetime!
* Scott Goehring goeh...@gnu.ai.mit.edu
* On exile in Indianapolis, IN
|>
|> But a stack frame seems to be the most efficient way of dealing with
|> calls and returns.
Wrong! Passing arguments in registers is more efficient. That is a
major reason why RISC's with 32 (or more) registers win. A fast
call/return is worth a great deal in the MIPS war.
In short, if your code makes any assumptions about where arguments
are located, you have reduced your portability by a mile.
--------------------------------------------------------------------
Donald A. Lewine (508) 870-9008 Voice
Data General Corporation (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580 U.S.A.
uucp: uunet!dg!lewine Internet: lew...@cheshirecat.webo.dg.com
> /* <GOEHRING.91...@gnu.ai.mit.edu> by goeh...@gnu.ai.mit.edu
> * In article <1...@epic.epic.com> t...@epic.epic.com (Andy Tan) writes:
> *
> * 1. Is it right to assume that the address of the last automatic
> * variable is the bottom of stack frame ?
> *
> * it is not right to assume that there is a stack frame, and some
> * compilers aren't going to put autos in the frame even if a frame
> * exists since they can be more cheaply handled with registers.
>
> If, of course, you have the registers (68K only have so many).
> If there's not a stack frame, how are parameters passed to the
> function...? And how would you return...?
The Intel i860 passes most parameters in registers. The processor has a
total of 15 integer and 15 float (32 bit) registers (actually 16, but r0
and f0 are hardwired 0). The float registers can be combined to form 64
bit doubles and 128 bit long doubles.
r16-r27 are used to pass scalar parameters. f8-f15 are used to pass up to
4 double parameters (all compilers promote floats to doubles). If a
struct, more than 12 scalar arguments, or more than 4 doubles are passed, a
block of memory is reserved on the "stack" and r28 is set to point to this
block. varargs/stdargs routines receive their parameters in this block as
well. Scalar return values are returned in f16, double return values are
returned in f16/f17.
The i860 does not have a real stack, although one of the integer registers
is used to point to a software stack. The return address for a call is
kept in r1. If the callee make a call, it is responsible for saving r1 on
the "stack".
> * every cpu is going to have varying stack frame format(s), assuming the
> * cpu enforces one at all, and OS and compiler vendors are more than happy
> * to create oddball parameter passing and stack frame conventions.
> I didn't think that a CPU ever "enforced" a stack frame; ostensibly one
> could ignore the references to "4(fp)" in the manual and do it their own
> way.
> But a stack frame seems to be the most efficient way of dealing with
> calls and returns.
We discovered that having a frame pointer and a true stack was more
expensive, CPU wise. A large percentage of CPU is spent in leaf routines,
where having the parameters in registers speeds things up.
-Israel Pinkas
Intel Corp
--
--------------------------------------
Disclaimer: The above are my personal opinions, and in no way represent
the opinions of Intel Corporation. In no way should the above be taken
to be a statement of Intel.
UUCP: {amdcad,decwrl,hplabs,oliveb,pur-ee,qantel}!intelca!mipos3!st860!pinkas
ARPA: pinkas%st860.i...@relay.cs.net
CSNET: pin...@st860.intel.com
>If there's not a stack frame, how are parameters passed to the
>function...? And how would you return...?
>... a stack frame seems to be the most efficient way of dealing with
>calls and returns.
There is a useful distinction between using the stack and having a stack
frame. Usually a stack frame means keeping the address of a known point in
the stack in a register, and storing known data at known places relative
to that fixed point. Debuggers and programmers looking at the code can
determine the actual parameters and return addresses relative to the "frame
pointer". This is convenient, but not necessarily efficient at run time.
The compiler can keep track of stack changes as it generates code, and
make all references relative to the current top of the stack. This
eliminates the need to save and restore frame pointers and sometimes
other related data. It makes debugging very hard, since it is not so
obvious where the parameters and local variables are. They shift
relative to the stack top, rather than being at a fixed offset from
the frame pointer.
Finally, parameters can be passed in registers rather than being pushed
on the stack. The return address can also be kept in a register. A
machine with a reasonable number of registers might not need to use the
stack at all for a routine with few parameters and local variables.
--
Steve Clamage, TauMetric Corp, st...@taumet.com
BZZZT. Thank you for playing today's game, but your response is
incorrect ;-)
There are machines which have =no= registers, other that don't
even have stack pointers, some have no program counters, and so
on.
Your assumption is that every machine has a push-down stack of
some sort and a small (16 is "small") set of machine registers.
The bad news is that some RISC'y chips have 200+ registers,
some older microprocessors (and even certain popular mainframes)
ahve =0= machine registers, or perhaps a single register which
pointed to what you consider to be "registers". Still weirder
machines have registers which specify which register is the
PC, making the notion of "return" fuzzier still.
> * every cpu is going to have varying stack frame format(s), assuming the
> * cpu enforces one at all, and OS and compiler vendors are more than happy
> * to create oddball parameter passing and stack frame conventions.
>
>I didn't think that a CPU ever "enforced" a stack frame; ostensibly one
>could ignore the references to "4(fp)" in the manual and do it their own
>way.
Yes, there are CPU's which have notions about stack frame and
support the conventions in hardware. If you "ignore" the
convention, you go whirring off into space when you get around
to executing that "ret" instruction and the machine expects
the stack frame it pushed to still be of the right shape and
size.
>But a stack frame seems to be the most efficient way of dealing with
>calls and returns.
No, there are =many= better ways.
--
John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832 | GEnie PROHIBITED :-) | Domain: j...@rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
rest of the Constitution, gun ownership would be mandatory."
Repeat after me: ALL THE WORLD IS NOT A VAX!!!! Repeat that 10 TIMES.
Many cpus are happy passing the first N parameters in registers (where
0 < n < <#-of-total-registers>). Many cpus are also happy stuffing the return
address of a jsr, bsr, <insert-favorite-subroutine-call-pneumonic-here> into
a register. You have to learn to think globally, instead of just your tiny
little world....
__________________________________________________________
Terry Laskodi "There's a permanent crease
of in your right and wrong."
Tektronix Sly and the Family Stone, "Stand!"
__________________________________________________________
You're right, there are machines which provide instructions that manipulate
the stack and assume a particular stack frame layout. However, there's
nothing *forcing* programs to use those instructions. So, if you ignore
the convention, don't use that "ret" instruction! You're only *forced* to
follow conventions when you want to interoperate with other routines. For
instance, when calling a library routine or system call you have to follow
the conventions it expects (usually the standard calling sequence), and if
you want standard debuggers to be usable you should use the standard frame
layout.
Many Lisp implementations use a nonstandard stack frame layout, since they
generally provide their own higher-level debugger. Disassembling Lisp
functions often reveals that they don't use the call and return
instructions. When calling out to conventional libraries they translate
from the Lisp calling sequence to the standard calling sequence, and vice
versa when implementing callbacks.
--
Barry Margolin, Thinking Machines Corp.
bar...@think.com
{uunet,harvard}!think!barmar
>>But a stack frame seems to be the most efficient way of dealing with
>>calls and returns.
>No, there are =many= better ways.
BZZZZZZZZZZZZZZZZZZ....
A "stack frame" is the ONLY way of dealing with calls and returns *if
they may be recursive*.
*Where* the stack frame lies is another question. Part of it may be in
registers. It's still a stack frame.
--
Rahul Dhesi <dh...@cirrus.COM>
UUCP: oliveb!cirrusl!dhesi
Even if you know that you have a real stack, some processors grow stacks
up from low address towards higher addresses, and some grow them from
higher addresses toward lower ones.
And some compilers put the first automatic (non-register) variable at the
top of the stack frame, and some put the last auto variable at the top.
So even if you have a real, contiguous stack, knowing the address of one
auto variable doesn't tell you anything portable.
And there are probably some processors that don't maintain a physical
stack at all -- they do the equivalent of a malloc for each stack frame,
and keep a pointer to the calling function's frame. So while each
function may have a stack frame (or a collection of them, depending how
much can be allocated in one chunk), the actual stack is a linked list.
(Don't laugh! This is how recursive PL/I procedures worked on the IBM
System/360 and 370; I wouldn't be surprised if the C compilers for their
descendants still do, since IBM had a _very_ standardized calling
sequence for all languages. Non-recursive procedures generally allocated
their stack frames statically, but all C functions are theoretically
recursive, so I wouldn't expect static allocation to be used except by a
_highly_ optimizing compiler that does inter-procedural control flow
checks.)
All the C language guarantees you is behavior _as if_ there were a
stack. Regardless of whether you're running it on a Unix system, some
other OS, or bare hardware...
-- Speaking strictly for myself,
-- Lee Derbenwick, AT&T Bell Laboratories, Warren, NJ
-- l...@cbnewsm.ATT.COM or <wherever>!att!cbnewsm!lfd
In registers.
>And how would you return...?
The return value might also be in a register.
Of course, at least some systems that pass parameters in registers also
tend to have stack frames (the SPARC calling conventions have them);
however, as indicated, there's no absolute guarantee that automatics are
on the stack frame, as compilers may just stick them in registers (yes,
even if they're not declared "register"), and a compiler might well not
bother allocating a stack frame at all for, say, a leaf procedure, if
there aren't any automatic variables in it.
On the more fascistic such machines, you don't get a choice: there is no
other way to do calls and returns.
--
"The stories one hears about putting up | Henry Spencer @ U of Toronto Zoology
SunOS 4.1.1 are all true." -D. Harrison| he...@zoo.toronto.edu utzoo!henry
It's probably better to simply say that autos and parameters are distinct
for each active invocation of a function. I don't like the "stack" model
since it can mislead the unwary. If one has to have a model, try the
linked activation record model a la Burroughs B5700 etc. (Interestingly,
that was a genuine "stack architecture", but the stack was not used for
the activation records.) However, a model should not be necessary.
If it's in the registers it certainly isn't on the stack and certainly
isn't a "stack frame". Every reference to "stack frame" I've seen
refers to the layout of parameters and call/return linkage on the
stack. I'm certain this is a semantic disagreement since using CPU
registers to hold parameters is certainly a better mechanism than
putting everyting on the stack, and that is but one example of something
better than a "stack frame".
Does calling it a stack frame make it a stack frame? It might be just a record
in the heap. Whether we call that a ``stack frame'' or not seems to be a matter
of taste.
--
Regards, Kers 24059 | "You're better off not dreaming of the things to come;
Caravan: | Dreams are always ending far too soon."
The better term here is activation record. An activation record (even with recursion)
need not be on the stack. You can have activation records as linked lists in the heap.
-------------------------------------------------------------------------------
Jeff Hollingsworth Work: (608) 262-6617
Internet: holl...@cs.wisc.edu Home: (608) 256-4839
X.400: <pn=Jeff.Hollingsworth;ou=cs;o=uw-madison;prmd=xnren;c=US>
"Activation record" is probably a better (more general) name for what
is being discused.
[ I *don't* know everything, and my current level of ability to grok
assembly code and concepts is about nil. Which is why I ask questions. ]
>Does calling it a stack frame make it a stack frame? It might be just a record
>in the heap. Whether we call that a ``stack frame'' or not seems to be a matter
>of taste.
A stack frame can be in the heap. (Some of the other posters would
then call it an activation record. But it quacks like a stack frame,
so I call it one.)
By the way, a stack can be in the heap too! In fact in many
environments a process can allocate memory in the heap, then create a
new process whose runtime stack is in that allocated memory.