《第一篇 linux 0.12 系统调用(int0x80)详解》
- 系统调用初始化
在系统启动时,会在sched_init(void)函数中调用set_system_gate(0x80,&system_call),设置中断向量号0x80的中断描述符:
#define set_intr_gate(n,addr) _set_gate(&idt[n],14,0,addr) #define set_trap_gate(n,addr) _set_gate(&idt[n],15,0,addr) <span style="color:#FF0000;">#define set_system_gate(n,addr) _set_gate(&idt[n],15,3,addr)</span> #define _set_seg_desc(gate_addr,type,dpl,base,limit) ......其中15指明是陷阱门描述符,注意,这个中断向量不是中断门描述符(14),此陷阱门描述符的DPL为3,addr为此陷阱门对应的中断处理过程的32位偏移地址。因为中断处理过程属于内核,所以段选择符为0x0008(内核代码段)。因为DPL为3,所以通过set_system_gate设置的中断处理过程能被所有程序执行。
中断门与陷阱门的区别在于对EFLAGS的中断允许标志IF的影响。通过中断门描述符执行中断会复位IF标志,以被免其它中断干扰当前中断的处理,并且其它的中断结束指令IRET会从堆栈上恢复IF标志的原值。而通过陷阱门执行中断则不会影响IF标志。
- 系统调用的执行--从用户态到内核态的过程
当执行int 0x80时,CPU会通过中断向量号0x80找到对应的中断描述符项,这中断描述符项是在初始化时设置的陷阱门(set_system_gate(0x80,&system_call))。此陷阱门含有一个长指针:段选择符(内核代码段)和偏移值(system_call函数地址)。由于中断是通过int n产生的,CPU才会检查中断或陷阱门中的DPL,此时CPL必须小于或等于门的DPL,这个限止可以防止运行在特权级3的应用程序使用软中断访问重要的异常处理程序,如缺页处理程序:set_trap_gate(14,&page_fault)。
当CPU执行完权限检查后,CPU会从当前任务的TSS段中得到中断处理程序使用的栈段选择符和栈指针(tss.ss0 & tss.esp0),然后将栈选择符和栈指针压入新栈中。如果特权级不发生变化(比如内核内部调用),直接将EFLAGS、CS、EIP压入当前被中断程序的栈中。如果特权变化(用户态过程执行系统调用),则将原SS、原ESP、EFLAGS、CS、EIP压入中断过程使用的新栈,即进程的内核态栈,此时ESP指向了新栈。
然后,CPU从中断描述符中取得CS:IP,此时CS为0x8(内核代码段),IP为system_call函数地址,CPU完成从用户太到内核态切换,开始执行system_call函数。
测试代码 //gcc -fno-builtin -m32 -c main.c; ld -static -e no_main -o run main.o -m elf_i386 char* str = "hello world!\n"; void print() { asm("movl $13, %%edx \n\t" "movl %0, %%ecx \n\t" "movl $1, %%ebx \n\t" "movl $4, %%eax \n\t" "int $0x80 \n\t" ::"r"(str)); &
Linux 0.12 系统调用深入解析:int 0x80 机制

本文详细介绍了Linux 0.12版本中,系统调用如何从用户态切换到内核态,包括初始化设置、权限检查、中断处理及现场保存。重点讲解了int 0x80中断向量的陷阱门描述符和系统调用的执行过程,阐述了系统调用参数传递、内核态堆栈的使用以及如何通过system_call函数执行具体操作。
最低0.47元/天 解锁文章
683

被折叠的 条评论
为什么被折叠?



