Finally understand the system call~

Edited from: https://mp.weixin.qq.com/s/ehJxuKp3CSfr9xSNqYn1eA

In the process of application development, IO devices are often operated, such as reading and writing of disks, reading and writing of network cards, reading and writing of keyboards and mice, etc. Most application developers use high-level languages ​​for development, such as C, C++, java , python, etc. These high-level languages ​​provide standard libraries or APIs to operate IO devices, but standard libraries or APIs ultimately operate IO devices through system calls. System calls are provided by the operating system, which is the operating system kernel. part.
The system call encapsulates all the details of the hardware operation, and the standard library or SDK has made a highly abstract package and optimization based on the system call, so the life of the application developer is much easier, and the development efficiency is also improved. few.

1. What is a system call

**This article mainly elaborates the following two parts:**1. What is a system call? 2. Implementation of system calls? Mainly take the Linux operating system and IA-32 processor as examples, the high-level language is C language as an example, and some other operating systems and processors will also be mixed.

What are system calls?

For modern operating systems, applications do not have permission to access system resources when they are running. In order to prevent various applications from destroying system resources, the operating system protects system resources and prevents applications from directly accessing these resources. Resources, and applications have the need to access these system resources, so the operating system provides system calls to allow all applications to access system resources through system calls. The system resources mentioned here include files, networks, memory, various Class IO devices, etc.
Applications can make system calls, and can also call standard libraries or APIs. There are many steps in a system call, such as the need to switch from user mode to kernel mode. * Here is a brief introduction to mode switching. We know that a complete application program is divided into two parts, one part is the code and data of the application program, and the other part is the code and data of the kernel. The switching mode is the watershed between these two parts, which means processing The server has entered a different mode. Different modes are different worlds. Different worlds have different permissions. The kernel mode is the king and can control all resources. The user mode can only control one-third of an acre. land. *As mentioned above, system calls require mode switching, and each complete application has two stacks, a user stack and a kernel stack, these two stacks are independent, the user stack is in user space, and the kernel stack In kernel space, so when switching modes, the stack also has to switch. Therefore, we can divide the execution steps of the system call into three steps: 1. Preparation before execution. 2. Execute the handler (handler function). 3. The aftermath of the execution, of course, the kernel mode switching and stack switching are the work of 1 and 3. The three steps here are all executed in the kernel mode, as shown in the figure below

picture

Steps for direct system calls of applications From the above figure, it is known that executing a system call is very complicated and requires a lot of work. The Linux compiler provides many shared libraries (so files) to provide system calls. For example, the Linux glibc library provides System calls related to file operations, such as the following code:

int read(int fd,void *buf,int count);//读文件数据int write(int fd,const void *buf,int couint);//写文件数据int open(const char * pathname,int flags,mode_t mode);//打开文件

The above codes are just a few representative examples in the glibc library. The Linux operating system provides hundreds of system calls. These system calls are scattered in various shared libraries, so I won't elaborate here. The Windows operating system provides an API, referred to as Windows API or SDK, which is not a system call but a secondary package for the system call. These APIs are provided by various DLLs (Dynamic Link Libraries), and developers can import these DLLs. Windows applications are developed through the Windows API, so the steps for a Widows application to execute a system call become as shown in the following figure

picture

Windows application system call steps As mentioned above, each operating system provides its own system call, so how can writing a piece of C code be cross-operating system? The answer is the C language standard library, the C language standard library The purpose is to allow developers to write a piece of C code. These C codes use the C standard library. Then this piece of code can cross operating systems without any modification. The premise is that after compiling with different operating system compilers, the C standard library The call relationship is as shown in the figure below

picture

The C standard library is known from the above figure, Linux directly provides system calls through shared libraries, while Windows indirectly provides system calls through Windows API, and a C standard library is added in the middle, which standardizes system calls between different operating systems and makes Secondary encapsulation is achieved, which simplifies the complexity of system calls and is provided to applications. The standard library also has its disadvantages. The disadvantage is that it can only take the intersection of system calls of various operating systems, which means that only the functions that the operating system has can be included in the standard library, and sometimes, when some operating system-specific functions are needed, You have to directly make system calls or call APIs, which will cause cross-system problems. For an application developed with the standard library, its system call steps can be summarized as follows

picture

The C standard library system call is done. The topic of [what is a system call] is introduced here. Let's take a look at how the system call is implemented.

2. Implementation of system calls

Implementation of system calls?

The previous link explained [what is a system call] and the general steps of the system call. This link will take the Linux operating system as an example to explain the implementation principle and details of the system call. Of course, the implementation principles of other operating system system calls are similar. You can infer other things from one instance.

Mainstream operating systems such as Linux and Windows implement system calls through interrupts.

Taking the operating system Linux (before 2.5) and the processor as Inter IA-32 as an example, let’s see how the fork system call is implemented. Other Linux system calls are similar. The overall process is as follows

picture

Linux system call process The above figure shows the 9 steps involved in the system call. Let’s look at them one by one. 1. The application calls the fork function provided by the linux library to initiate a fork system call. The purpose of this system call is to create a child process. This The child process copies a virtual process space of the parent process. 2. The first step of the fork function is to put 2 into the register eax, each system call has a number, 2 is the number of the fork system call, and eax is the register used to pass the system call number by default. If the system call has parameters, pass the parameters to the following registers EBX, ECX, EDX, ESI, EDI, EBP. It can be seen that the system call supports up to 6 parameters, and the fork system call has no parameters. The second step of the fork function is to execute the interrupt instruction int 0x80. The interrupt instruction int is used to send an interrupt signal to the processor. 0x80 is the interrupt vector number. This vector number is dedicated to the system call interrupt handler. The int instruction will also switch the mode from user mode to kernel mode, and switch the user stack to the kernel stack. At the same time, the currently interrupted application program and the register content at the time of interruption will be pushed onto the stack (SS, ESP, EFLAGS, CS, EIP) , The push here refers to the kernel stack (each application has a user stack and a kernel stack). Overall, the 2-step assembly code is as follows:

push EAX,2;//设置fork系统调用的系统调用编号mov EBX,arg1;//可选,参数1mov ECX,arg1;//可选,参数2mov EDX,arg1;//可选,参数3mov ESI,arg1;//可选,参数4mov EDI,arg1;//可选,参数5mov EBP,arg1;//可选,参数6int 0x80;//发送系统调用中断信号

3. After the processor executes the current instruction, it will check the interrupt pin of the processor and find that there is an interrupt signal, then check the status register (EFLAGS), and find that the interrupt mask IF flag is open (the system call interrupt signal will not be masked ), the processor analyzes the interrupt vector number according to the interrupt signal, and then searches the interrupt descriptor table according to the interrupt vector number, and finds the interrupt handler corresponding to the interrupt vector number. 4. The operating system jumps to the interrupt handler, and then starts to execute the interrupt handler. The interrupt handler corresponding to 0x80 is the system call interrupt handler (system_call). The interrupt handler will first push the registers EAX, EBX, ECX, EDX, ESI, EDI, and EBP onto the stack. The reason for stacking is to prevent subsequent work from overwriting these registers. The core assembly instructions are as follows:

push EAX;push EBX;push ECX;push EDX;push ESI;push EDI;push EBP;

5. The system call interrupt handler then goes to the system call table to search according to the system call number (here is the fork system call number, which is 2), and you can find the handler (also called a handler function) corresponding to the system call number. Linux The system processing function of the operating system generally starts with sys, and the system processing function of fork is sys_fork. 6. After finding the system processing function, start to execute the function. The processing function can obtain the parameters of the function from the kernel stack. After the function is executed, the return value of the function is returned by default using the EAX register. 7~8. After the execution of the system processing function is completed, it returns to the system call interrupt handler. The interrupt handler executes the iret instruction. The iret instruction is responsible for switching from the kernel state to the user state, and pops the register data stacked in the kernel state to the SS. ESP, EFLAGS, CS, EIP these registers, and then jump to the system call. 9. The system call fork returns to the application.

3. The mechanism is similar

The system call implementation principle of the Linux operating system (before 2.5) has been explained. The system call of the Windows operating system also adopts a similar mechanism. In addition, since Linux (2.5) and above, the processor Inter Pentium II, in order to improve The efficiency of the system call, the Inter processor provides two instructions to enter and exit the system call, namely the sysenter and sysexit instructions.

The sysenter instruction replaces the int interrupt instruction to initiate a system call. After executing this instruction, it will directly jump to the address of a system call processing function to execute the system call. The address of this processing function is stored in a specified register. sysenter This instruction is also responsible for switching modes and backing up the registers of the application program. This is the same as int. The transfer of processing function parameters is the same as before, and it is still passed through registers without any change.

The sysexit command replaces the iret recovery command, which is responsible for the mode switch and the recovery of the field registers, which is similar to the iret command.

The system calls of other operating systems such as Power PC and AMD are similar to those of Linux (2.5 and above), the difference is that they use different instructions for mode switching and register backup, and the transfer of parameters also uses registers, only the number of registers Just different from the name.

Original text: direct source official account: a mouthful of linux

素材来源于网络,
版权归原作者或平台所有,仅供学习参考与学术研究,如有侵权,麻烦联系删除~感谢

Guess you like

Origin blog.csdn.net/qq_41854911/article/details/131525252