您的位置:首页 > 运维架构 > Linux

Linux内核分析之四——系统调用的工作机制

2016-03-20 18:05 603 查看
作者:姚开健

原创作品转载请注明出处

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

学过计算机操作系统的都知道,CPU工作时有两种状态,一种是用户态,一种是内核态,用户态意味着代码访问的范围会受到限制,在32位X86的机器上,4G的内存里,在用户态的时候,只能访问0x00000000-0xbfffffff的地址空间。而内核态则不受限制,可以访问任意内存地址。当程序在用户态运行时,如果需要进入内核态执行,则会产生一个中断,然后系统进行中断处理,先是保存当前运行现场,将用户态栈顶指针,状态字,cs:eip值压栈:



然后进行中断处理程序,等处理程序运行结束后,则需要恢复现场:



当我们进行编程时,可以利用系统封装好的API来间接进行调用系统调用。一个API里面可能对应一个系统调用,也可能一个也没有,封装例程会将系统调用封装好,一个例程往往对应一个系统调用,当用户程序在执行API(xyz())调用时,将会进入封装例程(xyz())中,由封装例程里的中断汇编代码调用系统调用处理程序(system_call),然后系统调用处理程序调用系统调用服务程序(sys_xyz()):



这可以简化为系统调用三层皮:API,中断向量所指向的系统调用处理程序System_Call,中断服务程序Sys_xyz()。

进行系统调用时,如跟函数调用一般,也需要进行参数传递。系统调用至少有一个参数,就是系统调用号,通常会把它 传入eax寄存器,其他参数则传入其他寄存器,最多为6个参数,如果参数超过6个,则把最后一个寄存器该为指向一块剩余参数内存的指针。

下面通过两个程序来演示系统调用的工作机制:

程序一是直接调用sysinfo系统调用,返回系统信息,程序二则通过汇编代码调用系统调用,展示参数传递过程。

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

int
main(int argc, char *argv[])
{
struct sysinfo *info;
error = sysinfo(info);
printf("\n\ncode error = %d\n", error);
printf("uptime: %d\n"
"tatal ram: %d\n"
"free ram: %d\n"
"shared ram: %d\n"
"buffer ram: %d\n"
"tatal swap: %d\n"
"free swap: %d\n"
"process num: %d\n"
"tatal high: %d\n"
"free high: %d\n"
"mem_unit: %d\n",
sys->uptime, sys->tatalram,
sys->freeram, sys->sharedram,
sys->bufferram, sys->tatalswap,
sys->freeswap, sys->procs,
sys->tatalhigh, sys->freehigh,
sys->mem_unit
);
return 0;
}
这是编译运行后程序一的执行结果:



程序二:

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

int
main(int argc, char *argv[])
{
struct sysinfo *info;
int error;
asm volatile(
"mov %1, %%ebx\n\t"
"mov $0x74, %%eax\n\t"
"int $0x80\n\t"
"mov %%eax, %0\n\t"
: "=m" (error)
: "b" (info)
);
printf("\n\ncode error = %d\n", error);
printf("uptime: %d\n"
"tatal ram: %d\n"
"free ram: %d\n"
"shared ram: %d\n"
"buffer ram: %d\n"
"tatal swap: %d\n"
"free swap: %d\n"
"process num: %d\n"
"tatal high: %d\n"
"free high: %d\n"
"mem_unit: %d\n",
sys->uptime, sys->tatalram,
sys->freeram, sys->sharedram,
sys->bufferram, sys->tatalswap,
sys->freeswap, sys->procs,
sys->tatalhigh, sys->freehigh,
sys->mem_unit
);
return 0;
}
编译运行程序二的执行结果:



由程序二里汇编代码:

asm volatile(
"mov %1, %%ebx\n\t"
"mov $0x74, %%eax\n\t"
"int $0x80\n\t"
"mov %%eax, %0\n\t"
: "=m" (error)
: "b" (info)
);首先是把sysinfo系统调用的结构体指针参数传入ebx寄存器,接着把系统调用号0x74传入eax寄存器,接着进中断Int $0x80,最后把系统调用返回结果给error变量。可以看出,没有程序一的sysinfo(info),程序二一样成功调用系统调用sysinfo。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: