zoukankan      html  css  js  c++  java
  • [No000036]操作系统Operating Systems系统调用的实现System_Call

    实现一个whoami 系统调用

    系统调用的直观实现 问题+直观想法…

    用户程序调用whoami, 一个字符串"systemcall "放在操作系统中(系统引导时载入) ,取出来打印,有什么问题?

    • 不能随意的调用数据,不能随意的jmp 。
    • 可以看到root 密码,可以修改它…
    • 可以通过显存看到别人word 里的内容…

    地址:

    main()

    { whoami();}

    用户程序

    。。。

    whoami()

    {

    printf(100, 8);

    }

    内核,都在内存中,这内存不都是我买的吗…

    100:

    "systemcall"

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

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

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

    • 内核态可以访问任何数据,用户态不能访问内核数据
    • 对于指令跳转也一样实现了隔离…

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

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

    • int 指令将使CS 中的CPL 改成0 ,"进入内核"(此时,CPL=3 而DPL=0)
    • 这是用户程序发起的调用内核代码的唯一方式
    • 系统调用的核心:

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

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

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

    系统调用的实现

    最终展开成包含int 指令的代码…

    #include <unistd.h>

    _syscall3(int, write, int, fd, const char *buf, off_t, count)

    在linux/lib/write.c 中

    #define _syscall3(type, name, ...) type name(...)

    { __asm__ ("int 0x80" :"=a"(__res)...}

    在linux/include/unistd.h 中

    Linux 系统调用的实现细节!

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

    在linux/include/unistd.h中    _syscall3 表示有3 个参数

    #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 " "movw %0,%%dx "

    "movl %%eax,%1 " "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 //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

    call _sys_call_table(,%eax,4) 就是call sys_write // eax=4 ,函数入口地址长度也为4

  • 相关阅读:
    tomcat feign rocketmq 最大线程数
    rocketmq
    使用docker在linux上安装oracle数据库
    dnf 腾讯 解人脸
    记一次mysql慢查询优化
    python运行内存分析
    【转】【WPF】WPF强制刷新界面
    【转】【WPF】Grid显示边框线
    流媒体服务新手入门教程03--音视频基础
    流媒体服务新手入门教程02--m7s环境搭建
  • 原文地址:https://www.cnblogs.com/Chary/p/No000036.html
Copyright © 2011-2022 走看看