int $0x80系统调用的idea

来源:互联网 发布:中国太阳能统计网络 编辑:程序博客网 时间:2024/04/27 17:51

source from  http://blog.csdn.net/xuyuqingfeng953/article/details/50999170

一般现代CPU都有几种不同的指令执行级别,Linux总共划分为4个指令执行级别:内核运行在0级别上,1,2级别默认不运行,用户程序运行在3级别上。

          在内核指令执行级别上,代码可以执行特权指令,访问任意的物理地址。
          在用户指令执行级别上,代码的掌控范围会受到限制。只能在对应级别允许的范围内活动。
          cs寄存器的最低两位表明了当前代码的特权级:CPU每条指令的读取都是通过cs:eip这两个寄存器:其中cs是代码段选择寄存器,eip是偏移量寄存器。

         上述判断由硬件完成。



之所以会写篇博文说下int 80h中断, 是因为它是linux类操作系统内核在Intel类CPU架构上作为系统调用使用的中断号, 所谓系统调用是内核提供的一系列有特权功能的函数集合,为什么要有syscall是本着安全的角度来看的或者效率等等, OS把整个空间分为用户空间和内核空间,顾名思义,内核空间的特权比用户空间多, 比如系统调用就需要在内核空间运行, 可以看出系统调用只是OS提供给用户空间的一些接口,不允许用户随意进入内核区.

系统调用的时候, 是利用的软中断实现的, 就是int 0x80h指令, 当用户空间需要调系统函数的时候, 用户空间只有通过系统门陷入内核执行int 0x80h指令才能执行具有一些特权级的内核函数, OS再执行另外一组特权指令(iret)返回到用户空间(其中int 0x80h指令会产生一个编号为128(16进制就为0x80)的异常,这个编号索引的IDT(中断描述符)中的第128项, 指向的是系统门描述符,里面包含了一个内核空间地址sys_call .如图:

那如何调用相应的系统调用呢? 比如想调用sys_write, 很简单, OS系统调用会相应的进行编号从0开始, 比如下面列的一些:

#define __NR_setup 0#define __NR_exit 1#define __NR_fork 2#define __NR_read 3#define __NR_write 4#define __NR_open 5#define __NR_close 6#define __NR_waitpid 7#define __NR_creat 8#define __NR_link 9

当然不止上面这么多, 这些编号会保存在内核的一张系统调用表,还有编号对应的系统调用处理程序, 通过上面描述需要把系统调用编号传入给到内核(mov到eax即可),可通过下面的命令进行

mov eax, 4

这里4就代表sys_write系统调用.

我们通过程序来看下系统调用的过程:

[section .data]strHello    db  "Hello CB!"strLen  equ $-strHello[section .text]global _start_start:    mov edx, strLen    mov ecx, strHello    mov ebx, 0    mov eax, 4 ;sys_write    int 0x80    mov ebx, 1    mov eax, 1 ;sys_ext    int 0x80

这个程序进行了两个系统调用, 调用号分别为4(sys_write)和1(sys_exit).
可通过下面的Makefile进行汇编连接.

All:nasm -f elf -o a.o 1.asmld -o a.out a.o

效果很简单,就打印个字符串.

原创文章,转载请注明出处: http://www.crazyshell.org/blog/?p=1201
          一般来说在Linux中,地址空间是一个显著的标志:0xc0000000以上的地址空间只能在内核态下访问,0x00000000-0xbfffffff的地址空间在两种状态下都可以访问。


2、int $80汇编指令

          I386CPU将用户空间程序限制在0-3G空间,将内核程序限制在3G~4G空间,这样就实现了用户空间和内核空间的隔离;
          程序的执行过程需要访问特定的系统程序以完成相应的功能。而用户程序运行在用户态,不能够访问特定状态下的系统程序。而用户程序又需要执行系统程序,这就促使int $80的产生:
          应用程序通过int 0x80(软中断)指令实现用户空间与内核空间的交互。CPU会把软中断做为陷阱来处理,所以软中断也称为编程异常,其中int 0x80可以用于执行系统调用。

3、int $80的执行功能

     Int $80主要实现对寄存器的压栈:
  1. 保存:SS:esp,CS:EIP,eflag中的内容到进程对应的内核堆栈;
  2. 修改:SS:esp内容改为system_call对应的的内核堆栈的基地址,CS:EIP:内容改为system_call的第一条指令的地址,eflag内容修改为新的标志。

    

          总而言之,int $0x80的就是在系统调用产生时,完成用户态到内核态的切换。由于用户进程在用户态执行和内核态需要对应不用的内核堆栈,所以再进行系统调用时,需要保存用户态最后的esp,eip等状态信息,以便于系统调用结束能够返回到发生系统调用的地址继续用户程序的执行,这就是int $0x80完成的对寄存器内容的保存。

          执行系统调用的时候,先把系统调用号保存到EAX寄存器中,然后执行int $0x80,然后转入system_call系统调用指令开始执行,system_call根据保存到system_call内核堆栈中的系统调用号的值,转为执行相应的系统调用处理函数。
Iret指令指int $0x80的逆过程,弹出int $0x80指令所产生的内容堆栈块的内容到对应的寄存器中,CPU把控制权有内核交给用户程序,执行状态回到用户态,用户程序继续执行。至此,系统调用,系统返回过程结束
0 0
原创粉丝点击