_syscall 宏:
最簡單的沒有參數的系統調用的實現:

/**//*?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);
}
程序把系統調用號__NR_getuid放入eax寄存器,然后調用軟中斷。
include/asm-i386/hw_irq.h中的定義:
00025?? #define SYSCALL_VECTOR??0x80;
arch/i386/kernel/traps.c中把該中斷號綁定到system_call函數:
00944?? set_system_gate(SYSCALL_VECTOR,&system_call);
system_call函數在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. 保留一份系統調用號的最初拷貝
2. 保存堆棧環境(SAVE_ALL)
3. 得到當前task_struct的地址,保存到ebx中
4. 檢查系統調用號
5. 根據%eax調用號計算地址,調用相應函數
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);
}
很簡單的處理代碼,返回當前進程的uid。這里asmlinkage修飾符表示函數必須從堆棧中,而不是從寄存器中拿參數(防止gcc用寄存器傳參優化)。
7. 保存返回值eax到堆棧中的eax
8. RESTORE_ALL
另外這里再提一下GET_CURRENT的實現
#define?GET_CURRENT(reg)?\
????movl?$-8192,?reg;?\
????andl?%esp,?reg很巧妙的實現,把棧指針與掩碼-8192做與操作,末尾13位清零,就是當前的進程的task_struct地址了。
接下來是利用內核模塊動態添加一個系統調用的例程,由于2.4.20以后sys_call_table符號不再被導出了,要獲得這個地址得手動hack。尚未成功,下次回過頭來看看。
最簡單的沒有參數的系統調用的實現:

























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


















1. 保留一份系統調用號的最初拷貝
2. 保存堆棧環境(SAVE_ALL)
3. 得到當前task_struct的地址,保存到ebx中
4. 檢查系統調用號
5. 根據%eax調用號計算地址,調用相應函數
6. 在entry.S后面可以看到,

















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



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