在上一篇文章中简单分析了fork、pause等系统调用的实现,怀着对fork在父子进程中返回不同值的好奇,本文中将深入分析fork的执行过程以及如何实现在父子进程中返回不一样的值(父进程---子进程ID,子进程----0)。
为了分析fork,可以从它定义处开始一步一步的分析它执行的过程以及堆栈内容的变化。下面从syscall0(int,fork)展开后的结果:
static inline int fork(void)
{
long __res;
__asm__ volatile ("int $0x80" \ //调用系统中断0x80
: "=a" (__res) \ //__res用来承载中断返回值
: "0" (__NR_fork)); \ //输入为系统中断调用号__NR_fork ( = 2)
if (__res >= 0) \
return (int) __res; \ //如果返回值>=0,则直接返回该值。
errno = -__res; \ //否则置出错号
return -1; \ //并返回-1
}
从上面第2行代码可知,fork执行过程的起点为“int $0x80” ,通过调用系统中断0x80从而跳转到_system_call中去执行。返回值__res从eax寄存器中得到,当__res >= 0时返回__res值,否则报错并返回-1 。在调用系统中断0x80时,CPU保存现场,自动把一些寄存器的值按顺序压入栈,此时栈内的内容如下图所示,把ss、esp、eflags、cs寄存器入栈,在调用system_call函数时把返回程序的入口地址也入栈。
接下来,程序跳转进入/kernel/system_call.S文件中system_call系统调用入口函数_system_call处执行。
.align 2
reschedule:
pushl $ret_from_sys_call
jmp _schedule
.align 2
_system_ca