首页 > 其他 > 详细

深入理解系统调用

时间:2020-05-25 21:58:29      阅读:46      评论:0      收藏:0      [点我收藏+]

  为了安全,Linux 中分为用户态和内核态两种运行状态。对于普通进程,平时都是运行在用户态下,仅拥有基本的运行能力。当进行一些敏感操作,比如说要打开文件(open)然后进行写入(write)、分配内存(malloc)时,就会切换到内核态。内核态进行相应的检查,如果通过了,则按照进程的要求执行相应的操作,分配相应的资源。这种机制被称为系统调用,用户态进程发起调用,切换到内核态,内核态完成,返回用户态继续执行,是用户态唯一主动切换到内核态的合法手段(exception 和 interrupt 是被动切换)。

  
  当?户态进程调??个系统调?时,CPU切换到内核态并开始执?system_call(entry_INT80_32或entry_SYSCALL_64)汇编代码,其中根据系统调?号调?对应的内核处理函数。具体来说,在Linux中通过执?int $0x80或syscall指令来触发系统调?的执?,进?内核后,开始执?对应的中断服务程序entry_INT80_32或entry_SYSCALL_64。
  
  Linux内核中?约定义了四五百个系统调?,这时内核如何知道?户态进程希望调?的是哪个系统调?呢?内核通过给每个系统调??个编号来区分,即系统调?号。内核实现了很多不同的系统调?,?户态进程必须指明需要执?哪个系统调?,这需要使?EAX寄存器传递?个名为系统调?号的参数。除了系统调?号外,系统调?也可能需要传递参数,在32位x86体系结构下普通的函数调?是通过将参数压栈的?式传递的。系统调?从?户态切换到内核态,在?户态和内核态这两种执?模式下使?的是不同的堆栈,即进程的?户态堆栈和进程的内核态堆栈,传递参数?法?法通过参数压栈的?式,?是通过寄存器传递参数的?式。寄存器传递参数的个数是有限制的,?且每个参数的?度不能超过寄存器的?度,32位x86体系结构下寄存器的?度最?32位。除了EAX?于传递系统调?号外,参数按顺序赋值给EBX、ECX、EDX、ESI、EDI、EBP,参数的个数不能超过6个,即上述6个寄存器。如果超过6个就把某?个寄存器作为指针,指向内存,就可以通过内存来传递更多的参数。以上就是32位x86体系结构下系统调?的参数传递?式。
 
  由于压栈的?式需要读写内存,函数调?速度较慢,64位x86体系结构下普通的函数调?和系统调?都是通过寄存器传递参数,RDI、RSI、RDX、RCX、R8、R9这6个寄存器?作函数/系统调?参数传递,依次对应第 1 参数到第 6 个参数。
 
  下面用嵌入式汇编代码调用编号为8的系统调用creat,观察系统调用的过程。creat函数用来创建一个新的文件,函数原型为int creat(const char *pathname, mode_t mode);,成功返回为只写打开的文件描述符,若出错则返回-1。
 
  编译一个Linux内核,使用busybox自制简易根文件系统,使用qemu运行虚拟机,用GDB进行调试。
  
  触发系统调用的test.c程序如下:
#include <stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>

int main(int argc,char *argv[]) 
{ 
 int fd;
//fd= creat(argv[1],0755);
//if (fd<0)
//    printf("error!");

asm volatile( 
 "movl %1,%%ebx\n\t" //系统调?传递第?个参数使?EBX寄存器,为argv[1]
 "movl $0755,%%ecx\n\t"//系统调?传递第二个参数使?ECX寄存器,为0755
 "movl $0x8,%%eax\n\t"//使?%eax传递系统调?号8,?16进制为0x8
 "int $0x80\n\t" //触发系统调?
 "movl %%eax,%0\n\t" //通过EAX寄存器返回系统调?值 
 :"=m"(fd) 
 :"b"(argv[1])
 ); 
printf("%d\n",fd);
fclose(fd);
 return 0; 
}

 

在gdb中加断点__ia32_sys_creat,运行test.c编译成的可执行程序test,在断点处停止,观察堆栈情况。

 

技术分享图片

 

  "int $0x80\n\t"指令触发系统调用后,先执行entry_INT80_compat函数,该函数对现场进行保存,之后调用do_int80_syscall_32函数,由用户态切换至内核态,再调用do_syscall_32_irqs_on函数,在其内调用__ia32_sys_creat函数完成creat系统调用的功能,之后切换回用户态,entry_INT80_compat函数恢复现场。

 

技术分享图片

 

   运行test 2.txt命令成功创建了2.txt文件。

 

深入理解系统调用

原文:https://www.cnblogs.com/gy101/p/12960894.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!