- 1 week ago
Get hands-on with x86-64 YASM assembly in this in-depth tutorial on writing functions! Perfect for beginners and seasoned coders, we cover the basics of function creation, calling conventions, argument handling, and return values. Learn to avoid crashes, respect the ABI, and use prologue/epilogue for clean code. From printing messages to returning integers, see practical examples and tips to simplify your assembly programs. Subscribe for more low-level programming tutorials and take your skills to the next level!
Introduction to Functions 00:00:00
Makefile Overview 00:00:19
Assembly Program Setup 00:02:01
Data Section Definitions 00:02:08
Text Section and Entry Point 00:03:02
Basic Assembly Program Demo 00:03:38
Return Codes Explained 00:04:30
Function Concepts Introduced 00:06:10
Creating a Simple Function 00:07:04
Function Call vs Jump 00:08:00
Adding Return Statement 00:09:06
Moving Print Logic to Function 00:09:48
Benefits of Functions 00:10:01
Calling Function Multiple Times 00:11:58
Creating Print Function with Arguments 00:14:00
Handling Function Arguments 00:15:45
Respecting the ABI 00:17:16
Prologue and Epilogue 00:23:15
Stack Operations 00:24:34
Calling Print Function 00:25:25
Avoiding Recursive Loop 00:34:17
Modifying Print Function to Print Line 00:35:21
Adding CRLF Function 00:30:13
Printing Multiple Messages 00:37:00
Returning Integer Values 00:37:48
Preserving Registers in Entry Point 00:41:50
Final Program Demo 00:43:24
Conclusion and Call to Subscribe 00:45:16
Thanks for watching!
Find us on other social media here:
- https://www.NeuralLantern.com/social
Please help support us!
- Subscribing + Sharing on Social Media
- Leaving a comment or suggestion
- Subscribing to our Blog
- Watching the main "pinned" video of this channel for offers and extras
Introduction to Functions 00:00:00
Makefile Overview 00:00:19
Assembly Program Setup 00:02:01
Data Section Definitions 00:02:08
Text Section and Entry Point 00:03:02
Basic Assembly Program Demo 00:03:38
Return Codes Explained 00:04:30
Function Concepts Introduced 00:06:10
Creating a Simple Function 00:07:04
Function Call vs Jump 00:08:00
Adding Return Statement 00:09:06
Moving Print Logic to Function 00:09:48
Benefits of Functions 00:10:01
Calling Function Multiple Times 00:11:58
Creating Print Function with Arguments 00:14:00
Handling Function Arguments 00:15:45
Respecting the ABI 00:17:16
Prologue and Epilogue 00:23:15
Stack Operations 00:24:34
Calling Print Function 00:25:25
Avoiding Recursive Loop 00:34:17
Modifying Print Function to Print Line 00:35:21
Adding CRLF Function 00:30:13
Printing Multiple Messages 00:37:00
Returning Integer Values 00:37:48
Preserving Registers in Entry Point 00:41:50
Final Program Demo 00:43:24
Conclusion and Call to Subscribe 00:45:16
Thanks for watching!
Find us on other social media here:
- https://www.NeuralLantern.com/social
Please help support us!
- Subscribing + Sharing on Social Media
- Leaving a comment or suggestion
- Subscribing to our Blog
- Watching the main "pinned" video of this channel for offers and extras
Category
🤖
TechTranscript
00:00Hey there! Let's talk about functions in x8664 YASM assembly.
00:11I'm just going to give you the basics of how to write a function.
00:14So let's get started here. First thing I want to show you is just a makefile.
00:19This is not a makefile video, so you don't have to worry about it too much.
00:23I just have it up because I need it for this demo.
00:25If you're interested in makefiles, that would be a really, really good thing.
00:28I'll probably make videos in the future about them, but for now we'll just say
00:32you hopefully have a script or method already set up
00:36that allows you to compile or assemble assembly programs.
00:40So I'm just going to skim through it real fast. If you're interested you can kind of study it.
00:44But basically I have like a little define here that allows me to print out a message that looks nice.
00:49And then I define the repo path as the current path and I take the absolute path of that.
00:54This is where the real work happens.
00:57I have Yasm flags because I'm using the Yasm assembler.
01:02I'm going to be assembling to x86 64.
01:05I like to I like to convert all of my warnings to errors to make sure that I don't write sloppy code.
01:11Export debug symbols and export debug symbols for the linking stage to the name of my executable is going to be called main.
01:20And then I just have like a little make file menu here that I have set up.
01:25And well I can just do make run or make debug as a little shortcut to run it in GDB.
01:32If you don't know GDB don't worry that's going to happen in a future video.
01:35And make clean which just cleans the build area.
01:38I like a clean build area.
01:40And then this is the main command here.
01:43We're going to be using LD to do our linking because this is going to be a pure assembly program.
01:47Instead of a hybrid program which would require GCC or something else.
01:51And then here's my program.
01:54Main ASM is going to get compiled down to main.o.
01:57And that's it for the make file.
02:00Okay so for the main assembly program I have some stuff written up already here.
02:05But I think I'm going to modify it for this video.
02:08For starters we have our data section which hopefully you understand already.
02:12I'm just going to define a bunch of stuff in the data section.
02:15Like I'm going to define the system call code to write a string.
02:20So I can print a message pretty easily.
02:22The system call code to actually exit the program.
02:24Remember when you're writing a pure assembly program that has start as an entry point.
02:30You need to be you know you're responsible for exiting the program.
02:33So the system call code is 60 there.
02:36And then I'm going to say exiting for success is a zero.
02:39That's kind of a standard thing.
02:40And then I'm going to make two file descriptors.
02:43For the standard input it's going to be zero.
02:45And the standard output it's going to be one.
02:46Actually I don't think we need that for this video.
02:48We just need standard output but not standard input.
02:52And then I'm just going to make two strings.
02:54That's not my name but I like those names.
02:57And then the BSS section.
02:59Actually I'm going to get rid of that because we don't really need that for this video.
03:02And then I have a text section which is where all the code is.
03:05We're going to begin our entry point.
03:08If you are writing a pure assembly program and this is your entry point module.
03:12Again you will have to make a function called underscore start.
03:18It's not actually technically going to be a function because it won't return anywhere.
03:21It'll actually just call the system exit service.
03:25And then I mark start as global so that the operating system can go into it.
03:31Can call it from the outside.
03:33And then all I'm doing right now is I'm printing a hello.
03:35So, so far this is not really a demo of functions.
03:38This is just like a very basic pure assembly program.
03:41All it's going to do is it's going to enter.
03:43It's going to print the hello message.
03:45And then down here it's going to do a system call to exit the program with zero for success.
03:50So, let's just see what that looks like real fast.
03:53I'm going to do make run.
03:55And then make run you can see the first line.
03:58It just kind of prints.
04:00And then the second line that's make sort of echoing the command that I'm issuing.
04:04It's just going to assemble the main.asm into a main.o.
04:07And then it's letting me know that if there are any warnings it will refuse to compile.
04:13And then I use the LD linker to link the main executable.
04:17And then I actually run the executable.
04:19So, only below this line that I have highlighted right now is going to be the actual program.
04:24So, you can see all it really did was just, you know, print the message and then exit.
04:30Just, you know, a little note here.
04:32I've probably said this in other videos, but the return code zero is kind of a standard to indicate success for programs,
04:40which is very useful if you want programs to automate other programs.
04:43If I change the system, let's see, what is it?
04:46Exit success.
04:47If I just change that variable to a three so that I will exit with a return code of three instead of zero,
04:53then the operating system or actually bash, since we're in a terminal emulator,
04:57should consider the program to have exited in error.
05:00So, you can see now it's like, hey, hey, hey, the make file system.
05:04Oh, not bash.
05:05The make file system is like that program exited with code three.
05:08Something went wrong.
05:10And normally, if you don't add any extra stuff into your make file,
05:12it'll just refuse to continue at that point.
05:15So, I'm just going to change it back to a zero and make sure that it still works.
05:18And then we'll get on to actually writing functions.
05:21So, I'm going to go clear and make run.
05:23So, it's a little bit faster for me to run this repeatedly.
05:26You can see actually the first time that I did that, the make file recompiled.
05:34Notice how it recompiled and relinked because I changed that source code.
05:40This is not a make file video, but I just want you to be aware.
05:43One of the great reasons to use make or a build system in general
05:46is because it makes it really easy to compile your code faster.
05:50Notice how if I didn't actually change.
05:52Let's see.
05:53So, I recompiled it because I just changed it again.
05:55But now I haven't changed it since I'm going to recompile or rerun.
05:58Make just kind of like skips reassembling that file because it hasn't changed.
06:03So, it can make your compilations and assemblies much, much faster.
06:10So, anyway, functions.
06:12Functions in assembly are kind of simple.
06:15And you'll realize that some of the stuff that we take for granted in higher level languages
06:21is being done for us automatically by the compiler.
06:23But in assembly, we have labels.
06:27So, for example, this start entry point, that's actually a label, right?
06:31We just have like some valid symbols like characters, underscore, numbers.
06:35I don't think you can start a label with a number.
06:37Correct me if I'm wrong, but I don't think you can.
06:39So, we have like a label, which is just like this collection of characters.
06:43And then we have a colon after it.
06:45And so, you can jump into a label, which I'll talk about in a different video.
06:49But you can jump into a label.
06:51You can call a label as a function.
06:53And so, a label isn't actually a function by itself.
06:56You have to treat it in a certain way in order to consider it a function in the abstract.
07:01So, notice how there's no return statement at the bottom here.
07:04Let me write a function real fast.
07:06And maybe I will have it so that I have a function that just says hello for me.
07:13So, I'll make a label down here, function that says hello.
07:18And I'll give it a label and I'll say maybe like, say hello.
07:23And I'll do a little label there.
07:26First thing that you should do when you are trying to create a function is just put a return statement at the very end of it.
07:31That way, it will return to the caller.
07:35Because if you don't, then it's just going to continue to execute downward until it reaches no code.
07:42And then the program will probably crash.
07:44In fact, maybe I should do that.
07:45I'm going to do say hello as a label with no return.
07:48So, it's not really a function now.
07:50It's more of just like a label that you can jump to.
07:53But there's no code under it, so it should...
07:56I'm not even sure this will assemble, but it'll definitely crash if we can call into this.
08:00So, let me do...
08:02At the very start of our program, I'm going to type call say hello.
08:07Or actually, you know what?
08:09Maybe first, I'll jump to hello.
08:12Jumping is going to be for a different video, but jumping just means go to that place.
08:15It's a go-to statement essentially.
08:17You're not supposed to be able to return from a jump.
08:21If you jump somewhere and they want to jump back to you, okay.
08:24But it doesn't really follow the same design pattern logic as a function.
08:28So, I'm going to immediately jump to the say hello logic and see what happens.
08:32I think that it'll crash.
08:34Here we go.
08:35SegFault.
08:36CoreDumped.
08:37Oh, no.
08:38So...
08:39Hey, it crashed.
08:41So, instead of jumping there, let's do a call.
08:45Now, we're treating it a little bit more like a function.
08:47We still don't have the return statement down here.
08:50So, it should still crash, I think.
08:52Let's try that again.
08:54Yep, it crashed again.
08:55Okay.
08:56Because you're supposed to exit from the operator...
08:59You're supposed to exit from the program properly to the operating system.
09:03So, now I'm going to do a return statement here.
09:06There's never an argument for the return statement.
09:08You just simply return to the caller.
09:10This uses the stack.
09:12If you don't know what the stack is, I'll probably make another video about that in the future.
09:15But the stack, you know, it helps your program understand where it just called to and how
09:20to get back from it.
09:21It also stores local variables and things.
09:23So, if I have a call, it should jump down to the hello function and then return, meaning
09:29it'll just return to the caller immediately without actually doing anything.
09:33But the program should be able to continue without crashing.
09:36Notice how there's no crash here.
09:38All it does is print out the welcome message and then no problem.
09:42All right.
09:43So, now I'm going to take all of this hello printing stuff and I'm just going to cut it
09:51and stick it inside of the say hello function.
09:53That way, when I call that function, it should still print hello.
09:57But now notice how we have less code to deal with in this primary function.
10:01You know, one of the first things that programmers learn is that, you know, we're human beings.
10:06We're not computers.
10:07It's really hard for us to write complex logic in a program without tools to help us and design
10:12patterns to help us, to help us stay on track, to help us, you know, make sure that we're not
10:17going to be forgetting anything or screwing something up or, you know, to debug.
10:20So, you know, one awesome design pattern is to write functions because you realize in your
10:26program you might be calling the same logic several times.
10:29So you're sort of like repeating a bunch of code that already is bad.
10:33It's really hard to debug repeating code and it's really hard to make updates to it and
10:38it becomes unwieldy, right?
10:40So as soon as you realize you're repeating the same logic, the same code in several places,
10:45you should think about taking it and putting that logic into a function and then just simply
10:49calling that function many times.
10:51It makes your coding a lot easier.
10:53And then once you put all the work into getting a function to work,
10:58you're just, you can just be done with it.
11:00As soon as you're sure that this function actually works,
11:02you can just put it to the side and just forget about it.
11:04You can stick it at the bottom of the source or just ignore it,
11:07put it into a different module, whatever you want to do.
11:09And then the other parts of the program that you're still working on,
11:13they become a lot more simple.
11:14And so, you know, because we're human beings,
11:16we need all the advantages we can get to write powerful code.
11:19So I am now just, I'm not, I don't have to think anymore about all the system call things
11:25that's happening to print the hello message.
11:27All I have to do is think about calling the say hello function.
11:30And of course this is simple, but you can imagine using this for more complicated concepts
11:35in the future.
11:36So let's see if this still works if I didn't screw this up.
11:38Notice how it printed the same exact message.
11:41And if I keep running it, you know, the make file doesn't compile as much,
11:44but it still runs the program.
11:46If you don't believe me that this is inside of a function now,
11:49let's actually just call that same function many times.
11:52We'll call say hello.
11:54Let's say we call it five times.
11:57This should work.
11:58I'm going to run the program again.
12:00Notice how it printed that message five times.
12:03Just to reemphasize my earlier point,
12:05wouldn't it be a huge pain in the butt if you wrote out all the code for the system call
12:09and the message printing five duplicate times?
12:12Wouldn't that be hard to update?
12:13What if you had a hundred of those in there?
12:15What if you had something that was really complicated
12:17and you called on it like 50 times?
12:19Wouldn't that be so much better than maintaining 50 different versions
12:23of the exact same idea of code?
12:25And, and, you know, making sure that if you needed to upgrade it
12:28or change it in some way, you actually got it right for all 50 copies.
12:32So this is way better.
12:34All right.
12:35So that's the basic idea for a function.
12:38Let's see.
12:39What else can I do?
12:41Let's, let's make a function that just prints anything
12:45because that would be kind of a good little practice in the,
12:48in the arguments that we can use.
12:51Remember in C++ and other languages, you have function signatures that you can use.
12:56So for example, say hello.
12:58We know for sure that say hello is not actually doing anything.
13:01It's not receiving any arguments and it's also not returning anything.
13:05So if we know it's not returning anything, we can say that it's a void function.
13:08If we're talking C++, we'll do the name here.
13:11We'll say, say hello.
13:12And in the argument list, we know that it doesn't take any arguments.
13:15So it's just say hello with nothing.
13:17Right?
13:18Okay.
13:19So let's make another function that just prints something.
13:25And this function will kind of be a little redundant because if you know,
13:29if you just sort of look at the system call here,
13:31we have to load up the system call with the standard output and the system write code.
13:37So that's going to be repeated.
13:39So we could, we could move that into the print something function, but then, you know,
13:43giving an argument of like, here's the string I want to print.
13:45And here's the length of the string that I want to print that, that is something that
13:49we can, we can pass as arguments every time.
13:51So we'll be saving like a little bit of work, but it's still, I think, I hope illustrates
13:56the idea.
13:57Okay.
13:58So maybe we will.
14:01Oh, print something.
14:03Okay.
14:04So print something, maybe we'll do the signature here.
14:07Print something will not return any value.
14:09So we'll just give it a void return type and I'll, I'll do a description up here.
14:13Print a message given by a character pointer, pointer to a string.
14:26I mean, technically a pointer to one character is also a pointer to a, to a C string, not a
14:32regular string class, but a C string.
14:34So I don't know how to describe it.
14:35I think I'll just say a pointer to a C string and length and integer length, maybe.
14:44So that means the print something function should take two arguments.
14:47We want to be able to call that function and tell it, here's a pointer to the string.
14:51I want you to print.
14:52And here's how long the string is.
14:53So still talking about C plus plus, I'm going to say character pointer P and maybe I'll put
15:01a string just to remind myself when I look at this later, it's a pointer to the string
15:04or like P char for the pointer to like the first character in the string, something like
15:10that.
15:11And then length.
15:12So the length is going to be a long cause we're using 64 bit integers in this video long.
15:17And I'll just say maybe size or length or something.
15:20So now we can, we can remind ourselves what's actually happening.
15:24I want to use the same symbol that I'm describing in this little prototype here.
15:28So I'm just going to copy paste it and use a, a, a colon.
15:33And then because it's a function, I immediately want to put a return statement at the very end.
15:37Okay.
15:38So then what I need to do is grab the incoming arguments.
15:45Okay.
15:46So, well, the first thing that every system call that prints a string should do, at least
15:52if it's going to print it to standard output, is it should start setting up the system call
15:57code registers or the system call registers to say, all right, um, the system call wants
16:03RAX to describe what the system call is going to do.
16:05We already have system write set up.
16:06So that just means we're telling syscall that we want to print something.
16:10Where do we want to print it?
16:11We want to print to the standard output, which if you look at earlier in the video,
16:15that was just a file descriptor of one.
16:18So that's fine.
16:20Set up the system call.
16:23And then the next two things can be kind of variable.
16:27Uh, you know, we can, we can grab that from incoming arguments.
16:31So RSI wants a pointer to the string.
16:36We're not going to load hello string,
16:39but we're going to load whatever character pointer we were given in the incoming arguments.
16:44If you look at your assembly books, you'll know that RDI is the first incoming integer argument.
16:51Uh, we're not going to talk about mixed arguments with floats.
16:55If we just assume that we're only going to use integer arguments or pointer arguments,
16:59then the first one is going to be RDI.
17:01So that means by the time print something gets called, by the time we come into this code right here,
17:06RDI should be loaded with, uh, with the pointer to the character, to the C string that we want to print.
17:13Again, this follows something called the ABI, which you should absolutely respect.
17:17Even if you're the only one writing any of the code that you interact with,
17:20your code will be bad and considered not good.
17:24If you don't respect the ABI on, uh, this type of architecture.
17:27So we definitely still need to load RSI with the string pointer, but, uh, art whoops,
17:33but RDI is what's going to have the string pointer.
17:36So we actually already just ruined RDI when we were setting up the system called it.
17:43And we, so that means we should probably either load it up backwards,
17:47or I think probably a better way to explain functions is let's just use another register.
17:54So I'm going to use another register to sort of store our incoming arguments.
17:59I personally like to do this.
18:00I admit that this will cost you CPU cycles to sort of like move things around in registers,
18:04but it's still way faster than sticking something into a global variable
18:08because then you'll be hitting memory.
18:10So first I'm going to say, let's move something into R12 and I want to store the incoming arguments.
18:15So I'm just going to write here, uh, save the, uh, the, the peak hair, you know,
18:22C string character pointer or something like that.
18:26So we're going to save it.
18:28And then the next thing we need to do is save, uh, the size,
18:32because as soon as we load up RSI,
18:34we're also going to be destroying the second integer argument,
18:37which should come to us in RSI.
18:39Okay.
18:40So I'm going to save that too, I guess, with R13.
18:44So I'm going to move something into R13, RSI,
18:47and then, uh, save the size of the string, C string.
18:52Okay.
18:53So we saved both of those.
18:54Now, when we load RSI, uh, we can just sort of say,
18:58RDI is saved.
19:02And then when we load RSI.
19:04Oh, that'll be when we hit RDX.
19:09Okay.
19:10I got confused.
19:11So we stored, uh, R12 was the character pointer.
19:16And then, uh, for the length of the string,
19:19we stored that as R13.
19:21Also for me personally, I feel like it's a pretty good idea to
19:25kind of make a comment at the very top,
19:27because this is assembly.
19:28It's really, really hard, right?
19:29Uh, make a little comment at the top.
19:31Just kind of reminding yourselves what you use all of the registers for.
19:35I know sometimes you'll use the same register for multiple purposes.
19:38You could either write that down or you could consider breaking up your function
19:42into multiple functions.
19:43That's totally valid.
19:44And it probably will make your life a lot easier.
19:49Anyway, so I'm going to say register usage.
19:52And then I'm going to say R12, uh, pointer to string, C string.
20:00And then I'm going to say R13 is going to be a size of the string.
20:06And that seems simple, but remember assembly, especially when you're new,
20:09it's really confusing.
20:11And for me, when I was first learning and even sometimes now,
20:14I'll be staring at a big blob of assembly code and I'll just be like,
20:17what register was I using?
20:21You know, or I'll look at a register and I'll be like,
20:23what was that thing even for?
20:25So just make yourself a little comment up here to help you understand.
20:28And then you'll thank yourself later when, when you,
20:31when you get a little bit too overloaded,
20:33or maybe even if you come back to your code a month from now,
20:36probably having totally forgotten what you even wrote.
20:39Uh, then you'll just have a nice little reminder here.
20:42It's good to document.
20:43And, uh, this is one of the ways that I recommend.
20:45Okay.
20:46So we're, we're saying that R12 and R13 are going to be used.
20:49We're loading them up here from the incoming arguments.
20:51Now RDI and RSI are free to be destroyed if we want.
20:54And of course we have to destroy them because RDI and RSI were incoming arguments
20:59when this function first came in.
21:00But now that we're going to be doing a system call,
21:02we have to use them for incoming arguments to the sys call.
21:05So they're just, they're just meant to be constantly destroyed.
21:08So we're going to do call code there.
21:10And then the standard output is going to be the first argument.
21:12And then the string that we did, which is an R12 is going to be the second argument.
21:17And then RDX is going to be the next argument, which is R13,
21:21uh, which came into us through the second argument.
21:24Wait, wait, wait, wait, wait.
21:25The string to write came into us through the first argument.
21:27The size came into us through the second argument.
21:29But if you just kind of look at what we're doing to the system call,
21:32it's actually the second and the third.
21:35So, I mean, just forget about it.
21:37Okay.
21:38So we set all that up.
21:39Let me make sure I'm not forgetting something by scrolling up real fast.
21:41Yeah.
21:42So now we can do a system call.
21:45One other thing that's very, very important about functions is you have to respect the ABI.
21:50And that doesn't just include using the right registers for incoming arguments
21:54when you're either receiving a call or sending out a call.
21:57But you also have to keep in mind which registers are denoted as callee saved.
22:03If something is callee saved, then that means, you know, if I'm inside of print something,
22:09I'm being called, that means I'm the callee.
22:12So that means if I'm going to use R12 and R13, which are designated as callee saved,
22:17maybe I'll pull up that, my favorite assembly book after this.
22:20But if I'm using registers, which are designated as callee saved, then I have to preserve those registers.
22:26Meaning those registers, they should have their same values from when they first came in on the call when I exit the function.
22:34So when I exit the function, those registers, register values should appear to be untouched to the caller.
22:40Remember, these registers are not local variables.
22:43They're global to the entire system.
22:45There's only one R12 on the whole CPU.
22:48So every program that runs, every function that gets called, it'll see the same exact R12 register.
22:54So if we're not careful about preserving when we have to, we could end up crashing other programs or our own program.
23:00So anyway, let's do something that I like to call the prologue and the epilogue.
23:06That's another nod to my favorite assembly book, which I'll probably show at the end of this video.
23:12So prologue is just, hey, let's preserve the stuff that we need to preserve.
23:16We will preserve the R12 with a push and we will preserve the R13 with another push.
23:23We then have to restore them.
23:24So right now when we do this push, that just means that whatever value R12 and R13 had is going to go to the stack.
23:31So we're going to hit memory.
23:32That's not great, but like we have to in this case.
23:35We're going to push it onto memory in order to preserve the value.
23:39And now we're free to destroy the value if we want.
23:42And then right before we return, we'll just pop those values.
23:46So that means we're going to go to memory.
23:48We're going to go to the stack.
23:49We're going to grab the values that we just pushed and put them back onto the registers.
23:55Oops, forgot to do 13 and 12.
23:57And I'll call this the epilogue, just meaning like we're done, we're cleaning up.
24:03And of course, look very carefully at the fact that the push and the pop sequence are in reverse order.
24:10Notice how we push 12 first and we push R13 second.
24:15Then at the end, we pop R13 first.
24:18So it's backwards.
24:19It's like a little shell, you know, the R13s are on the inside and the R12s are on the outside.
24:24That logic would persist if we pushed or if we had to preserve more Kali saved registers, if we were using more stuff.
24:34The reason we do that is because the stack as a data structure will return data to you backwards in the reverse order that you returned it or that you sent it into the stack.
24:44So if I send a 12 and a 13, let's just say the number 12 and the number 13 into the stack, then if I start popping stuff out of the stack, it's first going to give me the most recent item, which is going to be the 13.
24:56So it's going to give me backwards data and then it'll give me the 12 seconds.
25:00So, um, the type of data structure a stack is, is first in last out or last in a first step or whatever you want to do.
25:10Let's see.
25:11Last in last out.
25:13No, that's a, that's a Q anyway.
25:16So we're preserving the registers.
25:20We're doing the system call.
25:21We're probably okay to call this function now.
25:24So let me see if I can do this.
25:25I'm going to comment out all of these things that the, the, the say hello function does.
25:32And I'm just going to call on print something in order to call that function, but I have to load up my arguments.
25:39I have to actually pass arguments.
25:41Remember in the print something function, it's got a signature.
25:45It wants a character pointer and a size.
25:47We can't just call it without giving it those things, or it's going to look at the registers anyway, and just grab whatever junk data happened to be in there.
25:55So that would be bad.
25:56So first we have to load up the registers load up argument registers and call print something.
26:07Okay.
26:09Load up the argument registers and call print something.
26:12So the first thing is going to be RDI.
26:14So we have to move something into RDI.
26:15And then the second register for the second integer argument is going to be RSI.
26:19As far as I recall, if I'm wrong, this is going to go horribly wrong.
26:22I'll double check the book, the book after this.
26:25And what do we want to do?
26:27We want to basically inside of say hello, we could assume for now that say hello, hard codes, the pointer and the length.
26:36So we'll just say it's going to grab the string from global and it's going to grab the string length from the global variables.
26:42So it's going to load up those two arguments and then call on print something.
26:46This still ends up being three lines.
26:47That's why I was saying before, we're not going to save too much, but we did save, you know, these two lines right here, you know, and the system call line.
26:56So it's like slightly faster to do.
26:59You just load up two pointers and then you make a call.
27:02I'm not going to talk about loops in this video, so I can't really make the function better.
27:07But in the future, when you learn how to loop and learn about null terminated strings,
27:12you could basically just pass a pointer to just the string only and then call on a function.
27:18If the function was smart enough to scan through the string and figure out how long it was based on where the null terminator was.
27:24But that's going to happen in another video.
27:27Anyway, so if we call print something, it should print the string.
27:31Notice also that we're having a function call another function, which is pretty cool.
27:36So we have our entry point, it's going to call on say hello.
27:39And then once we're inside of say hello, we're just going to load up some arguments and then call on the print something function.
27:46The print something function then does most of the work for the printing.
27:50And I think we're ready to go.
27:52Let's see if this works.
27:53All right.
27:54So we're going to clear and then just run the program.
27:56Oh, that was so fast.
28:01That was so fast.
28:02I don't even I don't even feel like I've proved anything.
28:06Let's let's comment out the system call so that all we really do is just load up some registers and then don't do anything.
28:12And then you should see here that the print something function no longer actually does anything because it was too fast.
28:18Now, if I uncomment the system call, you know that the print something function is actually doing something and it's printing the message five times.
28:27We could also make some more messages if we wanted to just as a way to make this video slightly more interesting.
28:34I'll say MSG one is going to be a string of bytes.
28:38And I'm going to say this is message number one boring.
28:43Sorry.
28:44And we'll do a CRLF there.
28:46Actually, you know what?
28:48Let's make a function that does a CRLF.
28:50Okay, let me just finish mission message one length and we'll do equals that special string that you can do in the ASM.
29:03Am I doing this right?
29:04Yeah.
29:05Okay.
29:06So this is message number one.
29:07So now we'll call again with message.
29:10We'll call say hello just once and then we'll call on.
29:15Print something.
29:17Loading it up first.
29:18Move something with RDI and then move something with RSI.
29:21RDI is going to take the message one.
29:25Is that what I had?
29:26Message underscore one.
29:28And then RSI is going to get message underscore one length.
29:32So basically we're just, you know, print the first message.
29:36It's always a good idea to put comments on each line when you're learning so that you don't forget what's happening.
29:41Um, in addition to like a comment for the whole block, but I'm not going to do that here.
29:45Let's just make sure that make sure that this actually works.
29:47So it should print two different messages.
29:49Yeah.
29:50Okay.
29:51So this is message one.
29:52Okay.
29:53Nice.
29:54Let's enhance this a little bit more later.
29:56I think I'm going to have us print like a, I don't know, a character or maybe we'll do a return value from something.
30:00So we can just show you how to do the return values, but I'm just going to enhance this a little bit more.
30:05We're going to say, let's make another function.
30:08We'll call it CRLF.
30:10The CRLF function.
30:12I don't want it to do all the system call stuff because print something already does that for us.
30:16I'm instead just going to make another function called CRLF that calls on print message.
30:20So now that means I'm going to go CRLF and that's just going to be a 13 and a 10.
30:26Remember, you can define a C string with quotes, but you can also separate quoted strings by commas and also integers just to sort of tack it on.
30:36So, you know, this variable right here, it's going to be a sequence of characters representing the string that you see.
30:42And then at the very end of the string, it's going to have a CRLF carriage return line feed so that the cursor goes to the next line.
30:49So I'm actually going to take that off of message one because it's going to be here just on CRLF.
30:56And then I'll say CRLF length is going to be two.
31:00I could also do that special thing, probably a little smarter.
31:04CRLF.
31:06Yeah, I mean, it's better to avoid hard coding things.
31:11If you can avoid hard coding the number two or any number, just do it.
31:14I guess I have to hard code these two though.
31:16So CRLF and then length.
31:20And so that means in my CRLF function, let's see, let's do CRLF, CRLF immediately return because it's going to be a function.
31:32I'll just say void CRLF with no arguments and prints a carriage return new line, also known as CRLF.
31:43And so that just kind of describes it.
31:47And I don't need to preserve RSI and RDI because those are not Kali saved registers.
31:53So respecting the ABI kind of helps you in this case.
31:56I'm just going to copy paste here.
31:58And maybe I'll copy paste that comment real fast too.
32:02So I don't have to like type that whole thing out.
32:04And instead of doing hello string, we'll just say CRLF.
32:08And then for here, we'll do CRLF length, CRLF length.
32:12And now when I call CRLF, it should just make the cursor go down a little bit.
32:17So let's test that out.
32:19I took the CRLF off of message one.
32:23So if we actually run this right now on modified, it should have the cursor.
32:28What did I just do wrong?
32:30On number 28 and 29 instructions expected after label.
32:35I guess I forgot to complete something.
32:37Oh, I forgot to put, it's a byte sequence right there.
32:40And I forgot to put that.
32:41This is basically a defined sequence, you know, the EQU.
32:44Okay.
32:45My bad.
32:47Okay.
32:48So now it prints.
32:49Notice how the message line, it no longer does a new line and no longer jumps to the next line, CRLF.
32:56So that means when the program exits, the terminal prompt is on the same line as the program just printed.
33:01That's ugly and awful.
33:03So let's call.
33:05We could either say, let's call CRLF after printing the first message,
33:13or we could just assume that print something is like print a line.
33:19I don't know how you feel, but I think if we always called CRLF after every time we printed a message,
33:25I would probably be a little irritated.
33:28So maybe let's change this to a print line and then make it call CRLF.
33:34Another thing you could do is, of course, you could just keep adding this like 1013 at the end of every string.
33:38But I think I want to try to make this as compact as possible.
33:41So let's add the CRLF for now and then we'll change print something later.
33:45So we print the message.
33:47Now the prompt should be, you know, a line further down.
33:50So great.
33:51Works.
33:52Works.
33:53I am now going to take the CRLF off and I'm going to put it inside of print something.
33:59So that right after we do the system call to print the string in question, we'll print a new line.
34:07This should now accomplish the same thing that we just saw.
34:11Oh no.
34:12What did I do?
34:13I think I did.
34:14I think I have an infinite loop of recursive calls in there somewhere.
34:18I had a stack overflow probably.
34:20So let's see.
34:21What did I just do?
34:23Say hello is call print something and then CRLF is call print something.
34:28Oh, whoops.
34:30Print something calls CRLF at the end.
34:33So I should do one or the other and not have them call both.
34:37So maybe just because CRLF is special, maybe I'll just use a direct system call inside of CRLF.
34:44I thought I was so clever, but I was wrong.
34:47So we're going to repeat a little code for the CRLF and we're going to load it up with
34:52CRLF.
34:55Dang, how embarrassing.
34:57I like to say this is the most public of my many humiliations.
35:02But anyway, so now we don't need to rely on print something.
35:06So this won't be an infinite loop and it should work if print something calls on CRLF.
35:14Now we do it again.
35:16Okay.
35:17It works.
35:18So now let's modify print something so that it is just print a line.
35:25Print a line.
35:26And then that in my eyes, you don't have to do it this way.
35:29It sort of justifies printing a CRLF at the end every single time.
35:33So this is just my personal thinking.
35:36And then maybe I'll add a comment after prints a CRLF.
35:42So now when we call print line, we no longer have to call CRLF.
35:47And then when we print that message should be pretty good.
35:51Oh, we got to update that to print line.
35:54Then for say hello, let's just double check.
35:59We can get rid of this system call code here.
36:01Probably a good idea at this point.
36:03And then we just say print hello string.
36:06And then from the hello string, we can get rid of this CRLF at the end of it.
36:12So I'm just going to get rid of that.
36:13Actually, let's do it first without getting rid of it.
36:15Just so you see.
36:16Oh, what did I do wrong?
36:17Why in 61 forgot to update the symbol name?
36:22Oh, there we go.
36:23So hello needs to call print line because we don't have print something anymore.
36:30And try it again.
36:31Notice how the first message.
36:34Hello, my name is.
36:35It has two line feeds after it because it is calling print line, which will do a CRLF.
36:43But then also in the string itself, there is a CRLF.
36:46So again, the point is I'm just trying to reduce my typing by leveraging functions to my advantage.
36:53OK, so we got that working now.
36:55I'm just going to print like five different kinds of messages.
36:59How about how about three?
37:00So we don't have to sit here and watch me typing for too long.
37:03So I'm going to say message two and then I'm going to do message three.
37:08Message three.
37:10This is message three.
37:11Unless I got that wrong.
37:12One, two, three.
37:13One, two, three.
37:14One, two, three.
37:15Now we can just call a print string on three different messages.
37:22And I'll just change this to say, you know, print the second message.
37:26Print the third message.
37:30And then I'm going to change that to message two.
37:35And then message three.
37:39All right.
37:40So then I'm going to do that again.
37:42And then all three messages get printed.
37:45Nice.
37:46So now one more thing.
37:47I just want you to show.
37:48I just want to show you how to return an integer to the caller in a basic Yasm x86 assembly function.
37:55Again, this will not cover floats.
37:58Floats.
37:59This does not show you how to return floats.
38:01With floats, you have to use a different register called XMM zero.
38:04That's going to be a different video.
38:06But for now, I'm going to say all integer or pointer return values like long.
38:11This is going to be what we're using will just be a RAX because that is the register that is designated for return values.
38:20So what about this?
38:22Instead of just returning the exit success code that I've defined up above, we'll return whatever some function call gives us.
38:32Maybe I'll make another function down here and then I'll say a function that just returns a simple long value.
38:42And we'll call this function gimme long.
38:47It'll take no arguments because we're just keeping this simple for now.
38:50And instead of having a void return type, it'll have a long return type because we expect RAX to be loaded up.
38:57So then I'm going to say gimme long and immediately do a return because it is a function.
39:04And then I'm just going to load up a value from somewhere.
39:07Obviously, it's better if you're doing something complicated to stick with registers as much as you can or defines and hit memory only if you need to.
39:15And try not to hard code immediate into your code if you can possibly avoid it.
39:19It's probably a lot better to define a value up at the top in the data area than to just hard code it here.
39:24But I'm going to just hard code something here.
39:26No, I always second guess myself.
39:31I'm going to say exit gimme.
39:34I'm going to define something up here.
39:35So it's easy to find what value I'm going to return for the gimme.
39:39I'm just going to say 88, 89, 90.
39:43I don't even know about 33.
39:45I don't even know.
39:47So we're defining exit gimme as a symbol to just be a replacement of just the number 33.
39:53So down here, I'm going to say, let's have gimme long simply return exit gimme into RAX.
40:03Nice.
40:04Okay.
40:05And so that means it's the official return value once you call gimme long.
40:10So that means up here, get our, whoops, get out.
40:17It's coming from inside the house.
40:18Get our return value from gimme long.
40:21And again, imagine gimme long might be a big complicated function that decides what a return value is going to be or does something.
40:30So I'll start with saying call gimme long because gimme long does not take any arguments.
40:35I don't have to load up any registers, nor do I have to worry about preserving them or setting them up or doing anything.
40:41I just call.
40:42But then, let's see, inside of this function, we'll use RAX in order to, you know, load up the system call to let it know what function or sorry, what function we want from the system call.
40:55So we got to give RAX system exit.
40:57So that means down here, we can't actually use RAX anymore because it's destroyed.
41:02Well, now is a job for those other registers.
41:05Again, I'm going to use, I'm going to use the R12 register.
41:11I'm going to do like a little comment here that says register usage and I'll say R12.
41:19Maybe I'll do a tab.
41:21R12 is going to be old return value.
41:25Or the sys call to exit, you know, whatever.
41:30And that's all we're going to do.
41:31So in the prologue, I'm going to push R12.
41:33You should probably even preserve registers in the start function because something might in your entry point because something that called you might be.
41:40counting on those registers.
41:42This is going to be probably especially true if you're using GCC to have a main entry point within a hybrid program.
41:50So I'm just going to go prologue, push R12 and then pop R12 at the very end.
41:54Pop R12.
41:55That's not going to work because by the time we get there, it's going to exit the program.
42:02I'll do this here.
42:03I'll just try to be a good citizen.
42:05I'm not actually sure if we need this for a pure assembly function, but it's just a really good habit to get into.
42:10And what, what is it going to cost you?
42:12Just a touch of memory.
42:13Just one time right before the program exit, exits.
42:15It's not going to be a giant for loop or anything.
42:17Okay.
42:18So epilog, probably I might be showing you bad practice by preserving things in the underscore
42:27start function.
42:28But again, you will definitely want to do this for the main when you return from main.
42:33So we do prolog R12 epilog R12.
42:38I made a comment there and then we're going to store the return value in R12.
42:45So that means here we're going to move something into R12.
42:52It's getting precarious because we restored it right before the system call, but I think
42:57it'll be okay.
42:59We're going to grab RAX because RAX is supposed to be the return value register.
43:03So when we called gimme long, it loaded up RAX with our return value.
43:07We then send RAX into R12.
43:10So we can use R12 even though our RAX has been, you know, destroyed.
43:15We'll still have the return value that we wanted to use.
43:17So I'm just going to load R12 up into the first argument of the sys exit call.
43:22Let's see if I, if I got this to work or if I totally ruin this.
43:27Okay.
43:30All right.
43:31So let's see here.
43:33What was, why is it not erroring?
43:37Gimme 33 exit gimme.
43:40Should I, did I load the wrong value?
43:43Exit gimme.
43:44What is it doing?
43:45Exit gimme.
43:46It's moving RAX into exit gimme.
43:48So you call gimme long and then you move RAX into R12.
43:53And then you, wow.
43:54R12.
43:55I wonder if that destroyed it.
43:59Hmm.
44:00Let me get rid of this push pop here.
44:02Cause it's supposed to be giving me an error message that the function or that the program did not exit.
44:08Maybe this is proof that you don't need to preserve inside of the underscore start function.
44:12Let's see here.
44:13Yeah.
44:14Okay.
44:15I guess that proves it.
44:16Hey, don't take my word for it.
44:17I'm wrong all the time.
44:18Uh, prove everything, uh, for yourself, be a scientist, be a computer scientist.
44:23Try it out.
44:24Try to do something different.
44:25Okay.
44:26So, uh, I guess this is proof.
44:27We don't really need a prolog and epilog in just a pure assembly, uh, at least the entry point for start.
44:34But if you were calling any other functions, then they definitely need to preserve.
44:38And again, if you're using GCC, so you can have a main for your entry point, then you, you still have to preserve.
44:44So that means now we are just saying, you know, print the message and then print our other three messages.
44:51And then the return code is going to be 33.
44:53That was the gimme code that we did.
44:55So now we know how to return a value from a function.
44:58And, um, let me set this back to just zero.
45:05So the make system thinks that we succeeded, run it again, succeeded.
45:11All right.
45:12I guess this concludes the video.
45:14I hope you had a little bit of fun learning and I hope you, uh, learn a little bit of stuff and, um, I'll see you in the next video.
45:21Hey everybody.
45:23Thanks for watching this video again from the bottom of my heart.
45:27I really appreciate it.
45:28I do hope you did learn something and have some fun.
45:30Uh, if you could do me a please, a small little favor, could you please subscribe and follow this channel or these videos or whatever it is you do on the current social media website that you're looking at right now.
45:42Um, it would really mean the world to me and it'll help make more videos and grow this community.
45:47So we'll be able to do more videos, longer videos, better videos, or just, I'll be able to keep making videos in general.
45:53So please do, do me a kindness and, uh, and subscribe.
45:57You know, sometimes I'm sleeping in the middle of the night and I just wake up because I know somebody subscribed or followed.
46:03It just wakes me up and I get filled with joy.
46:05That's exactly what happens every single time.
46:07So you could do it as a nice favor to me or you could, you could troll me if you want to just wake me up in the middle of the night, just subscribe.
46:12And then I'll, I'll just wake up.
46:14Uh, I promise that's what will happen.
46:16Um, also, uh, if you look at the middle of the screen right now, you should see a QR code, which you can scan in order to go to the website, which I think is also named somewhere at the bottom of this video.
46:26And it'll take you to my main website where you can just kind of like, see all the videos I published and the services and tutorials and things that I offer and all that good stuff.
46:35And, uh, if you have a suggestion for, uh, uh, clarifications or errata or just future videos that you want to see, please leave a comment.
46:46Or if you just want to say, Hey, what's up, what's going on?
46:48You know, just send me a comment, whatever.
46:50I also wake up for those in the middle of the night.
46:52I get, I wake up in a cold sweat and I'm like, it would really, it really mean the world to me.
46:57I would really appreciate it.
46:58So again, thank you so much for watching this video and, um, enjoy the cool music as, as I fade into the darkness, which is coming for us all.
47:16I'll see you next time.
47:17Bye.
47:18Bye.
47:19Bye.
47:20Bye.
47:21Bye.
47:22Bye.
47:23Bye.
47:25Bye.
47:31Bye.
47:32Bye.
47:35Bye.
50:14
|
Up next
Recommended
21:30
3:18
0:55
0:59