You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 21:14:58