可执行程序工作原理

读书笔记

  • ELF(Excutable and Linking Format)即可执行的和可链接的格式,是一个目标文件格式的标准。

    • 可重定位文件:一个源代码文件生成一个可重定位文件(.o文件),所有的.o文件会链接为一个文件————Linux内核。
    • 可执行文件:保存着一个用来执行的程序,一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件。
    • 共享目标文件:没有主函数main的“可执行”文件,只有一堆函数可供其他可执行文件调用。(.so文件)。
  • ELF格式

    • ELF文件的索引表
      • ELF文件的主体是各种节:
    • Header结构
      • e_ident数组的第五个字节,1表示32位,2表示64位。
      • e_type体现了ELF文件类型,e_type值1、2、3、4分别代表可重定位文件、可执行文件、共享目标文件和核心转储文件。
    • Section Header结构
      • 描述文件的信息
      • 用于链接的目标文件必须包含节区头部表
    • Program Header结构
      • 段头表和创建进程相关
      • 用来构造进程映像的目标文件必须具有段头表
  • 程序编译

    • 预处理:gcc -E hello.c -o hello.i
    • 编译:gcc -S hello.i -o hello**.s **
    • 汇编:gcc -c hello.s -o hello.o
    • 链接:gcc hello.o -o hello
  • 静态链接:在编译链接时直接将需要的执行代码复制到最终可执行文件中,优点是代码的装载速度快,执行速度也比较快,对外部环境依赖度低。缺点是如果多个应用程序使用同一库函数,会被装载多次,浪费内存。
    动态链接:编译时不直接复制可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。操作系统负责将需要的动态库加载到内存中,在程序运行到指定的代码时,去共享执行内存中已经加载的动态库去执行代码,最终达到运行时链接的目的。优点是多个程序可以共享同一段代码,而不需要在磁盘上存储多个复制。缺点是在运行时加载可能会影响程序的前期执行性能,而且对使用的库依赖性较高。分为装载时动态链接运行时动态链接

  • exec函数:用来执行一个可执行文件的函数,本质都是实现系统调用sys_execve()执行一个可执行文件.

    • 调用关系:sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()
    • fork与execve的区别和联系
      • 都是比较特殊的系统调用
      • fork在陷入内核态后有两次返回,第一次返回到原来父进程的位置继续向下执行,第二次是在子进程返回,这次会返回到ret_from_fork,之后正常返回用户态。
      • execve在执行时陷入内核态,在内核中调用execve加载的可执行文件把当前进程的可执行程序给覆盖了,当其返回时,返回的已经不是原来的那个可执行程序了,而是新的程序,返回的是新的可执行程序执行的起点,即main函数的大致位置(一般地址为0x8048xxx,由编译器设定).
      • 内核支持多格式是在执行execve时,它加载了文件的头部,来判断文件是什么格式,在链表中寻找能够解析这种文件格式的内核模块.

实验部分

  • 将menu目录删除。克隆一个新的menu,用test_exec.c覆盖test.c

  • 重新编译,执行exec指令
  • 启动内核,到调试状态,加载符号表并设置端口

  • 设置断点,在 sys_execve,load_elf_binary,start_thread设置断点
  • 执行到start_thread,使用po new_ip指令打印其指向地址
  • 继续执行,elf_entry指向了可执行文件定义的入口地址
  • 退出调试状态,输入redelf -h hello可以查看hello的EIF头部
 posted on 2019-11-07 15:48  捞起月亮的渔民  阅读(161)  评论(0编辑  收藏  举报