IT貓撲網(wǎng):您身邊最放心的安全下載站! 最新更新|軟件分類|軟件專題|手機(jī)版|論壇轉(zhuǎn)貼|軟件發(fā)布

您當(dāng)前所在位置:首頁操作系統(tǒng)LINUX → Linux下增加系統(tǒng)調(diào)用的方法

Linux下增加系統(tǒng)調(diào)用的方法

時間:2015/6/28來源:IT貓撲網(wǎng)作者:網(wǎng)管聯(lián)盟我要評論(0)

  1.linux系統(tǒng)調(diào)用的基本原理

  linux的系統(tǒng)調(diào)用形式與POSIX兼容,也是一套C語言函數(shù)名的集合。然而,linux系統(tǒng)調(diào)用的內(nèi)部實(shí)現(xiàn)方式卻與DOC的INT 21H相似,它是經(jīng)過INT 0X80H軟中斷進(jìn)入后,再根據(jù)系統(tǒng)調(diào)用號分門別類地服務(wù)。

  從系統(tǒng)分析的角度,linux的系統(tǒng)調(diào)用涉及4個方面的問題。

  (1)與系統(tǒng)調(diào)用有關(guān)的數(shù)據(jù)結(jié)構(gòu)和函數(shù)

  函數(shù)名以"sys_"開頭,后跟該系統(tǒng)調(diào)用的名字。例如,系統(tǒng)調(diào)用fork()的響應(yīng)函數(shù)是sys_fork()(見Kernel/fork.c),exit()的響應(yīng)函數(shù)是sys_exit()(見kernel/fork.c)。

  文件include/asm/unisted.h為每個系統(tǒng)調(diào)用規(guī)定了唯一的編號。假設(shè)用name表示系統(tǒng)調(diào)用的名稱,那么系統(tǒng)調(diào)用號與系統(tǒng)調(diào)用響應(yīng)函數(shù)的關(guān)系是:以系統(tǒng)調(diào)用號_NR_name作為下標(biāo),可找出系統(tǒng)調(diào)用表sys_call_table(見

  arch/i386/kernel/entry.S)中對應(yīng)表項的內(nèi)容,它正好 是該系統(tǒng)調(diào)用的響應(yīng)函數(shù)sys_name的入口地址。系統(tǒng)調(diào)用表sys_call_table記錄了各sys_name函數(shù)在表中的位 置,共190項。有了這張表,就很容易根據(jù)特定系統(tǒng)調(diào)用在表中的偏移量,找到對應(yīng)的系統(tǒng)調(diào)用響應(yīng)函數(shù)的入口地址。系統(tǒng)調(diào)用表共256項,余下的項是可供用戶自己添加的系統(tǒng)調(diào)用空間。

  (2)進(jìn)程的系統(tǒng)調(diào)用命令轉(zhuǎn)換為INT 0x80中斷的過程

  宏定義_syscallN()見include/asm/unisted.h)用于系統(tǒng)調(diào)用的格式轉(zhuǎn)換和參數(shù)的傳遞。N取0~5之間的整數(shù)。參數(shù)個數(shù)為N的系統(tǒng)調(diào)用由_syscallN()負(fù)責(zé)格式轉(zhuǎn)換和參數(shù)傳遞。系統(tǒng)調(diào)用號放入EAX寄存器,啟動INT 0x80 后,規(guī)定返回值送EAX寄存器。

  (3)系統(tǒng)調(diào)用功能模塊的初始化

  對系統(tǒng)調(diào)用的初始化也就是對INT 0x80的初始化。系統(tǒng)啟動時,匯編子程序setup_idt(見arch/i386/kernel/head.S)準(zhǔn)備了1張256項的idt表,由 start_kernel()(見 init/main.c),trap_init()(見

  arch/i386/kernel/traps.c)調(diào)用的C語言宏定義

  set_system_gate(0x80,&system_call)(見include/asm/system.h)設(shè)置0x80號軟中斷的服務(wù)程序為 system_call(見

  arch/i386/kernel/entry.S),system.call就是所有系統(tǒng)調(diào)用的總?cè)肟凇?/p>

  (4)內(nèi)核如何為各種系統(tǒng)調(diào)用服務(wù)

  當(dāng)進(jìn)程需要進(jìn)行系統(tǒng)調(diào)用時,必須以C語言函數(shù)的形式寫一句系統(tǒng)調(diào)用命令。該命令如果已在某個頭文件中由相應(yīng)的_syscallN()展開,則用戶程序必須包含該文 件。當(dāng)進(jìn)程執(zhí)行到用戶程序的系統(tǒng)調(diào)用命令時,實(shí)際上執(zhí)行了由宏命令_syscallN()展開的函數(shù)。系統(tǒng)調(diào)用的參數(shù) 由各通用寄存器傳遞,然后執(zhí)行INT 0x80,以內(nèi)核態(tài)進(jìn)入入口地址system_call。

  (5)ret_from_sys_call

  以ret_from_sys_call入口的匯編程序段在linux進(jìn)程管理中起到了十分重要的作用。所有系統(tǒng)調(diào)用結(jié)束前以及大部分中斷服務(wù)返回前,都會跳轉(zhuǎn)至此處入口地址。 該段程序不僅僅為系統(tǒng)調(diào)用服務(wù),它還處理中斷嵌套、CPU調(diào)度、信號等事務(wù)。

  2.通過修改內(nèi)核源代碼添加系統(tǒng)調(diào)用

  通過以上分析linux系統(tǒng)調(diào)用的過程,將自己的系統(tǒng)調(diào)用加到內(nèi)核中就是一件容易的事情。下面介紹一個實(shí)際的系統(tǒng)調(diào)用,并把它加到內(nèi)核中去。要增加的系統(tǒng)調(diào)用是:inttestsyscall(),其功能是在控制終端屏幕上顯示hello world,執(zhí)行成功后返回0。

  1編寫inttestsyscall()系統(tǒng)調(diào)用

  編寫一個系統(tǒng)調(diào)用意味著要給內(nèi)核增加1個函數(shù),將新函數(shù)放入文件kernel/sys.c中。新函數(shù)代碼如下:

  asmlingkage sys_testsyscall()

  {   console_print("hello world\n");

  return 0;

  }

  2連接新的系統(tǒng)調(diào)用

  編寫了新的系統(tǒng)調(diào)用過程后,下一項任務(wù)是使內(nèi)核的其余部分知道這一程序的存在,然后重建包含新的系統(tǒng)調(diào)用的內(nèi)核。為了把新的函數(shù)連接到已有的內(nèi)核中去, 需要編輯2個文件:

  1).inculde/asm/unistd.h在這個文件中加入

  #define_NR_testsyscall 191

  2).are/i386/kernel/entry.s這個文件用來對指針數(shù)組初始化,在這個文件中增加一行:

  .long SYMBOL_NAME(_sys_tsetsycall)

  將.rept NR_syscalls-190改為NR_SYSCALLS-191,然后重新獎勵和運(yùn)行新內(nèi)核。

  3).使用新的系統(tǒng)調(diào)用

  在保證的C語言庫中沒有新的系統(tǒng)調(diào)用的程序段,必須自己建立其代碼如下

  #inculde<linux/unistd.h>

  _syscall0(int,testsyscall)

  main()

  {

  tsetsyscall();

  }

  在這里使用了_syscall0()宏指令,宏指令本身在程序中將擴(kuò)展成名為syscall()的函數(shù),它在main()函數(shù)內(nèi)部加以調(diào)用。在testsyscall()函數(shù)中, 預(yù)處理程序產(chǎn)生所有必要的機(jī)器指令代碼,包括用系統(tǒng)調(diào)用參數(shù)值加載相應(yīng)的cpu寄存器, 然后執(zhí)行int 0x80中斷指令。

  3.利用內(nèi)核模塊添加系統(tǒng)調(diào)用

  模塊是內(nèi)核的一部分,但是并沒有被編譯到內(nèi)核里面去。它們被分別編譯并連接成一組目標(biāo)文件, 這些文件能被插入到正在運(yùn)行的內(nèi)核,或者從正在運(yùn)行的內(nèi)核中移走。內(nèi)核模塊至少必須有2個函數(shù):

  int_module和cleanup_module。第一個函數(shù)是在把模塊插入內(nèi)核時調(diào)用的;第二個函數(shù)則在刪除該模塊時調(diào)用。由于內(nèi)核模塊是內(nèi)核的一部分,所以能訪問所有內(nèi)核資源。根據(jù)對linux系統(tǒng)調(diào)用機(jī)制的分析,如果要增加系統(tǒng)調(diào)用,可以編寫自己的函數(shù)來實(shí)現(xiàn),然后在sys_call_table表中增加一項,使該項中的指針指向自己編寫的函數(shù),就可以實(shí)現(xiàn)系統(tǒng)調(diào)用。下面用該方法實(shí)現(xiàn)在控制終端上打印"hello world" 的系統(tǒng)調(diào)用testsyscall()。

  1)編寫系統(tǒng)調(diào)用內(nèi)核模塊

  #inculde(linux/kernel.h)

  #inculde(linux/module.h)

  #inculde(linux/modversions.h)

  #inculde(linux/sched.h)

  #inculde(asm/uaccess.h)

  #define_NR_testsyscall 191

  extern viod *sys_call+table[];

  asmlinkage int testsyscall()

  { printf("hello world\n");

  return 0;

  }

  int init_module()

  { sys_call_table[_NR_tsetsyscall]=testsyscall;

  printf("system call testsyscall() loaded success\n");

  return 0;

  }

  void cleanup_module()

  {

  }

  2)使用新的系統(tǒng)調(diào)用#define<linux/unistd.h>

  #define_NR_testsyscall 191

  _syscall0(int,testsyscall)

  main()

  {

  testsyscall();

  }

  3)編譯內(nèi)核模塊并插入內(nèi)核

  編譯內(nèi)核的命令為:gcc -Wall -02 -DMODULE -D_KERNEL_-C syscall.c

  -Wall通知編譯程序顯示警告信息;參數(shù)-02 是關(guān)于代碼優(yōu)化的設(shè)置, 內(nèi)核模塊必須優(yōu)化;參數(shù)-D_LERNEL通知頭文件向內(nèi)核模塊提供正確的定義; 參數(shù)-D_KERNEL_通知頭文件,這個程序代碼將在內(nèi)核模式下運(yùn)行。編譯成功后將生成 syscall.0文件。最后使用insmod syscall.o命令將模塊插入內(nèi)核后即可使用增加的系統(tǒng)調(diào)用。

  比較以上二種方法,筆者認(rèn)為采用內(nèi)核模塊的方法較好。因為這種方法可省去編譯新內(nèi)核并用新內(nèi)核重新 啟動的麻煩,這一優(yōu)點(diǎn)對于代碼的調(diào)試是非常有價值的, 可以節(jié)省大量時間。

關(guān)鍵詞標(biāo)簽:Linux

相關(guān)閱讀

文章評論
發(fā)表評論

熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程使用screen管理你的遠(yuǎn)程會話使用screen管理你的遠(yuǎn)程會話GNU/Linux安裝vmwareGNU/Linux安裝vmware如何登錄linux vps圖形界面 Linux遠(yuǎn)程桌面連如何登錄linux vps圖形界面 Linux遠(yuǎn)程桌面連

相關(guān)下載

人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址linux tc實(shí)現(xiàn)ip流量限制dmidecode命令查看內(nèi)存型號linux下解壓rar文件安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程Ubuntu linux 關(guān)機(jī)、重啟、注銷 命令lcx.exe、nc.exe、sc.exe入侵中的使用方法查看linux服務(wù)器硬盤IO讀寫負(fù)載