您的位置:首页 > 其它

随笔:操作系统:系统调用的实现

2017-05-27 17:24 281 查看
1.用户态与内核态:

*将内核程序与用户程序隔离!

内核态能访问任何数据,用户态不能访问内核数据。

当前程序执行在什么态?因CS:IP是当前指令,故用CS的最低两位来表示:0是内核态(00),3是用户态(11)

2.中断指令:int

Intel x86中,中断指令:int

将使CS中的CPL改为0,进入内核。这是用户程序(CPL=3,DPL=0)发起的调用内核代码的唯一方式

*系统调用:

(1)用户程序中包含一段包含int指令的代码

(2)操作系统写中断处理,获取想调程序的编号

(3)操作系统根据编号执行相应代码

过程:

应用程序:
调用printf(xxx)
c函数库:
库函数printf(xxx)
库函数write(xxx)
os内核:
系统调用write(xxx)

linux/lib/write.c

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

define _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;
errno =-__res;
return -1;
}
#define __NR_write 4 /* __NR_write 是系统调用号,放在eax中;同时eax也存放返回值。ebx,ecx,edx存放3个参数*/
void sched_init(void) {
set_system_gate(0x80,&system_call);
}
用于设置0x80的中断处理
linux/include/asm/system.h

#define set_system_gate(n, addr)
_set_gate(&ide
,15,3,addr); idt是中断向量表基址
#difine _set_gate(gate_addr, type, dp1, addr)
__asm__("movw %%ax\n\t" "movw %0,%%dx\n\t" "mov1 %%eax,%1\n\t" "mov1 %%edx,%2"::"i"((short)(0x8000+(dpl<<13)+type<<8))),
"o"(*((char *)(gate_addr))), "o"(*(4+(char *)(gate_addr))),"d"((char *)(addr),"a"(0x00080000))
linux/kernel/system_call.s

nr_system_calls=72
.globl _system_call /* 中断处理程序 */
_system_call: cmpl $nr_system_calls-1,%eax /* %eax存放系统调用号 */
ja bad_sys_call
push %ds	push %es	push %fs
push1 %edx	push1 %ecx	push1 %ebx	/* 调用的参数 */
mov1 $0x10,%edx		mov %dx,%ds		mov %ds,%es /* 内核数据 */
mov1 $0x17,%edx		mov %dx,%fs		/* fs找到用户数据 */
call _system_call_table(,%eax,4) 	/* ex:a(,%eax,4)=a+4*eax */
push1 %eax	/* 返回值压栈,被ret_from_sys_call使用 */
...

ret_from_sys_call: popl %eax,(其他的pop),iret
_sys_call_table+4*%eax 即为相应系统调用处理函数的入口
include/linux/sys.h

fn_ptr _sys_call_table[]= /* _system_call_table是一个全局函数数组 */
{
sys_setup, sys_exit, sys_fork, sys_read, sys_write,...
};
include/linux/sched.h

typedef int (fn_ptr *)();
call sys_table(,%eax,4)即为 call sys_write

用户态 内核态
printf

用户调用
->printf 展成int 0x80->system_call 中断处理->sys_call_table 查表->__NR_write=4->调用 sys_write
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: