Linux0.11中的fork实现和一些注意事项

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/25145.html