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