2021-2022-1 20212809《Linux内核原理与分析》第八周作业

Linux内核如何装载和启动一个可执行程序:

分析exec*函数对应的系统调用处理过程

可执行程序工作原理
ELF目标文件格式

ELF (Executable and Linkable Format)即可执行的和可链接的格式,是一个目标文件格式的标准。ELF格式的文件用于存储Linux程序。ELF是一种对象文件的格式,用于定义不同类型的对象文件中都有什么内容、以什么样的格式放这些内容。ELF首部会描绘整个文件的组织结构,它还包括很多节(sections, 是在ELF文件里用以装载内容数据的最小容器),这些节有些是系统定义好的,有些是用户在文件中通过.section命令自定义的,链接器会将多个输入目标文件中相同的节合并。

ELF文件的3种类型:可重定位文件、可执行文件、共享目标文件

  • 可重定位文件:这种一般是中间文件,还需要继续处理。由汇编器和编译器创建,一个源代码文件会生成一个可重定位文件。文件中保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件、静态库文件或者共享目标文件(即动态库文件)。
  • 可执行文件:一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件,文件中保存着一个用来执行的程序。
  • 共享目标文件:共享库,是指可以被可执行文件或其他库文件使用的目标文件,例如标准C的库文件libc.so。可以简单理解为没有主函数main的“可执行”文件,只有一堆函数可供其他可执行文件调用。
    ELF Header结构
typedef struct{
  unsigned char e_ident[EI_NIDENT];    //最开头是16个字节的e_ident, 其中包含用以表示ELF文件的字符,以及其他一些与机器无关的信息。开头的4个字节值固定不变,为0x7f和ELF三个字符。
  Elf32_Half e_type;       //该文件的类型 2
  Elf32_Half e_machine;    //该程序需要的体系结构 2
  Elf32_Word e_version;    //文件的版本 4
  Elf32_Addr e_entry;      //程序的入口地址 4
  Elf32_Off e_phoff;       //Program header table 在文件中的偏移量 4
  Elf32_Off e_shoff;       //Section header table 在文件中的偏移量 4
  Elf32_Word e_flags;      //对IA32而言,此项为0
  Elf32_Half e_ehsize;     //表示ELF header大小 2
  Elf32_Half e_phentsize;  //表示Program header table中每一个条目的大小 2
  Elf32_Half e_phnum;      //表示Program header table中有多少个条目 2
  Elf32_Half e_shentsize;  //表示Section header table中的每一个条目的大小 2
  Elf32_Half e_shnum;      //表示Section header table中有多少个条目 2
  Elf32_Half e_shstrndx;   //包含节名称的字符串是第几个节 2
}Elf32_Ehdr;
预处理:gcc -E hello.c -o hello.i
编译:gcc -S hello.i -o hello.s -m32
汇编:gcc -c hello.s -o hello.o -m32
链接:gcc hello.o -o hello -m32 -static

链接与库
链接从过程上讲分为符号解析和重定位两部分

符号解析:编译器到其他的共享库中找到无定义符号对应的机器指令片段,然后把该片机器指令与XXX.o拼接到一起,生成可执行文件XXX。
重定位:把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,是实现多道程序在内存中同时运行的基础。
根据链接时机的不同,分为静态链接和动态链接

静态链接:在编译链接时直接将需要的执行代码复制到最终可执行文件中。
动态链接:在编译时不直接复制可执行代码, 而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。
程序装载
fork与execve的区别和联系

fork两次返回,第一次返回到父进程继续向下执行,第二次是在子进程返回到ret_from_fork后正常返回用户态。
execve在执行时陷入内核态,用execve加载的程序把当前正在执行的进程覆盖,当系统调用返回时也就返回到新的可执行程序起点
execve()的系统调用实质试运行的内核态的函数,大致处理过程总结如下:

(1)sys_execve中的do_execve()读取128个字节的文件头部,以此判断可执行文件的类型

(2)调用search_binary_handle()去搜索和匹配合适的可执行文件转载处理过程

(3)ELF文件由load_elf_binary()函数负责装载,它调用了sart_thread函数,创建新进程的堆栈

使用gdb跟踪分析一个execve系统调用内核处理函数
执行下列命令删除并克隆Linuxkernel下的menu,用test_exec.c覆盖test.c,重新编译rootfs

$ cd LinuxKernel
$ rm -rf menu
$ git clone https://github.com/mengning/menu.git
$ cd menu
$ mv test_exec.c test.c
$ make rootfs
在这里插入图片描述
test.c文件中增加了exec系统调用,Makefile文件中增加了gcc -o hello.c -m32 -static,启动内核并检验execv函数是否正确

启动gdb调试
在这里插入图片描述
退出调试状态,输入redelf -h hello可以查看hello的EIF头部,可见头的大小为52字节,用dump命令16进制读取前52个字节进行分析
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值