[MUSIC].
So, we've now seen how to pass arguments
onto a stack, let's see how we can use
the stack for both allocating local
variables to a procedure.
And for saving registers that we have to
restore to the right value, for all the
procedures involved.
Let's start with the register saving
conventions.
let's go back to that procedure yoo and
procedure who that we've talked about
before.
Remember yoo is the caller and who is the
callee.
so let's take a look at this code here,
and we see that just here's the call to
who, but just before that, we put a value
into edx.
And then we expect to be able to use it
after the call to who.
So, we, in the function yoo, we would
hope that the value of edx would not be
disrupted by what might happen in the
call to who.
So, that the same value is still there
when we return.
So, in who however, which will might have
been written by a different programmer
edx might get a new value.
And that would destroy the one that we
had before, because there is only one
register edx in our CPU.
different procedures might use it, but
it's the same physical register.
So, we have to make sure that the
contents of that register which is
overwritten by who gets saved somewhere
before that happens.
So, what we have is some register saving
conventions that are split between caller
save and callee save.
In the caller save case the, the caller
procedure saves the values in a register,
in the registers before calling the other
procedure.
Callee save is complimentary, it says the
callee will do the saving before using
that register.
So when do we use each?
When does the caller save a register and
when does a callee save a register?
So, turn out that will begin to do with
three registers be callers save, eax, edx
and ecx and three registers be callee
save.
Sort of split the responsibilities, okay.
And then of course we have some, two
special registers that are the base
pointer and the stack pointer.
Those are handled a little bit
differently, but also involve restoring
them to their original values upon exit
from a procedure.
Okay the last thing to remember is that
eax the reason also its caller saved, is
because remember the returning procedure
puts its return value in eax.
And so if the caller wants to use what it
had in eax previous to the call, it
better save it somewhere else.
Okay.
And where might it save it?
probably in memory somewhere.
Okay.
Alright, now let's turn to local
variables, alright?
Here we have two functions.
We have a factorial function called
sfact, which calls a helper procedure
inside of it.
What the, the way this works is that we
create a starting point for the
factorial, in this case the number 1 here
at the beginning of sfact.
And what we're going to do is pass a
pointer to that value, an address along
with the value of the factorial we want
to reach, x.
And pass that to a helper function which
is defined here on the left.
Okay, the helper function is going to
see, if x is less than or equal to 1.
If it is, it's just going to stop.
And if it's not, it's going to perform
the multiplication of x times that of
value, that address that was passed to it
as an argument.
So, you'll notice that, that address of
val, was passed to this helper function
as a pointer.
Right, and then we de-reference the
pointer to go get that value and multiply
it times x.
So, when we start here, let's say that x
was equal to 3, right, we would start
with, s_helper being called with the
value three and the address of val.
Which is has a value of one stored at
that address.
So, when we come here to to the s_helper
procedure, what we'll find is that x is 3
and the value stored at the address of
val is 1, so we'll do a multiply 1 times
3.
And store that back into that address we
were passed as an argument, again by
using the dereference operator, okay?
So, now val is going to be equal to 3.
But now s_helper calls itself
recursively, this time with the value 2
and the address again of that same place.
Although this time we refer to it by it's
local name a, accum.
Right, so this is also accum, the same
address that we passed in.
So, now when we do this call to s_helper
x will be 2 and the value that we
dereference with the pointer is that one
that we just stored away earlier 3.
So, now we'll do 3 times 2 and put a 6 at
that place, at that address of value,
alright.
And you'll see that the next time of
course, s_helper is called now with 1 and
the address of our accumulating product.
And this time the procedure will just
stop right away, and return.
Okay, so how did this actually get
implemented in our stack?
So, lets start with the sfact procedure
at the very beginning and here's the code
corresponding to sfact or at least some
of it.
here is the stack inside of sfact.
You'll notice that its, it has a return
address for where it was called from and
it's argument.
x, the value x that it was given to start
with.
Okay, the very first procedure does that
set up stuff we always do at the
beginning of a procedure.
Adjusting base pointers.
So, we're going to save our old base
pointer by pushing it on to the stack and
of course, esp the stack pointer adjusted
as well.
Then we are going to adjust the value of
ebp to be to this new start of this frame
pointer, of this frame, on the stack.
and then we're, you'll notice we're
going to subtract 16 from esp creating
this temporary space on the stack.
essentially allocating four words 16
bytes on the stack for use by local
variables.
Now in this case it turns out we're not
really going to use all that space.
We only really needed four bytes, but for
argument's sake, let's allocate 16.
The next thing that we do is we go get
the value of x by accessing the location
where that argument was stored.
remember 8 plus the base pointer, okay.
We get the value of x and then we set the
value of val and how do we set the value
of val?
Val is a local variable declared inside
the procedure and you notice that we made
a place for it at minus 4 ebp.
That corresponds to this location, our
first temporary word on the stack.
And we're going to just put the literal 1
there, okay.
So that creates that variable val and
gives it the initial value of 1.
All right.
The next thing we're going to do is, is
call s_helper from sfact.
And, to do that, we need to set up the
arguments for that procedure call.
Now, this procedure, s_helper, has two
arguments, so we're going to need to push
both of 'em onto the stack.
So, the first thing we need to do is
remember we pushed the arguments in
reverse order, so the second argument and
then the first argument.
Here is the second argument the address
of val.
So, what we've done is used an effective
address computation.
Instruction to compute that address,
remember just that minus 4 ebp that's
this location right there where we stored
val.
And we're going to put that address in
eax, then push eax onto the stack.
And that puts our first argument onto the
stack.
And that is an address, that points back
to val, okay?
the next thing to do is to push the other
argument, x, well that member we had
stored that in edx, so we can just push
that value of the register onto the
stack.
And we see this, that appear here.
At this point we call s_helper now that
we have the arguments on the stack.
And that will go in execute the code for
s_helper.
And remember in this case s_helper
returns a void, so it does not have a
return value.
How do we get the result of what, sub
helper does?
Well, remember it modified the value that
was stored at this location, for which we
provided the address as an argument, so
that s_helper can go and modify that
location.
So, when we call s_helper, the result we
expect to happen is that now the value at
that location of our temporary variable
has been changed to x factorial.
Going through that series of recursive
multiplys okay?
So, then our result for sfact which does
have to return an int value, is to go get
that value, and it's going to do it again
by just going to that address and moving
that result to eax.
And leaving it in that register when it
executes its return, so whatever called
sfact can find x factorial in the
register eax, that int value that was to
be returned.
Okay, so let's just summarize that the IA
32 procedure.
stack frame.
The important points is there's a
combination of instructions and
conventions we need to use to get this
happen correctly.
we have to prevent the functions from
disrupting each others correct behavior,
alright.
So, that means not only figuring out
where to return and pickup where you left
off, but also making sure that they don't
step in each others toes and destroy the
contents of registers That one function
thought was going to stay the same.
Alright.
So the stack turns out to be great data
structure for doing this, because when we
call one procedure we're going to return
from that callee procedure before we
return from the caller.
So, it has that nice property of growing
the stack and then shrinking the stack on
the return.
And recursion can be handled by all of
these normal calling conventions, there's
really nothing special we need to do.
We can safely store values we need, local
variables we need, in the local stack
stack frame and in callee saved
registers.
we put new arguments at the top of the
stack, and then called the fun and then
called the function.
The return value is returned to the eax,
and we know where to go find it by
convention we know where we will find it
in that register and and usage .
Wyszukiwarka
Podobne podstrony:
Register to letitbit and earn at least 50$ per weekComprehending conventional and novel metaphors An ERP study05 Registration CardNatural Variability in Phenolic and Sesquiterpene Constituents Among Burdock1 Land and mortgage registers05 Structures and AlignmentArticle 05 10 Talk and Listen Quiz 565vpc 100 pin code calculator register and activate nstructionsregistering and unregisteringcomparative study islamic and conventional bankingGeneral Government Expenditure and Revenue in 05 tcm90 418882007 05 Type Tool Texmacs a Convenient Layout Program for Your Text Documents(2009) Professionalisms, Sublanguages and Registers of Sports Utterances J Ożdżyńskiwięcej podobnych podstron