[MUSIC].
We've now seen how a call chain gets
translated into stack frames.
how each call puts a new stack frame on
the stack, each return takes one off.
so now let's go into a little bit more
details on what's inside of those stack
frames.
So we going to look at the Linux stack
frame, what's used in the IA32
conventions.
again the stack frame in, in this diagram
am showing the caller's stack frame which
includes bunch of arguments that its set
up for the callee.
And some other space that it might of
used for it's own temporary variables.
And then when it makes the call, it also
stores the return address that it wants
the system to return to when the callee
procedure is finished, okay.
So, what the caller has done is built up
a bit of, a bit of an area here where
it's put in the arguments to the callee
function.
And then a little bit more space for that
return address.
Okay, what happens next in the callee's
frame is that we have the old base
pointer of the callers stack saved of the
caller's stack frame saved.
we're also going to save some other
registers that we might want to be able
to reuse, so we'll have to restore these
before we return.
And then of course, some local variables
as well, that we might want to use in the
callee procedure.
And we'll get ready building up arguments
for any other functions that we want to
call from this procedure.
Okay, and of course as we do this, the
stack pointer will continue to move as we
add more and more things to the stack
frame.
Okay, so has the basic idea.
Lets see this in the context of an
example.
Here we're going to go back to that swap
function swap procedure that we had do it
a little bit differently this time.
here we have a function called call_swap
which doesn't do very much.
All it does is it calls another procedure
called swap with two arguments, two
addresses you'll notice, right?
Two addresses there for the two variables
whose values we want to swap.
So, the address of zip1, the address of
zip2.
Alright, here's the definition of the
swap procedure.
You notice that it has its two argument
it's describe that the type they built
pointers and they both points to the type
int.
So, these match up because of course our
two zip in two zip variables were ints to
begin with.
Right well we do then is to have two
temporary variables t0 and t1.
we load them up with the values stored at
those pointers, remember we're
dereferencing the pointer.
Going to get the value at that address,
that's going to be the value 15213 and
98195.
then we take those temporary values and
put them in the opposite location.
Again, dereferencing the pointers.
Okay, that's our function call_swap and
swap, our two procedures.
Alright call_swap is pretty easy to see
in assembly code.
What it's going to be doing at at least
the parts we care about are going to be
doing something pretty straight forward.
They're going to be putting two arguments
onto the stack using push instructions,
okay?
These will push the two addresses of the
two variables onto the stack, and then
it's going to execute the call_swap.
to get the callee procedure started.
Well before we get, well before we get to
that, let's take a look at the stack
then, at the end of this we'll of had
some previous stack of course.
And then we've added two values during,
during the push instructions that those
two addresses for our two arguments.
And then of course, we've added the
return address at, of being the call.
which is where we want to return when we
execute the return statement in the
callee procedure in this case swap.
Okay, so that's now the contents of the
stack.
Alright, so now let's go look at what
swap looks like in assembly code.
And here we have that setup code you've
seen before in other examples.
some finishing up code that we've seen in
other examples, and we've ignored this
for the most part until now.
Now, we'll talk about it in some detail
and here's of course, the body of swap
that does the actual flipping of those
two values.
Alright, so what we're going to do is
look at this in a lot of detail in the
next few slides.
let's start with that stack that as it
was when we started executing the swap
procedure.
So here's the first few instructions of
swap that setup code, right?
What happens after these instructions
execute the first three instructions?
Alright, so the stack starts off with
having a new value to it you'll notice
here we have a push of the register ebp
onto the stack.
So what did ebp point to?
Well, it was pointing to the base of the
previous stack frame.
The one for call swap and we've just
saved that pointer onto the stack, okay?
And of course, the push instruction also
change the value of esp to now point to
this new point of the stack.
Okay, the next instruction is a move
instruction that takes the value of the
esp and moves it to ebp.
This is setting up the new base pointer
for the new stack frame for the swap
procedure.
Okay, so right now both of those pointers
are pointing to the same location, the
top of the stack.
The very next instruction pushes the
value of ebx.
This is maybe a register that we're
going to use inside a swap.
So, we're going to push that value onto
the stack so we can restore ebx before we
return.
Okay, so we've just pushed that onto the
stack.
The stack has grown some more, you notice
that esp has been adjusted yet again.
So now, esp and ebp are not the same any
longer.
We're starting to grow that frame down,
in this case by saving away a register we
need to restore later.
Alright, next step is to start looking at
the the instructions that look at the
arguments the function.
those were these two, the next two
instructions of swap and what is going on
here?
You'll notice that we're taking the
current value of our frame pointer the
base pointer to our frame, and adding 12
to it.
Okay, so we're taking that address,
remember the parentheses, in this case,
means use the address stored there.
Add 12, go get that value and put it into
ecx, okay?
So, what does that mean?
Well if we go to ebp, it's pointing to
this location here.
When we add 12 to it, we're now pointing
to this location, which is where we've
stored one of our arguments, right?
Because we're starting our frame right
immediately after the previous frame.
We know that if we just do a little bit
of an offset, we can get to the value of
those arguments, that's that calling
convention.
The fact, that we put those arguments in
the, in a certain order right there in at
the top end of that previous stack frame.
Okay, so this lets us get to yp that's
first pointed argument and then this as
statement adds eight to that same pointer
to go get the other argument xp.
Alright, so this is why we see these
frequently at the top of procedure the
instructions get to get the arguments.
We've now have the arguments stored in
ecx and edx.
Once we have the arguments, of course,
we'll perform the operations of the swap
function, but we've seen those before
already.
So, let's skip ahead and talk about the
finish portion of swap.
Those instructions at the end that clean
things up.
Here we see a a move instruction that
takes the base pointer, subtracts 4, so
we're actually going to look at this
location 4 down from the current value of
our base pointer, and go take that value
and put it in ebx.
In fact, that was the old value of ebx
and so we're going to restore the value
of ebx to what it was previously, okay?
So, we saved and restored the registered
ebx and put that back exactly where it
was when we came into the function.
The next instruction again, copies the
value of the base pointer into esp.
and you notice that's the adjusting the
stack so that we don't think about the
value, the old value of ebx being at the
top of the stack.
Now, you might ask why didn't we use a
pop instruction here, and move the value
at the top of the stack into ebx and
automatically add 4 to the stack pointer
to get that adjustment.
Well we could of done that, it would have
been the equivalent thing.
this is a, a bit of an optimization,
because if we had to do that for several
registers.
we could use some faster move
instructions to do a bunch of things at
the same time, rather than the pop
instructions.
but essentially, that those two lines are
equivalent to a pop in structure.
And you'll notice that the very next
instruction is another pop this time to
take the old value of ebp and put it into
the base pointer register.
So, now we've back to the state where we
first were when we entered the procedure.
swap with the frame pointers, the base
pointer pointing to the top of the frame
for, called swap and esp to the bottom.
At this point, we can execute the return
instruction and use the return address
that was at the top of the swap, pop that
off.
And jump to that address which is that
one immediately after the call
instruction inside of the call_swap
function, okay?
and of course we, with the arguments left
on the stack, now it's up to call swap to
remove those arguments if it needs to.
or it could choose to just leave them
there and return itself having its stack
pointer adjusted to the previous frame
for the function that called it.
Alright, so let's go back to look at all
of the code for the swap instruction,
here are all the insructions of for the
procedure, and the code that called the
swap.
From call swap maybe consists of these
few lines as well as maybe other things
that were in that other procedure.
I'm not showing all of those here, you
notice here's the call instruction.
It had to provide the address swap of
course, the address actually stored in
memory is a relative address, as we've
seen before.
So, you'll notice that this is a negative
value, and because it has leading ff
there so it's a negative value.
So, we're actually going to subtract a
little from our current address of 409
probably enough to get us to 3a4 which is
the start of the swap procedure.
Okay, and we can get listings like this
of course using gdp.
Okay the return value that was stored on
the stack was this address ending in
840e.
You notice a different instruction here
called leave, leave is just a shorthand
for in fact the equivalent to
instructions move edb to esp and pop ebp.
Because those are so common, we always
use these in combination as the very last
two instructions as we finish up a
procedure and clean up.
They've actually been given a special
code in the x86 archetecture.
using the word the keyword leave and a
code of c9 for its output.
The last observation to make is that
although we saved and restored the
register ebx, we didn't bother to do that
for eax, ecx, or edx.
we just didn't bother saving those at
all.
and why not, we used those registers as
well in the code turns out.
well the reason we didn't save them is
because our convention is that the caller
needs to save those registers.
We're going to talk more about this in
the next section.
Wyszukiwarka
Podobne podstrony:
04 Linux SYSLOG i logi systemowe04 Linux Konfiguracja serwera poczty elekrtonicznej POSTFIX2006 04 Images of the Empire Msn Messenger in Linux with Webcam Support2001 04 Using Xine for Dvd Under Linux04 (131)2006 04 Karty produktów04 Prace przy urzadzeniach i instalacjach energetycznych v1 104 How The Heart Approaches What It Yearnsstr 04 07 maruszewski[W] Badania Operacyjne Zagadnienia transportowe (2009 04 19)Plakat WEGLINIEC Odjazdy wazny od 14 04 27 do 14 06 14MIERNICTWO I SYSTEMY POMIAROWE I0 04 2012 OiOr07 04 ojqz7ezhsgylnmtmxg4rpafsz7zr6cfrij52jhi04 kruchosc odpuszczania rodz2więcej podobnych podstron