[comp.lang.c] Unix Stack Frame Questions

tan@epic.epic.com (Andy Tan) (03/23/91)

I am trying to save the content of stack frame, so I can restore it later.
The same source code runs on SunOS 3.x well, however, it does not work on
SunOS 4.x.  

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

henry@zoo.toronto.edu (Henry Spencer) (03/24/91)

In article <125@epic.epic.com> tan@epic.epic.com (Andy Tan) writes:
>I am trying to save the content of stack frame, so I can restore it later.

"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|  henry@zoo.toronto.edu  utzoo!henry

gwyn@smoke.brl.mil (Doug Gwyn) (03/25/91)

In article <125@epic.epic.com> tan@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 ?

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.

goehring@gnu.ai.mit.edu (Not Marc Spencer) (03/26/91)

In article <125@epic.epic.com> tan@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.

   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			goehring@gnu.ai.mit.edu
	On exile in Indianapolis, IN

greywolf@unisoft.UUCP (The Grey Wolf) (04/03/91)

/* <GOEHRING.91Mar25113709@gnu.ai.mit.edu> by goehring@gnu.ai.mit.edu
 * In article <125@epic.epic.com> tan@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...?

 * 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			goehring@gnu.ai.mit.edu
 * On exile in Indianapolis, IN

lewine@cheshirecat.webo.dg.com (Donald Lewine) (04/04/91)

In article <3465@unisoft.UUCP>, greywolf@unisoft.UUCP (The Grey Wolf) writes:
|> 
|> 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.
The VAX comes very close to enforcing a stack frame in hardware/
microcode.  

|> 
|> 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: lewine@cheshirecat.webo.dg.com

pinkas@st860.intel.com (Israel Pinkas) (04/04/91)

In article <3465@unisoft.UUCP> greywolf@unisoft.UUCP (The Grey Wolf) writes:

> /* <GOEHRING.91Mar25113709@gnu.ai.mit.edu> by goehring@gnu.ai.mit.edu
>  * In article <125@epic.epic.com> tan@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.intel.com@relay.cs.net
CSNET:	pinkas@st860.intel.com

steve@taumet.com (Stephen Clamage) (04/04/91)

greywolf@unisoft.UUCP (The Grey Wolf) writes:

>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, steve@taumet.com

jfh@rpp386.cactus.org (John F Haugh II) (04/04/91)

In article <3465@unisoft.UUCP> greywolf@unisoft.UUCP (The Grey Wolf) writes:
>/* <GOEHRING.91Mar25113709@gnu.ai.mit.edu> by goehring@gnu.ai.mit.edu
> * 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...?

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: jfh@rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
 rest of the Constitution, gun ownership would be mandatory."

terryl@sail.LABS.TEK.COM (04/05/91)

In article <3465@unisoft.UUCP> greywolf@unisoft.UUCP (The Grey Wolf) writes:
>/* <GOEHRING.91Mar25113709@gnu.ai.mit.edu> by goehring@gnu.ai.mit.edu
> * In article <125@epic.epic.com> tan@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...?

     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!"
__________________________________________________________

barmar@think.com (Barry Margolin) (04/05/91)

In article <19157@rpp386.cactus.org> jfh@rpp386.cactus.org (John F Haugh II) writes:
>>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.

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.

barmar@think.com
{uunet,harvard}!think!barmar

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (04/05/91)

In <19157@rpp386.cactus.org> jfh@rpp386.cactus.org (John F Haugh II) writes:

>>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 <dhesi@cirrus.COM>
UUCP:  oliveb!cirrusl!dhesi

lfd@cbnewsm.att.com (Lee Derbenwick) (04/05/91)

In article <3465@unisoft.UUCP>, greywolf@unisoft.UUCP (The Grey Wolf) writes:
> /* <GOEHRING.91Mar25113709@gnu.ai.mit.edu> by goehring@gnu.ai.mit.edu
>  * In article <125@epic.epic.com> tan@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...?

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
 --   lfd@cbnewsm.ATT.COM  or  <wherever>!att!cbnewsm!lfd

henry@zoo.toronto.edu (Henry Spencer) (04/06/91)

In article <1991Apr4.181854.5016@Think.COM> barmar@think.com (Barry Margolin) writes:
>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...

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|  henry@zoo.toronto.edu  utzoo!henry

guy@auspex.auspex.com (Guy Harris) (04/06/91)

>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...?

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. 

gwyn@smoke.brl.mil (Doug Gwyn) (04/06/91)

In article <1991Apr4.230716.21177@cbnewsm.att.com> lfd@cbnewsm.att.com (Lee Derbenwick) writes:
>All the C language guarantees you is behavior _as if_ there were a stack.

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.

jfh@rpp386.cactus.org (John F Haugh II) (04/07/91)

In article <3035@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>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.

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".
-- 
John F. Haugh II        | Distribution to  | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832 | GEnie PROHIBITED :-) |  Domain: jfh@rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
 rest of the Constitution, gun ownership would be mandatory."

kers@hplb.hpl.hp.com (Chris Dollin) (04/08/91)

Rahul Dhesi says:
   >>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.

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."

hollings@poona.cs.wisc.edu (Jeff Hollingsworth) (04/08/91)

In article <3035@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
|> In <19157@rpp386.cactus.org> jfh@rpp386.cactus.org (John F Haugh II) writes:
|> 
|> >>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*.
|> 

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: hollings@cs.wisc.edu				Home: (608) 256-4839
X.400: <pn=Jeff.Hollingsworth;ou=cs;o=uw-madison;prmd=xnren;c=US>

schwartz@groucho.cs.psu.edu (Scott Schwartz) (04/09/91)

kers@hplb.hpl.hp.com (Chris Dollin) writes:
   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. 

"Activation record" is probably a better (more general) name for what
is being discused.

greywolf@unisoft.UUCP (The Grey Wolf) (04/10/91)

Thanks for everyone who responded; thanks especially to those who
realised that I was asking a question because I didn't know the
answer.

[ 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. ]

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (04/12/91)

In <KERS.91Apr8095747@cdollin.hpl.hp.com> kers@hplb.hpl.hp.com (Chris
Dollin) writes:

>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.
--
Rahul Dhesi <dhesi@cirrus.COM>
UUCP:  oliveb!cirrusl!dhesi