概述

printf()是c语言中一个很常用的函数,printf()底层如何实现,如何在中断设备上显示出字符?

linux系统下,printf()的底层是对系统调用write()的封装。

应用程序在使用硬件资源时,一般都是通过系统调用来告知操作系统使用哪些资源,系统调用会通过int0x80中断进入到内核态工作,将应用程序的需求满足后,返回用户态,应用程序再继续执行。

  

linux下system调用不生效_#include

系统调用write

开机后,操作系统在进行初始化时会调用sched_init(); --->set_system_gate() 设置一个系统调用处理函数的入口地址(当应用程序再运行中进行任何一个系统调用时触发0x80中断,首先会找到处理函数的入口地址)

linux下system调用不生效_linux_02

  

linux下system调用不生效_#include_03

0x80中断处理程序system_call 首先进行系统调用号的检查(系统调用号放在eax中,参数分别放在ebx,ecx,edx中),匹配上之后进行sys_call_table[]中找到该系统调用号所对应的系统调用函数在内核中的地址,即sye_write()的地址,在调用sys_write()进行输出工作,此时一直处于内核态, 所有的资源都可以访问。sys_write()执行完毕返回,system_call返回,系统调用结束。

  

linux下system调用不生效_系统调用_04

 

在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下system调用不生效_系统调用_05

 ②在linux-0.11/kernel/system_call.s中修改 nr_system_calls = 74 //system_call会判断是否有该系统调用号

    ③linux0.11/include/sys.h

  

linux下system调用不生效_系统调用_06

   ④linux-0.11/kernel中定义who.h,并修改Makefile文件

  

linux下system调用不生效_#include_07

    

linux下system调用不生效_linux_08

 

#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;
}

结果

  

linux下system调用不生效_#include_09