歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux0.11中的fork實現和一些注意事項

Linux0.11中的fork實現和一些注意事項

日期:2017/2/28 16:22:47   编辑:Linux教程

Linux0.11中有一個fork的系統調用一直沒弄明白,自己添加一些自己的想法。下面是思路和提問。

內核是linux0.11版本,裡面的fork()用於創建子進程。
但我現在在找這個函數的具體定義時遇到了一些困難。
先把我的查找過程說下:
1、init裡的main.c中有static inline _syscall0 (int, fork);
2、在unistd.h中找到_syscall0是個宏,定義如下

Assembly code
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \ // 調用系統中斷0x80。
: "=a" (__res) \ // 返回值??eax(__res)。
: "0" (__NR_##name)); \ // 輸入為系統中斷調用號__NR_name。
if (__res >= 0) \ //如果返回值>=0,則直接返回該值。
return (type) __res; \ // 否則置出錯號,並返回-1。
errno = -__res; \
return -1; \
}
進行參數替換
感覺是int fork(void){....};
具體實現主要是:
__asm__ volatile ( "int $0x80" \ // 調用系統中斷0x80。
:"=a" (__res) \ // 返回值??eax(__res)。
:"" (__NR_##name)); 其中的__NR_##name是2,用來在一個指針函數的數組中作為索引號用的
這個數組定義如下:

C/C++ code
typedef int (*fn_ptr) ();

在sys.h中 fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, sys_setreuid, sys_setregid };
而__NR_##name的值為2感覺正好對應著上面那個數組裡的sys_call_table[2](也就是sys_fork)
感覺有點眉目了
3、繼續解釋這個指令

Assembly code
__asm__ volatile ( "int $0x80" \ // 調用系統中斷0x80。

:"=a" (__res) \ // 返回值eax (__res)。

:"" (__NR_ ##name));

感覺主要是調用系統中斷0x80
4、在匯編代碼system_call.s中找到該中斷的中斷處理函數
大概如下
#### int 0x80 --linux 系統調用入口點(調用中斷int 0x80,eax 中是調用號)。

Assembly code
.align 2
_system_call:
cmpl $nr_system_calls-1,%eax # 調用號如果超出范圍的話就在eax 中置-1 並退出。
ja bad_sys_call
5.5 system_call.s 程序
push %ds # 保存原段寄存器值。
push %es
push %fs

pushl %edx # ebx,ecx,edx 中放著系統調用相應的C 語言函數的調用參數。

pushl %ecx # push %ebx,%ecx,%edx as parameters

pushl %ebx # to the system call
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds # ds,es 指向內核數據段(全局描述符表中數據段描述符)。
mov %dx,%es

movl $0x17,%edx # fs points to local data space
mov %dx,%fs # fs 指向局部數據段(局部描述符表中數據段描述符)。

# 下面這句操作數的含義是:調用地址 = _sys_call_table + %eax * 4。參見列表後的說明。
# 對應的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定義了一個包括72 個
# 系統調用C 處理函數的地址數組表。
call _sys_call_table(,%eax,4)
如果上面的eax放的是__NR_##name,即2
那麼call _sys_call_table(,%eax,4)
相當於call sys_fork()
在該文件的下面一點找到該函數的定義
#### sys_fork()調用,用於創建子進程,是system_call 功能2。原形在include/linux/sys.h 中。
# 首先調用C 函數find_empty_process(),取得一個進程號pid。若返回負數則說明目前任務數組
# 已滿。然後調用copy_process()復制進程。

Assembly code
.align 2
_sys_fork:
call _find_empty_process # 調用find_empty_process()(kernel/fork.c,135)。

testl %eax,%eax
js 1f push %gs

pushl %esi

pushl %edi

pushl %ebp

pushl %eax
call _copy_process # 調用C 函數copy_process()(kernel/fork.c,68)。
addl $20,%esp # 丟棄這裡所有壓棧內容。
1: ret
裡面的_find_empty_process和copy_process()就是fork的主要子函數了.

問題1:請問我這個思路是不是對的。
問題2:匯編調用C函數為什麼名字不一樣啊
匯編裡是_find_empty_process 而在fork.c裡該函數名字是find_empty_process()
匯編這樣調用能找到這個函數麼????
問題3:__asm__ volatile ( "int $0x80" \ // 調用系統中斷0x80。
:"=a" (__res) \ // 返回值??eax(__res)。
:"" (__NR_##name));這個內嵌匯編裡的__NR_##name值是怎麼傳給eax的?以讓後面的call _sys_call_table(,%eax,4)正確調用sysfork;
希望能給我詳細講解這條指令:__asm__ volatile (僅這條)調用中斷int $0x80的具體操作
問題1:
差不多,但是有一個地方需要強調一下。static inline _syscall0 (int, fork),這個實際上隱含指出了系統調用的參數個數,注意這裡是以0結尾的,也就是說這個系統調用不需要傳遞參數。你應該還能從代碼中看到 _syscall1,_syscall2這樣的定義。
問題2:
gcc的C編譯器compile的時候,會在函數名字前面加上一個下劃綫,所以在彙編裏面調用C的函數的時候,要手動的加上這個下劃綫。注意:這裡說的是C編譯器,不包括C++的,C++的編譯器和C的有很多的不同,所以才會有extern "C"的存在。
問題3:
開頭你自己也說了NR_name 是定義的好的值。具體在 <>unistd.h>頭文件裡。怎麼傳給eax的?:"" (__NR_
##name) 這條語句就是傳給eax的意思。引號中省略表示用和輸出一樣的寄存器,也就是輸出中的a(eax)。gcc嵌入匯編的格式你應該了解吧。int $0x80就是調用系統中斷了,設置系統中斷的操作在sched.c 最後一行 set_system_gate(0x80,&system_call); set_system_gate是一個嵌入式宏匯編語句,設置中斷描述符表表項。具體實現在system.h.這樣調用0x80系統中斷後,執行的是 system_call eax中存放的是定義好的NR_name的值,以後處理過程你都說了。

Copyright © Linux教程網 All Rights Reserved