Okay, so we just saw how a stack can be used to keep track of the return address in a procedure call. Let's take this a little bit further now and look at stack-based languages in general. Alright, that's the next part of this section. So, stack-based languages are really common. that's in fact the majority of the languages we use today. they're languages that support recursion, namely a procedure that calls itself. so these are languages like C, Pascal, if you remember the, from the old days, and Java as well. to make it possible to support recursion in a programming language code must be what we call re-entrant. Meaning that we can have simultaneous instantiation of a single procedure. What does that mean? That means that we've just called a procedure and in the middle of executing it. And then that procedure can call itself again and start executing a new copy of itself. And that one can call itself again and execute a new copy of itself and so forth. So that's a, you can imagine is an interesting problem to try to keep track of all of that. And in order to make that happen, what we need to do is to make sure to have a place to store the information for each instantiation of that procedure. And what information do we need to hold on to? Well that's called the procedures state. And that includes the arguments we called it with any local variables it has to work on, and of course a return address or return pointer. to where it should go in the procedure that called it, including potentially itself. and to do that we're going to extend this stack discipline. Okay. So bascially the state for a given procedure is all this stuff above the three check marks there. That are things I need for a limited amount of time while that procedure is executing. And then when it returns I can remove that state, I don't need it anymore. so the callee fortunately always returns before it's caller. Because we're returning back to the caller and then continuing the execution where we left off in the caller procedure. So one last definition we're going to call these allocations on the stack frames, procedure frames, or stack frames in general. And for each procedure instantiation we will have all the state in one of these frames. So let's take a look at an example of a call chain, a string of procedure calls. Alright so here we have some fun funny functions the function yoo which calls the function who. Okay, and we can see in the that we somehow started with the function the procedure yoo and it then calls who, okay? Now the procedure who in its turn calls amI twice. and in between It probably does some other things, okay? So were going to call amI then return back to this point and do some other stuff and then call amI again. so here we see the two calls to amI. That happen one after the other in who. But the function amI is a recursive procedure that calls itself. So heres the definition of amI and yoo see that inside it calls itself again. Alright you have already seen factorial functions that do this for example. So amI here you noticed in the first call, called itself once and then that copy of amI call itself again. But then it stopped and returned and returned and then may the second call to amI here. And then amI returned again back up to who and then who returned up to U and then U returned to wherever it was called from okay. So here we see that chain descending down the tree of cause that we have here and basically following that a path. Okay. So, let's see how this looks on the stack. Okay, so, let's take a, review that stack frame concept again. In the Linux IA32 architecture. the contents of a stack frame includes the local variables, arguments to the function any information about return addresses that it needs to go to. And then maybe some temporary scratch space. This this function might need. Maybe things like it's another version of local variables if you will. But maybe more temporary. All right. So here's the previous frame on the stack. Okay. And when we call a function, we create a new frame for it by adjusting the stack pointer to create a space for all of these things that are going to have to go into that frame, okay. What we're going to do is since we have a pointer to the top of it in the stack pointer We're also going to use another special register called the base pointer. you've seen this alread ebp, the Extended Base Pointer register, to point to the bottom of that stack frame. Okay. So the management then of these frames is such that when a procedure is first entered, we run it's setup code that creates the stuff in this frame. And when we return before we do that we run some finish code, that sort of cleans up what's in this frame before changing the stack pointer. to go back to the previous frame Alright? So again lets take a look at how our example is going to do this. right? So here remember it is our call chain, that went through this. Sequence of things calls going down, returns coming back up. So here we are in the middle of a procedure yoo, and we're about to call who, right. So, here's our yoo, yoo stack frame on the stack, there's a base pointer to the bottom of it, stack pointer to the top of it. That helps us define that size of that stack, the size of that frame, okay? But now we've just called who, and we've put a new frame on the stack, okay? And of course, our base pointer got adjusted and our stack pointer got adjusted. And you'll recall from some of the previous examples you might've seen assembly language examples. You might've seen the old ebp saved away first before we did this, so we can reuse that registry, okay? The next that's going to happen is we're going to call is amI.Okay. And here we go. Another stack frame is put onto the stack. Again, we've had to save that, that previous value of ebp that was there, because we had to change that again, so, we've had to find a place to put that. we're going to go along and execute amI now. And it's going to call itself So we're going to say another stack frame from amI appear on the stack, again with updated pointers. And, yet a thrid one as it calls itself yet again. Okay. So now we're at the bottom here of our call chain and we're about to execute our first return in the thridy copy of amI. So when we do that we remove its stack frame, put the ebp and esp back to where they were for the previous instantiation of amI. Okay. And we're now going to return from that one and remove that from the stack by adjusting the, the pointers again. So we have a new value for ebp, a new value for esp, okay? And now our next thing is to return from this instance of amI back to who. And when we do that, we'll eliminate the last of those frames for amI. And we're now back at the frame for who with its base pointer and stack pointer at either end. So we're now in the middle of the procedure, who and where about to do our second call to amI where so that another copy of amI's stack frame on the stack. We'll return from that, back to who, and then done with who, so will return back to yoo. And just have that left on the stack.