Skip to playerSkip to main content
  • 2 days ago
Join me as I break down a simple yet powerful x86-64 YASM assembly program to copy files using system calls! Learn how to open input files, create output files, and use a looping buffer for efficient data transfer. I?ll demo the code, explain file handles, permissions, and error handling, and even verify the copy with MD5 checksums. Perfect for intermediate assembly programmers or anyone curious about low-level file operations. Check out my other videos for more assembly tips, and don?t forget to subscribe!

Introduction to File Copy Program 00:00:00
System Calls in YASM Assembly 00:00:06
Opening Input File 00:00:17
Creating Output File 00:00:22
Using Looping Buffer 00:00:28
Assembly Program Prerequisites 00:00:37
Overview of Source File 00:00:53
Data Section and Strings 00:01:06
Copy Buffer Length 00:01:21
File Permissions Explanation 00:02:05
System Call Codes 00:02:57
File Descriptors and Exit Codes 00:03:24
Text Section and Entry Point 00:03:45
Welcome Message Function 00:04:01
Print Null Terminated String 00:04:16
Running Initial Program 00:06:26
MD5 Checksum Explanation 00:07:00
File Tests Function Introduction 00:07:28
Open File Read Function 00:09:52
Checking File Handle 00:14:00
File Handle Concept 00:14:25
Error Handling Importance 00:15:24
Testing File Open 00:23:00
Create File Function 00:31:16
Testing File Creation 00:32:36
Copy File Function 00:36:14
Stack Buffer Creation 00:38:16
While Loop for Copying 00:40:14
Read System Call 00:40:47
Write System Call 00:45:03
Checking Read/Write Operations 00:46:51
Final Program Run 00:49:00
Verifying File Copy with MD5 00:49:22
Testing with Larger Input 00:51:20
Optimizing Buffer Size 00:53:41
Conclusion and Call to Subscribe 00:54:41

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

🤖
Tech
Transcript
00:00Hey everybody, in this video I'm going to show and explain a simple program that copies
00:05a file using system calls in an x8664 YASM assembly program.
00:17We're going to use the system calls to open an input file and read characters from it.
00:22We're going to use another system call to create a destination file and write characters
00:26to it and we're going to use a looping buffer which should be kind of fun in the middle.
00:32And I'm just going to do my best to explain as much as I can.
00:35I should say though that before you can watch this video you probably already need to know
00:38how to program an assembly at least in a basic level YASM assembly.
00:43And so if you don't know how to do that yet this video is probably going to be confusing
00:46for you.
00:47You probably need to look at my other videos dealing with YASM assembly and system calls
00:51and so forth.
00:53So I'm just going to show you real fast what's actually going on in this source file so far.
00:58So this is my assembly program.
01:00It's not finished I'm going to write it on screen for you for the most part.
01:04You can see I've got a data section here and then I just have a bunch of null terminated
01:07strings.
01:08So I've got a string saying hey the module started we're about to open the file we're
01:11about to you know create the file we failed to do something we're done copying you know
01:17we terminated the program you know whatever right so I just have some strings no big deal.
01:21Down here I have something called the copy buffer length which is which is just the size
01:25of the buffer that I'm going to use between the input file and the output file.
01:29So a two byte buffer is really inefficient it's too small but I made it two bytes just to show
01:35to you that our looping you know read area is going to actually work because if I make
01:40a buffer that's too big if it's bigger than the file then we won't actually know if the
01:45if the buffer loop works or not.
01:46So I'm just going to put two here could change that later if we wanted to we're going to
01:51be reading from a file called input and writing to a file called output so that's no big deal.
01:58In order to open a file with a system call for read mode we're just going to use a zero
02:03as the flags that just means read mode.
02:06And then for the creation of the file we're going to use some standard permissions.
02:10This is not a permissions video I'm going to probably release a permissions video at some
02:13later point in time not too important right now but basically this 640 is the heart of
02:20what permissions we're actually looking at.
02:22Q is quad word and 6 just means that the owner can read and write to the file.
02:284 means that the that anyone who is in the same group as the file has been assigned to
02:32which is usually the owner can just read it but not write to it.
02:36And then everybody else people who are not the owner and who are not in the right group they
02:40have no access to it just a simple you know security feature of Linux for file permissions.
02:45You can go a lot further than this in the terminal but for this assembly program we're just going
02:50to use basics we're not going to use ACLs I don't even know how to do that in assembly.
02:56System call codes so again if you don't understand system calls you got to watch my other videos
03:00but we you know we have a code of 0 to read from a file, 1 to write to a file, 2 to open
03:08a file, 3 to close an open file probably should have put that one before create but I don't
03:14really care.
03:1585 is the code to create a file for writing and then 60 is the code to exit from the program.
03:20So then we have file descriptors.
03:24Descriptor number one is a standard output descriptor number two is standard error and it's always
03:28one and two no matter what program you're dealing with unless you have some kind of really crazy
03:33non-standard thing going on and then for the exit codes we're just going to say exit zero for success
03:38and exit one for failure.
03:40Now to the actual text section where our instructions are in the assembly program so you can see
03:46section text here we've got a global entry point called underscore start so this is not
03:50a GCC program that requires a main entry point this is a pure assembly program that requires
03:56an underscore start entry point again see my other videos for more assembly explanation.
04:01I'm going to call on a method well not a method a regular function called welcome just to print
04:06a little welcome message you can see right here that's all that's doing is just loading
04:10you know a string sending it to standard output and calling on a helper function that I made
04:15called print null terminated string.
04:18When it's done with that it just uses the call code to exit the program no big deal nothing
04:23too advanced so far I have the the tests function commented out because I want to write that
04:29in front of you and if you look at what I have inside of print null terminated string this
04:34is not the point of the video so I'm just going to skim it it's not super important but you
04:39know I want a function called print null terminated string that takes in a pointer to a character
04:43array and a file handle for where you want to print it and what it'll do is it'll come
04:48in grab the incoming arguments it's only got two arguments so it uses r12 and r13 to store those
04:54arguments and then r14 is the result of calling another helper called string length you can
05:00imagine my string length function just kind of scans the string until it finds a null terminator aka
05:05the number zero not the ASCII code for zero but actually a zero in order to figure out how long the
05:12string is and then it can use a regular system call to print the string to the right file descriptor
05:18so uh we're going to be doing most mostly this kind of this exact same thing when we copy the file
05:25so I'm just definitely not going to explain it uh if you don't know pushes and pops and epilogues
05:29and prologues see my other videos crlf is just going to print a carriage return new line
05:35so it or sorry carriage return line feed so that's just like making the cursor go to the next line
05:40not a big deal we just print a string basically and then I have a custom die function that allows
05:45us to die with a failure code of one oh I forgot to mark that let's see 206 exit fail I'm just going
05:53to put that down here yeah instead of hard coding values it's a lot better to use variables if you can
05:58or defines so all it's going to do is just kind of print an error message and then exit with the
06:05uh you know the appropriate uh exit code which is just going to be one because this is a simple
06:13program so crlf print an alternated string dying string length a welcome message all this fun pretty
06:20stuff that doesn't really do anything except make the program more fun to look at so I'm going to run
06:24it here and make sure that it actually works okay nice okay so if I run it you can see that the the
06:31make file system again this is not a make file video so I'm not going to show you my make file
06:36see my other videos if you want to learn more about make files but um you can see that the assembly
06:40program says that it started and then it just exited then the make file continues to run these extra
06:46commands that I have set up so this is not part of the assembly program this is just taking a checksum
06:52an md5 checksum of the input file and then an md5 checksum of the output file if you don't understand
07:00what md5 checksums are I'll probably release a video sometime in the future if you're interested
07:05on all my platforms just talking about why we why you would use a checksum but for now just imagine this
07:11is a fingerprint so if the fingerprints don't match that means the files don't match right now the output
07:16file doesn't even exist so it just is an error and that's why the make file thinks there's an error
07:21because the output file didn't exist so that's the basics of kind of getting started with this you
07:27know bare bones program now let's start looking at running the file tests so file tests we got to
07:33make a new method I'm going to stick it down here let's see I got a solution up so that I don't have
07:39to spend too much time typing I'm going to try my best to balance between copy pasting and just typing
07:45very quickly but um let's see where's the file test so we got this I'm going to put the signature
07:51up here real fast and you know what I'm feeling pretty lazy I'm just going to copy paste the whole
07:58thing copy paste the whole thing so now this method right here is going to get called the file tests
08:06so I keep saying method because I teach C++ a lot too file tests if we go down further this function
08:14is called file tests here's the signature it doesn't take any arguments it just kind of does
08:19stuff it doesn't return anything and here are the registers that I'm going to use I'm going to have
08:24the input file handle the output file handle and then the count of bytes read from the input file
08:30at any given time inside of our looping buffer reader section so the first thing I've got to do is
08:35I've got to open a file to read the second thing I've got to do is create a file to write
08:42and then I'm going to copy the input file to the output file and then I'm going to print a message
08:47saying hey everything was successful and then I'm going to close both files notice how I'm not actually
08:51doing anything I'm just sort of calling other functions to do the work for me again if you don't
08:56know the prologue and epilogue stuff or calling functions and returning you should see my other videos
09:02but I just like to use helper functions assembly is like so unwieldy right it's it just gets out
09:07of control so quick and so confusing so fast so anytime you can just you know take a chunk out
09:14of your assembly code and move it somewhere to another module or to another function it's probably
09:20going to make your life a lot easier and make debugging a lot easier people who try to write
09:24the entire portion of their program in just one gigantic function those are the people who usually
09:30end up spending 10 times longer debugging for no reason at all so I believe in the power of modular
09:36thinking so anyway what are we going to do inside of the open file read function it's not too bad to be
09:43honest let's see if I can find it real quick open file read I'm going to copy paste it because again I'm
09:48pretty lazy I'll just explain what it is though so down here we need a function called open file read
09:56so I'm just going to do that and you can see the signature that I've chosen for this is you know I
10:02like to write all my functions in C++ kind of lingo or prototypes so that I can have a better understanding
10:09of what the assembly is actually supposed to do so you can see the function called open file read
10:15I want it to take two arguments the first argument should be a pointer to a string that represents
10:22the file name that I want to open and it should be null terminated again if you look back at my
10:27at my strings up here they all have little zeros at the end so they are all null terminated anyway so
10:34that's the first argument that's going to show up as RDI in assembly and then the second argument is
10:41the flags for opening the file so I think probably that was redundant if I if I name this open file
10:46read then I think it should be obvious that the flags are just going to be the read flags only so
10:50I probably didn't even need to provide this that was bad design on my part you could write a better
10:56one on your own where it's just one argument and if the name is read then just use the read flags but if
11:01the maybe if you want to leave the flags in there you could just say open file only it's up to you
11:08anyway so it attempts to open a file for reading if it is successful it'll return the file handle
11:13that's the long return type right here long file handle if it fails then it will just basically
11:19complain and exit the program you probably want a more sophisticated way of handling errors in your
11:25program I just decided to complain and exit the entire program because this is you know not supposed
11:31to be super complicated I just want to show you how to copy files and then for me I like to leave
11:36comments that just sort of explain what I'm using the registers for and once my functions get so
11:41complicated that I actually run out of registers then that tells me I probably need to just make
11:46another function you know split the work up in some way so far so good I only end up
11:54reusing the same registers for multiple purposes occasionally I'm not a hardcore assembly programmer I'm
12:00just you know I'm like medium so I'm going to use r12 and 13 and 14 that's why we have the prologue
12:08pushing all those registers to preserve them because they're callee saved and then the epilogue epilogue
12:12that just kind of pops them I've got a label here for the function remember a function is just a label
12:17and then a return statement as long as you obey and respect the abi like preserving certain registers
12:23then you should be okay first thing I'm going to do is grab the incoming arguments so I'm going to grab the file
12:27name which is a pointer which means it's just a 64-bit integer I can stick that into a register and then
12:33the flags same thing so I'm going to grab rdi and rsi the incoming arguments I'm going to stick them into
12:40r12 and r13 so the character pointer in the flags and then I'm going to attempt to open the file with
12:46a system call so system call is right there line 168 if you look up the table for system calls in my
12:55favorite book that I usually recommend or any table that knows the system call codes for x8664
13:01assembly then it'll say well the system call code to open a file is some number I've assigned that to
13:07sysopen if we look up here open is code 2 so that's why I you know I don't want to remember the numbers
13:15it's bad to hard code number so I just I just put it as a define and then the first argument that it
13:21wants in rdi is the name of the file so I just gave it r12 I guess I probably could have just used rdi
13:28directly in the system call but that tends to make me nervous reusing the argument registers I like to
13:33have them somewhere where they're not going to be destroyed if I like let's say I accidentally you know
13:37added some code here on line 163 if I wanted to reuse rdi and I accidentally added some code there then rdi
13:45would have been destroyed would have cost me a bunch of time debugging my program although I admit it's
13:50not super efficient to do it that way then we're going to do the file status flags as the second
13:54argument and then we just do a system call right away so the rex register gives you the result of
14:02your system call notice how we use rex to send in the call code and then the system call sends us back
14:09its return result also in the rex register so I'm just going to save that right away to r14 you can
14:15see up here it's just the file handle so we can assume maybe at this point that we have a file
14:20handle sitting in r14 you know what is a file handle when you ask the system to open a file for you
14:25the operating system under the hood is just going to do a bunch of stuff to actually open a file
14:30it's going to go it's going to take the string that you sent it and it's going to parse it and figure
14:36out you know how do i how do i interpret where that actually is on disk i'm going to look at
14:41like the file system in the past that you provided i'm going to look at the mount points and i'm going
14:45to figure out like where exactly on disk does that file start and then the operating system stores that
14:51the operating system stores the file name it stores where you're looking at the file currently
14:55stores a bunch of stuff that you don't want to have to remember you know it creates data structures
15:00under the hood and all it'll give you back in return is a file handle
15:06for simplicity because then later you can use that file handle to just sort of say
15:10i would like to write some bytes to a file or i would like to read some bytes from an open file
15:15here's the handle you gave me previously and then it'll just work assuming you have a valid handle
15:20so the handle is kind of the most important part we need to check to make sure that actually
15:23succeeded or failed because it's a mistake i've said this in other videos it's a mistake that new
15:28programmers make or lazy programmers make uh let's suppose for the sake of argument uh uh file
15:35open sys call pretend we're in c plus plus and there is some sort of an api function
15:40that we can call either directly to the system or some person's library and it'll open a file for us
15:46so maybe like a string path and then uh forget about the flags let's just say we call this right
15:53so i'm going to do like a little comment if inside of your program you just call it
16:03with uh you know some
16:07some path and then you assume that what you have is a valid you know handle if you assume that what
16:14you got back is a valid handle or maybe this is not a function that opens a file maybe it does
16:18something else if you just assume that the the call succeeded your program is probably going to
16:23have errors when you least expect it and it's not going to look good uh especially if you release a
16:28function like this to the public uh or if you have like a professor who's like grading your your code
16:34and they they are testing to see if you're checking for return codes and stuff like that that's not a
16:38smart idea right like you shouldn't uh should not shouldn't proceed as if everything went according
16:46to plan what what what i'm just proceeding as if everything went according to plan you want to use
16:50an if statement right you want to say if the handle has some value that seems to be valid
16:57like for example more than zero in the case of opening a file i would say probably more than two
17:03because all of our programs always have automatically assigned file handles of zero and one and two to
17:10represent standard input standard output and standard error but i think usually people just say like if it's
17:15greater than zero then it's fine uh you know for me i might put greater than two but more than zero
17:20is fine the point is check to make sure that it actually succeeded
17:28do i have spell check on this thing oh god you're all going to see my true spelling let me see if i can
17:32get it on real fast plugins spelled what how come this oh okay now it's highlighted
17:39okay so if it looks like it succeeded based on some kind of a comparison of the return result
17:46then we'll proceed in one way um otherwise we'll respond to the error by you know doing something
17:53else somehow like writing a log file sending an email complaining to the user doing any number of
18:00things where you can actually respond to the error maybe you probably want to change your execution path
18:04like if the file successfully opened then go ahead and start writing to it or reading from it or
18:09whatever but if the file did not successfully open then you probably want to do something else in the
18:13program and not just start trying to read from the the file so anyway super super good idea and so
18:20that's why i'm going to implement that inside of assembly 2. so instead of just immediately using the
18:26file handle i'm going to check it i'm going to say let's compare it to the number zero
18:29if we succeeded then let's go to another label called uh read success i personally when i'm doing
18:38branching logic i like to say open file read is the name of the function and i'll just i'll just uh
18:45append some kind of a suffix to the original function name that way it's it's easier to avoid
18:51collisions when you have lots of functions and lots of labels and things like that so i'm basically saying
18:55if we succeeded i'm going to jump to this label which is down here and so uh this video also is
19:03not about branching logic and and how to implement those instructions you can probably infer it by
19:08looking at my code but you know see another video in the future for that topic anyway if we succeeded
19:13in opening the file handle then we're just going to say oh we were successful and then we're going to
19:17uh um let's see we're going to print the name of the file that we just successfully opened
19:26and then we're going to send the file handle into rax so that this function has a return value of
19:35long file handle so when you open a file to read successfully the caller will receive the file handle
19:40you might be wondering yourself wait a minute wait a minute wait a minute
19:42it just gave us the file handle in rax remember we got to respect the abi
19:48anytime we jump anywhere or call another function or call another syscall which a lot of these things
19:54do we will probably lose the value of registers that are not callee preserved and that's definitely
20:01rax i mean just doing any system call like this print null terminated string function does that's
20:06going to destroy rax so that's why i saved it away first in r14 then at the very end of the function
20:11right before i return i'm just going to grab r14 and send it into rex again respect the abi do not
20:18return data as a return value in r14 or any other register you have to use the designated registers
20:27and in this case an integer that you're returning from a function call is always going to be rex
20:34anyway so that's the gist of that let me go back up for a second uh so notice how
20:39we're we're sort of comparing oh gosh i just i just reconfigured my annotator and i bought a new
20:45drawpad i wonder if this is going to work ah it works there's a bunch of stuff i added too
20:50so notice how uh we try to open the file and then we sort of compare the file handle to see if we
20:56actually succeeded or not if it succeeds it branches off to the success area down here oh my green's not
21:02working oh it's tricky it's tricky i gotta hit it in a certain way there we go if it succeeds we go
21:10down here to the success label so we basically at that point um totally ignore all of the fail code
21:17right we're just like branching around on the other hand if it fails then execution falls through because
21:26it's not going to jump if uh if if r14 is not greater than or equal to zero so if we fail maybe
21:32i should put this in a red if we fail then it's going to fall through to the next label and then
21:37the next instructions some people like to say let's uh let's jump to the success label and then if not
21:45let's jump to the fail label that can buy you a little bit more uh i don't know jump length if you
21:51have a giant program but in this case i'm just going to let it fall through it saves us one jump
21:54instructions a little more efficient and so if it fails then it's going to say first off let's print
22:00a message that we failed to standard error if you want a refresher on standard input standard output
22:06and standard error see my other videos and then it's going to print the name of the file that failed
22:13so that's this part right here it's going to say hey we uh we failed to print or sorry we failed to
22:17open this file name for reading and it's going to print a new line there with the crlf thing
22:25and then it's actually going to exit the program at that point it's going to say all right we failed
22:30and so the whole program just just quits and that's my die function that i showed you earlier it's just
22:34going to call the system call code for quitting and it's going to give a return code of one to indicate
22:39to anyone automating our program including new make that uh well our program failed at least it failed
22:47okay so we got all that and then we got the success and so now you kind of know the idea behind
22:53opening a file let's do that real fast just for fun so file tests um oh i know what to do i'll just
23:03comment out these uh instructions just so that we're only doing the file open
23:06yeah that's pretty good and then we won't close anything just yet
23:14so now let me run this in the terminal real fast make run it says it successfully opened the file
23:21input.txt and then the program exited no problem that error code one that's because uh the output
23:28file doesn't actually exist so don't worry about that and um let's change the name of the input file just
23:33to show you that it can fail and we can detect it i'm going to put a two there so that the program
23:38will try to open an input file that doesn't actually exist and then i'll run it again
23:42notice how it says fail to open file input 2.txt and then it says terminating program after failure
23:50to open file and then this time notice how the make file never got far enough so that it tried to
23:55print the md5 sums of the input and output files the assembly program just failed and so
24:00gnu make said i'm not going to proceed any further kind of useful when your program gives good exit
24:06codes right because then other programs know when to stop or maybe what to do depending on what's
24:11happening so i'm just going to fix this real fast then i'm going to go down here and maybe the next
24:17thing i want to add is closing the files so we've got a function to open a file for reading and then we
24:23have a function down here that is not implemented yet for closing the files so i'm going to do let's see
24:30what is r12 r12 is the input file so i'm going to close r12 uh so basically this function it's going
24:40to it's going to take one argument it's just going to take one uh file handle so that's why i'm giving
24:45the file handle of the input file as the first argument and then i'm just going to call it so
24:51let's copy paste uh close file underneath this so i'm going to do like some more space
24:56and let me let me go get this from my solution close file
25:03and it's going to be a pretty simple one really nothing much to it i'm just going to write my c
25:07plus plus prototype saying well it takes in one argument and it's a handle it doesn't return
25:13anything it attempts to close a file and i'm just going to use r12 to hold the incoming argument
25:20uh your programs at home should probably be a little bit better than mine you should check to see if the
25:24file successfully closed or not and respond in some kind of a way but for me i'm just saying
25:29i don't really care i already showed you that we can check for a return value so i'm allowed to be
25:34lazy now and um just sort of try to close it and then just assume it all went according to plan
25:40so uh grabbing the incoming arguments here that's why i'm uh i'm using r12 that's why i'm you know doing
25:46a push pop pair and then the system call code to close is pretty easy you just say here's the code to
25:52close stick that in rax let me go up real fast notice how sys close is the call code number three
26:00on line 43 there so i send it the call code three to say let's close a file it only wants one argument
26:06which is just what is the file handle that you want me to close remember before the operating system
26:11created a bunch of stuff under the hood and gave you a file handle you can then use the file handle
26:16to close a file read a file write to the file whatever to the file so it's pretty easy once i've set up the
26:21incoming arguments to the system then i actually use the system call instruction sys call and then i
26:27can assume it's probably closed at that point then a return statement at the end and now i should be
26:34able to run it again and we shouldn't see like any any additional thing happening it should just be
26:41it said it successfully opened the file and then it just exited okay now we're ready to add a little bit
26:48more let's create a file to write so this is going to be the same thing basically as opening a file
26:54to read except it's going to be a different call code and we'll give it to initial file permissions
27:00rather than a read mode flag but then we'll just get a file handle in return and i've also stuck this
27:06into another function of course so the file name to write line 109 if you just scroll up real fast here
27:13or if i scroll up real fast it's a line 27 here just output.txc and then the file permissions that
27:21we want to use i'm going to scroll up here that's the second argument to the system call code that's
27:26just this stuff that i talked about a little while ago where it's like we want the user to be able to
27:32read and write to the file we want people in the same group to be able to read only and we want
27:36everyone else to not be able to do anything basic uh linux permissions not a big deal uh at the end
27:44you should probably maybe note that uh you know this q i think i might have said this before this
27:49q just means quad word and these zeros are always going to be the same so really it's just like
27:54three numbers representing file permissions i'll go over that in more detail in some other video
27:59eventually so for now we know that we're going to uh open a file name to we're going to open a file
28:05for writing doesn't have to exist yet we'll give it some default permissions and those are the
28:11incoming arguments to the function that we're going to call now called create file when that file when
28:16that function comes back assuming it didn't decide to exit the program because we failed to open the
28:20file we will receive the file handle in rex per usual and so i'm just going to stash that away real
28:26fast into r13 remember r12 got r12 has the handle to the input file r13 has the handle to the output file
28:34and then you know for me personally i put that in comments to help myself remember what i'm even
28:38doing because things can get confusing really really fast and while we're at it before we even write
28:44the create file function i might as well just uncomment these things at the bottom just to say
28:50let's close both files properly you always want to do that so now let's uh let's use the let's copy
28:57paste the create file function let's see i didn't do that already right yeah okay so let's do that maybe
29:03like right here i'm gonna go grab it from my solution real fast create file
29:10okay about as complicated as opening a file just because i put in some some checking logic to see
29:16if it successfully opened the file which is a good idea so here's my function create file takes in two
29:23arguments oh shoot uh file creation hand let's see am i using r13 yeah oh i i i mislabeled
29:33that uh instead of saying flags it should be permissions so let me just do perms here long
29:39perms file creation perms perm i wish i could get a perm if you know what i mean anyway so uh you know
29:48we just have like the file name that comes in and the permissions that come in and it's going to return
29:52a handle just like we did with the uh read file for opening function but this time we're going to do
29:56something slightly different so the system call is going to be the code for creating a file sys create
30:03which is not real unless you define it so if we just look up i define that as
30:10where is it create uh 85 so like right here code 85 for system create again not a smart idea to hard
30:19code numbers defines are way better so then the first argument that it wants is the name of the file that's
30:26the incoming argument that i took into r12 it has to be a null terminated string it's going to be output
30:31dot txt then the second argument is the files permissions so that's r13 that i took here from
30:38the second argument long perms once i've set up those things i can do the system call right away the
30:45system again will try to open the file it'll try to create the file set up some data structures under
30:50the hood if it succeeds it'll give me a valid file handle in rax the return register if not then
30:58things have failed and i need to respond to that so i'm just going to stash the file handle in r14
31:03right away that's why i'm also preserving r14 in the push pop pair that i have r14 up at the top and
31:10the bottom um so now we got to check whether or not we successfully created the file again same logic
31:16as just opening a file for reading i'm going to compare r14 to zero if it's greater than zero i'm
31:21going to assume it's a valid file handle so jump if it's greater than or equal to to that label create
31:26file success i'm still using my appending uh can naming convention so the name of the function is
31:33create file so that means the success area is create file and then append underscore success
31:38and uh so then i'm just going to you know print a cute message saying hey we successfully created the
31:45file yay same thing that we looked at before basically and then i'm going to return the file
31:50handle in rax if we fail same thing that we did before when we were opening a read file i'm just going
31:57to complain basically to the user and then call on my little die function to properly exit the assembly
32:06program with a exit code of one you know and i could enhance that to exit with different codes like
32:12maybe exit code one means the read file didn't work and exit code two means the right file didn't work
32:16and exit code three means we failed for some reason while we were copying the data you know whatever you
32:21want i'm keeping it kind of simple so we got all that uh again this is not different than reading just
32:28you know the call codes pretty much and you know the arguments but um the idea is the same
32:34so now we're ready to uncomment i think we actually already did that we're ready to let the program
32:39try to create the file and the only thing we need to add after that is the copying portion and the
32:45successful message so let's see if this works do clear and make run uh so you can see that the program
32:53starts running here and then it says okay the module started and then it says we successfully opened
32:59the read file and then we successfully created the output file notice how the make file doesn't fail
33:05when it tries to call the md5 checksum of the output file because now it actually exists
33:10if we list the program uh list the directory here you'll see that the out file has actually been
33:15created it just has a length of zero because there's nothing inside of it notice also that the permissions
33:21match what we intended the initial user can read and write or the owning user can read and write
33:29the group can only read and everybody else can do nothing to heck with you you can change that real
33:35fast just to show you i can get this r to turn into an rw just by modifying permissions up here
33:42you know giving permissions to a group uh just is a nice way of allowing multiple users
33:47to have a shared file location you know add them all to the same group and then set uh that group
33:54onto the file and then set the group permissions uh to allow people to do whatever you want them to
33:58do read or read and write or whatever so let's see where are the perms i'm going to change this uh
34:03four to a six so now the group people should be able to read and write i can't remember if this will
34:08work because the file already exists let me give it a try okay i ran it one more time and
34:18it looks like it did not create the file because it already existed so let me just remove output.txt
34:24there should be another system call code you could use to just check to see if a file exists
34:29or if you wanted to be kind of hacky you could just try to open the file and see if it succeeded
34:33and then close it right away i wonder if there is a call code for just exists only i don't remember off the
34:39top of my head so i'm going to remove it and then run the program again and then we should see now
34:45yeah now that the file didn't exist and was newly created now those new permissions that we added
34:51are reflected so the group anybody who's on the group can read and write and obviously the group
34:55is just the same as my new user by default but again you could be more complicated than that if
35:00you were running a multi-user system and you wanted to share folders or whatever
35:04okay so i'm going to remove output real fast and i'm just going to revert the permissions
35:11to 640 so that um the group really can't do very much except just read it and then if i oh shoot
35:20ls okay yeah so now you can see it reverted
35:23okay so we got the out file i'm starting to get lost here what am i doing i'm supposed to copy the
35:32data i think so file tests and we are copying the file i think i just uncommented that really oh no
35:43no no i'm looking at my solution repo okay that's what i'm doing wrong so we'll look into uh
35:50your uh repo or your code we will uncomment the copy file i was like what how did i how did that
35:59program run if i already uncommented that and we'll we'll uncomment this message for now no
36:05let's leave it until we actually finish everything so now we got to do the copy file function
36:11so where's that okay i'm going to copy paste this whole thing you know what this would have been like
36:16a five hour video if i actually had to type this by hand i can't even remember how long it took me
36:20to write this program i think it was like an hour because i was doing it from scratch
36:24off the top of my head so this would be a nightmare to type i think on video even if i
36:29kind of already know how to do it now so let's see string length print an alternated string
36:36this is closed file this is create file okay so i'm just going to do copy
36:41file is going to be right before close file and right after a create file okay so copy file
36:47notice the signature that i've chosen for this one it's uh it doesn't return anything so
36:53that's like not great design you know i i need to check to see if the copying operations inside of my
36:59loop actually succeeded and maybe return something to indicate success or failure or at least exit the
37:05program but i'm not doing that right now i'm just keeping it a little bit more simple
37:08it takes two arguments the first thing is the input handle and the second thing is the output handle
37:13conveniently we have both of those now at this point and then here's my register usage i'm using
37:19r12 through r15 to just sort of grab the incoming arguments here for r12 and 13 and then
37:28r14 grabs the beginning of the temporary buffer which i'm going to make on the stack because i think
37:33i'm so cool um instead of making it as a global in the bss section and then uh r15 is going to hold
37:41the result from the copy operation or i guess the the write operation so that we can um sorry the read
37:49operation only oh i think i'm only checking the read bytes instead of the read and the write bytes
37:54i'll talk about that in a second so i could upgrade my program a little bit more if i wanted to but
37:58but basically r15 is going to be my temporary variable that looks at the return value to say
38:02hey did we do we read anything like how much did we read so copy file
38:10this is not a video about making local variables so just trust me on this
38:14i'm going to stay i'm going to save the base pointer so that i can use it to save
38:18the location of the stack pointer then i'm going to make a copy buffer on the stack
38:22uh just by uh subtracting the stack pointer because the stack grows downward in memory location
38:29numbers and then the base pointer is going to help me remember uh where the stack was when i started
38:35i'm just going to say that that's going to be the first byte in my buffer and i'm going to move that
38:40into r14 and let's see what did i do think about from the stack oh did i write like a good program
38:47or a bad program i feel like i should have actually saved the base pointer and not the stack pointer
38:56there let me see if this runs if it does run i probably have a naughty program that might self
39:00corrupt sometimes um and it might be a good idea to to move the base pointer as the first because
39:06this is not a stack video but basically the stack grows downward so if you subtract from the stack
39:13that means you're sort of like extending its reach you're allocating like a free space
39:18if i take where the stack
39:22nope nope nope i got it right i'm sorry if i take where the stack ends up after i extend it then i
39:27have a lower address right because it grows downward to memory if i then say that the new tip where it
39:34grew uh not where it grew from but where it grew to if i say that's the first byte in a buffer then
39:40when you're actually using the buffer you increase memory locations as you're filling up a buffer so
39:45then that's going to grow back towards where the stack started so it should be fine i think if i
39:50if i did go ahead and reverse this if i used rbp instead of rsp there then i think i would be going
39:57in the wrong direction and just corrupting memory so just so you know this is not a stack video but just
40:01so you know so here's a little label again i'm just kind of suffixing i'm saying let's copy the file
40:07and here's like an iteration label and um at the bottom i'm just kind of jumping back up to that
40:13label so this is a loop you can imagine this is a while loop maybe i should draw that for fun i gotta
40:18find more excuses to use my drophead so this is kind of like a while loop i'll say while true maybe
40:26and here's like the body and then here's like maybe the end of the body and so this jump statement just
40:31kind of goes back up to the top of the while loop hello green okay this thing's going to frustrate me
40:39so the first thing that happens is we read a portion of the input file into the buffer so what
40:45are we doing we're just using another system call we're saying let's use the call code for read i can't
40:51remember what that was it might have been uh whoops oh i cleared the dang drawing oh hang on i have
40:57undo i think wait i have that and then i have undo now nope okay i'm not going to mess with it because
41:06this will actually terminate my whole program one of these keys i forgot which one will just kill the
41:11whole annotator um so if we go up to sys read in the defines you can see that it is just call code zero
41:22so that means i'm telling the system i would like to read something first argument it wants
41:27is a file descriptor for the input file in a different video i showed you how to use exactly
41:31this sort of thing to read standard input from the user or from another program that launched your
41:36program but in this case r12 it's not going to be the file handle zero for standard input it's going
41:42to be the actual file handle of the file that you're trying to read from whatever that may have been
41:47whatever the os gave you and then here here's the address of where to store our characters
41:52and if you look up again we decided to remember where the first byte in our buffer on the stack
41:58was or you can imagine this is like a local array like uh oh shoot let's do it again let's do more
42:03drawings you have like a function right and c and then here it's like we declared a local variable
42:10maybe not int maybe a character array we'll call it a or how about b for buffer and then we just gave
42:17it you know let's say eight bytes or something for the buffer i think i still have it set to two bytes
42:22obviously you want to use more bytes for efficiency but just to prove that the loop actually works i'm
42:27keeping it small like i said before whoa what's all that you see that it's like smearing
42:33okay that's not good so uh anyway we remembered where the uh buffer starts and it's going to be r14
42:43and then the copy buffer length is being you know used here uh and i think i have that set up to uh
42:51two still right so basically we're saying we want to read from the input file and we want to read into
42:59our temporary buffer and we want to read at most this many characters and then we say system call and it
43:05does all the work for us to read that many characters and then we want to remember how many bytes were
43:10actually read because that could be different from the number of bytes we requested maybe we're at
43:14the end of the file maybe the system is having like some kind of a buffer issue or something
43:19so we just want to remember how many bytes we read and i'm going to stick that in r
43:22r15 per this little token up there to remind myself the temporary bytes read should go there
43:29notice also that when we created the stack this is not a stack video again but like
43:33i made the stack buffer equal to the length of the buffer that i actually wanted to use
43:38so i used the same symbol copy buffer length and copy buffer length
43:43so then it's going to try to figure out okay how many bytes did we actually read
43:48let me let me do that while loop thing again because i'm i'm feeling it i'm feeling it
43:53did i really have to write the word true especially my bad penmanship so we're doing while
43:58true and then i'll just say like read you know do some kind of a call to read maybe we'll say n
44:05equals read like a long you know the the r15 uh register is like the number of bytes that we actually
44:12read and then we do a comparison here so we're saying you know if you know n is um
44:22if it's equal to zero then we're going to jump to the position in the while loop where we're
44:27um done which is actually past the while loop if you scroll down you'll kind of see it so i'm just
44:32going to say break so basically if we read zero bytes then we're done reading bytes uh we're just
44:38finished so we just break the while loop and that's what's going to happen here when we say let's jump
44:44green let's jump uh past uh the end of the body and you'll see that in a second so then uh otherwise
44:53if we're not done that means execution is not going to jump it's going to just fall through to
44:57the next statement here and that's going to be another system call code to uh write to the output
45:02file and it's going to be very similar we just load it up with the system call code for right
45:08um let me just double check what code that is real fast for you so i'm going to go system call right
45:15which is code one and then
45:20we're going to give it the target for output which is going to be
45:26a file handle so you know r13 r13 right here that's a file handle that's where we want to write
45:33and then the next argument that it wants is the buffer and that's going to be r14 which is where
45:38we just what's going on green green there we go i'm having issues that's uh the buffer that we just
45:46read into right so if you look here r14 green oh my gosh okay so green we uh read from uh the buffer
45:57pointed to by r14 and then we uh we read into the buffer pointed to by r14 and then we are using that
46:04same buffer pointed to by r14 in order to grab the characters that we're going to send into the file
46:11and then r15 says how many files or sorry how many bytes green i'm having such problems
46:19r for r15 says how many bytes do you want to write to the file that should be our return value from
46:25before right because we want to read a certain number of bytes from the file and then write exactly
46:30that many bytes if we did more we would be writing some junk data probably and if we wrote less then
46:36we would be missing data in the output file that was originally in the input file so you want to do
46:41it exactly and of course i'm just doing a system call here but like i said before your program should
46:48probably be a little bit smarter and check rax after you write to the file just to make sure that you
46:54know how many bytes were actually written like what if you what if you read a hundred bytes but then you
46:59wrote 90 bytes only right that would be like a bad situation so you'd want to do some branching logic
47:06there so that if you read a hundred and you wrote 90 you probably want to backtrack the position of
47:12the file by like 10 you know just to make sure that you can actually get all of the bytes into the output
47:18file and seeking backwards 10 that's just another system call it's not in this program but it's not too
47:25bad you just make another system call give it the right call code tell it how far back you want to go
47:30no problem so then when by the time we make it here we're going to jump back up to the iterate label
47:38let's see where's that yeah right there we're going to jump back up to the iterate label so basically
47:42this is how the while loop continues looping so let me clear that real fast eventually when we're out of
47:49data to read you know that's because if we try to read and we end up with zero bytes that means we're
47:55done we'll break the while loop then we're going to go down here notice how it says copy file done
48:00what i was talking about before just sort of jumping past the end of the body so if we are done we jump
48:06to copy file done and all it does is just restore a bunch of registers for us
48:10and then return to the caller so copy file we have that handled now and if i go back up here
48:20file tests i guess i can i feel bad about this i can uncomment the success message
48:27but we probably should have done more checking on the reads and the writes just to make sure that we
48:32actually wrote the correct amount of characters and everything succeeded every time and if not we
48:37exit the program and only if everything went well then we print a successful message at this point in
48:42this program the way it's written it could totally fail and it'll still say that it was successful so
48:48just keep that in mind that's bad bad for your users
48:52okay i think we have everything that we need now i can probably just run the program and see that
48:57it works let's see clear and make run notice now oh shoot i didn't even show this to you before let
49:04me uh let me just emphasize this one more time real fast so i'm gonna comment out the part where
49:09we actually copy the file and i'm going to remove the output file then i'm going to run the whole
49:15program again notice how the two md5 sums are different so remember before i said that md5 sums
49:22they're basically fingerprints they're not actually considered secure in the modern era i just use them
49:27because they're small and fun if you are interested in security you probably want to use a modern hashing
49:33algorithm so don't use md5 but i am but don't but i am and it's basically saying the fingerprint here
49:42of input is different than the fingerprint here of the output quickly indicating to me that the files
49:47are different so if i list the contents of the directory obviously that's true because the output
49:52file is empty still but if i uncomment this part here where i'm actually copying the file
49:58then i should see that the fingerprints match and then if i look at what's inside of the output file
50:04it should match what's inside of the input file really fast let me open up a terminal and i'll just cat
50:09the input file so this is all i added you know why hello there added some stuff this is definitely more
50:14than two characters so we can be sure that our buffer loop is actually working and so i'm going to do
50:20clear and make run and now the output file notice how it has a matching file size it's got 38 bytes in
50:28there same thing for the input and then the thumb prints or you know the signatures whatever you want
50:34to call it the hashes they match exactly indicating that we probably have two identical files even with md5
50:42even though it's old and not considered secure the chances of two files kind of having random differences
50:48not hacked differences but just like random differences and having the same fingerprint is
50:53like astronomically almost impossible so if i do cat input oops input.txt that's what's in there like
51:02we showed before and if i cat the output now it is uh the same thing why hello there added some stuff
51:11for both i could make this as big as i wanted to just for fun maybe let's do uh let's do a nano
51:18on the input file i'll just add like i don't even know what i'm doing i'm just going to type a bunch
51:25of stuff oh wait what is this remember that thing that people got taught a long time ago it was like
51:30the quick brown fox uh jumped over the lazy dog and this was supposed to be all the letters of the alphabet
51:41there was a there's another one that i just heard about and i don't remember exactly how it goes look
51:48look it up on the internet it's it's pretty cool i think i need to memorize this and stop using the
51:52lazy dog it was um something like most sphinx of quartz hear my vow or something like that
52:06you know what i'm going to look it up for you right now i don't want to do the wrong thing it's really
52:10cool uh i'll type brown fox and then uh hear my vow
52:23oh sphinx of black quartz judge my vow that's what it is okay i'm going to go back to my little bm here
52:29sphinx of black quartz judge my i didn't even write vow correctly judge my vow and i think that
52:41has all the letters in the alphabet too probably less spaces i wonder if that's i mean that's what
52:48the internet says if this is true and it has all the letters of the alphabet that's going to be awesome
52:52i'm going to memorize that for sure sphinx of black quartz judge my vow anyway so i'm just kind of adding
52:58stuff into this file and if i run let me save that here i'll do it clear and then i'll do um
53:06i'll cat the input file here and then cat the output file so you can see they're different then
53:11if i run the program again let me remove the output file just in case i i can't remember if i'm supposed
53:16to remove it manually or if i put that into the program we'll just try it like this so now they match
53:24and then if i cat again the output file notice how it's a perfect copy of the input file nice
53:32so i think that's pretty much everything that i wanted to show you maybe um well maybe we can use
53:41a more efficient buffer now that it's done the copy buffer we could change this to like eight kilobytes
53:45or something we should end up with the same result let me run this just as is and see if it ends up
53:50being the same thing without erasing the file first yeah it looks good let me remove the output
53:56file and then run it one more time so make run and then cat the output file yeah okay so it still
54:04works but um you know whereas before we were just using a two byte buffer there's like very little
54:10chance except maybe at the end of the file that we would request more data than the file had
54:14but using the return value of the read operation always told us exactly how much was read by the
54:20operating system on the other hand if we have a giant buffer we could request way more bytes
54:26than the file could ever have because that file is way less than eight kilobytes
54:30so again we still want to look at the return value to make sure we know how many bytes were actually read
54:35and thus how many bytes should be sent into the right file so i guess that's everything that i wanted
54:41to tell you about reading and writing files using system calls i hope you've learned a lot of stuff
54:47and you enjoyed this video and had a little bit of fun uh thank you so much for watching i'm gonna
54:52cut the video i'll see you whoops i'll see you in the next video hey everybody thanks for watching this
55:01video again from the bottom of my heart i really appreciate it i do hope you did learn something and
55:05have some fun uh if you could do me a please a small little favor could you please subscribe and follow
55:12this channel or these videos or whatever it is you do on the current social media website that you're
55:17looking at right now um it would really mean the world to me and it'll help make more videos
55:22and grow this community so we'll be able to do more videos longer videos better videos or just i'll be
55:27able to keep making videos in general so please do do me a kindness and uh and subscribe you know
55:33sometimes i'm sleeping in the middle of the night and i just wake up because i know somebody subscribed
55:38or followed it just wakes me up and i get filled with joy that's exactly what happens every single
55:42time so you could do it as a nice favor to me or you could you could troll me if you want to just
55:46wake me up in the middle of the night just subscribe and then i'll i'll just wake up i promise that's what
55:51will happen also uh if you look at the middle of the screen right now you should see a qr code which you can
55:57scan in order to go to the website which i think is also named somewhere at the bottom of this video
56:02and it'll take you to my main website where you can just kind of like see all the videos i published
56:07and the services and tutorials and things that i offer and all that good stuff and uh
56:13if you have a suggestion for uh uh clarifications or errata or just future videos that you want to see
56:20please leave a comment or if you just want to say hey what's up what's going on you know just send me
56:25a comment whatever i also wake up for those in the middle of the night i get i wake up in a cold sweat and
56:29i'm like this it would really it really mean the world to me i would really appreciate it so again
56:36thank you so much for watching this video and um enjoy the cool music as as i fade into the darkness
56:44which is coming for us all
56:54so
56:56so
57:07so
57:09so
57:20so
57:22so
57:32so
57:34so
57:45so
57:47so
57:59so
58:01so
58:16so
58:18so
58:33so
58:35so
58:49so
58:51so
59:08so
59:10you
59:27so
59:29you
59:37you
59:51you
59:53you
Be the first to comment
Add your comment

Recommended