1、C程序通過包含頭文件#include<syscall.h>通過源文件追蹤,找到syscall()函數其實位/usr/include/unistd.h中
如下:
extern long int syscall (long int __sysno, ...) __THROW;
該函數使用INT 0x80軟中斷內核將系統調用號傳遞給保存到eax中,然后將按系統調用號來查找系統調用表中的相應index的函數入口地址。來執行服務例程。
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
其實是通過宏定義定義系統調用函數
位于./kernel/sys.c中
SYSCALL_DEFINE1(my_traverse_process,int,num)
{
..................................
}
SYSCALL_DEFINE1后的‘1’它表示該系統調用有一個參數,后面參數的含義依次是函數名、參數類型、參數名
該函數執行完畢后,執行syscall_exit并將值返回。
INT 0x80之所以能夠執行,因為系統在啟動時將0x80設置了系統調用中斷門。
三、步驟索引
?編譯升級內核
?添加系統調用后重新編譯內核
?編寫用戶程序調用自己添加的系統調用
四、實驗步驟
1、編譯內核
?從下載Linux內核版本2.6.39
?解壓內核到任意目錄(這里不用必須解壓到/usr/src/下,Linus也說不必那樣做,況且自己也試驗成功)
(*)注:這樣有個缺點,那就是在裝玩模塊后,系統會在/lib/modules/2.6.39/下創建該源碼的軟鏈接用于以后用戶編譯內核使用,當用戶無意將其刪除時,將會造成無法編譯自己的模塊。
?進入內核目錄
?首先配置make menuconfig配置裁剪內核(如果沒有什么必要可以復制/boot/config-***,這是現在的內核配置)
cp /boot/config-*** ./.config
?開始編譯,可以執行make all,當然也可以分步完成
make dep
make clean
make bzImahe
make modules
?安裝內核驅動
make modules_install
?安裝內核
make install
?生成引導鏡像文件,并將其復制到/boot目錄下
mkinitramfs -o initrd.img-2.6.39 2.6.39
cp initrd.img-2.6.39
?最后更新grub
update-grub
?啟動新的內核,成功。
2、修改內核源碼,添加系統調用
?首先打開文件./arch/x86/include/asm/unistd_32.h在最后添加系統調用號,如下(最后一行):
#define __NR_name_to_handle_at 341
#define __NR_open_by_handle_at 342
#define __NR_clock_adjtime 343
#define __NR_syncfs 344
#define __NR_my_traverse_process 345 /*This is added by yan,this is a test for system call*/
?打開./arch/x86/kernel/syscall_table_32.S(最后一行)
.long sys_prlimit64
/* 340 */
.long sys_name_to_handle_at
.long sys_open_by_handle_at
.long sys_clock_adjtime
.long sys_syncfs
.long sys_my_traverse_process
?打開./include/linux/syscalls.h添加系統調用函數的聲明
asmlinkage long sys_my_traverse_process(int num); /*This is added by yan*/
?打開./kernel/sys.c文件添加其實現函數
SYSCALL_DEFINE1(my_traverse_process,int,num)
{
struct task_struct *pos;
struct list_head *current_head;
int count=0;
printk("Traversal module is working../n");
current_head=&(current->tasks);
list_for_each_entry(pos,current_head,tasks)
{
count++;
printk("[process %d]: %s/'s pid is %d/n",count,pos->comm,pos->pid);
}
printk(KERN_ALERT"The number of process is:%d/n",count);
printk(KERN_ALERT"This is a sample test output from kernel!/nAnd this is added by yan/n");
return (long)num;
}
注:該函數的功能是遍歷系統中的進程,并輸出進程名和進程號,并返回輸入的參數值。
?重新編譯內核,這次只需編譯內核,驅動部分沒有改變不用再編譯一遍,以節省時間。
make bzImage
?然后執行 cp ./arch/x86/boot/bzImage /boot/vmlinuz替換原來的內核重新啟動。
?在用戶態編寫程序調用如下:
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>
#define __NR_my_traverse_process 345
int main(void)
{
int input;
printf("Input a num");
scanf("%d",&input);
long a=syscall(__NR_my_traverse_process,input);
printf("The return from kernel is %ld/n",a);
return 0;
}
然后gcc -o traverse_process traverse_process.c