At some point you may have heard:
In linux, everything is a file.
-common observation of unknown provenance
What does this actually mean though? Well in this post, we are going to find out.
In our previous post when we wanted to write to the terminal we used the following lines of code:
movq $1, %rax
movq $1, %rdi
movq $msg, %rsi
movq $12, %rdx
syscall
Now, in Linux, when we write to the terminal, we are actually writing to a special file called stdout
. Rather than saving this to disk, the kernel writes the contents of the file to the terminal. The same is true for reading from the terminal, reading and writing to sockets and many other I/O operations. We can perform all of these operations in the same way, because the kernel allows us to treat them all as if we are reading from or writing to a file.
So let’s describe how we read and write to files more generally. File I/O requires a system call and we need to set four registers to give the kernel the information it needs to perform the I/O for us.
We set the rax
register to 0 if we want to read from a file and 1 if we want to write to a file. We have to tell the kernel what file we would like it to read from/write to. To do this we set the register rdi
with the file’s file descriptor. File descriptors are the unique numeric identifies associated with the files that the kernel knows about. For example, stdout
‘s file descriptor is 1. We set rsi
to be the address of the data we would like to write to the file, or the address of the memory we would like to read into. Finally, we set rdx
to the size in bytes that we would like to read/write.