![](https://img.51dongshi.com/20250105/wz/18528804052.jpg)
?.longsys_add_key.longsys_request_key.longsys_keyctl.代表當前地址,sys_call_table代表數組首地址。這個表依次保存所有系統調用的函數指針,以方便總的系統調用處理函數(system_call)進行索引。調用具體的實現在kernel/sys.c中。asmlinkagelongsys_getuid16(void){returnhig2lowuid(current_uid);}?剛才我們提到,這一指令使用中斷/異常向量號128(即16進制的80)將控制權轉移給內核,那么中斷向量是怎么形成的。它的定義在(arch/i386/kernel/traps.c)中。void__inittrap_init(void){……set_trap_gate(0,÷_error);set_trap_gate(1,&debug);set_intr_gate(2,&nmi);set_system_gate(3,&int3);/*int3-5canbecalledfromall*/set_system_gate(4,&overflow);set_system_gate(5,&bounds);set_trap_gate(6,&invalid_op);set_trap_gate(7,&device_not_available);set_trap_gate(8,&double_fault);set_trap_gate(9,&coprocessor_segment_overrun);set_trap_gate(10,&invalid_TSS);set_trap_gate(11,&segment_not_present);set_trap_gate(12,&stack_segment);set_trap_gate(13,&general_protection);set_intr_gate(14,&page_fault);set_trap_gate(15,&spurIoUs_interrupt_bug);set_trap_gate(16,&coprocessor_error);set_trap_gate(17,&alignment_check);set_trap_gate(18,&machine_check);set_trap_gate(19,&simd_coprocessor_error);set_system_gate(,&system_call);……}上一句就是設置system_call的值。SYSCALL_VECTOR的值就是0X80.那么概括起來,系統調用的過程大致如下:(1)系統調用初始化在traps.c中,系統在初始化程序trap_init()中,通過調用set_system_gate(0x80,*system_call)完成中斷描述表的填充。這樣當每次用戶執行指令int0x80時,系統能把控制轉移到entry.S中的函數中去。(2)系統調用執行system_call會根據用戶傳進來系統調用號,在系統調用表system_call中尋找到相應偏移地址的內核處理函數,進行相應的處理。當然在這個過程之前,要保存環境(SAVE_ALL)。(3)系統調用的返回系統調用處理完畢后,通過sys_call_exit返回。返回之前,程序會檢查一些變量,相應地返回。不一定是返回到用戶進程。真正返回到用戶空間時,要恢復環境(restore_all)。用戶程序中系統調用的過程在前面提到system_call會根據用戶傳進來系統調用號,在系統調用表system_call中尋找到相應偏移地址的內核處理函數,進行相應的處理。那么系統調用號怎么產生,在include/asm-i386/unistd.h中可以看到系統調用號的定義。#define__NR_restart_syscall0#define__NR_exit1#define__NR_fork2#define__NR_read3#define__NR_write4#define__NR_open5#define__NR_close6#define__NR_waitpid7#define__NR_creat8#define__NR_link9……#define__NR_mq_open277#define__NR_mq_unlink(__NR_mq_open+1)#define__NR_mq_timedsend(__NR_mq_open+2)#define__NR_mq_timedreceive(__NR_mq_open+3)#define__NR_mq_notify(__NR_mq_open+4)#define__NR_mq_getsetattr(__NR_mq_open+5)#define__NR_sys_kexec_load283#define__NR_waitid284/*#define__NR_sys_setaltroot285*/#define__NR_add_key286#define__NR_request_key287#define__NR_keyctl288#defineNR_syscalls289此處的代碼是從2.6.11中的代碼,其中系統調用號已到了288,并且與前面system_call中的相對應。每一個系統調用號前都是相應函數名加了__NR_。內核跟用戶程序的交互,其實有標準C庫作為它們之間的橋梁。標準C庫把用戶希望傳遞的參數裝載到cpu的寄存器中,然后觸發0X80中斷。當從系統調用返回的時候(sys_call_exit),標準C庫又接過控制權,處理返回值。對于__NR_,標準C庫會作相應處理。轉換成相應函數。對于系統函數的調用,有幾個通用的宏在include/asm-i386/unistd.h中定義。#define__syscall_return(type,res)do{if((unsignedlong)(res)>=(unsignedlong)(-(128+1))){errno=-(res);res=-1;}return(type)(res);}while(0)#else#define__syscall_return(type,res)return(type)(res)#endif#define_syscall0(type,name)typename(void){long__res;__asm__volatile("int$0x80":"=a"(__res):"0"(__NR_##name));__syscall_return(type,__res);}這是無參函數調用的形式。#define_syscall1(type,name,type1,arg1)typename(type1arg1){long__res;__asm__volatile("int$0x80":"=a"(__res):"0"(__NR_##name),"b"((long)(arg1)));__syscall_return(type,__res);}這是含一個參數的調用形式,……標準C庫會把我們的調用如pause()轉換成相應的形式。pause()intpause(void){long__res;__asm__volatile(“int$0x80”:”=a”(__res):””(__NR_pause));__syscall_return(int,__res);}進入內核調用過程。基礎知識介紹完了,下面來進行我們的實驗:準備如果你安裝的系統包含內核源文件,一般在/usrc路徑下可以看到,那么可以直接跳到步驟3進行內核修改。??首先下載最新的linux2.6.37內核,先修改/usrcnux下的Makefile文件,將內核版本修改成自己的。把2.6.37中Makefile文件頭幾行為:VERSION?=?2PATCHLEVEL?=?6SUBLEVEL?=?37EXTRAVERSION?=?.1我們可以修改成自己版本(2.6.37.rangercyh):VERSION?=?2PATCHLEVEL?=?6SUBLEVEL?=?37EXTRAVERSION?=?rangercyh??下載源代碼如果系統不包含源文件,則需要在網站上下載系統源代碼。在官方網站上下到類似?linux-2.6.37.1.tar.gz的代碼后(大概有70兆左右),放在/usrc/?的目錄下,然后解壓,解壓后會出現文件夾?linux-2.6.37.1。不過貌似最新的代碼已經出到2.6.38了。?