概述
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;
}
结果