操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用
系统调用完成了下述功能:
a.把用户从底层的硬件编程中解放出来
b.极大的提高了系统的安全性
c.使用户程序具有可移植性
我们在编程时通过系统调用可以避免直接对硬件以及内核部分内存的访问。这样可以避免大多数的认为失误导致的系统挂掉,大大增加了系统的安全性。
系统调用的访问是通过内核软中断与内核进行交互的,每一个系统调用都有一个明确的系统调用号,当应用程序进行系统调用时,就会根据此系统调用号与内核进行连接。系统调用的流程如下:
a.当用户态进程调用一个系统调用时, CPU切换到内核态并开始执行一个内核函数。
b.在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常.
下面分析一个系统调用的例子:
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
//stat 106
-
int main(void)
-
{
-
struct stat myst;
-
int ret = 0;
-
char *p = "/root";
-
struct stat *pst = &myst;
-
-
#if 1
-
-
ret = stat(p, pst);
-
if(ret == 0){
-
printf("%s|%d, Get stat ok!\n", __func__, __LINE__);
-
}else
-
printf("%s|%d,Get stat failed!\n", __func__, __LINE__);
-
-
#else
-
asm volatile(
-
"mov %1,%%ebx\n\t"
-
"mov %2,%%ecx\n\t"
-
"mov $106, %%eax\n\t"
-
"int $0x80\n\t"
-
"mov %%eax,%0\n\t"
-
:"=m"(ret)
-
:"b"(p),"c"(pst)
-
);
-
printf("ret:%d\n",ret);
-
if(ret == 0){
-
printf("%s|%d, Get stat ok!\n", __func__, __LINE__);
-
}else
-
printf("%s|%d,Get stat failed!\n", __func__, __LINE__);
-
#endif
-
-
-
return 0;
-
-
}
我们可以通过14行来运行不同的代码。
通过man手册可以查看到stat函数的功能,我们在这里只进行传参、返回值的分析。我们直接进入到内嵌汇编部分分析,stat函数有两个参数,第一个是文件系统节点路径,第二个参数是传出参数,但是我们在汇编代码中,使用的是传入一个指针,stat函数将会把获取的值放入到指针指向的内存中。两个参数的使用如下:
-
"mov %1,%%ebx\n\t"
-
"mov %2,%%ecx\n\t"
-
"mov $106, %%eax\n\t"
-
"int $0x80\n\t"
-
"mov %%eax,%0\n\t"
-
:"=m"(ret)
-
:"b"(p),"c"(pst)
1-完成stat函数的第一个参数;
2-完成第二个参数的写入。
7-输入参数值。
传完参数后,将stat函数的系统调用号传入到eax中,然后通过int &0x80执行系统调用。
系统调用号查询:
运行截图:
作者程大鹏, 转载请注明出处 http://blog.chinaunix.net/blog/post.html
Linux内核分析》MOOC课程 ”
阅读(2038) | 评论(0) | 转发(0) |