Hello, everyone, and welcome back.
So let's start the last time we ended up here where we said talked about the stark frames and always,
again, just remember, always the current active static frame is number zero.
The previous one will be one, the previous will be two and so on and so forth.
Just make sure you remember that the current active stack is number zero.
Now managing stack frames, now the current stack frame is always the newest frame and a start frame
gets created when you call when a function is done.
So when you when your program calls a function, that's when we start playing with with a with a frame
or that's when the stack frame comes into the player of all or all of this.
So E.S.P points to the top of the current stack frame and it points to the top of the stack as well.
Why?
Because we just started our program.
Let's say let's just think of it like this.
We just started our program.
So we are now going to code mean so E.S.P will be top.
We we will now be in stock from zero and the E.S.P will be pointing to the top of the stack.
Now, whenever a function is called, a new start frame is created again.
Now, meaning, let's say when we looked at the previous code main called Myfanwy one.
When we want to do that, we will be creating a new stack for him, not us, but the system.
I mean, just just keep that in mind.
We are not the ones doing this.
So with that happening, local variables also are going to be allocated at the bottom of the creative
stack.
So once a new start frame has created, any local variables in that function will be added to the stack.
At the bottom of the stack, OK?
So and we will see this now when we go through this.
So let's start so to create a new start for him, simply change AVP value to be equal to E.S.P.
So that's what's going to happen.
SBP now will move it were to SBP E.S.P.
So now SBP equals E.S.P because now we want to create a new stock for him.
And again, why do we need to do that?
Because EBP will always be pointing to the base of that active stock from SBP again is always pointing
to the base of the active stock.
So now IDP's equal to E.S.P.
This means that the new stock frame is what?
It's empty like, like the the slide says and the previous stock frame now is indexed.
Astatke that number one, because this is like frame number zero, the one we are creating now.
But we have a problem here.
Hey, so how are we let's say we finish our function.
The computer or the system finishes executing that function, which is my first one, maybe, and we
want to go back to me.
How are we going to go back to I mean, we don't know where the base of the main stream or the stock
frame for the function mean.
We don't know where that is.
So how are we going to do that?
So let's try again.
OK, but this time we'll need to save Gbps value before changing it.
So before we change it, just not not rushing into things, just saying, yeah, let's keep it, let's
make it equal to S.P..
It's good.
But we missed something.
And that mess made us actually not able to go back to our previous frame.
So let's repeat the same steps.
But this time we will save EBP.
So first thing pushed the value of BP to save it were on top of the stack.
So that's what's going to happen now.
We copied that value.
We're on top of the stack.
What happened to E.S.P?
Look what happened to E.S.P and back and forth E.S.P changed.
Why?
Because E.S.P again, is always pointed to the top.
And since we pushed a value on top of the stack, then E.S.P also changed.
Now change the value of because we started.
So we currently have the value of EBP on top of the stack.
So now we can change it.
Why.
Because we don't need to worry about it.
It's already there.
We, we saved it.
We can come back to it later.
Now SBP equals to E.S.P.
So now we are creating a new stack for good.
Let's continue.
This is what is called, by the way, the prologue.
These operations is called the prologue.
So the prologue is creating a new start frame, then allocating space for local variables.
So assuming we have some function which requires local variables, we will be creating when we create
the static frame and then use that frame and allocate space for those local variables that start of
operations is called prologue.
OK, let's continue.
So now push and pop operations.
Keep that in mind.
Push and pop operations affect E.S.P value only.
Remember, when we push a value, then the the top of the stack needs to change.
So we need the E.S.P registered to always point on the top of the stack.
So it's going to change when we remove the value from the stack.
E.S.P is going to also change.
So and just keep in mind, when we push a value, the the address is going to be decreasing when we
when we paper value.
The address is going to be increasing y again because as you can see the the memories upside down.
Keep that in mind and I'm going to continue to remind you about that.
Now we don't need to see Vesp y for the previous Thackray because SPG actually equal to the SBP value.
We know the top of the previous stack frame is now actually the EBP value, so we don't need to save
it.
We already have it saved.
OK, the system already saved that.
So we don't need to worry about where was the top of the previous thackray.
We already have that value now to empty this current stack frame.
We want to empty it.
Let's say my fun one was done and I want to go back to mine now.
What will happen is ESPs value should be set to the same value of SBP.
What we need to do is just set E.S.P equal to SBP.
So what will happen here if we set E.S.P now TBP we actually deleted or we removed or it's really not
deleted?
I wouldn't say because it's not that, that's not what's going to happen.
The date is probably still there, but now we don't have access to it because the pointers have been
removed.
So to delete the current stack frame and return back to the previous one, we should pop out the top
of the top, out the top value from the stack into SBP.
OK, so now we we do that.
Now we are pointing to E.S.P, pointing to the top of the stack, which is also the top of the previous
iFrame.
Let's continue.
Again, the current stock frame is always the newest frame, and now we have since we see here now,
since we popped out the value of EBP, so this value which ESPN, EVP both are pointing to when we pop
that out.
So when we do a pop SBP, that value is now going to be stored in the register.
And what that means is now EBP will be pointing back to where it was at the beginning.
So this is how actually navigating the stack and creating frames and creating new frames, the prologue
removing frames, which is actually called the epilogue, this is how all of this happened.
So Epilog is emptying the current stack frame and deleting it, then returning to the content function.
So let's say we were in my fun one or my function one, and we finished the execution or the system
finished the execution.
Now my function one wants to go back to or the system wants to go back to Maine because that was the
one who called my function one or my phone one.
Then the epilogue is emptying the stack frame and then going back to the calling function.
So let's look at now functions both from a low level view.
OK, so we are we are going to understand the process by looking at the functions from a low level view.
So a simple function called in high level language is not simple operation as it seems like when we
do add X and Y, that's not just as easy as that.
That's not just one single instruction.
There's a set of instructions going to be happening behind the scene in order to do that.
So first, what's going to happen is we are going to push the arguments.
If there are any arguments, like if we have here X and Y, we are going to push those on top of the
stack and then we are going to do the call to the function.
And in order to do the function, this means we need to create a new frame for start working on the
ADD function.
So a prologue will happen, prolog operations will happen.
We will execute the function.
After the execution finishes, Epilog will jump in or the epilogue operation will jump in to clear the
stack in the frame, go back to the previous one and then any arguments which we pushed.
We mentioned this earlier.
They have to be popped out with a matching set of instructions.
So we have one push we need for that push.
So popping the arguments that we pushed will happen at the end and that's how the execution will happen.
Let's go to a little bit more details.
Let's look at that now, how we are breaking things down again.
We are we looked at the function, high level view.
We made it now.
We looked at the low level view, but we are now breaking things into how they really will look like.
So, again, push the arguments.
If we have any arguments, then we are going to push IP.
Why we are going to push IP because IP is the position where we need to come back.
When we start the execution, when we finish the execution of the function now jump to the functions
first instruction.
So we we jump to the functions first instruction.
But in order also to create the the frame for that new function, we need to push EBP.
So now we are saving the base pointer base of the stack on the on the stack, OK, the base pointer
on the stack.
Then we will set SBP to equal E.S.P.
So now they point at the same place.
So we now have a new function.
If there are any local variables, we will push them, execute the function now we'll do the reverse
thing now.
We'll pop out our local variables so we remove all of those because those were the last thing added
to the stack.
So Will, again, it's it's first in, last out.
So this was the first and so that's the last one out.
So we are going to remove them and then we are going to pop up so this value will pop back up.
So we are restoring the frame of the previous function and then pop IP.
So popping the IP, this is actually where the this push operation pupping IP.
So we are going to pop out this value, which is the position where I need to go back in order to do
the execution or continue the execution and then finally pop the arguments which were passed on to the
function.
We are also going to pop them.
OK, so they are breaking things down a little bit more and diving deeper into them.
Let's go continue.
Now, again, as you can see here, each push operation must be reversed by a proper operation somewhere
in the execution.
So as you can see here, this push for local variables was reversed with this pop, this push SBP was
reversed with this pop, this push i.p was reversed with this pop hip.
And then this push for the arguments was reversed by this pop of the arguments.
OK, so keep that in mind.
Now, performing a push up argument is done by the colored function.
So the caller, let's say the main was to call my friend one or my function one.
So the caller will push those values onto the stock.
Arguments are going to be pushed in reverse order.
So as you saw previously.
Here in this one, like add X Y, we will be pushing them in reverse order.
So just keep that in mind and you're going to see that in a minute.
Now, performing a pop argument, pop performing puppet arguments can be done by the caller or the calling
function.
Again, the pop.
Of the arguments will be done either by the caller or the COLLY, so when when we want to call on and
what if we go back to the mind, the mean and McPhun one?
So if me calls my phone, one man will be considered the caller and my phone one will be considered
the caller.
OK.
Keep that in mind, Maine is going to be considered the caller and my friend one is going to be considered
the.
OK, now who's going to be doing the pop of those arguments which the caller pushed on the stack?
So the caller puts those arguments on the stack.
Who's going to be popping those arguments out of the stack?
Who's going to be doing that?
That depends on the call type.
OK, so this is specified by the call type of the function.
OK, we're going to see what that is.
This is specified.
Who's going to do that as specified by the type of sorry, the call type of the calling function.
So return value of the caller call is served inside Ekso.
There is a return value.
Let's say you did add X and Y, you now return.
You want to return the sum of X and Y, that value is going to be returned into the X register while
the execution of the functions body.
So once the function is body is done, now that value which was to some, to some X and Y will be stored
in X, keep that in mind.
It doesn't have to mean, by the way, any function which will return a value, because in our case
it was at X and Y in any function.
Let's say it will return, let's say a memory location, it will return a subtraction, it will do any
kind of operation, that return value will be stored.
If it's a 32 bit value or it can fit within a 32 bit value will be stored into X or keep that in mind.
Now functions low level view, but this time focusing on cold types, now programming languages provide
a mechanism to specify the cold type of the function programming languages.
They can provide the mechanism or they provide some kind of mechanism that you can specify the call
type of the function.
Now, the call type guys is not a return value type.
OK, so we're not talking about the return value like integer void card or whatever.
That's not what we are talking about.
This is how the mechanism which we will be dealing with or the system will be dealing with and who is
going to be responsible of cleaning the stack.
So the caller needs to know the call type of the cauli, OK, to specify how arguments should be passed
and how that frame should be clean again.
Mean in order to call my phone, one needs to know what type what is the call type of my phone one.
Why?
Because based on the call type, the caller will decide who's going to be responsible of cleaning this
stack frame.
Is it going to be the argument?
I mean, is it going to be the COLLY or is it going to be the caller?
So let's see that in in some example.
Now, we are let's just talk about two quick, two quick different types of call types.
So these are two of them.
These are the most commonly used ones.
See declaration, which is the call type for functions.
Usually you can find this on Linux systems.
So the caller is responsible for cleaning the stack from the caller, is responsible for cleaning the
stack frame.
So if the caller is going to call a function and it's called type of C declaration or C, they can,
then the caller will be responsible of doing what?
Of doing the cleaning.
Now, as to Standard Caller, which is a default call for Win32 API, which is used on Windows, the
Cawley's responsible of cleaning, cleaning the stack.
OK, so the call the caller, let's say main cause my phone one.
And if it's using a static call, if my phone one is using a static call, then my phone one will be
responsible of cleaning the stack frame.
Let's see it individually.
So.
Again, if we go back to this, each of these steps are processed by one or many instructions.
Again, this is just like some visual view of what's happening, but it might be more than these instructions,
OK?
And we will see that actually in in a couple of minutes now as like as like as other programming languages.
Assembly provides many ways to perform the same operation.
Therefore, the disassemble code can vary from one compiler to the other another.
What this means here, and in case you are reading it, is sometimes we will see a push and pop, but
other times we will have probably some other ways of adding and removing values from the stack.
Now, this will depend on optimization.
We will talk a little bit about that after probably this video in the next video.
OK, but these operations will be different depending on the compiler and how the how the compiler actually
compiled the code.
OK, so this will be different from one compiler to another.
OK, keep that in mind.
But this is the base of all of them.
At the end, they even if they change them, even if they change these instructions, the concept is
the same.
But what's happening is at the lower end of the instructions, it's different for optimization reasons.
OK, so now we are going to go going to introduce the default way of performing each of these steps
using assembly language.
Again, this is the default or the basic way of how these operations are going to actually happen.
Let's continue.
So we have here side by side the declaration.
And then second, we can see here that the first to the one and this one was done are things done by
the caller.
And so these are the operations done by the caller.
These are the Cawley's operations.
So these are things done by the Collee and then these are operations done by the caller again.
OK, now.
And so this is when we have the declaration, when we said the caller will be responsible of the cleaning
as the call.
We have the same thing.
Nothing's changed.
Everything is the same.
But the only difference is here.
The return return will take some value, which is the size of the arguments that have been pushed onto
the stack.
So let's look at this again, push argument to push argument one they are pushing in reverse order called
the poly, which is my function.
One, push up.
We want to store the base of the, uh, the the main function, the base of the frame of the main function,
movable PSP.
Now we point them on the top.
If we have any local variables, we are going to push them.
Once that's finished, we are going to pop X, just pop that value, which is this value.
We are going to pop it into X pop.
So now we restore the the the base pointer for the previous frame return.
This will actually what, what it will do, it will take the position, put it into the EIP and then
continue the execution from there and then pop pop to put these two values from the top of the stack
while an entity called Push Push that's the same call, the same SBP move.
All of this is the same topics when everything is done is going to be the same.
Removing the local variable pop.
We are restoring the base of the main function return here is going to take a slice of, let's say,
these two values.
Each one of them was four bytes.
Then we are going to do return eight, which means remove from the stack eight bytes or just do that
and then go to the position where we have on the stack and continue the execution from that.
Let's look at an example.
So let's trace this, OK, by looking at this example.
And instead, we have not dive deeper into assembly will just giving basic high level view, so appears
the register is always pointing to the next instruction to be executed.
Once the CPU executes the instruction, it automatically moves EIP forward.
OK, so again.
Yipes.
Always pointing to the next instruction and once that instruction got executed by the CPU, the system
or the CPU will automatically move yippy to the next instruction.
OK, point to the next one or move it forward.
So now it is going to do the push argument to let's see what's going to happen.
So argument two got pushed again.
What happened?
E.S.P.
Now pointing to the top of the stack argument, one is going to be pushed.
So E.S.P again got decreased because we're now pointing also to the top of the stack and going to the
lower end of the memory.
Now, call what will what the call will do.
It will automatically push IP of the next instruction to be executed.
Were on top of the stack.
OK, and then do the unconditional jump.
So first it will push the position onto the stack and then it will do unconditional jumps.
What it will.
What does that mean?
It means it will go to the location where my fun one is located in memory.
So it's going to do that.
So that's why IP got put onto the stack.
Now we want to save the base pointer.
So SBP got saved.
EVP now equals DSP.
So now we have, we are creating a new frame and let's say we have one local variable here of type integer.
So it's four bytes.
We add that let's say it has a value of zero.
Now again, one very important thing E.S.P may change inside the call body, but SBP does not change.
Again, E.S.P might change inside the Colly body because it's going to grow up and down.
But SBP does not change.
Therefore, what what does that mean?
It means the system can use SBP to refer to locations of values on the stack.
Again, what this means since ESPs jumping up and down, depending on what you've done added to the
stack, we probably it's not a, let's say, a good way to refer to values on the stack because it's
keep up and down moving.
But EBP is always the location is always fixed so we can use it to refer to variable variables and arguments
which are already pushed onto the stack.
OK, so we will be using SBP to refer to values.
Let's look at an example here.
So if we look at EBP.
Which is pointing to the Eppy value, as you can see, EBP minus four points to the local variable.
Now Y when Y minus four.
And I mean by SBP minus four.
I mean the the memory address at that location, at the memory of SBP minus four will be pointing to
zero Y because remember the strong grows in the other way around, so it's growing to the the lower
end, so the addresses will be decreased and that and that end.
And as you can see here from EBP, if I want to access the first argument again, please make sure you
remember this because we are going to ask we have a quiz at the end of of the session, Gbps pointing
at that location, Heap's value.
And if I go to Eppy plus eight, it means it's pointing to the first argument SBP plus twelve.
That means is pointing to the second argument.
Why?
Because SBP plus four will be pointing here, SBP plus eight plus 12 here and so on and so forth.
OK, so this is good.
Let's continue.
Now, at the end of the call, which is when the epilogue kicks in, that set of operations happen is
Processo.
Cleaning the variable space is made by a pop operation.
So now this variable, we need to remove it from the top of the stack.
So we have this pop.
So we are going to do a up.
As you can see now, E.S.P points to EBP.
Now, if we do a pop for SBP, so we are going to restore this value, copy it into the Eppy register.
So this means now SBP points back to the base.
OK, so here is where the difference will happen between a C declaration and aesthetical.
OK, here is where the difference will happen between a C declaration and as to the standard currency
declaration.
But before we go and talk about that, just keep in mind that the return instruction here, this return
instruction, what it will be doing, it is going to be.
Copying this value, which is on the top of the stack, which is actually the iPod, the next instruction
or the position of where I want to continue is going to be copying it over into the extended instruction
pointer.
OK, so that now will redirect the execution were back to where it is.
It should continue.
OK, it's going to redirect the instruction back to where it should continue.
So when my when Min called my function one, my function one ended, we need to go back to the position
where I continue after I processed or after we did my function one.
So the return instruction is going to pop that value and it will now continue.
So we since we have here.
Two variables are two arguments on the stack, and since we are talking about the declaration, then
we mentioned the declaration is responsible of cleaning its mess.
So so the top of the values which were pushed are its responsibility.
So that's why now the caller will be cleaning the stacks of puppy puppies.
And now we go back to where we started while if we change this just to see the difference, if we go
back to now, which we have a second and let's say the argument size here is again, just one.
The argument is here.
We need to know how much is it?
But let's assume here we have two integers or two values, which each one of them is four bytes.
So, again, we will be doing great are the eight, which is for both of them.
So what will happen is the return instruction will pop that value from the start.
But now what will happen is.
We have each one of these are 32 bits, OK, in this example, each one of them is 32 bits and we are
going to move those, which is four bytes.
So we are going to move the two of them.
So we are going to move or let's say remove two of them, OK?
And we clean now the stack and now we are back to the caller execution.
OK, so as you can see here, the difference was between the standard call and see declaration is in
standard call.
The call is going to be responsible of cleaning the stack and see declaration.
The caller will be responsible of doing that.
OK, so let's stop here.
Will continue next time from this one code optimization.
We want to have gotten into the code optimization, but at least given an idea about what's happening.
OK, so that's it for this video.
I hope it was clear to you and you understand what we were talking about, about the static frames call
the different call types and how all of this is happening and all of this is going to, uh, working
in the system.
OK, so that's it.
See you in the next video.
Thank you.
Bye.