歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核編程實戰經驗談

Linux內核編程實戰經驗談

日期:2017/2/27 9:25:53   编辑:Linux內核
  當前,在國產自主版權的操作系統這面大旗的倡導下,IT界掀起了一浪高過一浪的Linux編程熱潮。Linux以其源碼開放、配置靈活等不可多得的優越性吸引著越來越多的編程愛好者深入Linux的內核開發。筆者近來實踐過一個Linux的實時化改造課題任務,積累了一點Linux內核編程的實戰經驗,在這裡想就編譯內核、增加系統調用等方面的問題和感興趣的愛好者共做切磋。     編譯內核      在Linux編程的實踐中,經常會遇到編譯內核的問題。為什麼要編譯內核呢?其一,可以定制內核模塊。Linux引入了“動態載入模塊”的概念,使用戶可以把驅動程序以及非必要的內核功能代碼編譯成“模塊”,由系統在需要時動態載入,不需要時自動卸載,從而提高了系統的效率和靈活性。其二,可以定制系統功能。當添加某種設備時、增加系統功能時、系統暴露出缺陷需要打“補丁”時,當新版內核出現准備用來升級時,編譯內核是不可避免的。而且,編譯內核正是Linux獨有的“系統級DIY”的魅力所在!     好,現在就讓我們一起開始——編譯內核!     (1)安裝源碼   首先要確定自己Linux系統是否已安裝了內核源碼:   # rpm -q kernel-source   kernel_source-2.2.5-16   如果證實沒有安裝,則需要找來安裝盤或從網上下載kernel-source-2.2.5-15.i386.rpm並安裝:   # rpm -Uhv kernel-source-2.2.5-15.i386.rpm   如果是升級到新版本,則需要找來升級包(linux-2.2.16.tar.gz),自己解壓安裝:   # cd /usr/src   進入源碼目錄。   # rm -rf linux   刪除以前的鏈接。   # tar xzvf linux-2.2.16.tar.gz   解壓升級包。   # ln -s linux-2.2.16 linux   重建目錄鏈接。     (2)配置內核   進入內核源碼所在目錄:   # cd /usr/src/linux   先清除多余的(一般是以前編譯生成的)文件:   # make mrproper   開始配置內核(如果對各選項不是很熟悉的話,建議按回車鍵):   # make config     (3)編譯內核   清除以前生成的目標文件及其他文件:   # make clean   理順各文件之間的依存關系:   # make dep   編譯壓縮的內核:   # make bzImage   編譯模塊:   # make modules-install     (4)裝新內核   將新內核文件復制到用於存放啟動文件的 /boot目錄:   # cp /usr/src/linux/System.map /boot/System.new   # cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz.new   進入啟動目錄:   # cd /boot   給新內核建立鏈接:   # rm System.map   # ln -s System.new System.map   # rm vmlinuz   # ln -s vmlinuz.new vmlinuz   編輯LILO的配置文件/etc/lilo.conf ,使LILO能啟動新內核:   # vi /etc/lilo.conf   在文件末加入以下部分:(後兩行內容要與舊內核相應行保持一致)   image=/boot/vmlinuz.new   lable=new   root=/dev/hda3   read-only   重寫LILO的啟動扇區,使改動生效:   # lilo     (5)重啟系統   # reboot   當重啟後出現 lilo: 提示時輸入新內核的標號(按TAB鍵可顯示所有的標號):   lilo: new   OK!!boot new......   .....   一切運行正常,新內核引導成功!   以上步驟在pentium Ⅲ/64M/20G、Red Hat Linux 6.0(2.2.5-15)機上測試通過。     增加系統調用      在實際編程中,尤其是當我們需要增加或完善系統功能的時候,我們經常會用到系統調用函數。系統調用函數通常由用戶進程在用戶態下調用,內核通過system_call 函數響應系統調用產生的軟中斷,在正確訪問核心棧、系統調用開關表之後陷入到操作系統內核中進行處理。      系統調用是用戶進程由用戶態切換到核心態的一種常見方式。利用編寫系統調用函數來直接調用了部分操作系統內核代碼,也是Linux內核編程者必修之功。下面筆者以在Linux中創建一個名為print_info的系統調用函數為例,來說明如何為內核增加系統調用。     需要以下幾個基本步驟:     1、編寫系統調用函數   編輯sys.c文件:   # cd /usr/src/linux/kernel   # vi sys.c   在文件的最後增加一個系統調用函數:   asmlinkage int sys_print_info(int testflag)   {   printk(" Its my syscall function!n");   return 0;   }   該函數有一個int型入口參數testflag,並返回整數0。     2、修改與系統調用號相關的文件   編輯入口表文件:   # cd /usr/src/linux/arch/i386/kernel   # vi entry.S   把函數的入口地址加到sys_call_table表中:   arch/i386/kernel/entry.S中的最後幾行源代碼修改前為:   ......   .long SYMBOL_NAME(sys_sendfile)   .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */   .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */   .long SYMBOL_NAME(sys_vfork) /* 190 */   rept NR_syscalls-190   .long SYMBOL_NAME(sys_ni_syscall)   .endr   修改後為:   ......   .long SYMBOL_NAME(sys_sendfile)   .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */   .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */   .long SYMBOL_NAME(sys_vfork) /* 190 */   .long SYMBOL_NAME(sys_print_info) /* added by I */   .rept NR_syscalls-191   .endr   修改相應的頭文件:   # cd /usr/src/linux/include/asm   # vi unistd.h   把增加的sys_call_table表項所對應的向量,在include/asm/unistd.h中進行必要申明,以供用戶進程和其他系統進程查詢或調用。   #define __NR_putpmsg 189   #define __NR_vfork 190   #define __NR_print_info 191 /* added by I */     3、編譯內核,再重啟動     4、測試   編寫用戶測試程序(test.c):   # vi test.c   #include   #include   extern int errno;   _syscall1(int,print_info,int,testflag)   main()   {   int i;   i= print_info(0);   if(i==0)   printf("i=%d , syscall sUCcess!n",i);   }    如果要在用戶程序中使用系統調用函數,那麼在主函數main前必須申明調用_syscall,其中1 表示該系統調用只有一個入口參數,第一個int 表示系統調用的返回值為整型,print_info為系統調用函數名,第二個int 表示入口參數的類型為整型,testflag為入口參數名。   編譯測試程序:   # gcc -o test test.c   執行測試程序:   # ./test   Its my syscall function!   i=0, syscall success!   ok!!!增加系統調用函數成功!   以上步驟在pentium Ⅲ/64M/20G、Red Hat Linux 6.0(2.2.5-15)機上測試通過。   (作者:李艷彬)




Copyright © Linux教程網 All Rights Reserved