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

来源:互联网 发布:淘宝活动报名流程 编辑:程序博客网 时间:2024/05/16 09:41

作者:姚开健

原创作品转载请注明出处

《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>intmain(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>intmain(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。

0 0
原创粉丝点击