您的位置:首页 > 运维架构 > Linux

[linux 0.11]fork()--子进程的返回

2010-04-10 21:10 176 查看
  fork()是linux下创建进程的函数,这里通过linux 0.11分析下fork()创建进程后,子进程是如何返回的,但并不打算分析完整的fork()。

  fork()是1个系统调用(int 0x80),主要由find_empty_process和copy_process两个内核函数组成。

  当调用fork()时(int 0x80),cpu会自动将调用fork()时的代码段cs和fork()指令的下一句指令地址eip压栈,在执行copy_process时,将此cs,eip作为copy_process的部分参数,而copy_process内将复制父进程的TSS给子进程,也即将cs,eip做为子进程的入口地址。

  但是copy_process并不是将父进程的TSS完全复制给子进程,而是将子进程TSS段内的eax字段设置为0,而eax正是函数fork()的返回值。

  copy_process中最后将子进程设置为就绪态(TASK_RUNNING),父进程就从fork()中返回。

  NOTE!子进程实际上并没有执行fork()
,fork()只不过是创建了一个新进程,而它被调度执行时候的eax,cs,eip早已被精心设计过了。 

  看个简单的关于fork()的小示例:

//fork.c:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

int main()

{

pid_t pid;

if((pid=fork())==0)
   //注意这里!对应下面的反汇编

{

printf("child/n");

}

else if(pid>0)

{

printf("parent/n");

}

else

{

printf("error/n");

}

exit(0);

}

将其编译:gcc fork.c -o fork.out

对fork.out进行反汇编:objdump -d fork.out后,截取关键代码段如下:

08048414 <main>:

8048414: 55 push %ebp

8048415: 89 e5 mov %esp,%ebp

8048417: 83 e4 f0 and $0xfffffff0,%esp

804841a: 83 ec 20 sub $0x20,%esp

804841d: e8 1e ff ff ff call 8048340 <fork@plt>   

8048422: 89 44 24 1c mov %eax,0x1c(%esp)  #eax值传给0x1c(%esp)

8048426: 83 7c 24 1c 00 cmpl $0x0,0x1c(%esp) #0x1c(%esp)与0比较,实际就是eax与0比较

804842b: 75 0e jne 804843b <main+0x27>

804842d: c7 04 24 34 85 04 08 movl $0x8048534,(%esp)

8048434: e8 f7 fe ff ff call 8048330 <puts@plt>   #

printf("child/n");

8048439: eb 21 jmp 804845c <main+0x48>

804843b: 83 7c 24 1c 00 cmpl $0x0,0x1c(%esp)

8048440: 7e 0e jle 8048450 <main+0x3c>

8048442: c7 04 24 3a 85 04 08 movl $0x804853a,(%esp)

8048449: e8 e2 fe ff ff call 8048330 <puts@plt>   


printf("parent/n");

804844e: eb 0c jmp 804845c <main+0x48>

8048450: c7 04 24 41 85 04 08 movl $0x8048541,(%esp)

8048457: e8 d4 fe ff ff call 8048330 <puts@plt>   


printf("error/n");

804845c: c7 04 24 00 00 00 00 movl $0x0,(%esp)

8048463: e8 e8 fe ff ff call 8048350 <exit@plt>

  我们调用fork()后,cpu自动压栈的eip 就是
指令:call 8048340 <fork@plt>下一句指令

mov %eax,0x1c(%esp)的地址0x8048422。

  从反汇编代码中我们可以看到eax正是fork()的返回值,当子进程被调度执行时候,它的第一条指令便是

0x8048422处的

mov %eax,0x1c(%esp),而此时子进程的所处的环境下eax已经被设置为0了--这正是fork()后子进程为什么返回0的原因。

---------------------附上copy_process()的代码,关于完整的fork()调用代码这里不给出了---------------

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,

long ebx,long ecx,long edx,

long fs,long es,long
ds,

long
ei
p
,long
cs,l

ong eflags,long esp,long ss)

{

struct task_struct *p;

int i;

struct file *f;

p = (struct task_struct *) get_free_page();

if (!p)

return -EAGAIN;

task[nr] = p;

*p = *current; /* NOTE! this doesn't copy the supervisor stack */

p->state = TASK_UNINTERRUPTIBLE;

p->pid = last_pid;

p->father = current->pid;

p->counter = p->priority;

p->signal = 0;

p->alarm = 0;

p->leader = 0; /* process leadership doesn't inherit */

p->utime = p->stime = 0;

p->cutime = p->cstime = 0;

p->start_time = jiffies;

p->tss.back_link = 0;

p->tss.esp0 = PAGE_SIZE + (long) p;

p->tss.ss0 = 0x10;

p->tss.eip = eip;

p->tss.eflags = eflags;

p->tss.eax = 0;   //子进程中fork()的返回值是0

p->tss.ecx = ecx;

p->tss.edx = edx;

p->tss.ebx = ebx;

p->tss.esp = esp;

p->tss.ebp = ebp;

p->tss.esi = esi;

p->tss.edi = edi;

p->tss.es = es & 0xffff;

p->tss.cs = cs & 0xffff;

p->tss.ss = ss & 0xffff;

p->tss.ds = ds & 0xffff;

p->tss.fs = fs & 0xffff;

p->tss.gs = gs & 0xffff;

p->tss.ldt = _LDT(nr);

p->tss.trace_bitmap = 0x80000000;

if (last_task_used_math == current)

__asm__("clts ; fnsave %0"::"m" (p->tss.i387));

if (copy_mem(nr,p)) {

task[nr] = NULL;

free_page((long) p);

return -EAGAIN;

}

for (i=0; i<NR_OPEN;i++)

if (f=p->filp[i])

f->f_count++;

if (current->pwd)

current->pwd->i_count++;

if (current->root)

current->root->i_count++;

if (current->executable)

current->executable->i_count++;

set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));

set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));

p->state = TASK_RUNNING; /* do this last, just in case */

return last_pid;    //父进程中fork()的返回值是子进程id

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: