1 / 22

三 系统调用

三 系统调用. 系统调用基础知识 相关数据结构,代码及流程 系统调用流程 添加一个系统调用. 为什么要分运行模式、运行空间 ? 从而需要系统调用? User mode , user space Kernel mode , kernel space 提高系统安全性 提供一个用户与内核交互的接口(通过它内核为用户程序提供系统服务)。 系统效率、应用开发效率. 1 系统调用基础. 地址空间 : 虚存管理机制。进程虚拟地址空间。 进程空间可以划分为两部分:用户空间及系统空间。 由于系统只有一个内核运行,故所有进程的系统空间都映射到单一内核地址空间。 上下文:

azize
Download Presentation

三 系统调用

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 三 系统调用 • 系统调用基础知识 • 相关数据结构,代码及流程 • 系统调用流程 • 添加一个系统调用

  2. 为什么要分运行模式、运行空间?从而需要系统调用?为什么要分运行模式、运行空间?从而需要系统调用? • User mode, user space • Kernel mode, kernel space • 提高系统安全性 • 提供一个用户与内核交互的接口(通过它内核为用户程序提供系统服务)。 • 系统效率、应用开发效率 1 系统调用基础

  3. 地址空间: • 虚存管理机制。进程虚拟地址空间。 • 进程空间可以划分为两部分:用户空间及系统空间。由于系统只有一个内核运行,故所有进程的系统空间都映射到单一内核地址空间。 • 上下文: • 用户级:正文,数据,用户栈及共享存储区 • 寄存器:通用寄存器,程序计数器(IP),处理机状态寄存器(EFLAGS),栈指针(ESP) • 系统级:进程控制块(task_struct),内存管理信息(mm_struct, vm_area_struct, pgd, pmd, pte等),核心栈等。

  4. 出错(fault):保存当前EIP,即异常返回时会重新执行该异常指令。出错(fault):保存当前EIP,即异常返回时会重新执行该异常指令。 陷入(trap):保存下一条指令的EIP,即异常返回时不重新执行该异常指令。 可编程异常(programmable exception)或软中断:由程序员用int指令触发。Linux用 int 0x80。 异常 • 中断和异常 • 中断:其产生与当前执行的进程无关。 • 异常:一般由当前执行的进程引起。 A system call is implemented by a “software interrupt” that transfers control to kernel code; in Linux/i386 this is ``int 0x80''.

  5. A system call is implemented by a “software interrupt” that transfers control to kernel code; in Linux/i386 this is ``int 0x80''. • The specific system call number is stored in the EAX register, and its arguments are held in the other processor registers. • After the switch to kernel mode, the processor must save all of its registers and dispatch execution to the proper kernel function, after checking whether EAX is out of range.

  6. 2. 相关数据结构、代码及流程 • arch/i386/kernel/entry.s汇编文件 • SAVE_ALL: 压栈宏 • RESTORE_ALL: 弹栈宏 • sys_call_table: 系统调用表,依次保存所有系统调用代码的指针,以便系统调用处理程序(system_call)索引。 • system_call: 根据系统调用号在sys_call_table中找到具体的内核系统调用代码,执行后将返回值保存到堆栈中。 • ret_from_sys_call: 所有的中断处理、系统调用均通过该过程返回到一个不确定的地方。

  7. Sys_call_table 398 ENTRY(sys_call_table) 399 .long SYMBOL_NAME(sys_ni_syscall) 400 .long SYMBOL_NAME(sys_exit) 401 .long SYMBOL_NAME(sys_fork) 402 .long SYMBOL_NAME(sys_read) 403 .long SYMBOL_NAME(sys_write) 404 .long SYMBOL_NAME(sys_open) /* 5 */ …... 635 .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lremovexattr */ 636 .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fremovexattr */ 637 638 .rept NR_syscalls-(.-sys_call_table)/4 639 .long SYMBOL_NAME(sys_ni_syscall) 640 .endr

  8. 系统调用索引

  9. 压入用户 SS 压入用户 esp 压入EFLAGS 压入 cs 压入 cip int 0x80 (system_call); Pushl %eax SAVE_ALL … 压入 eax Pushl %es ; Pushl %ds ; Pushl %eax; Pushl %ebp; Pushl %dei; Pushl %esi; Pushl %edx; Pushl %ecx; Pushl %ebx; …… Popl %es; Addl $4,%esp iret … RESTORE_ALL 内核堆栈 用户空间 内核空间 返回用户空间 系统调用时寄存器变化

  10. arch/i386/kernel/trap.c • trap_init 函数: 初始化中断描述符表IDT,向中断描述符表里填入中断门,陷入门和调用门。 • arch/i386/kernel/unistd.h • 定义所有的系统调用号,及与系统调用密切相关的关键的宏。

  11. arch/i386/kernel/traps.c 916 void __init trap_init(void) { …… 923 set_trap_gate(0,&divide_error); 924 set_trap_gate(1,&debug); 925 set_intr_gate(2,&nmi); 926 set_system_gate(3,&int3); …… 942 set_trap_gate(19,&simd_coprocessor_error); 944set_system_gate(SYSCALL_VECTOR,&system_call);

  12. arch/i386/kernel/unistd.h - 系统调用编号 8 #define __NR_exit 1 9 #define __NR_fork 2 10 #define __ NR_read 3 11 #define __NR_write 4 12 #define __NR_open 5 13 #define __NR_close 6 …… 240 #define __NR_llistxattr 233 241 #define __NR_flistxattr 234 242 #define __NR_removexattr 235 243 #define __NR_lremovexattr 236 244 #define __NR_fremovexattr 237

  13. arch/i386/kernel/unistd.h - 宏定义 #define _syscall0(type,name) \type name(void) \{ \long __res; \__asm__ volatile (“int $0x80” \ volatile不允许优化: "=a" (__res) \ : “”z(__NR##name))\__syscall_return(type,__res); \} 生成的 汇编代码 movl $__NR_##name, %eax /*为输入参数分配寄存器*/ #APP int $0x80 /*触发系统调用*/ #NO_APP movl %eax, __res /*处理输出参数*/

  14. 3 系统调用流程 用户程序 Int main() { … Getuid(); … } 标准C库 Int getuid(boid) { Long __res; … Int $0x80; … } 中断处理 ENTRY(system_call) Push1 %eax SAVE_ALL GET_CURRENT(%ebx) … Call sys_getuid16 … RESTORE_ALL 内核例程 Asmlinkage long Sys_getuid16(void) { Return high2lowuid (current->uid); }

  15. 4. 例:添加一个系统调用 要求:   在现有系统中添加一个系统调用,不用传递参数,使用户的uid等于0。

  16. 添加一个系统调用mysyscall • 确定系统调用的名字:mysyscall,则 -系统调用的编号名字为 __NR_mysyscall - 内核中系统调用实现的名字:sysy_mysyscall • 利用标准C库进行包装,以便通知编译器。 #include <linux/unistd.h> _syscall0(int, mysyscall) /* 通过_syscall0来定义mysyscall int main() { mysyscall(); }

  17. 添加系统调用号,改写/usr/include/asm/unistd.h 240 #define __NR_llistxattr 233 241 #define __NR_flistxattr 234 242 #define __NR_removexattr 235 243 #define __NR_lremovexattr 236 244 #define __NR_fremovexattr 237 245#define __NR_mysyscall 238

  18. 在系统调用表中添加相应表项改写arch/i386/kernel/entry.S在系统调用表中添加相应表项改写arch/i386/kernel/entry.S 398 ENTRY(sys_call_table) 399 .long SYMBOL_NAME(sys_ni_syscall) …… 636 .long SYMBOL_NAME(sys_ni_syscall) 637 .long SYMBOL_NAME(sys_mysyscall) 638 639 .rept NR_syscalls-(.-sys_call_table)/4 640 .long SYMBOL_NAME(sys_ni_syscall) 641 .endr

  19. (简化)实现系统调用:把代码添加在kernel/sys.c(简化)实现系统调用:把代码添加在kernel/sys.c asmlinkage int sys_mysyscall(void) { current->uid = current->euid = current->suid = current->fsuid = 0; return 0; } /*asmlinkage:Linux所有系统调用的实现都使用这个标志。*/ • 重新编译内核,启动新内核。

  20. 编写一段测试程序检验实验结果 #include <linux/unistd.h> _syscall0(int,mysyscall) /* 注意这里没有分号 */ int main() { mysyscall(); printf(“em…, this is my uid: %d. \n”, getuid()); }

More Related