在linux核心中增加乙個系統呼叫,並編寫對應的linux應用程式。利用該系統呼叫:(1)能夠返回指定程序(通過指定pid)的任務描述符;(2)能夠返回指定程序(通過指定pid)的程序位址空間的布局和統計資訊(**段、資料段、bss段、堆、棧等區域的位置和大小、包含多少個虛擬記憶體區vma、每個vma的屬性、該程序頁表的位址、已對映的物理記憶體大小等。)(該題目需要研究linux 程序描述符和記憶體描述符mm_struct。)
linux系統中新增新的系統呼叫有兩種方法。方法一:直接修改核心原始碼,在核心中增加乙個系統呼叫實現函式,並將該函式的名字新增到system_call_table中。該函式在system_call_table中的索引即為新增系統呼叫的系統呼叫號。最後重新編譯核心原始碼,生成新的核心。方法二:不用編譯核心,在核心模組中實現乙個系統呼叫實現函式,並將該函式的名字新增到system_call_table中。本實驗採用方法一實現新增系統呼叫。
第一步:編輯syscall_64.tbl檔案
syscall_64.tbl檔案位於linux-source-3.13.0/arch/x86/syscalls/sysc all_64.tbl(ubuntu是64位),主要定義系統呼叫號。本實驗定義新新增的系統呼叫號為314,在314號新增「314common mycall sys_ni_syscall」sys_ni_syscall
是最簡單的系統呼叫服務例程,表面上看,它可能並沒有什麼用處,但是,它在sys_call_table中佔據了很多位置。多數字置上的sys_ni_syscal都代表了那些已經被核心中淘汰或者沒有實際用處的系統呼叫。
第二步:編輯unisted.h檔案
unistd.h位於/usr/include/asm-generic/unistd.h,為每個系統呼叫規定唯一的編號。新增「#define __nr_mycall 314 __syscall(__nrmycall, sys_mycall)」由於新新增了乙個系統呼叫,__nr_syscalls需要加1,由原來的274變為275,表明有275個系統呼叫函式。
第三步:編輯syscalls.h檔案
syscalls.h檔案位於linux-source-3.13.0/include/linux/syscalls.h,用於宣告系統呼叫函式。在檔案最後新增「asmlinkage long sys_call(pid_t pid,char __user * buf);」,asmlinkage巨集是系統呼叫函式的關鍵字,
表示函式通過堆疊而不是通過暫存器傳遞引數。
sys_mycall
是函式名,第乙個引數是
pid程序號,第二個引數用於儲存
task_struct
部分資訊,由核心態傳遞到使用者態。
第四步:編輯mycall.c檔案
在linux-source-3.13.0/kernel/目錄下,新建mycall.c檔案。mycall.c檔案執行在核心態,為使用者態提供服務。實驗要求由pid獲得task_struct的相關資訊。把需要獲去的task_struct的資訊,封裝為乙個結構體,最後把該結構體傳到使用者態。linux核心提供find_task_by_vpid(),pid是唯一標誌乙個程序,通過該函式,直接獲得該pid標誌的程序task_struct。
#include #include #include #include #include #include struct mycall_taskinfo
;asmlinkage long sys_mycall(pid_t pid,char __user * buf)
}pgd=task_mm->pgd;
a[0].pgd=* pgd;
a[0].start_code=task_mm->start_code;
a[0].end_code=task_mm->end_code;
a[0].start_data=task_mm->start_data;
a[0].end_data=task_mm->end_data;
a[0].start_brk=task_mm->start_brk;
a[0].brk=task_mm->brk;
a[0].start_stack=task_mm->start_stack;
a[0].end_stack=task_mm->arg_start;
pid_t count=0;
vmalist=task_mm->mmap; /* list of vmas */
while(count<256 && vmalist )
a[0].vma_count=count;
if(copy_to_user((struct mycall_taskinfo *)buf,a,sizeof(struct mycall_taskinfo)))
return sizeof(struct mycall_taskinfo);
else
return 0;
}
至此,新增系統呼叫函式完成,接下來,開始對核心重新編譯。
第五步:編輯makefile檔案
修改linux-source-3.13.0/kernel/makefile檔案,把mycall.o加到obj-y中。
編譯核心需要安裝編譯環境必要庫:
安裝好編譯環境,為了減少編譯核心耗費的時間,把/boot/原核的配置檔案拷貝到linux-source-3.13.0下,並命名為.config。即輸入命令:
編譯核心指令:
#include#includestruct mycall_taskinfo
;int main()
{struct mycall_taskinfo a[1];
int i;
syscall(314,getpid(),a);
printf("程序pid: %d\n",a[0].pid);
printf("程序的vmas的個數為%d\n",a[0].vma_count);
for( i=0;i結果截圖:
問題1:無法確定指定程序號是多少
程序號是程式執行時分配的,事先不知道程序的程序號是多少。而且程序號的取值範圍為0-pid_max_default,順序使用和迴圈使用。隨便指定程序號,無法保證其task_struct存在。查詢發現,使用者態有getpid()函式,直接獲得該程序的pid。這樣即可以確定該pid一定存在task_struct。同時也能確定該pid由哪個程式執行產生。
問題2:核心態與使用者態資料的轉換
在系統呼叫中獲得的資料資訊需要傳送到使用者態進行輸出顯示,但核心態的資料和使用者態的資料不可以直接進行傳遞。linux提供copy_from_user()
和copy_to_user()
這兩個函式,負責在使用者空間和核心
空間傳遞資料。因此我們在測試程式中,將空陣列
a的位址作為引數傳遞給核心模組程式,
在核心中使用
copy_to_user()
函式將核心中的陣列資訊傳遞給使用者態下的位址。
copy_to_user()
複製成功返回0,複製失敗返回未複製成功的位元組數。
linux 系統呼叫
使用者應用可以通過兩種方式使用系統呼叫。第一種方式是通過c庫函式,包括系統呼叫在c庫中的封裝函式和其他普通函式。圖5.2 使用系統呼叫的兩種方式 第二種方式是使用 syscall巨集。2.6.18版本之前的核心,在include asm i386 unistd.h檔案中定義有7個 syscall巨集...
Linux系統呼叫
一 實驗目的和要求 1.學習linux核心的配置和編譯 2.深入理解linux系統呼叫 3.理解arm和x86的cpu模式 系統模式 使用者模式 的不同 4.掌握核心模組的編寫方法。二 實驗器材 1.linux實驗板卡一塊 2.5v 1a電源乙個 3.microusb線一根 4.macos一台 5....
Linux系統呼叫
linux系統呼叫 系統呼叫 system call 是使用者空間訪問核心的唯一手段,除異常和陷入外,他們是核心唯一的合法入口。通常情況下應用程式是通過應用程式設計介面api來訪問函式,而不是直接使用系統呼叫來程式設計。作業系統通常是通過中斷從使用者態切換到核心態。中斷就是乙個硬體或軟體請求,要求c...