新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 操作系统研究。UEFI
    [返回] 计算机科学论坛计算机理论与工程『 操作系统原理 』 → linux进程前世与今生  查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 4583 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: linux进程前世与今生  举报  打印  推荐  IE收藏夹 
       本主题类别:     
     enorm 帅哥哟,离线,有人找我吗?
      
      
      威望:4
      头衔:头衔
      等级:大三暑假(参加全国数模竞赛拿了一等奖)(版主)
      文章:144
      积分:854
      门派:Lilybbs.net
      注册:2005/12/1

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给enorm发送一个短消息 把enorm加入好友 查看enorm的个人资料 搜索enorm在『 操作系统原理 』的所有贴子 引用回复这个贴子 回复这个贴子 查看enorm的博客楼主
    发贴心情 linux进程前世与今生 

    一、process内功
    (待续)
    二、process的来龙去脉
    Linux下任何进程都是由fork(或vfork)产生,exec函数簇调用执行,因此,要知晓process流程,需从fork和execve入手。所谓:不知来路,焉知出来!不等内堂,焉知外堂!
    1、fork()之来龙去脉:
    首先说明两点:1,在系统引导和初始化完成后,系统main在创建新process时,不使用用户态stack,故不可以采用调用的方式创建进程,所以, fork()被设计成了宏_syscall0的形式。2,用户调用fork()时,编译器不是简单地将fork()代码展开到程序中,而是使用GOT将 fork()重新定位后再执行。具体分析容我有空再续,亦可参考“参考资料”。
    执行_syscall0(int, fork)之前,先将int &80中断调用号_NR_name入eax,调用int &80,中断结果入eax.,并赋给res,它就是fork()调用成功后的返回值。代码如下:
    ―――――――――――――――――――――――――――――――――――
    .//说明:一下嵌套汇编才用AT&T格式,linux亦支持intel格式。
    //参数:int,fork
    //返回:成功:res;失败:-1
    #define _syscall0(type,name) type name(void) { long __res; __asm__ volatile ("int $0x80" : "=a" (__res) : "0" (__NR_##name)); if (__res >= 0) \  
    return (type) __res; errno = -__res; return -1; ―――――――――――――――――――――――――――――――――――――
    int &80转入_sys_fork后,首先给新process分配id和task[i]中的位置i,然后再调用copy_process复制父进程任务数组结构,退出_sys_fork, 并返回eax中的值给_syscall0, 继续_syscall0直到return, fork()亦结束。
    2、execve()之来龙去脉:
    首先说明:execve采用宏_syscall13(不同于fork()),其他execve的原理基本同fork().首先_syscall13调用将 int &80中断依系统调用号转入_sys_execve,然后进入_do_execve()直到返回_sys_execve。在退出 _syscall13后, execve()亦即结束。

    三、用户main()的生与死
    "用户main"是指用户编写的非OS代码的任意C程序中的主函数.为什么叫"用户main"呢?因为OS也有一个,他们俩的“人生轨迹”可不一样哟,所以姑且取个名字,以示区别吧.既非用户,是名用户!!
    1. main之"生".
    为了main的诞生,系统是如何“十月怀胎”的呢?
    当用户在shell下执行main函数,shell根据输入的函数名fork出新process,并调用execve启动该process.此时,这个 process是作为sh的子process运行,而shell作为父process在等待子process结束后再运行.当shell解析出main函数后,main还是立即启动真正的main(),因为:
    从ELF Header:
    ......
    Entry point address:               0x8048244
    Start of program headers:          52 (bytes into file)
    Start of section headers:          16600 (bytes into file)
    ......
    知道main的入口地址是:0x8048244.
    而(gdb) disass main
    Dump of assembler code for function main:
    0x080482f9 <main+0>:    push   %ebp
    0x080482fa <main+1>:    mov    %esp,%ebp
    0x080482fc <main+3>:    sub    $0x8,%esp
    0x080482ff <main+6>:    and    $0xfffffff0,%esp
    0x08048302 <main+9>:    mov    $0x0,%eax
    0x08048307 <main+14>:   sub    %eax,%esp
    0x08048309 <main+16>:   call   0x80482f4 <f>
    0x0804830e <main+21>:   mov    $0x0,%eax
    0x08048313 <main+26>:   leave
    0x08048314 <main+27>:   ret
    (gdb) disass 0x8048244
    Dump of assembler code for function _start:
    0x08048244 <_start+0>:  xor    %ebp,%ebp
    0x08048246 <_start+2>:  pop    %esi
    0x08048247 <_start+3>:  mov    %esp,%ecx
    0x08048249 <_start+5>:  and    $0xfffffff0,%esp
    0x0804824c <_start+8>:  push   %eax
    0x0804824d <_start+9>:  push   %esp
    0x0804824e <_start+10>: push   %edx
    0x0804824f <_start+11>: push   $0x8048348
    0x08048254 <_start+16>: push   $0x8048318
    0x08048259 <_start+21>: push   %ecx
    0x0804825a <_start+22>: push   %esi
    0x0804825b <_start+23>: push   $0x80482f9
    0x08048260 <_start+28>: call   0x8048234 <__libc_start_main>
    0x08048265 <_start+33>: hlt
    知:main()的地址是:0x080482f9.因此.程序加载器为了将IP定位到地址0x080482f9。所以内核将
    控制权交给动态链接器的入口后,先调用_dl_start函数获得真实的程序入口,获得_start的入口,即”Entry point address: 0x8048244” 转入_start例程,该程序压入一些参数到堆栈,就直接调用_libc_start_main函数。这时再"变态"(bt)一下,
    gdb) bt
    ......
    #1  0x08048355 in main () at main.c:15
    #2  0x42015574 in __libc_start_main () from /lib/tls/libc.so.6
    欧!main()出来了,__libc_start_main ()距离它一步之遥了,曙光在前!
    libc_start_main.该函数注册了动态连接器解析器后,才进入main()。千呼万唤始出来!详细分析见参考资料.

    为什么一个用户main()函数,会经过如此复杂的程序呢?从kernel和用户交互层面看,因为在执行用户main函数时,需要用户到内核再到用户的切换,用户到kenerl的切换时,就需要libc库了.也就是上面的步骤了.这姑且也当做一种权益的理解吧.真是"曲经通幽"!

    2.main之"死"
    当main over后, 系统又魂归何处.
    在编写代码时,main的结束通常用两种方式,下面分别说明.
    一种是exit(0).代码如下:
    //exit(0)
    0x08048334 <main+16>:   sub    $0xc,%esp
    0x08048337 <main+19>:   push   $0x0
    0x08048339 <main+21>:   call   0x8048264 <exit>
    End of assembler dump.
    这种方式是通过系统调用,结束该process. 操作系统接管cpu,父process运行.

    另外一种是return.
    //return
    0x0804830e <main+21>:   mov    $0x0,%eax
    0x08048313 <main+26>:   leave
    0x08048314 <main+27>:   ret
    End of assembler dump.
    这种方式是借助IP寄存器退出程序,那到底退出到哪儿去了呢?我想应该是libc_start_main吧!查libc_start_main ()和exit的原代码,噢!果真如此!
    跟踪试试看:
    //main()原代码
    11      void main()
    12      {
    13          //fork();
    14          //exit(0);
    15          f();
    16          printf("main over!\n");
    17          return;
    18      }
    19
    20
    //main()汇编代码
    ......
    0x0804835d <main+29>:   call   0x8048268 <printf>
    0x08048362 <main+34>:   add    $0x10,%esp
    0x08048365 <main+37>:   leave
    0x08048366 <main+38>:   ret
    End of assembler dump.

    (gdb) b 17
    Breakpoint 5 at 0x8048365: file main.c, line 17.
    (gdb) b 18
    Note: breakpoint 5 also set at pc 0x8048365.
    Breakpoint 6 at 0x8048365: file main.c, line 18.

    (gdb) next
    main over!

    Breakpoint 5, main () at main.c:18
    18      }
    (gdb) i reg eip
    eip            0x8048365        0x8048365
    (gdb) next
    0x42015574 in __libc_start_main () from /lib/tls/libc.so.6
    噢,当leave后,再next时,eip值为0x42015574.这又到了libc_start_main中了!
    因此,return可以用来结束子程序.而exit不可以.


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    天亮了

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/12/9 13:46:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 操作系统原理 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/27 9:11:41

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms