内核如何在linux下运行得到一个可执行二进制文件?
- 2024-10-11 08:36:00
- admin 原创
- 95
问题描述:
内核如何在linux下运行得到一个可执行二进制文件?
这似乎是一个简单的问题,但有人能帮我深入挖掘一下吗?文件如何加载到内存中以及如何开始执行代码?
有人能帮助我并告诉我一步一步发生的情况吗?
解决方案 1:
exec
Linux 4.0 系统调用的最佳时刻
找出所有这些的最佳方法是使用 QEMU 对内核进行 GDB 步骤调试:如何使用 GDB 和 QEMU 调试 Linux 内核?
fs/exec.c
定义系统调用SYSCALL_DEFINE3(execve
只需转发至do_execve
。
do_execve
转发至do_execveat_common
。
do_execveat_common
要找到下一个主要函数,请跟踪返回值的retval
最后修改时间。
开始构建一个struct linux_binprm *bprm
来描述程序,并将其传递给exec_binprm
执行。
exec_binprm
再次按照返回值来寻找下一个主要调用。
search_binary_handler
+ 处理程序由可执行文件的第一个魔法字节决定。
最常见的两个处理程序是用于解释文件 ( `#!`magic) 和用于 ELF ( `ELF`magic) 的处理程序,但内核中还有其他内置处理程序,例如。用户还可以通过/proc/sys/fs/binfmt_misc`a.out`注册自己的处理程序
ELF 处理程序定义在`fs/binfmt_elf.c`。
另请参阅:为什么人们在 Python 脚本的第一行写 #!/usr/bin/env python shebang?
+ 该`formats`列表包含所有处理程序。
每个处理程序文件包含如下内容:
static int __init init_elf_binfmt(void)
{
register_binfmt(&elf_format);
return 0;
}
并在该文件中`elf_format`定义`struct linux_binfmt`。
`__init`是魔术的,并将该代码放入内核启动时调用的魔术部分:Linux 内核代码中的 __init 是什么意思?
链接器级依赖注入!
+ 还有一个递归计数器,以防解释器无限执行。
尝试一下:
echo '#!/tmp/a' > /tmp/a
chmod +x /tmp/a
/tmp/a
+ 我们再次跟踪返回值,看看接下来会发生什么,并看到它来自:
retval = fmt->load_binary(bprm);
其中,`load_binary`针对结构中的每个处理程序进行定义:C 风格多态性。
fs/binfmt_elf.c:load_binary
是否进行实际工作:
+ 根据ELF规范解析ELF文件,这里是ELF文件格式的概述:如何使用十六进制编辑器在Linux中制作可执行ELF文件?
+ 根据解析的 ELF 文件设置进程初始程序状态,最值得注意的是:
- 初始寄存器设置`struct pt_regs`
- 初始虚拟内存设置,内存在 ELF 段中指定:ELF 文件格式中 section 和 section 有什么区别
- 调用`start_thread`,标记该进程为可用进程,以便由调度程序进行调度
最终,调度程序决定运行该进程,然后它必须跳转到存储的 PC 地址,
struct pt_regs
同时转到权限较低的 CPU 状态,例如 Ring 3/EL0:在操作系统中,Ring 0 和 Ring 3 是什么?
调度程序会定期被时钟硬件唤醒,该时钟硬件会定期生成中断,如内核先前配置的那样,例如旧的 x86 PIT或ARM 定时器。内核还会注册处理程序,当触发定时器中断时,该处理程序会运行调度程序代码。
TODO:继续进一步分析源代码。我期望接下来发生什么:
内核解析ELF的INTERP头来找到动态加载器(通常设置为
/lib64/ld-linux-x86-64.so.2
)。如果存在:
+ 内核将动态加载器和要执行的 ELF 映射到内存中
+ 动态加载器启动,带入指向内存中 ELF 的指针。
+ 现在在用户空间中,加载器以某种方式解析 elf 头,并`dlopen`对其进行
+ `dlopen`使用可配置的搜索路径来查找这些库(`ldd`和相关库),将它们映射到内存中,并以某种方式通知 ELF 在哪里找到其丢失的符号
+ 加载器调用`_start`ELF 的
否则,内核将直接将可执行文件加载到内存中,而不使用动态加载器。
因此,它必须特别检查可执行文件是否为 PIE,以及是否将其放置在内存中的随机位置:gcc 和 ld 中位置无关可执行文件的 -fPIE 选项是什么?
解决方案 2:
Linux内核中的两个系统调用是相关的。fork系统调用(或者可能是或)用于创建新进程,类似于调用进程(每个 Linux 用户空间进程,除了由 或 朋友创建的进程)。execve系统调用用新的进程地址空间替换进程地址空间(本质上是通过从 ELF 可执行文件和匿名段中对段进行mmap操作,然后初始化寄存器,包括堆栈指针)。x86-64 ABI 补充和Linux 汇编指南提供了详细信息。vfork
`cloneinit
fork`
动态链接发生在文件之后execve
并涉及/lib/x86_64-linux-gnu/ld-2.13.so
文件,对于 ELF 来说,它被视为“解释器”。
解决方案 3:
阅读完已经引用的ELF 文档后,您应该阅读实际执行此操作的内核代码。
如果您难以理解该代码,请构建一个UML Linux,然后您可以在调试器中逐步执行该代码。
解决方案 4:
您可以从了解可执行文件格式开始,例如 ELF。http: //en.wikipedia.org/wiki/Executable_and_Linkable_Format
ELF 文件包含几个带有标题的部分,描述了二进制文件的各个部分如何以及在何处加载到内存中。
然后,我建议你阅读一下 Linux 中加载二进制文件和处理动态链接的部分,ld-linux。这也是对 ld-linux 的一个很好的描述:http ://www.cs.virginia.edu/~dww4s/articles/ld_linux.html
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件