Rust编译最小二进制文件出现冗余代码的原因及消除方法
Rust最小二进制编译与冗余机器码问题
测试程序配置与代码
.cargo/config
[target.x86_64-pc-windows-gnu] rustflags = ["-C", "link-args=-e _start -static -nostartfiles"]
Cargo.toml
[package] name = "r" version = "0.1.0" edition = "2021" [profile.release] panic = "abort" opt-level = "z" lto = true codegen-units = 1
main.rs
#![no_std] #![no_main] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } #[no_mangle] unsafe fn _start() -> isize { 42 }
操作步骤与问题现象
执行编译命令:
cargo build --target x86_64-pc-windows-gnu --release
提取.text段:
objcopy -j .text -O binary target/x86_64-pc-windows-gnu/release/r.exe r.bin
反汇编r.bin后得到冗余代码,超出预期:
% objdump -D -b binary -mi386 -Mx86-64 -Mintel -z r.bin r.bin: file format binary Disassembly of section .data: 00000000 <.data>: 0: b8 2a 00 00 00 mov eax,0x2a 5: c3 ret 6: 66 90 xchg ax,ax 8: ff (bad) 9: ff (bad) a: ff (bad) b: ff (bad) c: ff (bad) d: ff (bad) e: ff (bad) f: ff 00 inc DWORD PTR [rax] 11: 00 00 add BYTE PTR [rax],al 13: 00 00 add BYTE PTR [rax],al 15: 00 00 add BYTE PTR [rax],al 17: 00 ff add bh,bh 19: ff (bad) 1a: ff (bad) 1b: ff (bad) 1c: ff (bad) 1d: ff (bad) 1e: ff (bad) 1f: ff 00 inc DWORD PTR [rax] 21: 00 00 add BYTE PTR [rax],al 23: 00 00 add BYTE PTR [rax],al 25: 00 00 add BYTE PTR [rax],al 27: 00 .byte 0x0
预期仅保留核心代码:
% objdump -D -b binary -mi386 -Mx86-64 -Mintel -z r.bin r.bin: file format binary Disassembly of section .data: 00000000 <.data>: 0: b8 2a 00 00 00 mov eax,0x2a 5: c3 ret
问题解答
1. 地址0x6到文件末尾的机器码有什么作用?
这部分内容分为两类:
- 对齐填充字节:链接器默认会将代码段对齐到特定内存边界(如16字节或32字节),以此提升CPU执行效率。
66 90是16位空操作指令(NOP),属于对齐填充的一部分,剩余的无效字节也是对齐时补入的占位数据。 - 未被调用的panic函数代码:你定义的
panic函数(无限循环逻辑)虽不会被程序执行,但默认情况下链接器会将其包含在.text段中,这部分代码被反汇编器误解析为无效指令(实际是loop {}编译后的无限循环指令)。
2. 如何消除这些冗余代码?
可以通过以下步骤彻底清理:
- 开启链接器垃圾回收:修改
.cargo/config中的rustflags,添加--gc-sections参数,让链接器自动丢弃未被引用的代码段(如未调用的panic函数):[target.x86_64-pc-windows-gnu] rustflags = ["-C", "link-args=-e _start -static -nostartfiles -Wl,--gc-sections"] - 移除不必要的panic handler:如果程序逻辑完全不会触发panic,可删除
#[panic_handler]函数,同时保持Cargo.toml中panic = "abort"的配置,确保编译器不生成panic相关代码。 - 关闭不必要的内存对齐与保护:添加链接器参数减少填充字节,修改rustflags为:
[target.x86_64-pc-windows-gnu] rustflags = ["-C", "link-args=-e _start -static -nostartfiles -Wl,--gc-sections -Wl,--nmagic -Wl,-z,norelro"] - 编译后清理符号表:用
strip工具移除二进制中的符号信息,再提取.text段:strip target/x86_64-pc-windows-gnu/release/r.exe objcopy -j .text -O binary target/x86_64-pc-windows-gnu/release/r.exe r.bin
内容的提问来源于stack exchange,提问作者Xobtah
相关产品推荐
相关产品推荐

