Modern CPU and OS – System call

Think about a situation, program A wants to send an message to screen.

As we know, the modern CPUs are running on protected mode, which means that program A is not able to perform that task by itself – program A cannot access the hardware, OS, other program memory area, etc.

To finish this task, the program needs some help from the OS, which is able to access hardware, or has the fully control of the CPU so that enables the CPU to work in non-protected mode.

Here is helloworld.c:

#include <stdio.h>
int main(){
    printf("hello world!");
    return 0;
}

The program send “hello world!” to the screen.

To do this, it invoked a function called printf() from c standard library.

But is that possible that we can send a message without using printf(), or without including <stdio.h>?

/* Hello World with a direct write to stdout (file descriptor 1) */

#include <unistd.h>

int main() {
	write(STDOUT_FILENO,"Hello World!\n",13);
}

This still works.

We write “Hello world!” to STDOUT_FILENO, which is 1 in Linux. In this case, we give our string to Linux system, can Linux put this string in a file of STDOUT_FILENO. Linux monitoring the STDOUT_FILENO, if there is anything in there, the system just print it to screen.

But, more directly?

#include <unistd.h>
#include <sys/syscall.h>

int main() {
	syscall(__NR_write,1,"Hello World!\n",13);
}

This still works!

Here, we performed a system call. When system received the system call, the system will do the same thing that it did for us during the last example.

but we still included some libraries.

Is there any possible that we can do it without including any libraries?

int main() {
   char* c = "HELLO WORLD!\n";
   int len = 13;
   int result = 0;
   register int    syscall_no  asm("rax") = 1;
   register int    arg1        asm("rdi") = 1;
   register char*  arg2        asm("rsi") = c;
   register int    arg3        asm("rdx") = 14;
   __asm__ volatile(
      "syscall" :
      "=a" (result)
   );
}

This is it.

We did not include any libraries, but it still output HELLO WORLD to screen. This time, can we say that our program directly output the string to the screen?

The answer is no.

If we analysis the program, we can see there is a word: syscall.

After we passed the necessary information to the registers, we performed a system call.

In this case, the CPU still moves the control from our program to the Linux system.

How? We did not tell the CPU to do anything with Linux system involved.

In fact, the relationship between CPU and the system is created when the system is booting.

Before the CPU enters protected mode, the Linux system tells the CPU a table that contains many system calls.

In the table, read() is 0, write() is 1.(X86_64)

when the CPU execute system call, the CPU get a number from %rax, then the CPU open the table that it got when the system is booting.

In %rax is 1, CPU found it in the table, it is write()! Then the CPU move the control to the system, execute the code of write() that provided by the system. After it’s done, the system move the control of CPU back to our program!

In other word, the system call is a bridge between our program and other program area. If our program want’s to access other memory, the program can only perform system calls and the system calls follows the pre-defined behaviors.

This how the CPUs and Memory protected our PCs.

Leave a comment

Design a site like this with WordPress.com
Get started