讀核筆記(3) - 系統(tǒng)調(diào)用
Posted on 2008-02-18 14:35 ZelluX 閱讀(558) 評論(4) 編輯 收藏 所屬分類: Linux 、System
_syscall 宏:
最簡單的沒有參數(shù)的系統(tǒng)調(diào)用的實現(xiàn):

/**//*?XXX?-?_foo?needs?to?be?__foo,?while?__NR_bar?could?be?_NR_bar.?*/
#define?_syscall0(type,name)?\
type?name(void)?\


{?\
long?__res;?\
__asm__?volatile?("int?$0x80"?\
????:?"=a"?(__res)?\
????:?"0"?(__NR_##name));?\
__syscall_return(type,__res);?\
}
以getuid()為例,_syscall0(int, getuid)展開后就變成
int?getuid(void)


{
????long?__res;
????__asm__?volatile("int?$0x80"
????????????????????:"=a"?(__res)
????????????????????:"0"??(__NR_getuid));
????__syscall_return(int,?__res);
}
程序把系統(tǒng)調(diào)用號__NR_getuid放入eax寄存器,然后調(diào)用軟中斷。
include/asm-i386/hw_irq.h中的定義:
00025?? #define SYSCALL_VECTOR??0x80;
arch/i386/kernel/traps.c中把該中斷號綁定到system_call函數(shù):
00944?? set_system_gate(SYSCALL_VECTOR,&system_call);
system_call函數(shù)在arch/i386/kernel/entry.S中:
ENTRY(system_call)
????pushl?%eax????????????#?save?orig_eax
????SAVE_ALL
????GET_CURRENT(%ebx)
????testb?$0x02,tsk_ptrace(%ebx)????#?PT_TRACESYS
????jne?tracesys
????cmpl?$(NR_syscalls),%eax
????jae?badsys
????call?*SYMBOL_NAME(sys_call_table)(,%eax,4)
????movl?%eax,EAX(%esp)????????#?save?the?return?value
ENTRY(ret_from_sys_call)
????cli????????????????#?need_resched?and?signals?atomic?test
????cmpl?$0,need_resched(%ebx)
????jne?reschedule
????cmpl?$0,sigpending(%ebx)
????jne?signal_return
restore_all:
????RESTORE_ALL主要步驟:
1. 保留一份系統(tǒng)調(diào)用號的最初拷貝
2. 保存堆棧環(huán)境(SAVE_ALL)
3. 得到當(dāng)前task_struct的地址,保存到ebx中
4. 檢查系統(tǒng)調(diào)用號
5. 根據(jù)%eax調(diào)用號計算地址,調(diào)用相應(yīng)函數(shù)
6. 在entry.S后面可以看到,
.data
ENTRY(sys_call_table)
????.long?SYMBOL_NAME(sys_ni_syscall)????/*?0??-??old?"setup()"?system?call*/
????????
????.long?SYMBOL_NAME(sys_getuid16)
????.long?SYMBOL_NAME(sys_stime)????????/*?25?*/
????.long?SYMBOL_NAME(sys_ptrace)
????????
sys_call_table + %eax * 4是sys_getuid16地址,kernel/uid16.c中:
asmlinkage?long?sys_getuid16(void)


{
????return?high2lowuid(current->uid);
}
很簡單的處理代碼,返回當(dāng)前進(jìn)程的uid。這里asmlinkage修飾符表示函數(shù)必須從堆棧中,而不是從寄存器中拿參數(shù)(防止gcc用寄存器傳參優(yōu)化)。
7. 保存返回值eax到堆棧中的eax
8. RESTORE_ALL
另外這里再提一下GET_CURRENT的實現(xiàn)
#define?GET_CURRENT(reg)?\
????movl?$-8192,?reg;?\
????andl?%esp,?reg很巧妙的實現(xiàn),把棧指針與掩碼-8192做與操作,末尾13位清零,就是當(dāng)前的進(jìn)程的task_struct地址了。
接下來是利用內(nèi)核模塊動態(tài)添加一個系統(tǒng)調(diào)用的例程,由于2.4.20以后sys_call_table符號不再被導(dǎo)出了,要獲得這個地址得手動hack。尚未成功,下次回過頭來看看。
最簡單的沒有參數(shù)的系統(tǒng)調(diào)用的實現(xiàn):

























include/asm-i386/hw_irq.h中的定義:
00025?? #define SYSCALL_VECTOR??0x80;
arch/i386/kernel/traps.c中把該中斷號綁定到system_call函數(shù):
00944?? set_system_gate(SYSCALL_VECTOR,&system_call);
system_call函數(shù)在arch/i386/kernel/entry.S中:


















1. 保留一份系統(tǒng)調(diào)用號的最初拷貝
2. 保存堆棧環(huán)境(SAVE_ALL)
3. 得到當(dāng)前task_struct的地址,保存到ebx中
4. 檢查系統(tǒng)調(diào)用號
5. 根據(jù)%eax調(diào)用號計算地址,調(diào)用相應(yīng)函數(shù)
6. 在entry.S后面可以看到,

















7. 保存返回值eax到堆棧中的eax
8. RESTORE_ALL
另外這里再提一下GET_CURRENT的實現(xiàn)



接下來是利用內(nèi)核模塊動態(tài)添加一個系統(tǒng)調(diào)用的例程,由于2.4.20以后sys_call_table符號不再被導(dǎo)出了,要獲得這個地址得手動hack。尚未成功,下次回過頭來看看。