哈工大操作系统之系统调用的实现

系统调用的直观实现

实现一个whoami系统调用

  1. 用户程序调用whoami, 一个字符串“lizhijun”放在操作系统中(系统引导 时载入),取出来打印;(进入内核
  2. 不能随意的调用数据, 不能随意的jmp(保护数据隐私,让数据更安全);
  3. 可以看到root密码, 可以修改它…;
  4. 可以通过显存看到别人word里的内容;
    在这里插入图片描述

内核(用户)态,内核(用户)段

将内核程序和用户程序隔离!!!

区分内核态和用户态:一种处理器“硬件设计”

在这里插入图片描述

  • 当前程序执行在什么态(哪层环)?由于CS:IP是当前指令, 所以用CS的最低两位来表示: 0是内核态,3是用户态
  • 内核态可以访问任何 数据,用户态不能访 问内核数据
  • 对于指令跳转也一样 实现了隔离…

在这里插入图片描述

硬件提供了“主动进入内核的方法”

对于Intel X86,那就是中断指令int

**int指令将使CS中的CPL改成0,“进入内核” 这是用户程序发起的调用内核代码的唯一方式。**此时,CPL=3而 DPL=0

在这里插入图片描述
系统调用的核心:(由库函数完成)
(1) 用户程序中包含一段包含int指令的代码
(2) 操作系统写中断处理,获取想调程序的编号
(3) 操作系统根据编号执行相应代码

系统调用的实现

在这里插入图片描述
最终展开成包含int指令的代码:

//在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, ...) type
 name(...) \ { __asm__ (int 0x80:=a”(__res)...}

Linux系统调用的实现细节

将关于write的故事完整的讲完…

//在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;} 

显然,__NR_write是系统调用号,放在eax中 :

//在linux/include/unistd.h中 
#define __NR_write 4 //一堆连续正整数(数组下标, 函数表索引)

同时eax也存放返回值,ebx,ecx,edx存放3个参数

int 0x80中断的处理

void sched_init(void)
  { set_system_gate(0x80,&system_call); }
   显然,set_system_gate用来设置0x80的中断处理 :
  // 在linux/include/asm/system.h中 
  #define set_system_gate(n, addr) \ 
  _set_gate(&idt[n],15,3,addr); //idt是中断向量表基址 
  #define _set_gate(gate_addr, type, dpl, addr)\ 
  __asm__(“movw %%dx,%%ax\n\t” “movw %0,%%dx\n\t”\ 
  “movl %%eax,%1\n\t” “movl %%edx,%2:\ 
  :”i”((short)(0x8000+(dpl<<13)+type<<8))),“o”(*(( \ 
  char*)(gate_addr))),”o”(*(4+(char*)(gate_addr))),\ 
  “d”((char*)(addr),”a”(0x00080000))

在这里插入图片描述

中断处理程序: system_call

//在linux/kernel/system_call.s中
 nr_system_calls=72 
 .globl _system_call
 _system_call: cmpl $nr_system_calls-1,%eax
         ja bad_sys_call push %ds  push %es  push %fs 
         pushl %edx  pushl %ecx  pushl %ebx  //调用的参数 
         movl $0x10,%edx  mov %dx,%ds  mov %dx,%es //内核数据
         movl $0x17,%edx  mov %dx,%fs  //fs可以找到用户数据 
         call _sys_call_table(,%eax,4) //a(,%eax,4)=a+4*eax 
         pushl %eax //返回值压栈,留着ret_from_sys_call时用 
         ... //其他代码 
         ret_from_sys_call: popl %eax,     其他pop, iret 
_sys_call_table+4*%eax就是相应系统调用处理函数入口

_sys_call_table

//在include/linux/sys.h中 
fn_ptr sys_call_table[]= 
{sys_setup, sys_exit, sys_fork, sys_read, sys_write, ...};
//在include/linux/sched.h中
 typedef int (fn_ptr*)();

call _sys_call_table(,%eax,4)就是call sys_write:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值