Skip to playerSkip to main content
  • 12 hours ago
Quick but deep look at local variables on the stack in x86-64 assembly (YASM). We cover allocation with sub rsp, accessing via offsets, why the stack must be 16-byte aligned when calling libc functions like printf, and two practical ways to fix alignment crashes. Includes live segfault debugging and a full working example with a local array.

Great for anyone studying systems programming, computer architecture, or just trying to figure out why their assembly program randomly crashes on a library call.

Like + subscribe if you want more clear, practical assembly tutorials!

00:00 Introduction to Local Variables on the Stack
00:28 C++ Example of Function and Local Variables
01:06 Incoming Arguments in RDI vs Stack Variables
03:24 Pointers as Local Variables on Stack
04:34 Why the Stack ? Recursion and Multiple Calls
05:18 Visualizing Multiple Stack Frames
09:24 How Function Returns Adjust RSP
10:35 Stack Grows Downward in Memory
11:33 Program Setup ? Hybrid C++/Assembly
12:46 Assembly Module Overview
14:00 Function Prologue ? Register Push & Alignment
15:30 Allocating Stack Space for Local Array
17:45 Initializing Array in Loop
20:10 Printing Loop with printf
49:48 First Run ? Segfault Observed
51:00 16-Byte Stack Alignment Requirement
51:55 Fix 1 ? Extra Push/Pop in Prologue/Epilogue
53:15 Fix 2 ? Push/Pop Around Each printf Call
55:04 Testing Different Array Sizes
56:52 Debugging Alignment Behavior
58:54 Summary ? Creating Any Local Data on Stack
59:59 Closing Remarks & Subscribe Call

x86-64 assembly, x86 assembly tutorial, local variables stack, stack frame assembly, yasm tutorial, nasm tutorial, stack alignment, 16 byte alignment, printf crash assembly, assembly stack allocation, sub rsp assembly, rbp rbp stack, assembly array on stack, low level programming, systems programming, computer architecture, reverse engineering, assembly language, x64 assembly, calling convention

=-=-=-=-=-=-=-=-=

Thanks for watching!

Find us on other social media here:
- https://www.NeuralLantern.com/social
- Twitter / X: https://x.com/NeuralLantern
- Rumble: https://rumble.com/c/c-3696939
- BitChute: https://www.bitchute.com/channel/pg1Pvv5dN4Gt
- Daily Motion: https://www.dailymotion.com/neurallantern
- Minds: https://www.minds.com/neurallantern/
- Odysee: https://odysee.com/@NeuralLantern:5

Please show your support!

- Buy me a coffee: https://ko-fi.com/neurallantern

- Subscribe + Sharing on Social Media
- Leave a comment or suggestion
- Subscribe to the Blog: https://www.NeuralLantern.com
- Watch the main "pinned" video of this channel for offers and extras

Transcript
00:00:00Hi there.
00:00:01Today I'd like to talk to you about local variables on the stack in an x8664 assembly
00:00:06program written in YASM.
00:00:14If you don't understand assembly or local variables or other things like that, you might
00:00:18want to see my other videos, but I'm just going to give you a quick example.
00:00:21So what am I talking about with local variables on the stack?
00:00:24For starters, forget what you're seeing here for a second.
00:00:26I'm going to open up a little blank code page and pretend that we're coding in C++ just
00:00:32for a moment.
00:00:32This is an assembly video, but pretend this is C++.
00:00:35So suppose you have C++, you have a main function here, and at the end of it, you know, this
00:00:40is your entry point for your program.
00:00:42We return zero and maybe above it, there's a function called F.
00:00:46I'm putting it above because I don't want to use prototypes in this video, but you should
00:00:49probably use prototypes.
00:00:52Maybe main calls on F, and so then inside of F, what happens?
00:00:57I don't know.
00:00:57Maybe we have some arguments.
00:00:58We'll call this integer argument A that comes in.
00:01:03If you've watched my other videos, hopefully you have by now, you'll know that A comes into
00:01:07the function as RDI because that's the first integer argument register.
00:01:13But then when we start creating local variables, we'll say integer B equals, let's say a five
00:01:19and then integer C is equal to an eight for whatever reason.
00:01:22Maybe there will be an array.
00:01:24So I'll call this int array, I guess.
00:01:30We'll say that we have a hundred integers in our array.
00:01:34We could also have a pointer in pointer P and then allocate it to some kind of new memory
00:01:38just to prove a point.
00:01:40And then, you know, later in your function, you're probably going to want to do something
00:01:44with your data.
00:01:44So I don't know, maybe A, how about like B is plus equal to A and then C plus plus
00:01:53and
00:01:53then, oh, C plus plus.
00:01:55C is plus equal to B for some reason.
00:01:58I'm just making random nonsense up, honestly.
00:02:00I'm just showing you that we use our variables and then maybe you want to build an array.
00:02:06So we just declared the array up here on line six, but maybe you want to actually do something
00:02:10with it.
00:02:10You want to fill it with data, maybe.
00:02:11So I'll do size type.
00:02:12I is zero.
00:02:14Keep going until I is less than, as long as I is less than a hundred, I plus plus.
00:02:18And now I'm going through every single index of the array.
00:02:20Maybe I'll say the array at index I is equal to C and then we'll just say C is plus
00:02:31equal
00:02:31to B and then we'll do B plus plus just to have something in there.
00:02:34Okay.
00:02:35So let me explain the parts of your program real fast.
00:02:38If you haven't watched my other videos, please do because this should help a little bit.
00:02:43But anyway, so a is an incoming argument, like I said before, that's usually coming
00:02:48to you in the RDI register because it's the first integer argument.
00:02:53So we don't need to worry too much about that.
00:02:55We know that a is actually just a register in your CPU and B that's created on the stack.
00:03:03And C is created on the stack also.
00:03:05And the array is created on the stack.
00:03:07By the way, I could name the array anything if I wanted to like just V I'm using the name
00:03:11array because it's easier for me to say, but notice also that we have a pointer here.
00:03:18I just wanted to make a point that the pointers we make in our function are, are considered
00:03:24local variables.
00:03:24And that means they do sit on the stack because what I'm trying to say is that local variables
00:03:29that are not arguments, they sit on the stack.
00:03:32But the memory we allocated and then gave to the pointer that's sitting in the heap somewhere.
00:03:37So when you use the new operator or the malloc operator, or you know, you're just
00:03:41like making dynamic memory.
00:03:44That dynamic memory sits in the heap, but the pointer itself, since we just declared
00:03:49it here, that sits on the stack.
00:03:51That means later on when your, when your function ends, the P pointer itself will get cleaned
00:03:56up automatically and itself won't be leaked memory.
00:03:59But if you forget to clean up your memory here, like I did, you'll have a memory leak.
00:04:03But I'm going to talk about memory leaks probably in some other videos somewhere else at another
00:04:09time.
00:04:10So anyway, so then we have our local variables here.
00:04:12Remember B and C and array are all on the stack.
00:04:17And well, we just have our for loop here where we just kind of start modifying data.
00:04:22So why would we use the stack?
00:04:24Let me just do a quick tutorial.
00:04:26This is not a stack video.
00:04:27I'm going to make a stack video in the future, but I'll just do like a quick little rundown
00:04:31of what is the stack and why is it really good for function calls?
00:04:35Consider that sometimes F might want to call itself.
00:04:37Maybe it's a recursive function or consider that there might be like a long chain of function
00:04:41calls like F calls G and G calls H and H calls, you know, whatever.
00:04:46And it just goes on and on and on.
00:04:47As long as it's not infinite recursion, like all the functions are calling themselves in
00:04:51one circle that never ends.
00:04:53You should be allowed to do that.
00:04:54We should be allowed to have a function F that sometimes calls itself or other functions,
00:04:59or maybe it's called multiple times within our giant call stack or call graph.
00:05:05And this will work because these variables, you know, A, B, and C and array are sitting
00:05:11on the stack and the stack allows you to have sort of different instances of variables.
00:05:16So for example, and this is just a quick thing.
00:05:18I'm not, this is not supposed to be a full stack tutorial here, but you know, if we have
00:05:22like the function F and let's say we call it at some point, maybe, maybe main calls F and
00:05:29then let's, let's pretend there's another function here.
00:05:31Main calls G and then G calls F and then F calls H and then maybe H calls F and
00:05:42did I
00:05:44write an H there?
00:05:45No, I think that's supposed to be a parenthesis.
00:05:48I'm sorry.
00:05:49I have bad penmanship.
00:05:51Oh God, it's even worse.
00:05:52Hang on.
00:05:53Let me do, let me do another H here.
00:05:54I'll just do it.
00:05:55I'll just do a G.
00:05:56How about that F and G and then, uh, what am I doing?
00:06:02Okay.
00:06:03And then G calls, uh, F again, let's just pretend that, uh, we can have a call graph where F
00:06:08is
00:06:09sometimes called by something and sometimes call something else, or maybe sometimes, uh,
00:06:13F is called by a different thing.
00:06:14So like, uh, I guess this was supposed to be the G function.
00:06:18So maybe that's why down here was the H.
00:06:22Should I delete this video?
00:06:23I don't know.
00:06:24You know what?
00:06:24I'm going to start.
00:06:25I'm going to delete this, uh, this drawing and just do it again.
00:06:27Okay.
00:06:28Pretend we have F calls G, uh, and then G calls H and then H calls F and then F
00:06:40calls, uh,
00:06:42I guess.
00:06:43And then eventually these functions start returning, right?
00:06:46Oops.
00:06:47How come my green's not working green?
00:06:48There we go too late now.
00:06:52So we can have like a really complicated call graph and F might appear in there multiple
00:06:56times.
00:06:56And the point that I'm trying to make is, um, each call to F along the call graph should
00:07:02have its own copy unique copy of local variables.
00:07:06So the B for this first F call, let me just do an arrow here.
00:07:10We'll have a B and you can imagine it as B subscript one.
00:07:15And down here when F executes, you can imagine that it's got its own copy of B.
00:07:19So we can imagine this as B subscript two.
00:07:21So these are two totally different Bs.
00:07:23If you tried to use global variables for this, uh, it would be really, really, really hard
00:07:27to get the code to work.
00:07:29Uh, and it would be really, really hard to debug.
00:07:31So that's kind of why we have local variables.
00:07:33The stack allows us to do this.
00:07:36So what is the stack itself?
00:07:37Again, this is not, you know, a full tutorial on the stack, but I just want you to kind of
00:07:41see what's happening.
00:07:42Imagine a data structure that kind of grows upward.
00:07:45Um, I'll say that here's the floor at the bottom.
00:07:49And when you put an item onto the stack, the items kind of stack on top of each other.
00:07:54So imagine that this is the call to F and embedded within this little stack frame area,
00:08:02we'll call it a stack frame, but actually the stack continues to grow as you create and
00:08:05destroy local variables within a function call.
00:08:08We'll just imagine that there's, I don't know, a mini stack sitting inside of the stack that
00:08:12contains all the local variables.
00:08:13I'll just put, I'm not going to put A because A is an argument.
00:08:17So it's sitting in a register, but we could do, dude, I got to learn how to, how to draw
00:08:22with this tablet.
00:08:24We got to do, uh, B and C and the array.
00:08:28I'll put, uh, AR for array sitting in, you know, their own little spots on the stack within
00:08:34the, the major portion of the stack that is designated for that first F call.
00:08:39And then, you know, maybe F calls G and some other stuff happens.
00:08:42I'll just pretend that a bunch of other stuff, stuff happened.
00:08:44And then eventually, um, F is called again, but there's a different, this is a different
00:08:50instance of the call to F.
00:08:51So that means it's got its own little area that is separate, uh, from the, the previous
00:08:57call to F.
00:08:57And again, we'll also have, uh, variables that we can create locally that are supposed
00:09:03to be separate, um, from the original variables.
00:09:07Oh God, that's awful and ugly.
00:09:09I need to maybe decrease the size of my eraser or something.
00:09:13Um, but imagine this is, uh, you know, these are two separate copies.
00:09:16So that's like what I said before, when we have like a B1 and a B2, basically, they're
00:09:20not going to be called B1 and B2, but they're just two separate instances.
00:09:22And I just want you to know.
00:09:24So then when we start returning from functions, like when this, uh, when this F eventually
00:09:29returns, and by the way, I know that what I'm drawing on the right doesn't match the
00:09:32code because this is not a function that calls itself, but just suppose that your code is
00:09:37a lot more complicated than what I drew up.
00:09:39Um, when it eventually returns, all that happens is those items on the stack just sort
00:09:43of get, uh, not necessarily deallocated, but ignored.
00:09:47We'll just say that they're gone.
00:09:49Um, they're still sitting as junk data in system RAM somewhere.
00:09:52Um, and in assembly talk, we know that we have a stack pointer called RSP.
00:09:58We have a, a register called RSP that just sort of points to the location in the stack that
00:10:04is considered the top of the stack, like the most recent piece of data that we have available.
00:10:09So all the other data is actually still kind of above, but we're not pointing to it anymore.
00:10:14So we consider that it doesn't exist.
00:10:16So then when G eventually returns, you know, we, uh, we just change the stack pointer RSP
00:10:25to point to that other piece of data, the G data frame and the other F data frame are still
00:10:30sitting above somewhere in memory, but we just ignore them.
00:10:33Right?
00:10:33So that's how the stack works.
00:10:35And that's how we have, uh, uh, local function call copies of all of our local variables.
00:10:42Uh, something to note, this is not a stack video, but you know, just something to note
00:10:47that even though I draw the stack visually as growing vertically up, uh, when you actually
00:10:51manipulate the stack in, uh, in assembly or just like in any language, the stack grows
00:10:57downward in terms of memory locations.
00:10:59So you can imagine, I'm trying so hard not to make this like a huge stack video, imagine
00:11:05this is a memory location, 80, we'll say, uh, you would think that memory location 81 would
00:11:11be the next item of the stack.
00:11:12Or I guess if you, if you're considering the fact that the items on the stack are quad words,
00:11:17we would say it goes up to 88, but that's not true.
00:11:20It goes down to 72.
00:11:23So the memory location goes down, even though we imagine the stack growing, uh, upward vertically,
00:11:28just so you know, that's the kind of thing we're going to do.
00:11:29So what I'm going to do is just show you an assembly program where we can create local
00:11:34variables.
00:11:35And I'm just going to show you how to create an array because this array is just like a
00:11:40bunch of integers.
00:11:41And you can imagine it would be really easy to create only one integer by just imagining
00:11:46an example where the array is a size of one.
00:11:50So keep that in mind.
00:11:51And I'm not going to show you a malloc or anything like that.
00:11:53We're just going to look at the local variables.
00:11:55Okay.
00:11:56So for starters, I have a make file here that's just going to compile a hybrid program.
00:12:00If you don't know make files or you don't know hybrid programs, that's okay.
00:12:04Just see my other videos.
00:12:05I've explained them in detail.
00:12:07Uh, the first source code file here is just driver.cpp.
00:12:11Uh, again, this is a hybrid program.
00:12:12So I'm going to mix my C++ modules with my assembly modules, which is pretty cool.
00:12:18The whole point of the driver is just to contain the entry point, you know, main, and I'm just
00:12:23going to print a hello message, and then I'm going to call the real function that I'm interested
00:12:28in, which I've named local underscore VAERS.
00:12:31And that's going to be all the assembly stuff that we talked about.
00:12:34I do an extern C block so that C++ can call an assembly module that's explained in other
00:12:40videos.
00:12:41And then, uh, here's the real heart of what we got to do.
00:12:44Let's, let's write up an assembly module that can do local variables.
00:12:50Okay.
00:12:50So again, if you don't know assembly, that's okay, but you need to watch my other videos
00:12:55before you can understand this one.
00:12:57So I'm going to just copy paste some starter code here.
00:13:00This is Yasm assembly in x86 64.
00:13:03So I've got a data section up top and I'm just going to define some messages.
00:13:07So, uh, you know, I've got like an intro message that just says, hello, I'm so-and-so and that's
00:13:13not my name, but I like those kinds of names.
00:13:16And then over here, I'm going to do some, uh, print F formatted strings.
00:13:21That's why I'm using a hybrid program for this video.
00:13:24I don't want to import my own personal library.
00:13:27I want you to be able to do this at home with, uh, just the GCC libraries.
00:13:30So if we link a hybrid library, you know, linking against GCC, instead of linking against LD again,
00:13:37if you don't know that stuff, check my other videos, then, uh, we're allowed to call C functions.
00:13:41In this case, we're going to call print F and we're just going to give it the string %LU, uh,
00:13:47meaning I would like you to print just, you know, an unsigned long integer.
00:13:51So I'm going to give it a value at some point on the stack, uh, representing a local variable.
00:13:57And then I want it to print as just like a long, like a string that a human can read.
00:14:03Then after that, this is the carriage return line feed, the CRLF.
00:14:07Print F won't flush its output unless that is sitting at the very end of the string.
00:14:12So I'm just going to use print F to also print my new lines.
00:14:16And then I'm going to null terminate the string so that print F doesn't freak out and try to print
00:14:20a bunch of stuff after the CRLF.
00:14:23And, uh, oh, I, this was from another video.
00:14:26Let me get rid of that.
00:14:27We don't really need CRLF in this video because, uh, we're just putting it directly
00:14:32inside of the print F, uh, string.
00:14:34We're not making our own function to do that.
00:14:37So then I'm going to make some defines.
00:14:38I'm going to define that we're going to have, uh, 50 integers.
00:14:41So I'm calling this define 50, uh, I'm calling it num integers.
00:14:44And I'm saying that it has a value of 50.
00:14:45So I want to make an array that has 50 integers.
00:14:48I don't know.
00:14:49Maybe if you want to imagine a hundred, uh, you know, like the example that I just showed,
00:14:53I'm going to keep it at 50 and then we're going to define what is the integer size.
00:14:58So I'm going to use quad words, which are 64 bit integers.
00:15:01So I'm just going to say that there are eight bytes per integer that will help me multiply
00:15:05later.
00:15:06And then I'm going to decide to fill up the array on the stack with just some numbers,
00:15:12just to prove that I can just to prove that we can like, uh, you know, manipulate and, and
00:15:17fetch the values of all this stuff going on in the stack.
00:15:21And I'm going to say that the starting value is seven.
00:15:23So when we're done with this, we should expect to see like an array of numbers that starts with
00:15:28seven and it just kind of increases somehow.
00:15:31Then I'm going to do some system call codes.
00:15:33We talked about that in a different video and then some file descriptors.
00:15:37I don't think we actually need anything but standard output, but I put it in there anyway.
00:15:41Then the next thing we're going to add is the text section.
00:15:47Let me just do copy paste on my solution here.
00:15:50So here's the text section, uh, section text, uh, in YASM.
00:15:55And I'm going to let my module know that I want to be able to call printf,
00:15:59which is a function sitting in the GCC libraries.
00:16:02When I link against a GCC, I have the ability to do that.
00:16:05That way I don't have to come up with like a complicated printing
00:16:08method or, or, or use it.
00:16:10One of my own shared libraries or something.
00:16:12So we can just ask printf to do everything.
00:16:14So now here's the entry point for the module.
00:16:16It's just a function called local VAERS.
00:16:18I mark it as global.
00:16:19So it's accessible to outside modules, i.e.
00:16:23or e.g.
00:16:24Um, driver dot CPP.
00:16:27And then, so here's the label saying the function starts.
00:16:30And here's the return statement saying that we're done with the function.
00:16:33I'm not going to manipulate any registers inside of the function.
00:16:36So I don't really need to do any push pop to preserve them.
00:16:39First thing I'm going to do is call a welcome.
00:16:41Let me comment this part out, by the way,
00:16:43I'm going to call a welcome a function.
00:16:46And the whole job of the welcome function is just to,
00:16:49you know, print a welcome message to the user.
00:16:51So nothing that I haven't talked about before in other videos.
00:16:54So it's just, we're using a system call to print a string.
00:16:58Okay.
00:16:59So with that in mind,
00:17:00let me open this up here and see if this is going to work.
00:17:04I just want to basically print the welcome message at this point,
00:17:09clear and make run.
00:17:10And again, if you don't know make files or anything like that,
00:17:12see my other videos.
00:17:14So this is the driver.
00:17:16I think that prints,
00:17:17maybe I should change the driver's message to make it more clear.
00:17:22Um, hello.
00:17:24How about this is the driver and my name is whatever.
00:17:30So I'm gonna do it again.
00:17:32And now it says, hello, this is the driver.
00:17:34Okay.
00:17:35So that's the CPP module.
00:17:37And then here is the assembly module.
00:17:39And then finally the driver gets control back.
00:17:41And then the program exits.
00:17:43So nothing really happened.
00:17:44So now let's upgrade the assembly module a little bit.
00:17:47Next thing I want to add is the actual, uh, demo function,
00:17:51which is going to be absolutely huge.
00:17:53So first I'm going to start off with, um,
00:17:57how about just the signature here?
00:17:58Let's go right after the welcome module.
00:18:02And I'm just going to copy paste the signature,
00:18:04put a return at the end of it.
00:18:05So we'll consider this a function that can be called.
00:18:08And, uh, that means up here,
00:18:10I can just use that call demo, uh, instruction on line 47 of the entry point.
00:18:16And then, um, now we have a demo function that is being called,
00:18:19but it does nothing for starters.
00:18:22Uh, you know, I, in my comments, I like to put the signature of the function
00:18:26and I like to remind myself of how I'm using my registers.
00:18:30Hopefully I'm not using the same register in two different ways,
00:18:32but you know, sometimes it happens if it does.
00:18:35And I'm able to break my function up into multiple parts.
00:18:37I'll probably do it.
00:18:38Uh, cause that's easier to code, you know,
00:18:40with modular thinking modular programming.
00:18:43But in this case, I'm just using these registers.
00:18:46It's fine to use them.
00:18:47They are all designated per the ABI as callee saved.
00:18:51So that means the callee, which is the demo function is responsible for
00:18:55preserving them.
00:18:56So if you don't remember that, or if you don't know about that,
00:18:59see my other videos, this is not an ABI video.
00:19:03So I'm just going to push all of them to make sure that they're preserved.
00:19:07I'm going to call this the prolog.
00:19:09Then at the end of my function,
00:19:10I'm going to call this the epi log where I just restore them in reverse order,
00:19:14because that's the way the stack returns data to you.
00:19:17The stack returns data to you in reverse order.
00:19:19So I have to pop in the reverse register order to un-reverse the reversal,
00:19:24if that makes sense.
00:19:26Pop R13, pop R12.
00:19:29Okay.
00:19:29So I think 15, 14, 13.
00:19:31Okay.
00:19:32So I got that.
00:19:33Next thing we'll do is, um,
00:19:34let's remember where the stack pointer started,
00:19:36because we have our register here that we're going to mess with.
00:19:40Let me just type RSP real fast.
00:19:41So this is the stack pointer register, RSP.
00:19:44This helps all programs know where, where they're looking at in the stack.
00:19:50All of your functions have to be really, really careful about messing with the stack pointer.
00:19:53If you do it wrong, you will crash the entire program.
00:19:56Because not only will your local function not really know
00:19:59where its local variables end and begin,
00:20:01it probably also won't be able to remember
00:20:03its return address when you try to return from the function,
00:20:06because that is also sitting on the stack.
00:20:07And even if you were lucky enough to be able to jump back correctly
00:20:10to whoever called you,
00:20:12if you messed up the stack pointer,
00:20:14then you've also messed it up for any
00:20:15caller of you and any of their callers.
00:20:18So the whole program is ruined.
00:20:20So we'll start off by trying to remember where the stack pointer was.
00:20:24We'll move the stack pointer into the base pointer.
00:20:31All right.
00:20:31There's something that I didn't do here that I, that I want to do.
00:20:34We should, since we're messing with the base pointer and other programs,
00:20:38sorry, other functions or modules might also rely on the base pointer
00:20:41and it's considered Kali saved.
00:20:42We probably also want to preserve that too.
00:20:45So I'm going to do push RBP to basically say,
00:20:49um, I would like to restore,
00:20:50I would like to preserve the base pointer so I don't mess it up for my callers.
00:20:56So that means I have to restore it, uh, with the pop.
00:20:59So RBP, the base pointer isn't necessarily a pointer to the stack,
00:21:03but it's often used as kind of like a bookmark.
00:21:07So we have RBP at the front and the back there.
00:21:11Let's see.
00:21:12Next thing I want to add is, um, so, so now that we've restored it,
00:21:17we're allowed to just override it because, you know,
00:21:20we're kind of like keeping its value at the top.
00:21:22Then we're restoring its value at the bottom.
00:21:24And that means we can actually mess it up in the middle if we want to,
00:21:27and it'll be fine.
00:21:28Let me show you real fast.
00:21:29What happens, what happens is nothing.
00:21:32The program is still okay because we, uh, we restored it.
00:21:36So now we're using the base pointer to remember where the stack was.
00:21:40Now we've got to, uh, sort of calculate how much room we want to make on the stack.
00:21:45Let me show you what I'm talking about here.
00:21:48Remember all of our local variables are going to be on the stack.
00:21:51And before we drew this thing where it was like, well, we've got like a stack sitting here
00:21:55and let's just pretend that there's some kind of data sitting on the stack.
00:21:59Data, data, data, right?
00:22:01Uh, if the stack pointer, dude, green, green.
00:22:06There we go.
00:22:07Oh, I erased my green RSP.
00:22:10Uh, if the stack pointer is currently pointing to this frame,
00:22:13uh, then in order for us to make room on the stack to hold our array.
00:22:19Well, if the whole array is going to be sitting on the stack, that just basically means
00:22:23let's suppose that we have five integers.
00:22:26Suppose five, uh, suppose that we want to make five integers on the stack.
00:22:31That just means we need to do five extra slots.
00:22:33Let me draw it in red here.
00:22:35Well, let's see, can we get a green?
00:22:37No, how about a yellow?
00:22:39My green is just having a hard time.
00:22:41We can do it in red, even though this is not a bad thing to do.
00:22:43So I'll just draw like five extra frames on top of, on top of the stack here.
00:22:50Five extra pieces of data.
00:22:51You can imagine these are all 64 bit integers.
00:22:55And so they take eight bytes on the stack.
00:22:57Even though in our previous example, we were using, uh, just regular ints, which are 32.
00:23:01We'll just say we're going to make five 64 bit integers because that's easier.
00:23:05So they're quad words.
00:23:06So every frame is actually eight bytes and not just four bytes.
00:23:10And it's definitely not one byte.
00:23:11So we make five of those.
00:23:12How do we make five slots?
00:23:16It's pretty easy.
00:23:17We, we literally just move the stack pointer.
00:23:19Let's see.
00:23:20We just move the stack pointer to, or the, you know, the RSP register to just say,
00:23:26let's, let's point, you know, further out and how do we get that number?
00:23:29We're just going to multiply the size of one integer.
00:23:31So, you know, the size of one integer here, we know it's going to be eight bytes.
00:23:35We just multiply that by the number of integers that we want.
00:23:38You know, that's going to be 40.
00:23:39So we'll just increase, uh, sorry, decrease the stack pointers value by 40.
00:23:46Because remember again, when the stack grows vertically,
00:23:48it's actually growing downward in memory.
00:23:50So we're going to decrease by 40 there, at least in this drawing example.
00:23:54And that gives us a bunch of junk data, you know, because there is always going to be
00:23:59some kind of a value sitting at every memory location in your computer.
00:24:02It's impossible that there is literally nothing at some memory location.
00:24:07Um, unless you're trying to go beyond your RAM stick, but then the system will still acknowledge that,
00:24:13you know, you, you've done that and, uh, it won't just give you back nothing if you try to read.
00:24:17Um, so there's going to be junk data sitting on there and then we'll loop, uh, through all those
00:24:22slots on the stack and we'll just modify the data one by one so that we can control what it
00:24:27is
00:24:27instead of just printing whatever junk data we end up with.
00:24:30So really we're just moving the stack pointer, just making room and then just remembering where
00:24:34our array is.
00:24:36We could put, you know, another frame on top.
00:24:39If we wanted to make just like one integer as a local variable,
00:24:42you just got to remember where it is.
00:24:43You know, what is it?
00:24:44What is its offset?
00:24:47Okay.
00:24:48So I'm going to erase this because we're going to do a lot more than, uh,
00:24:53than five, uh, integers on the stack, but I just want you to understand what we're doing before we do
00:24:58it.
00:24:59Okay.
00:25:00So the next thing I'm going to grab is a move instruction and I'm going to put it right here.
00:25:06So what is this?
00:25:09We're going to calculate how far to move the stack pointer.
00:25:15Uh, rsp.
00:25:17So the first thing I'm going to do is I'm going to use a temporary register.
00:25:19We don't need to preserve this in the push and pop because it's marked as temp.
00:25:23So we're not responsible for preserving it.
00:25:26Um, so I'm going to say r10 is just going to be the number of integers that we want to
00:25:30create.
00:25:30If you recall at the top of our program here, num integers is just 50.
00:25:35Okay.
00:25:35So then the next thing that I'm going to grab is,
00:25:39well, I'm not going to grab it.
00:25:40I'm going to straight multiply by integer size.
00:25:44So again, if you look at integer size,
00:25:46that's going to be eight because we're using quad words for our integers.
00:25:50So we're really just going to take 50 times eight, whatever number that is.
00:25:56Is that 400?
00:25:57Tell me in the comments if that's a right or wrong.
00:26:00And so, uh, you may or may not know if you don't see more videos, see more textbooks.
00:26:06You may or may not know that the iMole instruction just multiplies two numbers.
00:26:10If you use the three, uh, operand format, then the last two operands get multiplied
00:26:15and the results stored in the first operand.
00:26:18But if we use the two operand format, like I've done here,
00:26:21then both of those operands get multiplied and then the result gets stored in the first operand.
00:26:25So basically at this point, R10 should hold the number of memory locations
00:26:31that we should move the stack pointer in order to make room for all those integers,
00:26:35like I showed you a second ago.
00:26:38So then we're going to move the stack pointer.
00:26:43And maybe I'll leave a little comment here.
00:26:45Remember the stack grows downward in memory.
00:26:51And so all I'm doing is subtracting the stack point.
00:26:55Remember the stack pointer register.
00:26:56It just holds a number, which is a memory location.
00:27:00So if you subtract some numbers from it, you're really having it go downward in memory.
00:27:04And that's what we want to do to, you know, grow the stack for a local variable.
00:27:08So I'm going to say, well, I should also say that we're using the two operand version.
00:27:13So just like iMole, if we had the three operand version,
00:27:17then the last two operands would have one subtracted from the other.
00:27:20And the result will be stored in the first one.
00:27:22But since I'm using the two operand version,
00:27:25basically it's taking RSP minus R10 and then storing it in RSP.
00:27:31So this instruction just says,
00:27:33let's move the stack pointer downward in memory enough times that we have room for all of our integers.
00:27:39Okay, no problem.
00:27:41Next thing that we're going to do
00:27:44is we're going to move R12.
00:27:48We're going to move into R12, the current value of RSP.
00:27:53Remember is RSP.
00:27:58So let's see downward in memory.
00:28:05Um, right.
00:28:09Let's okay.
00:28:10So the first integer, you know, it's up to you how you style this.
00:28:14Because once we do the subtraction,
00:28:16then RSP is actually going to be pointing towards an integer.
00:28:21You could consider that to be the first integer or the last integer,
00:28:25because all we have is an array of integers.
00:28:27So you could say, you know,
00:28:29RSP, wherever it's sitting, when we're finished,
00:28:31we could say that's pointing to the first integer,
00:28:33or we could say it's pointing to the last integer.
00:28:36But, um,
00:28:38if we decide to say that it is pointing to the, let's see.
00:28:45Yeah, if we're deciding that it points to the first integer,
00:28:48let me just do a little comment here.
00:28:49First integer, it just makes it a little bit easier for me
00:28:52to write our loop that iterates through integers.
00:28:54But just, just keep in mind,
00:28:56you could start by pointing to the,
00:28:57to the one that RSP is pointing to,
00:29:00or you could start by pointing to the,
00:29:01to the other one that was like the first one that you added onto the stack.
00:29:04You could call either one of those the first integer,
00:29:06as long as you remember where you're,
00:29:08where you started.
00:29:09So you can increase or decrease the memory location,
00:29:13to get to the next integer.
00:29:15So I'm just going to do it in this style.
00:29:16But keep in mind,
00:29:17as long as the only thing that you modify and read is within that range,
00:29:21it's, it's okay.
00:29:22So let's remember where is RSP.
00:29:24So that's like the top of the stack.
00:29:25We're going to say R12 holds the,
00:29:27the stack pointer.
00:29:29Um,
00:29:30so that we can use R12 as sort of a running pointer.
00:29:35I think that's the way I'm going to use it.
00:29:36Let me just double check my solution.
00:29:48Yeah.
00:29:49Okay.
00:29:49So let's,
00:29:50let's now do a calculation where we remember where the last integer is.
00:29:55So we know where the first integer,
00:29:56we're just going to call this the first integer.
00:29:59I'll put it in quotes just to remind you that this is just the style I happen to be using.
00:30:04So here,
00:30:05we're going to say that the first integer is wherever RSP is pointing.
00:30:09And then in R13,
00:30:10we're going to remember where the other side of the array is.
00:30:12In this case,
00:30:13we're calling it the last integer.
00:30:14And pretty much it's just R12,
00:30:17which is where the first integer is.
00:30:19And then we,
00:30:21we add to it a memory location.
00:30:23So remember,
00:30:24we said before that the stack grows downward in memory.
00:30:26So if we consider the top of the stack to be the first integer,
00:30:30then that means previous items,
00:30:32maybe I should draw this,
00:30:34are going to be increased memory locations.
00:30:36So that's kind of like the,
00:30:37the backwards of what you imagine a stack is doing,
00:30:40but that's kind of the way that I like it sometimes.
00:30:42So imagine,
00:30:44just in a very simple stack,
00:30:46let's pretend that the stack has one byte of values,
00:30:49which it doesn't,
00:30:50but let's pretend if you,
00:30:52if you do it,
00:30:54I got to learn how to draw.
00:30:55I can't get that five right.
00:30:59Okay.
00:31:01I'm defeated.
00:31:03So let's pretend that that address on the thing sitting at the bottom of the stack is five.
00:31:07So then that means the next address would be four,
00:31:09right?
00:31:12But if we decided,
00:31:14let's say that the,
00:31:15well,
00:31:15let's do like a few more just to make it a little bit more interesting.
00:31:19Let's do a total of five.
00:31:21So we'll say four,
00:31:22three,
00:31:23two,
00:31:24one.
00:31:24Maybe I should just add some numbers in front of those values.
00:31:29So it doesn't feel like we're hitting zero,
00:31:30but so just pretend we have a memory location of 15.
00:31:33That's not going to be the case in real life.
00:31:35Pretend that we have one byte integers on the stack,
00:31:37which is not going to be the case.
00:31:38We're going to have quad words,
00:31:39but you know,
00:31:40you can see the memory locations go downward,
00:31:41right?
00:31:42So then we'll see that to the stack pointer is pointing to the top most location.
00:31:49We have to remember that anything up here might exist in system RAM,
00:31:55but it's not considered valid data because we didn't,
00:31:57you know,
00:31:58make it part of the stack by,
00:31:59by growing the stack pointer.
00:32:01So that means these,
00:32:06these items,
00:32:07well,
00:32:07maybe I'll do a check instead of an X because X looks bad.
00:32:11I'll do a check and a check and a check and a check.
00:32:15These items are okay to use.
00:32:18So if I have RSP,
00:32:21or in this case,
00:32:22we just remembered where RSP was by storing R12.
00:32:25If we have that memory location 11 and we want to get an additional integer,
00:32:30like somewhere else,
00:32:31like the next integer,
00:32:32well,
00:32:33that would be,
00:32:33you know,
00:32:34this one down here,
00:32:34we wouldn't go in the other direction.
00:32:37We wouldn't go,
00:32:39you know,
00:32:40up,
00:32:40we would just go down in the stack,
00:32:42but down visually is actually growing upwards in memory.
00:32:47Because remember when we grow upwards,
00:32:49visually we're growing downward in memory.
00:32:51So,
00:32:51and you can see here too,
00:32:52if we're,
00:32:53if we're increasing 11 to 12,
00:32:56that means we're adding memory locations to get to the next,
00:32:58uh,
00:33:00integer that we have in the stack.
00:33:02So that's why here,
00:33:05my green is just like frustrating me.
00:33:07I still have to fix this.
00:33:09So that's why here we're adding a little formula instead of subtracting,
00:33:13because the RSP started there.
00:33:15We're saying that the top of the stack is the first integer,
00:33:17just so we can add in a more convenient,
00:33:20nice way.
00:33:23So what are we adding to it?
00:33:25We're just adding to it.
00:33:27Um,
00:33:28the number of integers minus one.
00:33:31Uh,
00:33:31and then,
00:33:31so that's,
00:33:32that's the number of slots that we'll jump over and multiply that by the
00:33:35integer size.
00:33:36So if you imagine,
00:33:38you know,
00:33:38if we had 10 integers,
00:33:40then,
00:33:41uh,
00:33:41you know,
00:33:4210 minus one is nine slots.
00:33:44So if you imagine that zero is the first integer,
00:33:48let's say the memory location again,
00:33:49then that means one,
00:33:50two,
00:33:51three,
00:33:51four,
00:33:51five,
00:33:51six,
00:33:52seven,
00:33:52eight,
00:33:52nine,
00:33:5410 minus one is nine.
00:33:55So if we added,
00:33:57uh,
00:33:57the number of integers minus one from the start,
00:34:00which we'll consider zero here,
00:34:01that means it goes to the last integer directly.
00:34:04So that's just like a little math.
00:34:05Cause sometimes when you,
00:34:08when you think of adding two numbers together or taking the difference or
00:34:12including the first number or not including the first number,
00:34:14it's a little confusing,
00:34:15right?
00:34:15So keep in mind for this particular calculation,
00:34:18uh,
00:34:19we are adding to it the number of integers minus one.
00:34:23So that will be sitting on the last integer rather than going past it.
00:34:28So start with the first integers memory location,
00:34:31and then the number of integers minus one or size minus one times the integer
00:34:34size,
00:34:35because remember every integer is going to be eight bytes and that will give us
00:34:38the memory location of the last integer
00:34:41in R13.
00:34:43And then I've said this in other videos,
00:34:45but basically you're only allowed to make these sorts of calculations in YASM
00:34:49when you have the calculation inside of brackets,
00:34:51but brackets will automatically de-reference the value on the inside.
00:34:56It'll consider it as a pointer that needs to be de-referenced,
00:34:58but we don't want to de-reference anything.
00:35:00We don't want to go to a memory location and take a value.
00:35:03The memory location is the value.
00:35:05So these de-referencing brackets which are required for the formula are kind of bad.
00:35:10So that's why we use the LEA instruction instead of the move instruction.
00:35:14If I put move there,
00:35:17it would definitely de-reference the memory location and give me a value in R13.
00:35:21So R13 wouldn't actually be a pointer.
00:35:23It would just be the value of the junk data of the last integer.
00:35:28Keep that in mind.
00:35:29OK, so where's RSP? So we got that.
00:35:33So now let's do a loop.
00:35:35I'm going to start off with a label called demo loop init.
00:35:41So for me personally, when I'm looping, you know,
00:35:43I like to make my labels inside of my loops start with a prefix that matches the function.
00:35:49So it's like demo and then everything else is going to be demo underscore something.
00:35:53So init loop init, I'm going to make a loop where I initialize the values of the array.
00:35:58So I'm calling this loop the init loop.
00:36:02And then the last part is just like this is the initialization part of the loop.
00:36:07This is where we sort of like set up the initial values to loop.
00:36:11So we have R12 and 13 that point to the first and last integers.
00:36:15Now we're going to set up R14 and 15 where R14 is the running pointer.
00:36:21I think before I might have accidentally said that R13 is the running pointer.
00:36:24It just points to the last integer.
00:36:25But if you look back up at my comments, R14 is the running pointer to the current integer.
00:36:30What is a running pointer?
00:36:32It's just a pointer that runs.
00:36:34It's just a pointer that just keeps increasing.
00:36:36So we can look at different data values.
00:36:38So I'm going to start it by looking at the first integer.
00:36:42So now R14 is pointing to the first integer.
00:36:44And then R15 is going to be the value that I want to put into that position in the array.
00:36:51So like the first integer, I want to put some kind of a starting value into it.
00:36:55You can put the number zero or whatever you want.
00:36:57I just wanted to have a start value so that it sort of looks more like I'm putting data
00:37:02and less like I have a loop counter.
00:37:05So remember the integer start value up here is just seven.
00:37:08So I'm just going to start at the number seven.
00:37:11And now I'm done initializing my loop.
00:37:14Then the next thing I'm going to add is the top of my loop.
00:37:17So you can imagine this as the top of a while loop where you start comparing
00:37:24some sort of an expression.
00:37:26Maybe I'll say, you know, EXPR to say that we're comparing some sort of an expression.
00:37:31And if that expression evaluates to true, the loop continues.
00:37:34If it evaluates to false, then the loop does not continue.
00:37:39Let's see.
00:37:41So I'm going to compare R14 with R13 inside of the top part.
00:37:47What is R14 and R13?
00:37:48Remember, R14 is the running pointer and R13 is the last integer.
00:37:54So basically, I'm trying to figure out,
00:37:56am I looking at or like, let's compare the running pointer with the pointer of the last integer.
00:38:03Then I'm going to say, if the running pointer has a greater memory location,
00:38:09than the last integer, that means I've gone beyond the last integer.
00:38:13And again, the way I arrange the first and the last integers just makes it easier for me to think
00:38:18of them as having increasing memory locations.
00:38:21So I'm going to jump if the running pointer has already surpassed the last integer by saying,
00:38:26let's jump if it's greater than.
00:38:29So you can imagine, maybe in the expression here, I should probably say, while not.
00:38:37R14 is greater than R13.
00:38:40Not a great expression, but it'll do.
00:38:42So that's what I'm implementing up there at the top.
00:38:45Let me just put that into my notes too, so that my notes match the video.
00:38:52Okay, so we are comparing and then we're jumping to the end of the loop.
00:38:58If we end up, you know, going beyond the last integer.
00:39:03So that label is not created yet.
00:39:04I'll create that in a moment.
00:39:05But pretty much that's a label that's just going to be below the loop,
00:39:08just to say like we're finished with the loop.
00:39:11Okay, now we're going to begin the loop body.
00:39:13I like to put comments here to help myself remember.
00:39:15Oh, this is the part of the while loop that I'm currently inside of.
00:39:18Just makes things a little bit easier to understand.
00:39:20You know, you put a block comment up top of every label or every,
00:39:24you know, chunk of instructions just to let you know the general idea.
00:39:27And then, you know, sometimes you put comments also on the right side
00:39:31to help you remember what each instruction is actually doing.
00:39:35So then what am I going to do here?
00:39:36Remember, R14 is the running pointer.
00:39:39If I deref R14, that means I want to move an actual value into that memory location
00:39:45rather than changing the memory location that R14 points to.
00:39:49So R15 is going to be the integer that we want to write into the array.
00:39:54So all I'm doing here is I'm saying, let's take that value seven,
00:39:57which is what it starts as, and just move it in to, you know,
00:40:02the RAM stick at that memory location.
00:40:03So I'm setting the first integer to the R15's value, which is seven right now.
00:40:09Then I'm going to increase R15.
00:40:10So that means every time we iterate the loop, we should see that the value increases.
00:40:14So the first integer should be seven.
00:40:16The second one should be eight.
00:40:17Next one should be nine and so forth.
00:40:19So just a simple loop where I'm just writing data into my array.
00:40:23So now that we've ended the loop body, let's write the bottom of the loop,
00:40:29which is just going to increase the running pointer
00:40:34and jump back up to the top.
00:40:36And this is not necessarily the only style for translating while loops.
00:40:40I'm just doing it.
00:40:41And, you know, I'm going to make another video in the future where we talk about,
00:40:43you know, for loops and while loops and all that stuff.
00:40:46But this video is just really about local variables on the stack.
00:40:49So I'm not going to go over all the different ways you can do it.
00:40:53Anyway, so R14 is the running pointer.
00:40:55So I'm going to just make the running pointer jump to the next integer.
00:40:59And we can do that by increasing its memory location by the size of one integer.
00:41:04Again, this is another benefit of the first and last pointers that I chose at the beginning.
00:41:09I can just increase to go to the next integer.
00:41:12So we're going to increase by eight bytes to just go to the next integer.
00:41:15If you increase by one byte, you'll probably have a huge corrupted mess
00:41:20because you're messing with eight byte integers, but you're only increasing by one byte.
00:41:25And then after we increase, we're just going to jump to the top of the loop.
00:41:29So notice how I have a jump statement here.
00:41:30It's going to go just to loop top.
00:41:32So now this part is here is basically just going to execute over and over and over again
00:41:38until we finally scan through all of the integers in our array.
00:41:42So that's the bottom of the loop.
00:41:45And then I'll make the label for the loop being done.
00:41:50It's not really going to do anything except just be done.
00:41:55And do you, you know, I don't know, depending on your style, maybe you can let it drop through
00:42:00if the loop's done rather than always jumping to the top.
00:42:03But I'm just going to say when we're done, we jump to the loop done label and therefore
00:42:08there's no more looping of that initialization loop.
00:42:11Okay.
00:42:12So we got that done.
00:42:14Let me just run the program real fast to make sure that I haven't screwed it up.
00:42:17We actually should not see anything right now.
00:42:20Oh, what did I do?
00:42:23Must have done something naughty.
00:42:25Maybe if I finish
00:42:28this program, then everything will be okay.
00:42:33Oh my gosh.
00:42:34What did I even do?
00:42:37Well, I've got a working solution in the other window.
00:42:39So hopefully when I paste all the extra steps, everything will be fine.
00:42:43You never know.
00:42:44Subtract the stack pointer.
00:42:45Oh, did I forget to?
00:42:48Oh, did I forget to restore something at the very end?
00:42:52Print body.
00:42:54Move the base pointer into the RSP stack pointer.
00:42:59Oh yeah.
00:43:00Okay.
00:43:00That's definitely what you got.
00:43:01That's why I crashed.
00:43:03Okay.
00:43:04So, um, remember I said, you got to be very careful about the stack.
00:43:06This is a great lesson.
00:43:08So I did preserve the base pointer, but I didn't actually preserve the stack pointer.
00:43:12Um, notice how right here I subtracted from the stack pointer,
00:43:16but I did not restore the stack pointer anywhere.
00:43:19So that means I corrupted the stack for anyone that called me and also for my return address.
00:43:25So I'm kind of trying to copy paste my instructions from top to bottom,
00:43:29but I think I'm just going to copy paste something else
00:43:31to make sure that we can actually run this.
00:43:34So I'm going to copy paste into the epi log a restoration of the stack pointer.
00:43:40And that's why we saved the stack pointer in the base pointer,
00:43:42just to remember where it was when we originally started our function.
00:43:46So now on line 128, it should be restored and the program should work.
00:43:50Let me just double check here.
00:43:52Yeah, it worked.
00:43:53Okay.
00:43:54Nothing happened that we can see, but it did write values into the array.
00:43:58Okay.
00:43:59Now let's do another loop where we just print the array.
00:44:02So let's see loop in it done.
00:44:06Loop in it to bottom and loop in it done.
00:44:08Okay.
00:44:09So now there's like going to be another loop here.
00:44:11Um, we're going to call this the print loop.
00:44:16And so the print loop, uh, is going to be kind of the same pattern.
00:44:19We're just going to loop through all the integers in the array,
00:44:21but instead of, um, modifying them, we're just going to print them.
00:44:25So now, you know, the first thing we'll do is we'll set, uh, R12.
00:44:29We'll store that inside of R14 in order to start the loop at the first integer.
00:44:34What was R14 again?
00:44:35That was the running pointer.
00:44:36Remember?
00:44:36Let's see.
00:44:37Where's that?
00:44:38Yeah, it was the running pointer.
00:44:38So now we're resetting the R14 running pointer to the very beginning of the array.
00:44:43And we know where the beginning is because we remembered that with R12.
00:44:47Then the next thing we'll do is we will set up the top of the loop and the body.
00:44:51So I'm just going to copy paste again, this stuff right here.
00:44:57Um, right there.
00:45:00Okay.
00:45:02So the top of the loop we're asking ourselves, you know, we're going to compare,
00:45:05I'm not going to put all the extra while stuff that I put in the previous loop.
00:45:11Cause hopefully by now you understand loops a little bit better,
00:45:13but I'm just going to compare R14 to R13.
00:45:16And, uh, if we're beyond the last integer, because the running point of R14 is beyond
00:45:21the memory location of R13, that means we're totally done.
00:45:23So we should jump if it's greater than now.
00:45:26I feel bad.
00:45:28Let's, uh, let's put a comment in here on the top.
00:45:31Let's go.
00:45:33Basically that, you know, if, uh, keep going as long as R14 is not greater than R13.
00:45:38So if it is, then just jump.
00:45:43Okay.
00:45:43So now we begin the body and, um, in the body, all I'm going to do is use R14,
00:45:48the running pointer to print, uh, you know, whatever value is sitting in that particular
00:45:54integer.
00:45:55So how do we do that?
00:45:56I'm just going to use the print F statement or sorry, the print F function,
00:45:59which is provided by the C libraries.
00:46:01That's why we're doing, you know, a modular, um, or a hybrid program with, uh,
00:46:05multiple modules and C linking.
00:46:08Um, so this is not a video about that, but just very quickly,
00:46:12there is a function called print F, which I can call it, uh, it takes multiple arguments,
00:46:18but the, uh, first two arguments that I can give it are, uh, the string, uh,
00:46:24that represents the formatting that I want to print.
00:46:26Like I could do like a regular string message.
00:46:28I could do tokens to format some data inside of them.
00:46:31And then the second argument is going to be, uh, the piece of data
00:46:35that I actually want to use.
00:46:36Let me see if I can just type that up for you real fast.
00:46:40So, you know, the print F instruction or sorry, this is not an instruction.
00:46:46This is a, a function and see we would typically, you know, give it some kind of string.
00:46:51The string should be null terminated and it should have a new line at the very end of it
00:46:56to make sure that print F actually flushes.
00:46:58It won't flush if you don't have a new line.
00:47:00So the program will look really weird.
00:47:02Um, uh, but I guess it's more performant if you, if you have a way to delay the flushing
00:47:08and you know that you can flush it later at the very end.
00:47:11But for now, I'm just going to flush every time.
00:47:13And then every argument after that is some sort of, you know, data that we can print.
00:47:19So imagine we have a long and we'll call it a, and we'll say that it has like some giant
00:47:24value.
00:47:25Um, so that means we would give that long as the next argument, uh, the RSI argument.
00:47:31And then for the string formatting, if you just kind of look up, this is what I'm using right here.
00:47:37Uh, percent LU.
00:47:41So you can imagine instead of this string, it is, uh, this string right here, whoops, too many,
00:47:47too many quotes.
00:47:48It's just this string right here.
00:47:50And then instead of a 10, 13, uh, that's the same thing as just doing a N or if you
00:47:54want to be,
00:47:54you know, more of a windows, windows person slash R slash N, it's all good.
00:47:59And the zero is not needed because the string, if you put a string literal,
00:48:02it's automatically going to be null terminated, which means there's just a zero at the end of the string in
00:48:06memory. So this is basically what I'm doing. I'm, I'm making a, uh, an integer, uh, in the case of
00:48:12the assembly program, it's going to grab an integer from that position in the array that we're looking
00:48:16at, and it's going to give it as an argument. And then the first argument is going to say,
00:48:19let's just print this as a unsigned long. Uh, so that's why I have that string here. Let me search
00:48:25for it and go down a little bit again. So I'm saying first argument is this, the format that I
00:48:30want to be
00:48:30printed. Second argument is the actual value. And then I'm going to make a call to print F.
00:48:37Why do I have this weird push and pop pair sitting around a print F? So this is not a
00:48:44video about
00:48:44stack alignment in GCC, but basically the GCC libraries, uh, expect that your stack is aligned
00:48:52to, I think 16 bytes. But since we use eight byte integers, every single time we call a function,
00:48:58we're pushing a return address to the stack, which is eight bytes. And then every time we do one
00:49:04single push or pop, we're modifying the alignment of the stack by eight bytes. So if you think about
00:49:09it, when we're programming in assembly, for the most part, the stack is going in and out of alignment
00:49:15because every time we modify it by eight bytes, it, it might line up with a 16 byte alignment or
00:49:20it
00:49:20might not. It's just kind of like oscillating, right? So when I first wrote this solution,
00:49:25I wasn't doing the push pop pair and this is what happened. Oh, actually
00:49:33maybe
00:49:36I guess I don't need to jump to the top right now. I don't need to finish the loop. Let's
00:49:40see if this
00:49:40prints just one number. Well, let me, let me, let me see if this prints one number
00:49:44certainly. And if it's an okay assembly program, just to print one number,
00:49:48it's going to work. Okay. We got to do the done symbol. Okay. So I'll show you in a minute
00:49:54why we
00:49:54need push and pop, uh, around that for stack alignment, but I guess I'll just finish the loop.
00:49:59So, uh, demo print loop done. So we just did print loop top and that means we need, uh, the
00:50:05bottom
00:50:06and the done. So I'm just going to copy paste into program here. I'll just say nada, because we're
00:50:14not really doing anything. And then, uh, at the bottom, you know, that's the epilogue that's separate
00:50:18from the, uh, the other label. So basically now let me finish describing the loop because you know,
00:50:24we already know the loops, but I'll just, I'll just say it at the bottom of the loop.
00:50:27We do the same thing that we did with the, uh, initialization loop. We just increase the running
00:50:32pointer. You know, we move it along to the next integer and then we jump to the top of the
00:50:36loop.
00:50:36That's it. And then the done label, we don't really do anything. We're just letting execution
00:50:42drop through down to that point so that the loop doesn't continue. So now we should be able to run
00:50:46the program. Don't get excited. Oh, actually, you know what? Get excited. I was going to say,
00:50:51don't get excited because it was going to totally work now, but now I think we can just say that
00:50:55it's
00:50:55going to crash. So if I run it, notice how there's a seg fault. So the GCC libraries, uh, many
00:51:02functions,
00:51:03uh, expect your stack to be aligned to 16 bytes. So if you see mysterious crashes and you are absolutely
00:51:09sure that you're not ruining the stack pointer or ruining something else, you're doing everything
00:51:13correctly, but the program still crashes, it might be stack alignment. So one way to get around stack
00:51:19alignment is just to move the stack pointer. Like at the top here, we could have said,
00:51:24Oh, we've got one, two, three, four, five. We've got five pushes. Uh, and then here we're moving the
00:51:31stack by, I don't know how many other addresses the stack might be out of alignment somehow. So we could
00:51:36add an extra push up here and then add a corresponding pop down at the bottom. Like we could easily
00:51:42do this.
00:51:42Let me just show you real fast. We could push our 15 twice for no reason. I acknowledge.
00:51:48And then at the bottom we pop our 15 twice that would change the alignment because that's one more
00:51:53eight byte push. Uh, but in my case, and actually that would be a little bit smarter because you
00:51:59will, you know, if you have our loop where it's constantly calling on print F, uh, this is a lot
00:52:05of hits to memory, right? This is like a hundred hits to memory. Cause every single time we do a
00:52:08push pop
00:52:09pair around to call to print F we're like touching memory. Whereas if I did it at the beginning and
00:52:14the end, maybe I should just do it this way. I want to do it both ways. So you understand,
00:52:21but
00:52:22it's more efficient. I think if we do it this way anyway, so we'll do pop twice at the bottom
00:52:27and
00:52:27then push twice at the top. And so then we don't really need to surround it with a push pop
00:52:32pair.
00:52:32I think I haven't tested this. Uh, we'll, we'll hope now that the stack is in alignment at all times
00:52:38in our functions so that it doesn't crash. Yeah. So now see how the program works.
00:52:42So I'm going to do it the other way now, which is the less efficient way. Cause here,
00:52:46we just have one extra push pop pair, but if we do it the other way, it'll still work,
00:52:52but we'll be hitting memory much more often. So I'm just going to do it this way just to show
00:52:56you,
00:52:56you can surround any call because sometimes in your programs, you might have the stack like,
00:53:02you know, modified throughout the function many different times. So it wouldn't make too much sense
00:53:06for you to add an extra push pop pair in the prologue and epilogue. Cause that might not solve
00:53:11it for all of your calls to all of your, you know, C library functions. So in that case where
00:53:16you can't
00:53:17really predict the stack well enough, um, you can just surround your call with the push pop pair.
00:53:22It hits memory more, but it'll work. So this is basically, you can imagine by the time we get to
00:53:28line
00:53:28135, 139, the stack is out of alignment. So I just do a push that puts it into alignment.
00:53:34And then after the call comes back, I just pop it. So it's back out of alignment again,
00:53:40but I don't have extra erroneous data sitting on the stack. Cause if I only had push and not pop,
00:53:45then it's going to push it more and more out of alignment. It's going to push it in and out
00:53:49and
00:53:49in and out, but it's going to add a bunch of junk data to the stack that I'll never recover
00:53:52from.
00:53:53Or actually, I guess I will recover at the very end when I restore the stack pointer,
00:53:57but it's pointless. It's going to consume too much memory. What if I was, uh,
00:54:01what if, what if I was writing like a billion or like a million items as like on the stack,
00:54:07right? So like a billion iterations of the loop would probably be a bad idea to start adding onto
00:54:12the stack. We'll probably end up stack overflowing probably with far less than a billion items.
00:54:18So anyway, I'm going to surround the call, uh, with the push pop pair. And then at the bottom,
00:54:23we just do the same thing, you know, increase the integer and then go to the top. And so now
00:54:31uh, we are, you know, you already can see it on the screen, but basically the program works.
00:54:35And what it does is it starts off, uh, printing. Well, it starts off initializing the array,
00:54:40but then the thing that we can see starts off printing the first integer. And then the next
00:54:45iteration of the loop prints, the second integer and the third and the fourth and so forth
00:54:49until we get all the way down. Just to prove to you, maybe we can
00:54:53increase it by two instead of one each time. Uh, I'll just modify that real quick. We'll do
00:55:01where's the bottom of the loop. Oh,
00:55:05Oh no, that's the print loop. Let's do the init loop. Init loop bottom.
00:55:11Oh, right there when we're in the body. So I'm just going to increase our 15 twice
00:55:15just to show you, you know, we can kind of control what's going inside of the local array.
00:55:21So see how it goes from seven to nine to 11 instead of seven, eight, nine. Um, so I'm going
00:55:25to take that out and then just show you that we can control how many integers we have in our
00:55:30local
00:55:30array with just the number of integers. So I'm going to change the 50 to a five and run it
00:55:35again.
00:55:36And you can see what the dang did I do?
00:55:41Number of integers is five and then it was 50.
00:55:46Did I put the stack out of alignment? No, I have a push pop pair there.
00:55:52Number 50 is not hard coded anywhere anywhere. I wonder if I just mess something up.
00:55:58Yeah, it works when it's there.
00:56:02Oh, I have a bug that I can debug. That's nice.
00:56:05I guess the bug debugging is not for this video.
00:56:10I wonder if some other value would work for that.
00:56:15There's an, yeah, there's a number of things that could be the problem. It could be like stack
00:56:18alignment somehow. It could also be, um, let's see, am I making any calls here inside of my function
00:56:24demo? I'm saying sub and LEA and then start and then jump and then increase and then jump and then
00:56:35RDI. Not really doing anything else. So I don't think it's stack alignment. I must have, uh,
00:56:41miscalculated somewhere somehow for changing that. All right. Well, if I figured it out,
00:56:45uh, then I will release another video, but basically this is the idea. A hundred works,
00:56:5050 works. What about 99? Would that work?
00:56:55Save faults on 99 and then 98.
00:57:0198 works. So like every two seems to work, but that is a two quad words or 16. Oh,
00:57:10right. So like a hundred integers. If we assume that that's in alignment,
00:57:15then 99 would be eight bytes less that we're moving the stack by notice how it seg faults,
00:57:22right? Okay. And then, uh, 98 notice how
00:57:28it, uh, is okay. And then 97, it's going to say fault again. Watch.
00:57:33This is a great, uh, stack alignment video, I guess 96. It won't say fault. So it's going in and
00:57:39out
00:57:39of alignment. I think I figured it out. So if we use the number 100, it's in alignment, sorry,
00:57:47it's out of alignment. If we use the number 100, the program works because the number 100 throws it
00:57:53out of alignment, but then we have this push pop pair here around the call to print F, which puts
00:58:00it
00:58:00back in alignment. So if I change the number of integers, I'm actually changing the number
00:58:06of memory locations that I modify the stack pointer. So I have to do it by twos. If I wanted
00:58:12to do 99
00:58:12here, then that means the stack is in alignment by the time I call, um, by the time I'm getting
00:58:18ready
00:58:18to call print F, which means the push pop pair around it throws the stack out of alignment. So just
00:58:26say false by comment that out. Now it won't throw it out of alignment. Okay. Should have known that
00:58:35before I recorded the video. It's fun to guess sometimes though, you know, I get a little nervous.
00:58:41Oh no, my program broke on camera. Can I debug it live? Well, I guess I can, but kind of
00:58:47slowly
00:58:50anyway. So we, I think we've gone over every single part that I wanted to show you. Um, we know
00:58:55how to
00:58:55create a local array on the stack and, and therefore you also know how to create like any other data
00:59:00type
00:59:01on the stack. If you want, you want to create a long, a 64 bit integer, just move it by
00:59:05eight bytes
00:59:05instead of moving it by eight times, however many integers we were doing in this video. You want to,
00:59:11I don't know, put a character on the stack. Uh, you can do that if you really, really want to
00:59:15just, uh,
00:59:17you know, move it by one memory location instead of eight memory locations. So, you know, one bite
00:59:21instead of eight bytes, you want to store, uh, a short, you know, a two byte integer. We'll just
00:59:28move it by two bytes instead of eight bytes, right? So you can, you can do this as many times
00:59:31you want.
00:59:31Do you want to have several local variables? Just move it one time for every local variable.
00:59:38Same thing for, uh, accessing. You just have to remember where everything is either.
00:59:43Remember what is the offset of the, of the first variable local variable, and then the offset of
00:59:47the second local variable. You can store those in globals or store those in registers. If you can,
00:59:52you just got to remember somehow where everything starts, but it's all sitting on the stack. If it's a
00:59:57local variable. Okay. I guess that's everything that I really have to say. Uh, I hope you enjoyed this
01:00:04video. Uh, I hope you learned a little bit of stuff and had a little bit of fun.
01:00:08I'll see you in the next video. Have a good one.
01:00:15Hey everybody. Thanks for watching this video again from the bottom of my heart. I really
01:00:19appreciate it. I do hope you did learn something and have some fun. Uh, if you could do me a
01:00:23please,
01:00:24a small little favor, could you please subscribe and follow this channel or these videos or whatever
01:00:30it is you do on the current social media website that you're looking at right now. Um, it would really
01:00:35mean the world to me and it'll help make more videos and grow this community. So we'll be able to
01:00:39do more
01:00:40videos, longer videos, better videos, or just, I'll be able to keep making videos in general.
01:00:44So please do, do me a kindness and, uh, and subscribe. You know, sometimes I'm sleeping in
01:00:50the middle of the night and I just wake up because I know somebody subscribed or followed.
01:00:54It just wakes me up and I get filled with joy. That's exactly what happens every single time.
01:00:59So you could do it as a nice favor to me, or you could, you could troll me if you
01:01:02want to just
01:01:02wake me up in the middle of the night, just subscribe and then I'll, I'll just wake up. Uh, I
01:01:06promise
01:01:06that's what will happen. Also, uh, if you look at the middle of the screen right now, you should see
01:01:11a QR code, which you can scan in order to go to the website, which I think is also named
01:01:16somewhere
01:01:16at the bottom of this video. And it'll take you to my main website where you can just kind of
01:01:20like
01:01:20see all the videos I published and the services and tutorials and things that I offer and all that
01:01:30the suggestions for, uh, uh, clarifications or errata or just future videos that you want to see,
01:01:36please leave a comment. Or if you just want to say, Hey, what's up, what's going on? You know,
01:01:40just send me a comment, whatever. I also wake up for those in the middle of the night. I get,
01:01:44I wake up in a cold sweat and I'm like, it would really, it really mean the world to me.
01:01:49I would
01:01:49really appreciate it. So again, thank you so much for watching this video and, um, enjoy the cool music
01:01:56as, as I fade into the darkness, which is coming for us all.
Comments

Recommended