04 Linux Stack Frames


[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 systemowe
04 Linux Konfiguracja serwera poczty elekrtonicznej POSTFIX
2006 04 Images of the Empire Msn Messenger in Linux with Webcam Support
2001 04 Using Xine for Dvd Under Linux
04 (131)
2006 04 Karty produktów
04 Prace przy urzadzeniach i instalacjach energetycznych v1 1
04 How The Heart Approaches What It Yearns
str 04 07 maruszewski
[W] Badania Operacyjne Zagadnienia transportowe (2009 04 19)
Plakat WEGLINIEC Odjazdy wazny od 14 04 27 do 14 06 14
MIERNICTWO I SYSTEMY POMIAROWE I0 04 2012 OiO
r07 04 ojqz7ezhsgylnmtmxg4rpafsz7zr6cfrij52jhi
04 kruchosc odpuszczania rodz2

więcej podobnych podstron