##用户态、内核态以及中断
具有高执行级别的程序可以执行特权指令
intel X86 CPU 具有4种级别:0 ~ 3
Linux 只用了0和3(0表示内核态,3表示用户态)
特权级的表示:使用 CS 寄存器的低2位
内核态逻辑地址空间:0xc0000000以上
用户态逻辑地址空间:0x00000000 ~ 0xbfffffff中断是从用户态到内核态的一种方式,即通过系统调用(系统调用是一种特殊的中断)
中断过程寄存器上下文的保存
- 保存到什么地方?堆栈
- 保存的内容: 用户态栈顶地址、当时的状态字、当时的 cs:eip的值
##系统调用概述
系统调用是操作系统为用户态进程和硬件设备交互提供的一组接口
- 把用户从底层编程中解放出来
- 提高系统安全性
- 提高用户程序的可移植性
API(应用编程接口)
- libc库定义的一些 API引用了封装例程(为了发布系统调用)
- 一般一个系统调用对应一个封装例程
- 库通过封装例程定义提供给用户的 API
- 不是每个 API都对应一个特定的系统调用
- API 可能直接提供用户态的服务
- 一个 API 可能对应几个系统调用
- 不同的 API 可能对应一个系统调用
- libc库定义的一些 API引用了封装例程(为了发布系统调用)
系统调用和 API 比较:
- 系统调用通过软中断向内核发出一个明确的请求
- API只是一个函数定义
使用寄存器传递参数
- 传递一个重要的参数系统调用号:使用 eax 寄存器
- 每个参数长度不能超过寄存器长度
- 每个参数长度不能超过6个
- 如果超过6个?把某一个寄存器作为指针指向内存地址空间
##实验
###使用库 API 来完成系统调用 chmod
源代码(chmod.c)
#include<sys/types.h> #include<stdio.h> #include<sys/stat.h> #include<errno.h> int main() { int i; i = chmod("file", 0777); if(i == -1) fprintf(stderr,"chmod failed, errer number = %d\n",errno); else printf("chmod success !\n"); return 0; }
编译&执行
gcc chmod.c -o chmod -m32 ./chmod
执行结果
如果不存在 file
建立文件 file 之后,chmod 成功
###使用汇编来完成系统调用 chmod
找到 chmod 对应的系统调用号
在 arch/x86/syscalls/syscall_32.tbl 中我们可以找到15 i386 chmod sys_chmod,由此可知,chmod 系统中断号为15(0xf)
源代码(chmod_asm.c)
#include<sys/types.h> #include<stdio.h> #include<sys/stat.h> #include<errno.h> int main() { int i; char* name = "file"; asm volatile( "mov $0777, %%ecx\n\t" "mov $0xf, %%eax\n\t" "int $0x80\n\t" "mov %%eax, %0\n\t" :"=m" (i) :"b" (name) );
if(i == -1)
fprintf(stderr,"chmod failed, errer number = %d\n",errno);
else
printf("chmod success !\n");
return 0;
}
编译&执行
gcc chmod_asm.c -o chmod_asm -m32 ./chmod_asm
执行结果
- 汇编代码分析
mov $0777, %%ecx\n\t
: 将chmod参数放入 ecx 寄存器
mov $0xf, %%eax\n\t
: 将系统调用号15(0xf对应 chmod)放入 eax 寄存器
int $0x80\n\t
: 启动系统调用(中断号0x80)
mov %%eax, %0\n\t
: 将执行完 chmod 的返回值返回至 i
:"=m" (i)
: i 作为输出参数
:"b" (name)
: name 作为输入参数放入 ebx 中
###简述系统调用 chmod 的过程
首先程序触发中断 int 0x80(系统中断),然后存放于 eax 中的数值作为系统调用号,这样系统就知道对应的是哪一个系统调用,然后系统会检查参数无误后,将返回值置于 eax 中。
版权声明:本文为博主原创文章,未经博主允许不得转载。