linux0.11添加系统调用
概述
printf()是c语言中一个很常用的函数,printf()底层如何实现,如何在中断设备上显示出字符?
linux系统下,printf()的底层是对系统调用write()的封装。
应用程序在使用硬件资源时,一般都是通过系统调用来告知操作系统使用哪些资源,系统调用会通过int0x80中断进入到内核态工作,将应用程序的需求满足后,返回用户态,应用程序再继续执行。
系统调用write
开机后,操作系统在进行初始化时会调用sched_init(); --->set_system_gate() 设置一个系统调用处理函数的入口地址(当应用程序再运行中进行任何一个系统调用时触发0x80中断,首先会找到处理函数的入口地址)
0x80中断处理程序system_call 首先进行系统调用号的检查(系统调用号放在eax中,参数分别放在ebx,ecx,edx中),匹配上之后进行sys_call_table[]中找到该系统调用号所对应的系统调用函数在内核中的地址,即sye_write()的地址,在调用sys_write()进行输出工作,此时一直处于内核态, 所有的资源都可以访问。sys_write()执行完毕返回,system_call返回,系统调用结束。
在linux0.11内核上添加系统调用
1、添加foo() 系统调用的步骤为:
①在linux-0.11/include/unistd.h下定义系统调用号,并声明系统调用函数的形式。
②在linux-0.11/kernel/system_call.s中修改系统调用的个数,以使此系统调用被调用时,可以识别到。
③在linux0.11/include/sys.h中添加extern头,再在sys_call_table[]中加入系统调用的‘地址’。
④在linux-0.11/kernel中实现该系统调用,并修改Makefile文件。
⑤将usr/include/unistd.h文件中添加(第①步)系统调用号和系统调用的声明。
⑥写测试程序进行测试。
2、实现
① define __NR_iam 72
define __NR_whoami 73
②在linux-0.11/kernel/system_call.s中修改 nr_system_calls = 74 //system_call会判断是否有该系统调用号
③linux0.11/include/sys.h
④linux-0.11/kernel中定义who.h,并修改Makefile文件
#define __LIBRARY__ #include<asm/segment.h> //定义了get_fs_byte()和set_fs_byte() #include<errno.h> //定义EINVAL char ch[24] ; int len = 0; int sys_iam(const char* name) { int i = 0; while(get_fs_byte(name + i) != '\0' && i<=23) i++; if( i == 24) return -EINVAL; len = i ; for(;i>=0;i--) {//将用户数据段的数据复制到内核数据段 ch[i] = get_fs_byte(name + i); } return len; } int sys_whoami(char* name,unsigned int size) { int i = len ; if(len > size - 1) return -EINVAL; while(i>=0) {//将内核数据段的数据复制到用户数据段 put_fs_byte(ch[i],name + i); i--; } return len ; }
⑤同第一步(usr/include/unistd.h)
⑥测试代码(usr/root-->whoami.c、iam.c)
#define __LIBRARY__ #include<errno.h> #include<unistd.h> _syscall1(int, iam, const char*, name); int main(int argc, char * argv[]){ if(iam(argv[1])<0) { printf("error\n"); return -1; } return 0; }
#define __LIBRARY__ #include<errno.h> #include<unistd.h> #include<stdio.h> _syscall2(int,whoami,char*,name,unsigned int,size); int main(int argc, char * argv[]){ char str [24]; if(whoami(str,24)<0) { printf("error\n"); return -1; } printf("%s\n",str); return 0; }
结果