课本相关知识学习
系统调用的三层机制
API(应用程序编程接口) 中断向量(系统调用处理入口) 服务程序(系统调用内核处理系统)
内核态&用户态
计算机的硬件资源是有限的,为了减少有限资源的访问和使用冲突,CPU和操作系统必须提供一些机制对用户程序进行权限划分,Linux系统采用了Intel x86 CPU的0和3两个特权级别,分别对应内核态和用户态。当CPU的执行级别对应的是内核态时,代码可以执行特权指令,访问任意的物理内存。相应的,在用户态,代码能够掌控的范围会受到限制。
用户态和内核态的区分方法
CS:EIP的指向范围(对于32位的X86机器): 内核态下可以访问0x00000000~0xffffffff的地址空间,共4GB。 用户态下只能访问0x00000000~0xbfffffff的地址空间,不能访问从0xc0000000开始的地址空间。
中断
一般来说,进入内核态是由中断触发的,系统调用是一种特殊的中断。
中断的类别 硬件中断:在用户态进程执行时,硬件中断信号到来,进入内核态,就会执行这个中断对应的中断服务例程。 软中断(trap的方式):用户态程序执行的过程中,调用了一个系统调用,陷入了内核态。
实验
实验准备
在/LinuxKernel/linux-3.18.6/arch/x86/syscalls 目录下查看syscall_32.tbl 文件,获取系统调用号信息。选择write进行此次实验,其系统调用号为4,即0x4 通过man write 查看write系统调用相关信息,
函数定义:ssize_t write (int fd, const void * buf, size_t count); 函数说明:write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。 返回值:如果顺利write()会返回实际写入的字节数(len)。当有错误发生时则返回-1,错误代码存入erro中。
使用库函数API的方式利用系统调用
编写writetest.c文件,通过write()返回输入的字符串:
#include<unistd.h>
int main(){
char *message = "Hello and write 20212805\n";
write(1,message,25);
return 0;
}
unistd.h 是 C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的头文件的名称。
成功运行
在C代码中嵌入汇编使用系统调用
修改writetest.c 文件,嵌入汇编代码:
int main(){
char *message = "Hello and write 20212805\n";
int length= 25;
int ret;
asm volatile(
"movl $0x4, %%eax\n\t"
"movl $0x1, %%ebx\n\t"
"movl %1, %%ecx\n\t"
"movl %2, %%edx\n\t"
"int $0x80\n\t"
"movl %%eax, %0\n\t"
:"=m"(ret)
:"c"(message),"d"(length)
:
);
}
结果如下图:
|