Operating system notes (1)------printf() story

1. Citation

insert image description here

  • 1. Why can't the user program directly call the whoami() function in the kernel program?

    When we implement a whoami() system call, we cannot call data arbitrarily, and we cannot jump arbitrarily. If you call it at will, you can see the root password and modify it; you can see the content in other people's world through the video memory. This is very unsafe.

  • 2. Why not let jump? How is it done?
    A processor "hardware design" can distinguish between kernel mode and user mode.
    Computers use memory in segments. Since CS:IP is the current instruction, the lowest two bits of CS are used to indicate: 0 is the kernel mode, and 3 is the user mode. Kernel mode can access any data, while user mode cannot access kernel data.

    Privilege level check: DPL>=CPL
    DPL indicates the target privilege level, and CPL is the current privilege level.
    DPL initial state is 0

    The hardware checks whether the current program meets the privilege level check. If the condition is met, it can be transferred to the kernel for function calling and program execution.
    A brief summary:
    when the system is initialized, a GDT table will be created for the kernel-mode code and kernel-mode data, and its corresponding DPL is 0. After the system is initialized, when the user mode is executed, a user program will be started. The CPL=3 of the user program cannot enter the kernel at this time; and when the system calls, the CPL will be changed to 0, so that it can enter the kernel for execution. After the kernel is processed, the CPL of the program will be changed to 3

  • 3. How to "actively enter the kernel?"
    The hardware provides "主动进入内核的方法".
    For Intel x86, the interrupt instruction int 0x80 can be in the machine core.

2. The story of how printf() is executed

1. Simple illustration
insert image description here
2. Detailed explanation

  • (1) 调用write()变成一段包含"int 0x80"的中断代码How does this process work?


#include <unistd.h> in linux/lib/write.c
_syscall3(int,write,int,fs,const char *buf,off_t,count)


#define    _NR_write  4
#define    in linux/include/unistd.h_syscall3(type,name,atype,a,btype,b,ctype,c)   type name(atype a,btype b,ctype c){   long _res;    _asm_volatile(“int 0x80”:"=a"(_res):""(_NR_##name),“b”((long)(a)),“c”((long)(b)),“d”((long)(c)));if(_res>=0)   return   (type)_res;…}(汇编代码)

These two pieces of code are actually equivalent to

在linux/lib/write.c中
#include <unistd.h>
int   write(int  fd,const  char  *buff…){
         把_NR_write置给eax
         把第一个参数置给ebx
         把第二个参数置给ecx
         把第三个参数置给edx
         执行"int 0x80"
         把"=a"(也就是eax)赋给_res
         返回_res
}

To briefly summarize, when calling write(), in the process of pointing to this write() function, set a system call number to eax, and then call "int 0x80" to enter the kernel.

  • (2) "int 0x80"What did it do? Why can it enter the kernel?

void sched_init(void){
set_system_gate(0x80,&system_call);
}

在linux/include/asm/system.h中
#define   set_system_gate(n,addr)   _set_gate(&idt[n],15,3,addr)
define _set_gate(gate_addr,type,dpl,addr) …

The execution of this code is equivalent to
<1>. In the IDT table, theDPL set to 3, so that it can jump into interrupt number 80.
<2>. After jumping into the interrupt, use the segment selector in the IDT table (CS becomes 8,CPL becomes 0) and the handler function entry point offset (IP) is set to the new PC pointer (CS+IP).
<3>.CS is 8, which is equivalent to assembly code jumpi 0,8. The code segment of the kernel will be found through the GDP table, and the function system_call will be processed.

A brief summary: the code "int 0x80" changes the DPL of the 80th interrupt from 0 to 3, so that the user program with CPL=3 can jump into the 80th interrupt. Then change the CPL from 3 to 0 in the No. 80 interrupt, take out the interrupt processing function in the IDT table, and jump to the function in the kernel (the DPL in the kernel is 0) to execute. After the interrupt processing is completed, it means that the kernel processing has been completed.

  • (3) system_callWhat did you do again?
    There is such a line of code in the system_call function
    call _sys_call_table(,%eax,4)that will enter the _sys_call_table function for execution.
  • (4) _sys_call_tableWhat did it do again?
    It will find the function corresponding to the starting address of _sys_call_table + 4*eax, that is, sys_writethe function. Then execute call sys_writeit so that sys_write is actually called to enter the kernel.
  • (5) The next thing is really handed over to the kernel. The story of printf is over here.

3. Summary

Through the story of whoami cannot directly enter the kernel program and the story of printf, we can summarize the core of the system call:
(1) The user program contains a code containing int
(2) The operating system writes interrupt processing to obtain the number of the program to be called.
(3) The operating system executes the corresponding code according to the number

Guess you like

Origin blog.csdn.net/qq_44875145/article/details/104711756