Linux内核分析第四周作业

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核分析第四周作业相关的知识,希望对你有一定的参考价值。

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

首先从系统调用表中选择一个系统调用,我选择了122号系统调用——uname

122	i386	uname			sys_newuname

先用man查一下api是怎么使用的

man 2 api

这里的2表示查询系统调用uname(2),否则默认查的是uname(1),也就是在shell中运行的uname程序。

技术分享

可以看到,要使用uname,首先要include头文件sys/utsname.h。然后定义一个utsname结构体的变量,将这个变量的指针作为参数传递给uname。系统就会在结构体中填充信息,都是字符串,可以直接打印。

于是写下最简单的代码:

#include <stdio.h>
#include <sys/utsname.h>

int main()
{
    struct utsname name;
    uname(&name);
    printf("--API--\\n");
    printf("%s\\n", name.sysname);
    printf("%s\\n", name.nodename);
    printf("%s\\n", name.release);
    printf("%s\\n", name.version);
    printf("%s\\n", name.machine);
    return 0;
}

编译以后看一下运行结果

技术分享

 

然后考虑用内联汇编实现系统调用。将代码修改一下

 1 #include <stdio.h>
 2 #include <sys/utsname.h>
 3 
 4 int main()
 5 {
 6     struct utsname name;
 7 
 8     asm volatile(
 9         "mov %0, %%ebx\\n\\t"
10         "mov $122, %%eax\\n\\t"
11         "int $0x80\\n\\t"
12         :
13         :"r"(&name)
14     );
15 
16     printf("--ASM--\\n");
17     printf("%s\\n", name.sysname);
18     printf("%s\\n", name.nodename);
19     printf("%s\\n", name.release);
20     printf("%s\\n", name.version);
21     printf("%s\\n", name.machine);
22     return 0;
23 }

编译以后看一下运行结果

技术分享

和API的调用方式结果一样。

 

下面分析一下汇编代码调用的细节。

第9行向EBX写入参数,即name结构体的地址

第10行将系统调用号122写入EAX

第11行引发0x80的中断。中断会立刻运行IRQ。

Linux内核在启动之初的trap_init函数中就将0x80的IRQ固定为系统调用的处理函数

技术分享

其中SYSCALL_VECTOR的值就是0x80

技术分享

因为中断是内核处理的,所以此时已经进入内核态。

 

0x80的IRQ——system_call是用汇编写的

技术分享

一开始保存了现场

 

技术分享

然后根据EAX中的系统调用号,去调用对应的系统调用。最后将调用结果保存起来,退出IRQ的时候通过EAX返回给用户程序。

 

顺便看一眼这次选择的系统调用代码。根据系统调用表,112对应的系统调用名字叫做newuname(居然还有olduname和oldolduname。。。)

技术分享

很简单,uname的内容一直在内核中保存着,每次系统调用只要将内容从内核态复制到用户态即可,并且复制的时候用锁保护了一下。

 

 

总结

Linux为了系统的稳定性,分为用户态和内核态。用户态的程序无法使用系统的底层功能,因此需要系统调用临时地让内核替用户程序去完成一些底层功能。

无论是API还是汇编的方式,都是通过0x80中断进入内核态,然后内核根据EAX中的系统调用号去调用对应的系统调用函数,最后将返回值通过EAX返回给用户态程序。

此外,系统调用是进程调度切换的时机,因为此时控制交给了内核。对于用户程序来说仅仅是调用了系统调用,然后从系统调用返回。在系统调用中发生的进程切换对于用户程序是透明的。

 

 

 

王岩

原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

以上是关于Linux内核分析第四周作业的主要内容,如果未能解决你的问题,请参考以下文章

20169203《Linux内核原理与分析》第四周作业

20169217 《Linux内核原理与分析》 课程总结

linux内核分析第四周-使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

《Linux内核与分析》第四周

20135327郭皓--Linux内核分析第四周 扒开系统调用的三层皮(上)

《Linux内核分析》第四周 扒开系统调用的“三层皮”