秦鼎涛 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、用户态、内核态和中断
二、系统调用概述
1、系统调用的意义
操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用
·把用户从底层的硬件编程中解放出来·极大的提高了系统的安全性·使用户程序具有可移植性
2、API和系统调用
·应用编程接口(application program interface, API) 和系统调用是不同的
API只是一个函数定义 系统调用通过软中断向内核发出一个明确的请求·Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系统调用) 一般每个系统调用对应一个封装例程 库再用这些封装例程定义出给用户的API·不是每个API都对应一个特定的系统调用。
API可能直接提供用户态的服务 如,一些数学函数 一个单独的API可能调用几个系统调用 不同的API可能调用了同一个系统调用·返回值 大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用 -1在多数情况下表示内核不能满足进程的请求 Libc中定义的errno变量包含特定的出错码3、应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的关系
三、使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(源自网络)
选择sysinfo库函数116号系统调用
库函数API代码百度自网络:
#include
#include
intmain(void)
{
structsysinfo info;
if(sysinfo(&info) < 0)
{
perror( sysinfofailed );
return-1;
}
printf( uptime %ld , info.uptime );
printf( loads %.2f, %.2f,%.2f ,
(double)info.loads[0] / (1<< SI_LOAD_SHIFT),
(double)info.loads / (1 <<SI_LOAD_SHIFT),
(double)info.loads / (1 <<SI_LOAD_SHIFT));
printf( totalram %ld , info.totalram );
printf( freeram %ld , info.freeram );
printf( sharedram %ld ,info.sharedram);
printf( bufferram %ld ,info.bufferram);
printf( totalswap %ld ,info.totalswap);
printf( freeswap %ld , info.freeswap );
printf( procs %d , info.procs );
printf( totalhigh %ld ,info.totalhigh);
printf( freehigh %ld , info.freehigh );
printf( mem_unit %d , info.mem_unit);
return0;
}
编译运行程序得到系统信息结果
给出了总的可用的内存大小,还未被使用的内存大小,共享的存储器的大小,缓冲区大小,交换区大小,还可用的交换区大小, 当前进程数目等数据
C代码中嵌入汇编代码
编写嵌入汇编的版本
asm volatile( mov $0,%%ebx mov $0x80,%%eax ...);
事实上在系统调用时,system_call是linux系统调用的入口点。每个系统调用至少有一个参数,那就是eax,它负责传递系统调用号,同时获取返回值。
除了eax外,还允许至多6个参数,分别是ebx,ecx,edx,esi,edi,ebp。
另一方面,容易观察到,实际上time()函数除了自身的传入系统调用号(同时接收返回值)外,还传入了一个参数NULL。
结合上面的叙述,应该可以猜到,其实代码 mov $0,%eax 是相当于向ebx传入了一个参数NULL,也就是0。
同理,对于sysinfo这个库函数API,它也有一个返回值,表示是否成功,并且传递进来一个参数sys_info来接收系统的相关信息。因此,我们可以编写下面的代码:
// syscall_asm.c#include #include .h>int main() { struct sysinfo sys_info; int error; //error = sysinfo(&sys_info); asm volatile( movl %1, %%ebx movl $0x74, %%eax // sysinfo 的系统调用号是 116 所以十六进制为 0x74 int $0x80 movl %�x, %0 : =m (error) // eax来负责传递返回值,我们同样用error来接收 : b (&sys_info) // sysinfo的地址作为参数,传递进ebx中作为参数被修改接收系统信息 ); printf( code error=%d ,error); printf( Uptime = %lds Load: 1 min%ld / 5 min %ld / 15 min %ld RAM: total %ld / free %ld / shared%ld Memory in buffers = %ld Swap: total%ld / free%ld Number of processes = %d , sys_info.uptime, sys_info.loads[0], sys_info.loads, sys_info.loads, sys_info.totalram, sys_info.freeram, sys_info.sharedram, sys_info.bufferram, sys_info.totalswap, sys_info.freeswap, sys_info.procs); return 0;}
所以,最后的执行结果是一样的