Linux内核之vmlinuz反汇编

本文介绍在Fedora上对Linux内核的vmlinuz进行反汇编的方法。先安装kernel - devel软件包,接着提取vmlinux,再对其反汇编,最后以tcp4_proc_init函数为例进行查看,还提及了内核符号表的相关文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文介绍在Fedora上对Linux内核的vmlinuz进行反汇编。如果内核是debug版本,可以用来查看某个函数的源代码。

1. 安装kernel-devel软件包

dnf -y install kernel-devel

2. 提取vmlinux

  • vmlinux是一个包括Linux kernel的静态链接的可运行文件。
  • vmlinuz是vmlinux经过gzip和objcopy制作出来的压缩文件。
/usr/src/kernels/$(uname -r)/scripts/extract-vmlinux /boot/vmlinuz-$(uname -r) > vmlinux

3. 反汇编vmlinux

objdump -D vmlinux > vmlinux.out

4.  查看vmlinux里的函数

这里以函数tcp4_proc_init为例。/proc/kallsyms存储了所有的内核符号表,/boot/System.map则存储了静态的内核符号表。有关System.map,请阅读这里

e.g.

root# grep tcp4_proc_init /proc/kallsyms
ffffffffa37dd330 t tcp4_proc_init_net
ffffffffa479d258 T tcp4_proc_init

root# grep tcp4_proc_init /boot/System.map-$(uname -r)
ffffffff817dd330 t tcp4_proc_init_net
ffffffff8279d258 T tcp4_proc_init

root# egrep -in ffffffff8279d258 vmlinux.out
8960512:ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
8960912:ffffffff8279d96d:       e8 e6 f8 ff ff          callq  0xffffffff8279d258

root# N=8960512
root# sed -n "$((N-5)),$((N+5))"p vmlinux.out
ffffffff8279d24e:       e8 7d 14 91 fe          callq  0xffffffff810ae6d0
ffffffff8279d253:       eb bd                   jmp    0xffffffff8279d212
ffffffff8279d255:       5b                      pop    %rbx
ffffffff8279d256:       5d                      pop    %rbp
ffffffff8279d257:       c3                      retq   
ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
ffffffff8279d25d:       48 c7 c7 40 ca 31 82    mov    $0xffffffff8231ca40,%rdi
ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
ffffffff8279d269:       e8 82 47 26 ff          callq  0xffffffff81a019f0
ffffffff8279d26e:       48 c7 c7 60 c8 31 82    mov    $0xffffffff8231c860,%rdi
ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590

函数tcp4_proc_init()的源代码如下:

/* https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/ipv4/tcp_ipv4.c?h=v4.16.9#n2392 */ 
2377  static int __net_init tcp4_proc_init_net(struct net *net)
2378  {
2379          return tcp_proc_register(net, &tcp4_seq_afinfo);
2380  }
2381  
2382  static void __net_exit tcp4_proc_exit_net(struct net *net)
2383  {
2384          tcp_proc_unregister(net, &tcp4_seq_afinfo);
2385  }
2386  
2387  static struct pernet_operations tcp4_net_ops = {
2388          .init = tcp4_proc_init_net,
2389          .exit = tcp4_proc_exit_net,
2390  };
2391  
2392  int __init tcp4_proc_init(void)
2393  {
2394          return register_pernet_subsys(&tcp4_net_ops);
2395  }
2396  
2397  void tcp4_proc_exit(void)
2398  {
2399          unregister_pernet_subsys(&tcp4_net_ops);
2400  }

从L2394,我们可以看出tcp4_proc_init()调用了函数register_pernet_subsys(), 重新查看vmlinux.out验证一下。

root# egrep 'T register_pernet_subsys' /boot/System.map-$(uname -r)
ffffffff8175a590 T register_pernet_subsys

root# sed -n "$N, $((N+20))"p vmlinux.out > /tmp/1
root# egrep -in retq /tmp/1
11:ffffffff8279d28a:    c3                      retq   

root# sed -n '1,11'p /tmp/1 | cat -n
     1  ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
     2  ffffffff8279d25d:       48 c7 c7 40 ca 31 82    mov    $0xffffffff8231ca40,%rdi
     3  ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
     4  ffffffff8279d269:       e8 82 47 26 ff          callq  0xffffffff81a019f0
     5  ffffffff8279d26e:       48 c7 c7 60 c8 31 82    mov    $0xffffffff8231c860,%rdi
     6  ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590
     7  ffffffff8279d27a:       85 c0                   test   %eax,%eax
     8  ffffffff8279d27c:       74 0c                   je     0xffffffff8279d28a
     9  ffffffff8279d27e:       48 c7 c7 c0 d0 14 82    mov    $0xffffffff8214d0c0,%rdi
    10  ffffffff8279d285:       e8 b4 c1 90 fe          callq  0xffffffff810a943e
    11  ffffffff8279d28a:       c3                      retq   
root# sed -n '1,11'p /tmp/1 | cat -n | egrep ffffffff8175a590
     3  ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
     6  ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590

 

参考资料:

转载于:https://www.cnblogs.com/idorax/p/11171394.html

<think>首先,用户的问题是:“linux kernel compile generate vmlinux but not vmlinuz”。用户提到在编译Linux内核时生成了vmlinux文件,但没有生成vmlinuz文件。我需要帮助用户找出原因和解决办法。 根据系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识。 用户可见层指令: - 回答结构清晰,逐步解决问题。 - 保证回答真实可靠。 参考站内引用: - 引用[1]:用户尝试安装RTLinux,但遇到编译错误。 - 引用[2]:解释了编译产物,如vmlinuxvmlinuz、bzImage等。 - 引用[3]:展示了如何生成bzImage和vmlinuz。 - 引用[4]:讨论了vmlinux的大小和位置。 - 引用[5]:描述了内核编译和安装步骤。 用户的问题核心是:编译生成了vmlinux但没有vmlinuzvmlinuz是压缩的内核镜像,通常用于引导。 从引用[2]: - vmlinux是未压缩的内核。 - vmlinuz是压缩的内核映像文件。 - bzImage是压缩的内核映像,通常用于x86架构。 - 编译过程生成vmlinux,然后通过压缩生成bzImage或zImage。 引用[3]显示:make bzImage 然后复制为vmlinuz。 引用[5]提到了内核编译步骤,包括生成initrd.img和grub更新。 可能的原因为什么没有生成vmlinuz: 1. 编译过程没有完成:可能编译在生成vmlinux后失败。 2. 配置问题:内核配置中可能没有启用压缩或指定了错误的输出格式。 3. 输出路径问题:vmlinuz可能被生成在arch/x86/boot/目录下,而不是根目录。 4. 缺少依赖:可能需要特定的工具,如gzip或objcopy。 5. 编译命令错误:用户可能没有运行make bzImage或make zImage。 解决方案: - 检查编译日志:查看是否有错误信息。 - 确保运行了正确的make目标:如make bzImage。 - 确认输出目录:vmlinuz通常位于arch/x86/boot/bzImage(对于x86),然后可能需要复制到/boot。 - 验证内核配置:确保配置正确。 回答结构: 1. **问题分析**:解释为什么可能没有生成vmlinuz。 2. **常见原因**:列出可能的原因。 3. **解决步骤**:提供逐步的解决办法。 4. **验证**:如何确认成功生成。 5. **生成相关问题**:在最后添加相关问题。 使用中文回答。 生成相关问题: - 例如:如何配置内核编译选项? - 如何解决内核编译错误? - 如何安装内核模块? 引用标识:在回答中引用站内内容时添加[^数字]。 现在,构建回答。</think>### Linux内核编译生成vmlinux但未生成vmlinuz的原因和解决方法 在编译Linux内核时,生成了`vmlinux`文件(未压缩的内核可执行文件)但未生成`vmlinuz`(压缩的内核引导镜像),这是一个常见问题。`vmlinux`是编译过程的中间产物,而`vmlinuz`(或其等效文件如`bzImage`)是最终用于系统引导的压缩镜像。下面我将逐步分析原因并提供解决方法,确保回答真实可靠,基于Linux内核编译的标准流程和参考信息。 #### 问题分析 - **为什么只生成vmlinux?** `vmlinux`是编译链接后生成的未压缩ELF格式内核文件,包含所有符号和调试信息。而`vmlinuz`是通过压缩`vmlinux`(或直接生成压缩镜像如`bzImage`)得到的引导文件。未生成`vmlinuz`通常表示编译过程未完成压缩步骤,或配置/工具问题导致压缩失败[^2]。 - **关键区别**: - `vmlinux`:未压缩、不可引导,用于调试(大小可达数百MB)。 - `vmlinuz`:压缩后的可引导镜像(通常基于`bzImage`或`zImage`),大小较小(如512KB以内),位于`arch/<arch>/boot/`目录下[^2][^4]。 - **常见症状**:编译日志显示成功生成`vmlinux`,但缺少`arch/x86/boot/bzImage`(或类似路径),或未自动复制为`/boot/vmlinuz-<version>`。 #### 可能原因 根据编译流程和参考信息,以下是常见原因: 1. **编译过程未完成**:运行`make`后未执行压缩步骤(如`make bzImage`),导致只生成`vmlinux`而跳过`vmlinuz`[^2][^3]。 2. **内核配置错误**:配置文件中未启用压缩选项(如未设置`CONFIG_KERNEL_BZIP2`或`CONFIG_KERNEL_GZIP`),或架构相关选项错误。 3. **输出路径问题**:`vmlinuz`等效文件(如`bzImage`)被生成在`arch/x86/boot/`目录,但未被复制到`/boot`目录,误以为缺失[^3][^4]。 4. **依赖工具缺失**:缺少压缩工具(如`gzip`、`objcopy`)或库文件,导致压缩步骤失败[^2][^5]。 5. **编译中断或错误**:编译日志中可能存在未处理的错误(如符号冲突或内存不足),但被忽略,只部分完成。 #### 解决步骤 按照以下步骤检查和修复问题,确保操作在Linux源码目录(如`/usr/src/linux-<version>`)进行。 1. **检查编译日志** 首先,查看编译输出日志,确认是否有错误: ```bash # 重新运行编译,捕获日志 make clean # 清理旧文件 make -j$(nproc) 2>&1 | tee compile.log grep -i "error" compile.log # 搜索错误 ``` 常见错误:缺少库(如`libssl-dev`)或工具(如`bc`),需通过包管理器安装(例如Ubuntu:`sudo apt install build-essential libncurses-dev bison flex libssl-dev`)[^2][^5]。 2. **运行正确的make目标** 确保执行压缩步骤生成`bzImage`(x86架构标准): ```bash make bzImage # 生成压缩镜像,输出为 arch/x86/boot/bzImage ``` 完成后,检查输出文件: ```bash file arch/x86/boot/bzImage # 应显示 "Linux kernel x86 boot executable bzImage" ls -l arch/x86/boot/bzImage # 确认文件大小(通常几百KB) ``` 如果成功,`bzImage`等效于`vmlinuz`,可手动复制到`/boot`[^3][^4]: ```bash sudo cp arch/x86/boot/bzImage /boot/vmlinuz-$(uname -r)-custom ``` 3. **验证内核配置** 检查配置文件(`.config`)是否支持压缩: ```bash make menuconfig # 或使用 make oldconfig ``` 确保以下选项启用: - `Processor type and features` → `Kernel compression mode` 设置为 `Gzip` 或 `Bzip2`。 - 确认架构正确(如x86选`CONFIG_X86_64=y`)。 保存后重新编译: ```bash make bzImage ``` 4. **解决依赖问题** 如果编译失败,安装常见依赖: ```bash # Ubuntu/Debian sudo apt update sudo apt install gcc make flex bison libelf-dev libssl-dev # CentOS/RHEL sudo yum groupinstall "Development Tools" sudo yum install elfutils-libelf-devel openssl-devel ``` 5. **完整编译和安装流程** 参考标准步骤确保所有环节完成[^5]: ```bash make clean make menuconfig # 配置 make -j$(nproc) # 编译所有,包括模块 sudo make modules_install # 安装模块 sudo make install # 自动生成vmlinuz并更新GRUB ``` `make install`会自动将`bzImage`复制为`/boot/vmlinuz-<version>`并生成`initrd.img`[^5]。 #### 验证成功 - 检查文件: ```bash ls /boot/vmlinuz-* # 应包含新版本 file /boot/vmlinuz-<version> # 输出应为 "bzImage" 或 "gzip compressed" ``` - 更新GRUB并重启: ```bash sudo update-grub # 或 grub2-mkconfig -o /boot/grub/grub.cfg sudo reboot ``` #### 注意事项 - **性能考虑**:编译大型内核时,内存不足可能导致失败,建议在4GB+ RAM环境中操作。 - **调试帮助**:如果问题持续,分享`compile.log`内容以便进一步分析。 通过以上步骤,大多数情况下能成功生成`vmlinuz`。如果编译日志显示特定错误,请提供详细信息以便针对性解决[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值