Linux ELF文件装入与执行概述

来源:互联网 发布:现在做网络主播赚钱吗 编辑:程序博客网 时间:2024/05/20 09:10


ELF是linux中使用最广泛的一种应用程序格式,为了弄清楚Linux内核是如何讲ELF文件精确映射到指定内存空间,上周末把内核sys_execve部分好好看了一遍,小结如下:

1. ELF格式
ELF指定了进程中text段、bss段、data段等应该放置到进程虚拟内存空间的什么位置,以及记录了进程需要用到的各种动态链接库的位置。


2. sys_execve的大致执行流程
  1) 打开ELF二进制文件,读入ELF头
  2) 删除从父进程继承过来的mm相关内容
  3) 根据ELF头将interpreter段、text段、data段等映射进内存(由此知linux不支持压缩了的二进制程序)
     设置好堆栈等,更新mm内容。
  4) "伪造"好本进程的内核栈,为进程返回用户态执行做好准备。内核栈中的ip指向了interpreter段入口。
  5) sys_execve系统调用返回到用户态,开始interpreter的执行(interpreter一般为linux-ld.so.2 or similar)

 进入到用户态后,interpreter做了些什么呢?

  6) interpreter帮助用户进程装入动态链接库,做好全部重定位映射工作。
  7) interpreter返回到main开始执行。

这里面有几个问题需要深究:
  1> sys_execve被调用的时候内核栈长什么样?用户态参数是如何传入到内核的?
    只有弄明白了这个问题,才知道如何从内核返回到interpreter入口开始执行
     A: 关于这个问题请参考linux系统调用相关章节。linux系统调用采取了一个一致的方法来处理系统调用参数问题,非常值得借鉴,将另外撰文梳理其设计思路。
  2> interpreter的参数从哪里来?interpreter如何返回到main?
     A: 如果从传统的C语言函数调用的角度来理解,这个问题会很费解。但是如果能从汇编的角度,动态地、有目的地调整和"伪造"调用栈,就能够做到方便地再各个函数间切换和传参。
     内核会构造好interpreter所需要的参数栈,interpreter会构造好main所需要的参数栈。用户栈是在setup_arg_pages函数中构建的。
  3> 内核是如何保证将各个段映射到期望的位置?
     mmap函数有一个参数取MAP_FIXED参数即可。