(done) 解析 qemu-6.0.0 源码 (2) 寻找入口函数 main
寻找 ./output/qemu/bin/qemu-system-riscv64 的入口函数 main首先这个时代最好还是让 AI 帮忙做软件工程分析没有必要再去看构建系统这些东西。毕竟构建系统换了一代又一代 (Makefile, cmake, ninja, meson …)我们还是最好关注一些原理、设计哲学的东西而不是盯着构建系统不放。推荐的顺序是1.先让AI帮你找入口代码2.让AI在找的同时把可复现的步骤依据给你大概看看就行不需要全记住甚至不用复现要确认AI的结论对不对加个 printf(“here”); exit(0); 就行3.等待AI确实找错且多尝试几遍都没用的时候再去钻研这个构建系统、钻研那些古老的 trick不过为了保持严谨度这里我们还是复现一遍古法 trick 寻找入口函数 main 的流程。古法软件工程 trick 开始 ------- !!!首先看 build.shSHELL_FOLDER$(cd$(dirname$0);pwd)cdqemu-6.0.0if[!-d$SHELL_FOLDER/output/qemu];then./configure--prefix$SHELL_FOLDER/output/qemu --target-listriscv64-softmmu --enable-gtk --enable-virtfs --disable-giofimake-j16makeinstallcd..可以看到有 make -j16 和 make install根据经验是的根据一种非常普遍的开源项目非成文惯例同时有 make -j16 和 make install 说明 ./output/qemu/bin/qemu-system-riscv64 不是原始构建产物原始构建产物在其它地方./output/qemu/bin/qemu-system-riscv64 是被处理后放在这里的。通常原始构建产物包含调试信息./output/qemu/bin/qemu-system-riscv64 这种最终构建产物不包含。可以使用find.-nameqemu-system-riscv64去找原始构建产物实际上很容易找到在 qemu-6.0.0/build/qemu-system-riscv64。运行fileqemu-6.0.0/build/qemu-system-riscv64\output/qemu/bin/qemu-system-riscv64会发现 qemu-6.0.0/build/qemu-system-riscv64 是with debug_info, not stripped而 output/qemu/bin/qemu-system-riscv64 是stripped也就是前者带调试信息后者不带。接下来使用readelf-hqemu-6.0.0/build/qemu-system-riscv64(output/qemu/bin/qemu-system-riscv64 也行一样的)\|grep-EType:|Machine:|Entry point得到Type: DYN (Position-Independent Executable file) Machine: Advanced Micro Devices X86-64 Entry point address: 0x2bf900也就是程序入点是 0x2bf900当然了这是虚拟地址空间的地址。对了这里有个有趣的地方你会发现 qemu-system-riscv64 的 Type 是 PIE。 根据我的理解PIE 汇编指令会拖慢性能。Linux 本身为应用层程序提供了独立地址空间按理来说不需要 PIE直接 ET_EXEC 就行了可以避免 PIE 带来的性能开销。可这里却把 qemu-system-riscv64 编译成了 PIE 类型为什么呢原因是为了防御 ROP (return-oriented programming) 攻击现代操作系统一般会采用 ASLR 防御机制应用程序普遍使用 PIE 类型是为了配合 ASLR 机制。接下来运行下面的命令nm-anqemu-6.0.0/build/qemu-system-riscv64 这里如果用 output/qemu/bin/qemu-system-riscv64 会显示没有符号因为已经被 stripped 了\|grep-E (_start|main)$会得到结果00000000002be650 T main 00000000002bf900 T _start说明一开始执行的是 _start 程序。执行objdump-d--disassemble_start\qemu-6.0.0/build/qemu-system-riscv64得到qemu-6.0.0/build/qemu-system-riscv64 qemu-6.0.0/build/qemu-system-riscv64: file format elf64-x86-64 Disassembly of section .init: Disassembly of section .plt: Disassembly of section .plt.got: Disassembly of section .plt.sec: Disassembly of section .text: 00000000002bf900 _start: 2bf900: f3 0f 1e fa endbr64 2bf904: 31 ed xor %ebp,%ebp 2bf906: 49 89 d1 mov %rdx,%r9 2bf909: 5e pop %rsi 2bf90a: 48 89 e2 mov %rsp,%rdx 2bf90d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 2bf911: 50 push %rax 2bf912: 54 push %rsp 2bf913: 45 31 c0 xor %r8d,%r8d 2bf916: 31 c9 xor %ecx,%ecx 2bf918: 48 8d 3d 31 ed ff ff lea -0x12cf(%rip),%rdi # 2be650 main 2bf91f: ff 15 c3 f6 ad 00 call *0xadf6c3(%rip) # d9efe8 __libc_start_mainGLIBC_2.34 2bf925: f4 hlt Disassembly of section .fini:可以看到 _start 函数后面调用了 main 函数。接下来运行下面的命令addr2line-eqemu-6.0.0/build/qemu-system-riscv64(这里不能用 output/qemu/bin/qemu-system-riscv64因为没符号)\-f-C0x2be650就能直接看到 main 符号来自具体哪个文件的第几行qemu-6.0.0/build/../softmmu/main.c:48稍微补充一下qemu-6.0.0 构建系统里用到了 meson所以实际上可以在 quard_star_tutorial 文件夹下执行meson introspect--installedqemu-6.0.0/build|grepqemu-system-riscv64会得到非常长的一行往上翻一翻会看到红色高亮的quard_star_tutorial/qemu-6.0.0/build/qemu-system-riscv64: quard_star_tutorial/output/qemu/bin/qemu-system-riscv64说明这两者被 meson 映射了前者是原始构建产物后者是 make install 后的安装产物。我们做个实验在 qemu-6.0.0/softmmu/main.c : main 函数开头加个日志 “hello from MEEEE!!!”运行 ./output/qemu/bin/qemu-system-riscv64 时成功打印上述日志说明我们找对了。到此qemu-system-riscv64 的入口 main 已经被我们找到就是 qemu-6.0.0/build/…/softmmu/main.c:48
上一篇/下一篇内容由系统自动关联
返回资讯列表 →