Quick but complete guide to writing proper functions in YASM x86-64 assembly on Linux. See how to pass integers, pointers & floats, return values, follow the ABI, disable C++ name mangling with extern "C", and call back and forth between C++ and assembly in a real working example.
Great for people moving from NASM/GAS or trying to mix assembly with higher-level code.
00:00 Introduction and Video Overview
00:28 What Are Functions in Programming
00:56 Why Functions Are Harder in Assembly
01:24 Topics Covered in This Video
01:59 About the Makefile and Prerequisites
02:28 Hybrid C++ and Assembly Program Plan
03:01 Using extern "C" to Disable Name Mangling
04:03 Main Driver Function in C++
05:00 Adding a Callable C++ Function for Assembly
05:42 Explaining extern "C" Placement
06:16 Assembly File Skeleton and Data Section
06:41 Creating Null-Terminated Strings
07:49 Section .text and External Symbols
08:52 Declaring my_cpp_function as extern
09:20 Defining my_assembly_function
09:40 Labels vs Real Functions
10:31 The call Instruction and Return Address
11:16 Why Jumping Instead of Calling Crashes
11:47 Global Directive for Exporting Functions
12:32 Basic Function Structure
13:20 Implementing my_assembly_function Prologue
14:50 Receiving Arguments in ABI Registers
16:30 Printing Received Integer Arguments
18:10 Handling Pointer Arguments (C Strings)
19:40 Passing Floating-Point Arguments in XMM
21:15 Printing Floats from Assembly
23:00 Calling Back to C++ Function
25:40 Preparing Arguments for my_cpp_function
27:20 Loading XMM0 and XMM1 for Floats
29:10 Making the Call to C++ Function
30:50 Receiving Double Return Value in XMM0
32:30 Saving Returned Float to Memory
34:10 Printing the Returned Value
36:00 Final Messages and Program Flow
38:20 Fixing String Pointer Crash Issue
40:00 Correcting Argument Loading
42:10 Passing String Owned by Assembly
44:00 Observing Successful Output
45:47 Saving and Restoring XMM0 Safely
47:14 Printing Final Returned Float
48:32 Importance of Following the ABI
50:29 Summary of Covered Topics
51:03 Closing Remarks and Call to Subscribe
#x86Assembly #YASM #AssemblyLanguage #x64 #LowLevelProgramming #ReverseEngineering #SystemsProgramming #LinuxDev #ABI #CPlusPlus
=-=-=-=-=-=-=-=-=
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
Great for people moving from NASM/GAS or trying to mix assembly with higher-level code.
00:00 Introduction and Video Overview
00:28 What Are Functions in Programming
00:56 Why Functions Are Harder in Assembly
01:24 Topics Covered in This Video
01:59 About the Makefile and Prerequisites
02:28 Hybrid C++ and Assembly Program Plan
03:01 Using extern "C" to Disable Name Mangling
04:03 Main Driver Function in C++
05:00 Adding a Callable C++ Function for Assembly
05:42 Explaining extern "C" Placement
06:16 Assembly File Skeleton and Data Section
06:41 Creating Null-Terminated Strings
07:49 Section .text and External Symbols
08:52 Declaring my_cpp_function as extern
09:20 Defining my_assembly_function
09:40 Labels vs Real Functions
10:31 The call Instruction and Return Address
11:16 Why Jumping Instead of Calling Crashes
11:47 Global Directive for Exporting Functions
12:32 Basic Function Structure
13:20 Implementing my_assembly_function Prologue
14:50 Receiving Arguments in ABI Registers
16:30 Printing Received Integer Arguments
18:10 Handling Pointer Arguments (C Strings)
19:40 Passing Floating-Point Arguments in XMM
21:15 Printing Floats from Assembly
23:00 Calling Back to C++ Function
25:40 Preparing Arguments for my_cpp_function
27:20 Loading XMM0 and XMM1 for Floats
29:10 Making the Call to C++ Function
30:50 Receiving Double Return Value in XMM0
32:30 Saving Returned Float to Memory
34:10 Printing the Returned Value
36:00 Final Messages and Program Flow
38:20 Fixing String Pointer Crash Issue
40:00 Correcting Argument Loading
42:10 Passing String Owned by Assembly
44:00 Observing Successful Output
45:47 Saving and Restoring XMM0 Safely
47:14 Printing Final Returned Float
48:32 Importance of Following the ABI
50:29 Summary of Covered Topics
51:03 Closing Remarks and Call to Subscribe
#x86Assembly #YASM #AssemblyLanguage #x64 #LowLevelProgramming #ReverseEngineering #SystemsProgramming #LinuxDev #ABI #CPlusPlus
=-=-=-=-=-=-=-=-=
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
Category
🤖
TechTranscript
00:00Hello there. In this video, I'm going to teach you how to write functions in YASM x8664 assembly
00:07inside of Ubuntu, although probably any YASM assembler will be fine. I've covered these
00:12topics before in other videos, but I thought it would be nice to put them all here in one
00:16single video to make it a little bit easier to understand.
00:25Okay, so first off, what the heck am I talking about? Well, you know, when you have a program,
00:31let's say we have a higher level language program and we have like, you know, void or actually
00:35probably not void main, let's say int main and we'll forget about the arguments and inside
00:42of main, it just sort of calls F and then we have an F function over here and it, you
00:46know,
00:46does stuff, right? So that's the basic idea of having a function that you can call and
00:51calling it. We sort of take the whole process for granted in higher level languages, but
00:55in assembly, we have to do a lot more from scratch. So I'm going to show you about how
01:01to pass arguments, how to pass integer arguments, pointer arguments, floating point arguments,
01:07return types, you know, double like floating return types, integer return types, pointer
01:12return types, how to use special registers to actually pass the arguments into the functions,
01:20how to write a function in the first place in assembly. So that's basically what we're
01:25going to do before, before I get any further here, I just want to point out that this video
01:30is not about the basics of assembly, nor is it about the basics of make files or some of
01:36the other related technologies that I'm going to show. I've covered everything in this video,
01:40in a previous video. So if you, if you find yourself getting lost and you don't understand
01:46what I'm saying or what I'm doing, you probably want to look at my previous videos because this
01:50is sort of a summary video to kind of help you help you really lock down on the concepts
01:56of writing functions. Okay. So for starters, this right here that you're looking at is a
02:00make file. This is not a make file video. If you want to learn how to make make files or
02:05why they're awesome, see my other videos, but I'm just going to assume at this point,
02:09you're either willing to research my other video or you already know, or you don't care
02:12how to make a make file. So, you know, we're just going to skip this. I'm going to close it.
02:17The next thing I'm going to do is write a driver, um, function or sorry, a driver module.
02:25And what I'm going to do is, uh, I'm going to write this program that I'm showing you now
02:30as a, uh, as a hybrid program, a program with, uh, modules of different languages. So this module
02:37right here is going to be C plus plus, and then we're going to have an assembly module and then
02:41they're going to be able to call each other. So the first thing that I'm going to do is I'm
02:44going
02:44to name some functions that are going to be inside of, uh, my assembly module and also name some
02:50functions that are going to, we'll name a function that's going to be just inside of the C plus plus
02:54module, but it should be callable by the assembly module. So for that, we use a little block called
03:00extern C and long story short that disables name mangling, which C plus plus does in order to
03:06provide overloading functionality. So we're basically going to disable overload functionality in order to
03:12have simple function names that way assembly can call these functions. And also when we attempt to
03:18call a function inside of assembly, we'll just call it by its simple name rather than try to
03:24mangle the name based on the, uh, the arguments and return type and such. So that that's something
03:29we have to do for compatibility, uh, at least for this video. And, uh, I'm just going to move on.
03:34So basically you just take, you just take the keyword extern and you put a C in a quote, and
03:40then you
03:40make a block, right? A little braces scope. And then you just list prototypes of either the functions
03:46inside of the current module, which you would like to demangle or, uh, other modules functions that you
03:51would like to be able to call in a demangled or I guess a non-mangled way. Mangled meaning name
03:57mangling. Okay. So then I'm going to copy paste, uh, the main function that I'm going to do. So this
04:03is a hybrid program, uh, which means, you know, there are several different modules of different
04:08languages. Um, and usually what I like to do is have a module called the driver, which just launches,
04:14uh, the program. And it contains like the entry point, like see how there's like the,
04:17uh, the main entry point, which if you know how to do other languages, this is usually
04:22where you start in C plus plus or like the GCC libraries. So this is the entry point for
04:27our whole program. And then once we're inside of here, we're just going to print out a message
04:30to the user. We're going to make a C string. Uh, and then we're going to call on the assembly
04:34function. We're going to give it, you know, some numbers, some integers and some floats,
04:38and we're going to give it our C string. And then when we're inside of the assembly function,
04:42we're just going to print those things to prove that we know how to call and we know how to
04:45receive a data from C or C plus plus into assembly. And then we're just going to print,
04:50you know, goodbye basically. Okay. So, uh, I'm going to make another, uh, let's see another
04:57function in the driver so that assembly has something to call. Cause I don't just want
05:02to be able to call assembly from C. I also want to be able to call, um, C from assembly.
05:07So I'm going to put in something that we can call on from assembly here. I'm going to call
05:11it my CPP function. And it's just going to have like some arguments, just some nonsense
05:16arguments. And all it's going to do is just print out that it's entering, print out the
05:20arguments and then, uh, just sort of say goodbye and then just return a value to the caller.
05:25We're going to return a floating point value to the call.
05:33And, uh, we're going to return a floating point value to the caller. Okay. So notice how at the
05:39top here I have, uh, in the extern C, my CPP function. It's the same thing that we see at
05:44the
05:44top is now at the bottom. And that just means, uh, this normally would be compiled and linked with
05:50name mangling. And so because it's in the extern C block, there's no name mangling. And the reason
05:56that works with an extern C block is because there's no name mangling in C that's sort of
06:00like a C++ thing with overloads and like all these extra data types and whatever. Okay.
06:05So we have like the basics for our driver. It's a simple module. Uh, the hard work is going
06:10to be inside of assembly. So, uh, maybe before we write assembly, no, you know what, let's
06:16write the skeleton of the assembly. And then I'll start explaining what it means to call back
06:20and forth and to make functions and things like that. Okay. So for starters, I'm just going
06:24to make a data section with a bunch of stuff inside of it. And I'll explain it just very
06:30briefly. Again, this video is not about the basics of assembly in Yasm. Uh, if you want
06:34to learn the basics, go see my other videos, but for now I'll just assume that you understand
06:38why we're making variables in the data section and, uh, kind of how to do it. So I'm just,
06:43you can see here, I'm making a bunch of null terminated strings. They're null because they
06:47have a zero at the end. And I'm just saying, well, here's a message. When we begin the program,
06:51here's a message to announce, we're about to print some integers to prints, uh, a C string
06:55to print some floats. Here's another message for this, another message for that. It's just
06:59a bunch of method of messages, right? Then a CRLF that's just, you know, taking the cursor
07:05down to the next line and then back to the very beginning. So it's like a, basically a
07:08new line. And then I'm going to have some, uh, floating point numbers and, uh, I'm going
07:15to have an A and a B number. And then I'm going to have a, a B and a D
07:18that I'll send somewhere
07:20else. And so I'm going to populate them, uh, with numbers from the start, uh, the B and
07:25the D that just are not being sent. They start at zero because we're going to receive those
07:29numbers from C and then, uh, we're going to get a return value as a floating point from
07:37the C function that we call. So we're just going to store it there. So I'm just like making
07:41a bunch of room to store some, from some variables. And then here, we're just going to do system,
07:45right. And we're going to send to standard output. Uh, that's covered in other videos,
07:50but basically we're just going to be printing stuff. Okay. So section texts. Now this is
07:55where the program actually starts. Well, sort of, this is where the, uh, the program contains
08:00instructions to execute. So section text. And, uh, the first thing I'm going to do is I'm
08:06going to name some external symbols, uh, that I have for myself just to help me print integers
08:11and floats. So, you know, if you've seen my other videos, you know, that you can, uh, you
08:17can do a wide variety of things to sort of print characters and, uh, numbers, if you were
08:20clever, and you can also call on C library functions like print F if you really wanted
08:26to print a floating point numbers and signed integers and stuff. So you don't have access
08:30to this library. So don't worry about putting this part in your code. If you're working at
08:33this from home, unless you're someone that has taken a class that I've taught somewhere.
08:39Um, for now, just, just assume that this just lets me print very easily. No problem. You
08:44don't really need that. If you're just kind of experimenting with the functions. Okay. So
08:49then, uh, extern my CPP function. Uh, this is the name of the function that we've made in
08:55the driver. My CPP function. Notice how it's over here. My CPP function. We're just letting,
09:01uh, our assembly module know that there's a function in another module that we should be able to call
09:07on even though all of these modules are going to be linked into the same program. We still
09:11have to do this just to let the assembly module know. Okay. So now we need to make a function
09:17called my assembly function. If you look at the top right here, we had this other, uh,
09:22D name mangled, uh, prototype my assembly function. So we have to actually write that somewhere.
09:27It's not in the driver. Let's write it inside of assembly. So my assembly function is going
09:32to start right here, right there. So this is when we kind of start on the basics of writing
09:40a function. So for starters, uh, hopefully you understand labels. If you don't understand
09:44labels by now, you might want to see my other videos, but basically a label is just some
09:48sort of an alphanumeric symbol that you just kind of write as sort of, sort of like a variable
09:52name. Um, you can't use every symbol available. I would just start with using letters and numbers
09:58in the underscore. Um, of course you can always experiment if you want to see what's allowed and what's
10:02not just type something and see if it compiles. So the label starts with just, you know, this
10:09name and then a colon, right? So that's a label. You can jump into labels. Like if we were somewhere
10:14else in the program right now, we could like, if we wanted to do an infinite loop, we could
10:18say jump and then the name of the label. And what would happen is execution would go back
10:23up to this label and then it would jump again. That would go back up. It would be an infinite
10:26loop. Uh, but we wouldn't technically be calling a function. Uh, we're just sort of
10:32jumping. So labels are sort of the first step, but we have to do a little bit more to actually
10:36make a function. So we have an assembly function, which right now is just a label. And in order
10:42to make it callable from the outside, we have to mark it as global. So remember when we marked
10:47my CPP function as extern, that means we can call a function that lives somewhere else.
10:52Now we're marking this function as global, which means it lives here, but we want other modules
10:57to be able to call on our function or our label. Okay. So how do we actually make a function?
11:03Let's see. The first thing that you should do is try to understand that if that all functions
11:07return, even if they don't return any, any values. So I'm going to do a return statement
11:13under the hood. What this is actually going to do is crash the program. If you, if you just
11:16jumped into this label and didn't call it like a function, because the return instruction
11:21will look onto the call stack and try to find a return address for wherever this function
11:26was called from, and then go jump, do a jump, a jump instruction to return there. And so
11:31if you, if you just jumped into this label and then there's a return, it's going to pop
11:36something up the stack. That's not actually a return address and probably crashed the program.
11:41So that means now that we have a return statement, we definitely have to call this, uh, like a
11:46function. And I guess that's pretty easy because, well, if we were inside of assembly and we wanted
11:51to call another function, let me just show you real fast. I'll say some other, other function.
11:58Uh, if we were inside of this label, for some reason, we could call the above function by just
12:03saying call and then the label. So now it's being treated like a function. What the call
12:10instruction really does is it just looks at the address of the next instruction that would
12:15have been executed. So, you know, whatever, let's say we have like a nope on the next line,
12:18whatever the memory location or the relative memory location is of that nope instruction,
12:22it's going to push that onto the call stack. And then it's going to just do a jump instruction,
12:27uh, to this label. So then later when we hit this return statement, then it's going to look onto the
12:32call stack and it's going to find that return address, which is going to correspond with the
12:35nope instruction. And the return instruction is going to do a jump, uh, back to that, uh, address. So
12:42basically you have to use the call instruction to get there and then use the return instruction
12:46to return from there. And then now we can actually call it a function, but then there's other things
12:51that functions have to do, uh, to behave, to behave themselves, uh, without crashing the program.
12:57So for example, um, notice up here that I've copy pasted the, uh, let's see, call on assembly. Oh,
13:03I think I forgot to update that. Let's see. Call on this. Yeah. It's supposed to be called my
13:07assembly function now. Hold on. Let me update my, uh, my solution. Whoops. Hold on. Call on.
13:17There we go. Okay. So I've got my solution up above on another monitor. So I have the prototype
13:23of the function here. Uh, it's just going to return nothing and it's going to like take in
13:27a long and a double and a long and a double and a character pointer. So some mixed arguments. And
13:32then
13:32my intention here is to save these arguments, uh, with some registers. So notice how I'm saying
13:37we're going to use our 12, 13 and 14 to save the arguments, a, C and E. And we'll talk
13:43about why
13:44we're not saving the other ones with those registers in a second, but basically we're going to use those
13:47registers. So the thing about the registers is, uh, we have to do something called respecting the ABI
13:56respect the ABI. The ABI stands for the application binary interface. And it's just sort of like a standard
14:02that governs all of the things that you can do. And you're supposed to do when you're working
14:07with X86 64 assembly. So the ABI is pretty cool. Hang on a second.
14:17The ABI is pretty cool because it actually, uh, standardizes things. Uh, for instance,
14:22if we didn't have the ABI and we didn't respect it, then we couldn't actually call on assembly from
14:27C plus plus, uh, or vice versa because C plus plus the higher level languages, they're going to use
14:33the ABI. So if you try to do things your own way, then all you're going to end up doing
14:37is wasting time
14:37and energy coming up with two different ways of doing things when you could have just done it
14:42the ABI way. Right? So in one of those, in one of those ways, your way wouldn't even work, uh,
14:48for cross, you know, module calling. Uh, it would only work internally to your own program. So we're
14:54going to respect the ABI. So what does the ABI say about these registers? And again, I've talked
14:58about this extensively in other videos, but let me pull up a fun book that I love to, uh, to
15:04talk about.
15:05Uh, so this book right here, I did not write it. Uh, the book here is written by a really
15:09wonderful,
15:10uh, professor, Dr. Ed Jorgensen, PhD. And, um, this book is totally free. It's not, I'm not selling you
15:17anything. Uh, this is literally, you can just go to this, this professor's website and download his book
15:23for free. And he's already given me permission to just tell everybody to just share it with everybody.
15:28If you, if you look in the license area, it's a copyleft license. So it's sort of like the spirit
15:33of open
15:34source, uh, just sort of like sharing knowledge and stuff. So it's awesome. So I suggest everybody,
15:38you know, follow the link that I hopefully put in the video, um, and, and grab a copy of this
15:43book.
15:44But basically what I'm going to do is I'm going to go to a special area and I'm going to
15:47search for
15:48colleagues saved in my little PDF here. And, um, so that would be, I guess, section 12.8.2
15:58and it's called register usage, subsection 12.8.2. Notice how it lists all of the registers and kind
16:06of how they are typically used. Uh, this falls under the scope of the ABI. So this is not all
16:11the ABI is, but this is one of the things you're supposed to do when you're respecting ABI is, uh,
16:16you're supposed to sort of like respect the way these registers are supposed to be used. Notice R12,
16:22which is one of the registers that we're going to use is designated as callee saved. So that means
16:27whoever is being called has to preserve that register if they intend to mess it up. So for
16:33example, if I just had this function here, move some value into, you know, R12, I have now basically
16:42broken the program. If any, you know, a C function or other library that you didn't write just any,
16:48anywhere else calls on this function, then their version of R12 was going to get destroyed
16:53by what I just did. And so I'm not respecting the ABI. When this function returns to the caller,
16:58they're going to expect that their original data was intact. And if it's not program, it's not going
17:02to work. It's going to screw up. So respecting the AI means you have to preserve any registered mark as
17:08callee saved, or that's one of the things that it means. So notice how R12 through R15 are callee saved.
17:15So we have to respect the ABI now and sort of preserve 12, 13 and 14. We can do that
17:20pretty
17:20easily with some push and pop statements. So I'm going to do push R12, push R13, push R14. And now
17:29what happens is those values are actually on the stack now, and I can retrieve them later
17:33at the end of the function. Even if I destroy them while I'm inside of the function, I'll just
17:38restore them right before I return. So we usually call this the prologue because it happened before
17:45the function does anything. And then we have to make sure that we pop those values because
17:50you have to be careful with the stack. If you just start pushing values and you don't restore
17:54the stack to its original state by the time you return, you've basically broken the program.
17:58It's either going to crash right away or whoever called it is not going to function correctly anymore.
18:03So let's do some pops. We're going to do three pops and we'll call this the epilogue,
18:12which means, you know, something we do right before we exit the function.
18:15And keep in mind that the order of the pops should be reverse of the order of the pushes. Notice
18:21how
18:21we're popping in reverse order from what I did before. So we're going to pop
18:2612, 14, 13, and 12, whereas we pushed 12, 13, and 14 before. If you pop in the wrong order,
18:33like if you try to do it in the same order as the pushes, then you're still going to end
18:38up
18:38destroying data for the caller because you're going to be restoring data to the wrong registers.
18:42So just keep that in mind. Okay. So now the ABI is being respected.
18:47Let me see, by the way, do we have enough to actually even run the driver right now?
18:50We're just calling it and then it didn't really do anything. Yeah. I think we could probably
18:56this might compile. Okay. Let me, let me just check this out. I'm going to say clear and make run.
19:03Yeah. Compiles. Okay. So the driver printed its hello message. If you looked at the driver again,
19:08it's just sort of, sort of saying like, hello from the driver. And then, um,
19:15uh, when the driver comes back, it says the driver regained control and nothing really happened
19:19because, uh, well, we didn't do anything in our assembly function yet, but at least we're calling
19:23multiple modules. And again, if you want to know how to do hybrid programs and linking and compiling
19:27and all that stuff, see my other videos for now, I'm just going to move on. So the next thing
19:35we have
19:35to do is we have to try to understand, like, how are we going to receive these arguments? So this
19:41is one
19:41of the other, you know, building blocks to making functions. Notice how the assembly function,
19:45I'm sending it an integer and then a float and then another integer and then another floats. I'm kind
19:50of mixing the arguments. Then at the very end, I'm sending in a pointer. If I look back up at
19:55the
19:55prototype here, which matches what I've, what I, how I've used it, it's a long, a double, a long,
20:01a double and a character pointer. So longs, uh, and doubles, they actually, they're, they're called
20:08mixed arguments and they don't actually count against each other. When you're, when you're looking at the
20:13order of the registers to stuff them into. So for example, let me, uh, let me show you here.
20:20We have a, what did I just do? I clicked on the wrong computer. Okay. I'm on the wrong computer.
20:25Okay. Let me close this real fast. So, um, uh, when you, when you think about, uh, registers, uh, for
20:35incoming arguments, you, you, you basically start to think about this, you know, RDI and RSI,
20:40those registers represent the first and the second, uh, integer arguments. If we look back to the
20:44book real fast, we can see in that same section, RDI is the first argument and then RSI is the
20:51second argument. And then RDX is the third. And then the fourth, we can do up to six arguments
20:56with the R9. And then after that, we have to start pushing arguments to the stack. I'm not going to
21:00go
21:00that far in this video. I've actually done that already in a previous video. Um, but basically we, for,
21:06for now we can just use six registers to push arguments. But if you think about it,
21:11these registers, these are not floating point registers. These are general purpose registers.
21:15They're meant for integers and pointers. The reason they're used for, uh, for pointers also
21:21is because a pointer is just an integer. A pointer is just a 64 bit integer unsigned,
21:26which represents a memory location. So we can use these registers only for integers and pointers,
21:31but we can't use them for floats. So that means the first integer argument is going to be RDI.
21:36And the second integer argument is going to be RSI. But if there was a float argument in between,
21:42then RSI would still be the second integer argument. The floats don't count against the
21:47integers and vice versa. So for example, um, if we're talking about float registers, you know,
21:53the first one available is XMM zero, and then we have XMM one, and then we have XMM two,
21:58and it goes all the way up to, I think XMM 15. So we have 16 floating point registers.
22:04So we could pass in 16, uh, floating point arguments just using these registers if we wanted to.
22:10And then if we want to do even more than that, we'd probably have to get, you know,
22:14funky with the stack or something, or maybe hopefully you just have an array somewhere and
22:17you're just going to pass in a pointer. But, um, the way you have to think of these arguments is
22:23that
22:23even though they might be mixed in the prototype of the function that you're calling from a higher
22:27level language, you shouldn't think of them as being mixed when you're actually loading up registers.
22:32So, uh, again, if we just kind of like go back here to this prototype, uh, notice how that, uh,
22:39a variable, we're going to say that the a is RDI because a is along it's an integer,
22:45but then right after that, there's a double B. We would not, uh, skip RSI or assign B to RSI.
22:52B would just be the first float argument. And then when we go back to long C, long C is
22:59actually
22:59the second integer argument because that double doesn't count against the integer. So it's going
23:04to be C is going to be RSI. And then, uh, uh, for double D, uh, same thing. Uh, we're
23:12not going to
23:12skip XMM1 just because there was an integer. We're going to go straight to saying that XMM1 is the
23:19second float argument. So it's the D then for the last argument that we have, I'm just going to erase
23:23this stuff down here. Um, it was going to be E and remember pointers are integers. They're just
23:28unsigned, uh, 64 bit integers. We have to go into the next one, which I think I recall is like
23:34RDX.
23:34Let me just double check. I don't want to say this wrong RDX. Yeah. The third argument.
23:39So I'm going to do RDX. And now, uh, that we've kind of like mapped this out, we, we know
23:46now
23:47what, what registers we should be looking for when the function comes in, in order to receive our data,
23:52we should look at those registers for those variables. Another thing to keep in mind, by the
23:56way, is that usually when we return something in assembly, we will, uh, move a value into RAX,
24:03right? Like some value if you've been following my assembly videos so far. Uh, but that only counts
24:08if you want to return an integer or a pointer. If you instead wanted to return a floating point number,
24:13uh, then you would have to, uh, use XMM0 and I'll just, you're not allowed to, you're not allowed to
24:20hard code a floating point number in assembly like this, or at least in the ASM. So we'll just pretend
24:25that there's like a float somewhere and I'll just load it from memory and I'll say like the float,
24:29something like that. So notice how we're using a different instruction. Uh, we're not using the
24:34regular move instruction that, that works with integers. We're instead using the floating point
24:38version. We're saying, let's move a single piece of data and let's move a double precision floating
24:42point number into XMM0. And then we'll just grab from memory, whatever, whatever that variable has,
24:48we'll just take that floating point number and stick it into XMM0. So, uh, if you want to return an
24:55integer
24:55or float, you use RAX. If you want to re sorry, if you want to return an integer or a
24:59pointer,
24:59you use RAX. If you want to return a float, you use XMM0. You shouldn't do that at the same
25:04time.
25:05If you have like two assembly functions calling each other, you might be tempted to do that. And I guess
25:09nobody would really stop you, but your program would not be, you know, very standard and it
25:14wouldn't work very well with other people's code or library code or higher level language code.
25:19So only one or the other, and it just has to match your prototype. So notice how here
25:23inside of my CPP function, notice how it's going to return a double, right? So when the assembly module
25:32is done calling on this function, it should expect XMM0 to be loaded up with that double precision
25:37floating point number. Okay. So that's the basic idea. Um, so now let's, uh, maybe let me pin this.
25:44Let's kind of fill this out a little bit more. So the first thing that we should do is we
25:48should save
25:49our integer or pointer arguments. So I'm going to leave the respect ABI thing there and notice how
25:56I'm just looking at RDI and RSI and RDX. And, um, well, I guess, you know, we have it in
26:04a comment
26:04up here, A, C and E, but I'll just make another comment here. I'll say like A and, uh, A
26:12or sorry,
26:13A, C and, um, E and maybe we'll, we'll specify the data types for fun. So it's going to be
26:19long
26:19A and then long C and then a character pointer C, even if this was a float pointer, it would
26:27still
26:27be an integer because all pointers are integers, no matter what they're pointing to. So just keep that
26:32in mind anyway. So we're going to save, uh, our 12, our 13 and 14 with the incoming arguments.
26:37And the reason we want to save those right away is because RDI, RSI and RDX, those are not callie
26:42saved, which means the moment we call on another function, they'll possibly be destroyed because
26:49we don't really know what's going on in other functions that we might call. Uh, so it's a good
26:53idea to just kind of save right away, either to a global or the stack, or in this case, just
26:57registers
26:58being faster. Okay. So we have that. Now we have to save our float arguments. And if you recall,
27:04B and D were XMM zero and XMM one. So I'm just going to save both of those.
27:11And, um, if you're wondering what this float B and float D are, that's just,
27:15you know, up here, I just have a global variable so I can save them to memory easily and not
27:19worry
27:19about the stack. This is not a stack video so much. Uh, but yeah. Okay. So I'm just saving all
27:26of
27:26the incoming arguments. That's all I've done so far. And let's see, it should probably still
27:31compile. Let me see if this works. I'm going to go make run. Okay. So nothing happens,
27:36but it at least worked. So I'm going to same as other windows for that, uh, so that we don't
27:41have
27:42to look at it anymore. And now that we're done saving our float arguments, let's, uh, let's print
27:46a welcome message. So I'm going to do, you know, welcome. And I'm going to use a special function
27:52that I've made in previous videos called print null terminated string, which means I should
27:57probably copy paste that into this program now. So what is print null terminated string?
28:02It's just another convenience function that I wrote. Uh, I'm not going to explain it too much
28:06because it's in other videos and, uh, I'm already here trying to explain functions to you in general.
28:11So long story short, it takes in a C string and a file handle, you know, to like where you
28:16want to
28:16write, like if you want to write to a file or you want to write to standard output or standard
28:20error.
28:21And it just takes those arguments. And then it sort of says, all right, how long is the string?
28:25And it uses another function called string length to figure out how long the string is.
28:29And then it just uses a system call, uh, uh, to actually print the string. And again,
28:34system calls are covered in other videos. This one looks really convoluted because it's like,
28:37you know, customized for this function, but just trust me on this, this prints a string.
28:42Next function, I got to paste in real fast again, explained in other videos is, uh,
28:47the string length function. So all this does is it just takes a pointer to a string and it sort
28:52of
28:52scans the string, uh, counting how large the string is. And as soon as it sees a zero, like a
28:58null
28:58terminator, then it just says, all right, that's, that's the end of the string and it'll just return
29:02the length to the caller. So that's all you need to know about this covered in other videos. Then I'm
29:07going to make a convenience function here called CRLF. And all that's going to do is just print the new
29:13line that we talked about earlier. So just, just a bunch of convenience functions on top of, uh,
29:17the real part of the program. So now that we have the convenience functions in there,
29:21we should be able to see the welcome message. Let me just double check that.
29:27Yeah. Now inside assembly entry point. Oh, what did I do wrong now inside? I keep forgetting to
29:33change the strings on this now inside. Where's that now inside my assembly function? Okay. Let me
29:39change that in my solution too. You know, I'm just kind of like writing these things and I'm having
29:44fun and I keep changing my mind about what they should be named. And then I, I get some inconsistencies.
29:50Okay. All right. So then, uh, we printed the welcome message and now let's print the integer arguments,
29:56but first let's print a little introduction, uh, to the integers. Let's just say, Hey, we're about to
30:02print the integer. So that's just this other string, a message saying we're about to print the integers,
30:06nothing really that complicated so far. It says now we're printing all the integer arguments.
30:11So now we can actually print the integer arguments. So we have two integer arguments. Um, right now
30:18they're stored in R 12 and R 13. If you recall, um, let's see. Yeah. We had like a and
30:25C those were
30:26integers. I'm not going to talk about E right now because that was a pointer, but you know, right now
30:30we're just saying a and C so that was R 12 and R 13. So I'm just going to paste
30:35some code here to
30:36actually print those and, um, talk about this library and other videos, but basically I'm moving
30:44R 12, which is the first integer that I want to print into RDI, which is the first integer argument
30:49that functions typically receive. And once that's loaded up, I'm just going to call on my special
30:54function to just print the integer. Um, and again, you could use, uh, print F, uh, from the C libraries
31:00if you actually wanted to print it and not just experiment, uh, and stuff like that. So I'm going
31:05to use, uh, R 12 and R 13. And, uh, I'm just going to print both of those integer arguments.
31:11And then
31:12after each one is printed, notice I'm calling the CRLF function, which is just the convenience
31:17function of just like doing a new line. So now we should see two numbers. Yeah. Now printing all integer
31:23arguments. We've got 88 there. And then that other giant number there, let's just double check that
31:27that's actually what we're supposed to be seeing. So I'm going to do this and I'm going to say
31:33the driver called the assembly module with these numbers.
31:38It gave it an 88. And then, uh, for the next integer, it gave it the two eight seven
31:43giant number. So great. Uh, we were printing the integers. Now let's print the floats. So we should
31:48see like a 99 point something in a 32 point something next. Okay. So, uh, let's continue
31:55with, uh, printing. Oh, sorry. Actually let's print the, uh, the C string because that's a pointer
32:02that's still more closely related, uh, than the floats. So the first thing I'm going to do is I'm
32:06going to, um, let's see, print the received C string. How about like announce that we will print the C
32:17string because that's what we're doing right here. Let me change my solution to match.
32:22And then we'll, uh, uh, we'll actually print the received C string next.
32:28So same stuff as before. First we call print null terminated string to print out a little welcome
32:33message or just like an intro message. Like we are going to print the C string and then we'll use
32:38that print function again, but we'll give it the C string. So it just prints the whole C string out.
32:42And this should prove to you that we are indeed receiving a pointer
32:45to some data owned by the C plus plus module. So if we run this real fast, um,
32:51it should just tell us two more things. It'll give us the announcement. Now printing the received
32:58C string. And then on that same line, it says, hello, this is the C string owned by main. And
33:04if
33:04we just look back at, uh, the driver real fast, that's exactly what string, uh, is inside of that
33:11variable. So hello, this is a C string owned by main and we gave it to the function by just
33:16kind
33:17of passing it in. And we know that, uh, character arrays are basically character pointers or any array
33:23is just a pointer to the first item in the array. So, uh, my C string is really a pointer
33:27to that H
33:28character. So if we pass that in, uh, then a pointer based print function should be able to work.
33:33And that's what happened. Okay. So we've done that. And then, uh, the next thing we should do
33:39is let's print the floats. So first let's announce that we're going to print the floats.
33:44Same thing we'd before we're just printing like an announcement message. If we run the program again,
33:49it's just like now printing the floats, but it doesn't actually do anything. So then the next step
33:53is let's, uh, let's grab the first float into XMM zero and then let's call a function to print it.
34:04So right here we have like that 99 number that we expected from before, uh, by the way,
34:09so why am I doing it this way? Why am I not just keeping, uh, XMM zero? Cause you remember
34:15before
34:15we had XMM zero had the, had the float that we received and then we're using it again down here,
34:21but remember XMM zero and all the other float registers, they're not designated as callee
34:27saved, which means the moment we call any other function, we should expect that that data has
34:31been destroyed. So I can't actually count on XMM zero surviving just this little simple function.
34:38Instead, I have to save it somewhere to the stack, uh, to memory, you know, whatever. So I'm just,
34:42that's why I put that into a global variable. So it's sitting in float underscore B right now.
34:47And then, uh, we saved it at the beginning to float underscore B. And if you just kind of look
34:51up to the data area, uh, well, it was just float underscore B was just a little quad word, you
34:57know,
34:57eight bytes of memory that can hold our float. So we have like float, uh, allocations for B and D
35:04the first and second float arguments. So we're saving it there and then we're recalling it here.
35:10And, uh, remember the first function argument is going to be XMM zero, uh, regardless of where
35:16that data originally came from. So if we look at the next one here, if we kind of like, let's
35:22see,
35:22copy paste this and we, we want to grab like the D floats, we're still going to load it into
35:28XMM zero
35:29because right now it's not about what we originally received as an argument. It's what this function
35:34expects as an argument. This function only takes one argument. It just wants a float so that it can
35:39print it and that's it. So both times we're going to load it up into XMM zero and then we're
35:45going to
35:45print a new line. Okay. So let me just run the program one more time. And we should now see
35:49we've got two floats and they should match, uh, what the driver tried to send in. Right? So
35:5699, that's the first one. And then a 32 point something. That's the second one.
36:00So cool. We have received integers and pointers and floats. We've recalled them and then we've
36:06printed them pretty, pretty slick. What do you think? Anyway, so we've done that. And, um,
36:14the next thing that we should probably do is, uh, well, at this point, well, we just maybe have to
36:20mess with return types, uh, even though I've told you about it, we'll just, we'll mess with it a little
36:24bit. Um, but let's call the C plus plus module. So what I'd like to do first is just sort
36:30of
36:30announce that we're going to call on the C plus plus module again, typical design pattern. Let's
36:35just print a message saying what we're about to do. And if we run this now, it's going to say
36:40assembly module will now call on the C plus plus module. So nothing really too complicated.
36:46So now we're going to call on that function. Let me, uh, let me paste the name of it here.
36:51Uh, actually I'm going to put this one right here. It's the, my CPP function function.
36:56So if we look back at the driver and look at the signature for my CPP function, whoops,
37:03it, uh, has this signature. And if you wanted to look up higher, you totally can just look into the
37:08the name mangling section. Uh, whoops, the my CPP function, it returns a double. It takes in a long,
37:15a double, a long, a double, and a character pointer, basically the same thing, uh, as the other one,
37:20except it returns a double. So what's going to happen is when it takes all of these in,
37:25it's just going to print all of them. And then I'm just going to have it return just kind of
37:29like
37:29some random double that I decided to type because this is not an arithmetic video. Okay. So CPP
37:36function. And then, um, now how do we interpret that? So if we, uh, let's see, let me, maybe just
37:43for help this, that usually helps me when I'm trying to do this, I'm going to take the prototype
37:48and just sort of like paste it right where I'm about to call the function. So I'm going to do
37:53this just to remind myself of what I'm actually calling. Let me add that to my solution, by the
37:58way. Okay. So we're going to call my CPP function, which means it's expecting some registers to be
38:06loaded up with arguments. If we don't actually load up anything right now, it'll probably do some sort
38:11of nonsense. Let's actually see what happens right now. If we don't load up the appropriate registers,
38:17then C++ will still look at those registers expecting to see valid data. Let's see what
38:21happens. I don't know if it's going to be good or bad. Uh, this would probably be something called
38:26undefined behavior, meaning you did something wrong and probably sometimes your program will
38:31work and sometimes it won't. Sometimes you won't understand what's going on. So, uh, I'm going to,
38:36I'm going to do this right now. And it's saying, oh, it's saying faulted. Okay. Okay.
38:43Why did it say fault? All right. Well, I guess maybe because I did something naughty. I don't know.
38:49If this say faults by the end, we're going to be in trouble. I'll have to debug on camera.
38:53So, uh, we're going to enter into my CPP function. And then it says we got a variable a,
38:58which was a long, we didn't give it a one. A one was just probably sitting in there
39:02before we even called that function. So like one is definitely not it. And then B was like some,
39:09I guess, very, very, very small floating point number. And then C was just like another seemingly
39:15random value that kind of looks a little bit more like a pointer. I'm not really sure. It's probably
39:19not, but it's just some junk data coming from somewhere. And then D, which I think D was supposed
39:26to be a character pointer. It says not a number. So we just got like a, a really bad value
39:34for D.
39:35Let me upgrade this real fast. Cause maybe we should be printing what printing it as a memory
39:39location. So E is, um, let me, let me bring this down real fast. So E is supposed to be
39:45a character
39:45pointer. Let me, uh, instead of printing the C string, uh, as just like itself, let's first print
39:51the memory location and I'll just say memory and then we'll do a static cast. Oh, I wonder if this
40:00actually changed anything. I wonder, let's data cast both of them just to see what happens.
40:07So I'm going to print E and, uh, C string here. And then it's going to be, um,
40:17um, no, I don't think that's actually going to change anything because if I cast it as a point,
40:22as a character, that's definitely wrong. And if I don't cast it, then it's going to show up as its
40:27original data type. How do I get the memory location? Hmm. Oh, I know what to do. I can static
40:34cast it maybe as a, as an unsigned long. Okay. So a character pointer, we'll leave that for the C
40:40string
40:41unsigned, uh, long, long, just in case. And I think I should see the memory location first
40:47and then the actual C string later. If not, then whatever. Let's try one more time.
40:54Oh dear. Invalid static cast from a character pointer to a type long, long unsigned integer.
41:01What have I done? How about unsigned long? See if that works.
41:07Character pointer to long int. Hmm.
41:13I guess I forgot how to cast pointers to longs. I'll look that up and post another video in the
41:19future, but I guess for now we'll just, we'll deal with this humiliation and I'll just print E by itself.
41:27All right. So I'm just going to run it one more time. It should say fault again.
41:30Okay. So obviously something is wrong. Let's, uh, let's just fix the arguments.
41:35So before we make that call, uh, we should load up some stuff, right? So
41:40I'm going to do maybe like a semicolon comment here, and then I'm going to do
41:44what else do I have? I've got three move instructions. So, uh, the first argument is going
41:50to get seven, seven, one, one, eight. The second argument is going to get one, one, one, one.
41:54And the third argument looks like it's going to get a pointer that I've defined inside of the assembly
41:57module. So if you look back up at the top, let's see message string inside ASM message
42:05string inside ASM. So basically I'm going to be sending a character pointer to this
42:10T right here, uh, which is just this string says this string is owned by the assembly module
42:16and it's a null terminated string, which, uh, C definitely needs in order to print correctly.
42:21If we took that zero off, we'd probably get a bunch of junk data.
42:24We might crash the program. I don't know. So anyway, basically we're just going to be saying,
42:29you know, here you go. Here's a pointer where the heck, where the heck am I? Okay.
42:33Here's a pointer to a C string. And so we're giving it one, two, three arguments. We're giving it the
42:38A
42:38and the C and the E. Now we just have to load it up with the other two floats. So,
42:44um,
42:47I'm going to do this real fast. Remember the first float argument is going to be XMM zero.
42:51And the second one's going to be XMM one. And you can see that, uh, send B corresponds to the
42:56first
42:57float argument. That's why it's XMM zero. And then the float send D corresponds to the second argument.
43:03That's why it's XMM one. And that's, um, the D right here, and there's no other floats.
43:09And if we just kind of look back up real fast, the float send B and D, uh, I just
43:14defined those
43:14arbitrarily to just these two random numbers. So we should see like a two one nine and then a nine,
43:20nine, eight, eight, seven, seven, six sort of, you know, weird number. Then when we're done loading
43:27all those things, you know, all of these registers up now, the function should be able to receive
43:32something. I bet you the reason it crashes, cause we, we had like a bad address for the, uh, the
43:36string
43:36previously, cause we didn't load it. So let me go up here and now it doesn't crash. Uh, so if
43:43you just
43:43kind of like, look, uh, we have hard coded a and B, sorry, not, not a and B a, and
43:49also C. So that's
43:50the seven seven one. And then the bunch of ones and then the string, which was RDX, which was the
43:55E.
43:56So this string is owned by the assembly module. Nice. We're now able to print a string that's owned
44:02by assembly in another module in the C plus plus module. And then, uh, XMM zero and XMM one. Those
44:08are the two floats. So if we look back up again, that's, uh, we should expect to see these two
44:13numbers right here. Whoops. Um, float send B and D, which is B and then D. So the printing kind
44:23of
44:23turned it into scientific notation. That's okay. You know, there's other stuff you can do in C plus plus to
44:27just not print in scientific notation, but for now I don't really care. It's basically the same
44:32value. Uh, so it's fine. I just want to show you how to transport data. Uh, this is not a
44:37C plus plus
44:37video. Anyway, if we go back down to the end of that, so we, we called the function, but then
44:45this
44:45function, if you, if you notice it returns a double, right? Which means we should expect to see something
44:49loaded into the XMM zero register. So I'm going to move a single piece of data and it's going to
44:56be a
44:56double precision floating point number. And I'm just going to store it into my float got return
45:01value global variable, which I defined up above. So let me scroll up real fast.
45:06So where's that? Where's that float got return value. I initialized it with a zero just because
45:11we're going to receive something in there. Uh, I could have used the BSS section if I wanted to
45:15probably would have been a little bit smarter and more performant, but I don't know. I personally
45:19don't like using the BSS section in YASM unless, uh, I want to allocate an array. If I'm just doing
45:25one variable here and there, then I'm just going to put it into globals or, or the data section.
45:31So float got return value. I'm saving it in there. And then, uh, I want to grab it from XMM
45:39zero.
45:40So that's where it comes from. When, uh, my CPP function returns, it's going to return, uh,
45:44the double to us inside of XMM zero. So I'm just moving that into my data section into the global
45:49variable.
45:51And then now that we have finally returned from the C++ module, uh, I'm just going to announce that
45:59we have indeed returned from the C++ module. Let's get that far real fast. So this string is owned and
46:08then, um, uh, my CPP function exiting. And then now it says the re the assembly module received this
46:17return value from the C++ module. And then it says the driver has regained control because we were
46:22supposed to print the float and do a line feed after that. And we didn't. So basically
46:26assembly just printed this string. That was the last part we just added,
46:29and then it returned right away to the driver. So let's finish this up.
46:34So, uh, next thing we're going to do is, uh, we're going to
46:42move the float value back into XMM zero. Remember anytime you call a function,
46:47all your float registers could be destroyed. So it makes sense that we saved XMM zero,
46:52and then we loaded it only several instructions later because you don't know what's happening
46:56under the hood inside of print null terminated string or any of the system calls that it uses.
47:02Uh, your XMM zero is likely destroyed. Um, but you don't know for sure, right? So if you,
47:07if you, if you count on it, not being destroyed, you might be introducing undefined behavior to your
47:12program. So that's not good anyway. Um, so we're just loading back up from that global
47:20into XMM zero. And then we're calling that function again to just sort of print the float.
47:26And it wants the float as argument zero. So we're just sticking into XMM zero and then we're printing a
47:32new line. So then when we're done here, run it. And now it says
47:39the assembly module received this value from the C plus plus module. And notice how it's that special
47:45value that I hard coded, uh, one, one, two, two, two, two, two, whatever. Uh, so that's this value right
47:51here. And again, if we had this, uh, CBP function returning along, uh, then all we would have to do
47:57is
47:57look at the RAX register. And if we had, let's, let's say for some reason that this assembly function,
48:04we wanted to, to, to get something from it, we could say, you know, double temp equals that.
48:11Then all we'd have to do is make sure that we returned, uh, sorry, we loaded XMM zero, uh, with
48:17our return value in the assembly module because XMM zero is the return register for floats. Or if we
48:22wanted to do like a long, then just load RAX with something at the end of my assembly function.
48:28And that's how C would be able to get it. Remember C is a following C and C plus plus
48:33they're following
48:33the ABI. So if you personally don't follow the ABI, you're just going to end up memorizing two
48:39different ways of doing things. And your way is not going to be compatible with all the other modules
48:43written in higher level languages. So it's kind of a waste of time and your modules won't be
48:48compatible with other people's libraries and functions. It's just a huge waste of time. So just
48:52follow the ABI in the first place. I've literally known people who said, you know what? I don't
48:57want to learn the ABI that's dumb. Then as they wrote a bunch of assembly, they just started
49:02thinking like, Oh, this is too confusing. Cause I keep forgetting what registers I was going to pass
49:06back and forth between my functions. And like a month goes by, I come back to an old program.
49:11I can't remember. I have to like look through all my code again. So then they started accidentally
49:16inventing their own little scheme. Like, Oh, I know what to do. I'll put the first argument in this
49:20register and I'll put the second argument in this. All they were doing is just reinventing the ABI
49:25from scratch and then wasting a bunch of time before they got to that point. And then later
49:30wasting more time when they realized they just needed to learn the ABI and forget about their way.
49:35So don't let that happen to you. And you should probably just try to do it the right way the
49:38first
49:39time, right? A lot of things in coding and computer science in general are just time savers that feel
49:46like wastes of time at first. Okay. What else do we have anything that I wanted to show you?
49:51That was actually, I think the entirety of that program, let's run it one more time for posterity
49:56while I check to see if there's any other stuff that I was supposed to show you.
49:59So let's do this.
50:03Everything seems to be working. Uh, let's see. I wanted to tell you about labels, return, call,
50:07the stack, the return address, prologue and epilog, pushing and popping, respecting the ABI.
50:13I wanted to show you that textbook function arguments, mixed arguments, int or pointer,
50:18return types and float return types. I guess I got through everything without forgetting
50:22something huge, which, Hey, that's probably a first. Not that I recall at the moment,
50:27but it probably is anyway. So, uh, I guess that's it. I hope you feel like function experts now in
50:33YASM
50:34X86 64 assembly, also known as a AMD 64 assembly in Ubuntu. Okay. Thank you so much for watching
50:43this video. I hope you learned a little bit and had a little bit of fun. I'll see you in
50:47the next video.
50:54Hey everybody. Thanks for watching this video again from the bottom of my heart. I really appreciate it.
50:59I do hope you did learn something and have some fun. Uh, if you could do me a please, a
51:03small little
51:04favor, could you please subscribe and follow this channel or these videos or whatever it is you do
51:10on the current social media website that you're looking at right now. Um, it would really mean the
51:14world to me and it'll help make more videos and grow this community. So we'll be able to do more
51:19videos, longer videos, better videos, or just, I'll be able to keep making videos in general. So please
51:25do, do me a kindness and, uh, and subscribe. You know, sometimes I'm sleeping in the middle of the
51:30night and I just wake up because I know somebody subscribed or followed. It just wakes me up and I
51:34get filled with joy. That's exactly what happens every single time. So you could do it as a nice favor
51:39to me or you could, you could troll me if you want to just wake me up in the middle
51:42of the night,
51:42just subscribe and then I'll, I'll just wake up. Uh, I promise that's what will happen.
51:47Also, uh, if you look at the middle of the screen right now, you should see a QR code,
51:51which you can scan in order to go to the website, which I think is also named somewhere at the
51:55bottom
51:56of this video. And it'll take you to my main website where you can just kind of like see
52:00all the videos I published and the services and tutorials and things that I offer and all that good
52:05stuff. And, uh, if you have a suggestion for, uh, uh, clarifications or errata or just future videos
52:14that you want to see, please leave a comment. Or if you just want to say, Hey, what's up,
52:18what's going on? You know, just send me a comment, whatever. I also wake up for those in the middle
52:22of the night. I get, I wake up in a cold sweat and I'm like, it would really, it really
52:27mean the
52:28world to me. I would really appreciate it. So again, thank you so much for watching this video
52:32and, um, enjoy the cool music as, as I fade into the darkness, which is coming for us all.
Comments