第四周 利用嵌入式汇编调用系统调用

1.内核态和用户态

对于一台计算机来说,有些硬件的控制直接影响到计算机是否可以稳定的运行。操作系统为了维持计算机的可持续的工作,要对这些可能影响到系统稳定的因素进行严格控制,不能让用户随意进行操作。这就是操作系统区分内核态和用户态的思想。对于一些可能影响系统稳定的函数,操作系统将它们放到内核态当中,在用户态中用户只能调用一些用户态的函数,而对于一些对内核函数,用户只能通过中断进入内核态中进行调用。下图简略的说明了用户态和内核态的程序调用关系(截图来自ppt)

上图中xyz()是用户态的函数,这个函数需要调用一个内核态的函数sys_xyz()来完成它的功能。这里可以看出它首先通过int 0x80进行中断,然后对进入内核态System call handler中进行相关的寄存器的保存工作,然后调用系统调用sys_xyz()。当sys_xyz()完成后返回System call handler进行相关寄存器的复原,过程类似于程序之间调用的过程。随后再返回xyz()中。

除了程序分为用户态和内核态之外,内存的访问也区分内核态和用户态,以下是32位地址的内核态和用户态的访问控制。

0xc00000000以上地址在内核态访问

0x00000000-0xbfffffff 地址内核态和用户态都可以访问(这里注意并不是仅仅只有用户态可以访问)

2.实验

下边利用C语言嵌入式汇编代码的方式实现对fork函数的系统调用,linux中系统调用号可以查看以下网址,这里可以看出fork的系统调用号是2.

http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl

实验代码如下,很简单

 1 #include<stdio.h>
 2 #include<sys/types.h>
 3 #include<unistd.h>
 4 #include<sys/stat.h>
 5 
 6 int main(void)
 7 {
 8     pid_t n;
 9     asm volatile(
10             "mov $0x2,%%eax
	"
11             "int $0x80
	"
12             "mov %%eax,%0
	"
13             :"=m"(n)
14             );
15     if(0 == n)
16     {   
17         printf("this is child process
");
18     }   
19     else
20     {   
21         printf("this is parents process
");
22     }   
23     return 0;
24 }

实验结果

通过实验结果,我们可以看出,我们成功的通过这种嵌入式汇编的方式,实现了fork的系统调用。这里主要分析下上图中的9-14行的代码:

因为系统主要通过eax判定系统调用,而fork的系统调用为2,所以10行中将2传递给eax。又由于fork无需传入参数,所以这里不需要对ebx进行设置。

紧接着11行就通过int 进入内核态执行fork的系统调用。由于系统的传入参数是通过eax传出的,所以12行中将eax传入到,%0,%0是指下边的n。-m表示n存储在内存当中。

3.总结

这一节主要通过实验,了解了系统如何进行系统调用的,加深了对内核态和用户态的理解。操作系统平常工作都在用户态当中,当用户态需要操作一些内核数据时,才会通过系统调用进入内核态,而这些系统调用都是操作系统本身实现了,用户无法修改。可以看出通过这种方式,操作系统实现了对关键数据的保护,从而维护了系统的高效稳定运行。

原文地址:https://www.cnblogs.com/qtalker/p/4372316.html