Parameters and the Stack

I

IMSHURKKPWII

Hi all,

I am confused about the methods by which C passes things to other
routines. If I have a routine,

void rt([type] [name1], [type] [name2], ...);

Then I know that the process to call this function is this:

1. Push values onto the stack, from right to left.
2. Push return address onto stack.
3. Set PC = address of rt.

The stack looks like:

---
arg_n
---
arg_n-1
---
....
---
Return Address
---

I noticed that when exiting a function, the stack pointer should be
pointing to the position on the stack where the Return Address is
stored; and when returning to the caller, PC gets set to SP, and then
SP gets incremented by 4 bytes or so-- however long the Return Address
is.

Now I have a problem with this: SP will be pointing to the last
argument on the stack that was pushed by the caller. I've looked at
assembly listings and I can't seem to find any section that is
responsible for actually removing those arguments from the stack once
they've been pushed.

Thanks
-HG.
 
D

Dennis Bliefernicht

Now I have a problem with this: SP will be pointing to the last
argument on the stack that was pushed by the caller. I've looked at
assembly listings and I can't seem to find any section that is
responsible for actually removing those arguments from the stack once
they've been pushed.

Afair in the C calling convention the caller removes the arguments. So a
typical thing would be:

push param3
push param2
push param1
call foobarfunc
add esp, 0xc
 
B

Bertrand Mollinier Toublet

Hi all,

I am confused about the methods by which C passes things to other
routines. If I have a routine,
The "method by which C passes things to other routines" is not
specified. Every implementor is free, from the C standard's point of
view, to implement it as they please.

Now, there are conventions amond implementors, but

a) I am far from clear about them
b) in any case, we do not discuss them in comp.lang.c
 
M

Matt Taylor

Hi all,

I am confused about the methods by which C passes things to other
routines. If I have a routine,

void rt([type] [name1], [type] [name2], ...);

Then I know that the process to call this function is this:

1. Push values onto the stack, from right to left.
2. Push return address onto stack.
3. Set PC = address of rt.

The stack looks like:

---
arg_n
---
arg_n-1
---
...
---
Return Address
---

I noticed that when exiting a function, the stack pointer should be
pointing to the position on the stack where the Return Address is
stored; and when returning to the caller, PC gets set to SP, and then
SP gets incremented by 4 bytes or so-- however long the Return Address
is.

Now I have a problem with this: SP will be pointing to the last
argument on the stack that was pushed by the caller. I've looked at
assembly listings and I can't seem to find any section that is
responsible for actually removing those arguments from the stack once
they've been pushed.

Thanks
-HG.

Usually the function is followed by an add esp, n instruction to remove all
of the parameters simultaneously rather than tediously popping them off one
at a time. Some compilers will even delay cleaning up the stack across
several functions. The space wasted by the parameters is negligible, and you
save yourself a few instructions.

There are other methods of passing parameters to a function, too. One
popular variant requires the called function to clean up the stack. Another
convention passes parameters in registers and the stack is completely
avoided except for the call/ret implicit usage.

Here's an example from GCC 3.2:

subl $12, %esp
pushl $LC0 ; "0\0"
call _atoi
addl $16, %esp

It reserves an extra 12 bytes to try and keep stack allocations to a
multiple of 16 for architectural reasons (at least, I think). After the
function call, it cleans up the stack with the add instruction.

-Matt
 
R

Randall Hyde

You might want to take a look at the chapter on
"Mixed Language Programming" in "The Art of Assembly Language"
http://webster.cs.ucr.edu.
It wouldn't hurt to read the chapters on procedures in that book too.
Cheers,
Randy Hyde
 
J

Jack Klein

On 28 Sep 2003 14:37:10 -0700, (e-mail address removed) wrote in
comp.lang.c:

While this message is topical in comp.lang.asm.x86, it is severely
off-topic in comp.lang.c.
Hi all,

I am confused about the methods by which C passes things to other
routines. If I have a routine,

C does not have either "things" or "routines".

The methods that any particular C compiler uses to pass _arguments_ to
_functions_ are not specified at all by the language, and as such are
completely off-topic in comp.lang.c.
void rt([type] [name1], [type] [name2], ...);

Then I know that the process to call this function is this:

1. Push values onto the stack, from right to left.

No such guarantee or requirement in the C language standard, and quite
a few compilers do not do it this way.
2. Push return address onto stack.

On my ARM compiler, the return address goes into the link register
(R14), no stack involved.

In the future please keep your questions about low-level mechanisms of
compilers for the x86 architecture in clax where they belong, and out
of comp.lang.c where they don't.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
R

R.Wieser


Hello HG,
I am confused about the methods by which C passes things to other
routines. If I have a routine,
[Snip]

Now I have a problem with this: SP will be pointing to the last
argument on the stack that was pushed by the caller. I've looked at
assembly listings and I can't seem to find any section that is
responsible for actually removing those arguments from the stack once
they've been pushed.

There are two way's to handle the arguments that where pushed onto the stack
before a routine is called :
1) The routine itself removes them off the stack.
2) the program that calls the routine removes them off the stack.

if 1) is used, you will probably see that the RETF command of the routine
allso has a number behind it. Like : RETF 4 -> return and add 4 to the
stack-pointer (removing 4 bytes off the stack)

In the case of 2), you will notice a "ADD SP,{value}" command, just below
the call to the routine. the {value}should equal the number of bytes
pushed.

Regards,
Rudy Wieser
 
C

Chris Dollin

Hi all,

I am confused about the methods by which C passes things to other
routines. If I have a routine,

void rt([type] [name1], [type] [name2], ...);

Then I know that the process to call this function is this:

1. Push values onto the stack, from right to left.
2. Push return address onto stack.
3. Set PC = address of rt.

No; you do *not* know this. It may (or may not) be the way that the
call gets executed on some processor, but that's a detail not addressed
by the C standard.

If you _need_ to know how your C implementation passes arguments
to functions, you need an implementation-specific resource [newsgroup,
documentation, whatever].

If you don't _need_ to know, then what we can tell you is that the
arguments are evaluated in some order, possibly interleaved, and
that when that's done, the values are assigned to the freshly-created
function-local argument variables, and execution of that function
starts, and that when it finishes [normally], control will return
to just after the call.

No stack need be involved *at all*. For example, this:

int spoogleAdd( struct spoogle *spoo, int n )
{ return spoo->anIntField + n; }

will compile to something like this:

LDR r0, [r1, #anIntFieldOffset]
ADD r0, r0, r2
MOV pc, r14

No stack for the arguments - they come in in registers; no stack for
the result; that goes out in a register; no stack for the return
address: that arrives in r14.

Of course that's on a real processor, not the x86 :)
 
C

CBFalconer

R.Wieser said:
I am confused about the methods by which C passes things to
other routines. If I have a routine,
[Snip]

Now I have a problem with this: SP will be pointing to the
last argument on the stack that was pushed by the caller. I've
looked at assembly listings and I can't seem to find any
section that is responsible for actually removing those
arguments from the stack once they've been pushed.

There are two way's to handle the arguments that where pushed
onto the stack before a routine is called :
1) The routine itself removes them off the stack.
2) the program that calls the routine removes them off the
stack.

if 1) is used, you will probably see that the RETF command of
the routine allso has a number behind it. Like : RETF 4 ->
return and add 4 to the stack-pointer (removing 4 bytes off
the stack)

In the case of 2), you will notice a "ADD SP,{value}" command,
just below the call to the routine. the {value}should equal
the number of bytes pushed.

This is still OT for c.l.c. In addition, as others have pointed
out, there need not be any stack, or stack use, whatsoever. Even
if a stack and method 2 is used there is no need to clean up
immediately. Some code generators postpone stack cleanup to a
convenient point. No C system is required to have a RETF or an
"ADD SP,(value)" instruction. My Microdata 810 certainly doesn't.
 
R

R.Wieser

CBFalconer <[email protected]> schreef in berichtnieuws
(e-mail address removed)...

Hello CB,
This is still OT for c.l.c. In addition, as others have
pointed out, there need not be any stack, or stack
use, whatsoever.

1) if this is OT, than your own "in addition" is certainly too ... Tsk, tsk.
:-\

2) If parameters are transferred by pushing them on a stack (as the OP
describes), that stack should bloody well be there :)
Even if a stack and method 2 is used there is no
need to clean up immediately.

Ofcourse. But would your "explanation" add something to the comprehension
of the matter with the novice the answer was aimed at ? Or are you out to
complicate matters ? Maybe even initiate a (pardon my language)
pissing-contest ?
Some code generators postpone stack cleanup to a
convenient point. No C system is required to have a RETF or an
"ADD SP,(value)" instruction. My Microdata 810 certainly doesn't.

Jup, it's a pissing-contest allready :-(((

Man, get a *life* for gods sake ! Having problems with what others do, but
nevertheless adding to them yourself. Bad show I would say.

And please learn to read a message (the OP's) before you answer it ... It
should save you some embarrassment.

Regards,
Rudy Wieser
 
M

Mike Wahler

R.Wieser said:
CBFalconer <[email protected]> schreef in berichtnieuws
(e-mail address removed)...

Hello CB,


1) if this is OT, than your own "in addition" is certainly too ... Tsk, tsk.
:-\

I don't think so. I think he explained *why* OP's
query is OT.
2) If parameters are transferred by pushing them on a stack (as the OP
describes), that stack should bloody well be there :)

But 'stack' is not part of the language. OP was observing
and asking about behavior of a given *implementation*, not
the language itself. Particular implementations are not
topical here, only the language.
Ofcourse. But would your "explanation" add something to the comprehension
of the matter with the novice the answer was aimed at ? Or are you out to
complicate matters ? Maybe even initiate a (pardon my language)
pissing-contest ?


Jup, it's a pissing-contest allready :-(((

I don't think so. I think he's trying to clarify things
for OP.
Man, get a *life* for gods sake !

A very common utterance by those who don't understand,
or simple refuse to accept reality.
Having problems with what others do,

When folks post off topic in a topical forum, it is
indeed a problem. This is why we point it out when
something is OT, so that the OP and anyone else
reading becomes informed.
but
nevertheless adding to them yourself.

I don't see any additional problems, only an attempt
to correct one, and hopefully prevent future ones.
Bad show I would say.

Good show I say. Chuck informed OP about OT-nes,
and gave a simple example to illustrate why.

And please learn to read a message (the OP's) before you answer it ...

Chuck's reply indicates to me that he *did* read the message.
I find his words quite appropriate to the situation.
It
should save you some embarrassment.

Go look in a mirror. :)

-Mike
 
C

Charles A. Crayne

On Mon, 29 Sep 2003 22:42:29 +0200

:Jup, it's a pissing-contest allready :-(((

And therefore, it has been placed on the Robomoderator's "suspicious
subjects" list. So play nice. :)

-- The Moderator
 
R

Robert Redelmeier

This is still OT for c.l.c. In addition, as others have pointed
out, there need not be any stack, or stack use, whatsoever. Even

Perhaps I can bring it a bit closer to c.l.c and clax86:

`c` permits variable numbers of perameters in a fn call.
`printf` is an excellent example.

If there is a hardware stack as on x86, it is more robust
the caller adjust it (2 above via add esp,NPARMS) than the
callee adjust it (1 above via ret NPARMS). The caller is
more likely to get it right and is less bug-sensitive:

printf ("%d one bug %d", i);

will likely crash the caller when it tried to return if
`printf` has done stack adjustment. If the caller does
adjustment, the printf will just print i & it's return addr.

-- Robert
 
G

Glen Herrmannsfeldt

"Bertrand Mollinier Toublet"
(e-mail address removed) wrote:
The "method by which C passes things to other routines" is not
specified. Every implementor is free, from the C standard's point of
view, to implement it as they please.

Well, not completely free. C's use of functions with a variable number of
arguments limits it somewhat.

For example, a convention where the called routine pops the arguments off
the stack, while assuming that the number of arguments agrees with the
number in the function definition would not work. The called routine must
be able to get to earlier arguments to determine the number of arguments,
which is one reason for the right to left push of the arguments on the
stack.

(I believe it is legal to use a different calling convention for varargs
functions and normal functions, but it is more convenient not to do that.)

Note that the IBM S/370 doesn't have a stack, and the normal calling
convention doesn't require one.

Whether or not a particular calling convention was compatible with the
requirements of C should be on topic. The advantages or disadvantages might
also be. The ability to call subprograms in other languages, or to call C
functions from other languages might be.

-- glen
 
I

IMSHURKKPWII

Thanks everyone! That was very helpful. Adding to SP to remove
arguments turned out to be the method employed.

-HG.
 
M

Mark Gordon

"Bertrand Mollinier Toublet"


Well, not completely free. C's use of functions with a variable
number of arguments limits it somewhat.

For example, a convention where the called routine pops the arguments
off the stack, while assuming that the number of arguments agrees with
the number in the function definition would not work. The called
routine must be able to get to earlier arguments to determine the
number of arguments, which is one reason for the right to left push of
the arguments on the stack.

The called routine does not need to be able to determine the number of
arguments, only where to find them. One option if using a stack and
pushing the left most argument first is to leave a register pointing to
the first argument. Another is to leave a register pointing to the last
argument before the varargs.
(I believe it is legal to use a different calling convention for
varargs functions and normal functions, but it is more convenient not
to do that.)

It is legal to use different calling conventions for every individual
function as long as the compiler/linker make it all tie up at the end of
the day.
Note that the IBM S/370 doesn't have a stack, and the normal calling
convention doesn't require one.

Whether or not a particular calling convention was compatible with the
requirements of C should be on topic. The advantages or disadvantages
might also be. The ability to call subprograms in other languages, or
to call C functions from other languages might be.

Calling conventions are completely OT for this group because they are
entirely implementation dependant. If you want to discuss the merits of
different calling conventions you either want a group dealing with
writing compilers or a group for a specific processor (since the "best"
convention will depend on the details of the processor).
 
C

Charles A. Crayne

On Tue, 30 Sep 2003 10:30:45 +0100

:Calling conventions are completely OT for this group because they are
:entirely implementation dependant.

Please note that the phrase "for this group" is a meaningless referent,
because there is no way for a reader to determine which newsgroup you are
posting from.

-- clax86 moderator
 
M

Mark Gordon

On Tue, 30 Sep 2003 10:30:45 +0100

:Calling conventions are completely OT for this group because they are
:entirely implementation dependant.

Please note that the phrase "for this group" is a meaningless
referent, because there is no way for a reader to determine which
newsgroup you are posting from.

Sorry, I missed the cross-post. Calling conventions are OT in
comp.lang.c, over in comp.lang.asm.x86 I can see that they could be on
topic.
 
R

R.Wieser

<[email protected]> schreef in berichtnieuws
(e-mail address removed)...

Hello HG,
Thanks everyone! That was very helpful. Adding to SP to remove
arguments turned out to be the method employed.

I'm glad our answers helped. Thanks for telling us :)

Regards,
Rudy Wieser
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top