为什么组装的可执行文件大小相同

Bul*_* M. 2 assembly x86-64 intel instructions

在x86_64架构中,可以将一些指令操作数组合更改为较短的组合以实现相同的效果,但可执行文件较小.例如,通常写:

xor eax, eax
Run Code Online (Sandbox Code Playgroud)

代替:

xor rax, rax
Run Code Online (Sandbox Code Playgroud)

我想测试它,在汇编中编写简单的程序:

    segment .text
    global main
main:
    push rbp
    mov rbp, rsp
    xor rax, rax ; line in question
    leave
    ret
Run Code Online (Sandbox Code Playgroud)

内置:

yasm -f elf64 -m amd64 -g dwarf2 main.asm; clang -o main main.o
Run Code Online (Sandbox Code Playgroud)

检查尺寸:

stat main
Run Code Online (Sandbox Code Playgroud)

拿到:

....
Size: 9184
...
Run Code Online (Sandbox Code Playgroud)

好的,将问题更改为:

xor eax, eax
Run Code Online (Sandbox Code Playgroud)

希望获得更小的可执行文件,但获得相同的9184字节大小.使用较短的指令表格为什么尺寸没有减少?

Pet*_*des 6

当目标文件链接在一起时,链接器在.text部分的末尾插入填充,main.o因此文本部分的crt0.o开头从16B对齐边界开始.

如果你像我建议的那样拆解你的二进制文件,你会看到这个:

$ objdump -Mintel -drw main
...
0000000000400500 <main>:
  400500:       55                      push   rbp
  400501:       48 89 e5                mov    rbp,rsp
  400504:       48 31 c0                xor    rax,rax
  400507:       c9                      leave  
  400508:       c3                      ret    
  400509:       0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]    <--- padding inserted by linker

0000000000400510 <__libc_csu_init>:
  400510:       41 57                   push   r15
  ...
Run Code Online (Sandbox Code Playgroud)

更改大小main()只会改变NOP填充的大小,直到通过16B边界.


有趣的是,如果你反汇编main.o,之后就没有填充ret,所以我认为NOP必须已被链接器插入.

使用readelf -aW main.o节目:

Section Headers:
  [Nr] Name       Type            Address          Off    Size   ES Flg Lk Inf Al
...
  [ 4] .text      PROGBITS        0000000000000000 000040 000009 00  AX  0   0 16
....
Run Code Online (Sandbox Code Playgroud)

如果没有-W,您可以看到完整的列名,而不是将它们打包在一行上.最后一列是"对齐".这就是yasm如何告诉链接器该对象的.text部分需要32B或链接器输出的文本段内的任何其他对齐.

加入ALIGN 4096前main:在的.text的对准柱具有4096导致的.o.它在链接二进制文件之前 将NOP填充添加到函数的末尾main,因此main位于0x00402000.这确实会改变二进制文件的大小.


fuz*_*fuz 5

使用该size命令可以找出二进制文件的大小.使用ls或stat不准确,因为二进制的部分被填充到2的幂(例如,到16的下一个倍数).

但是,在您的情况下,仍然没有区别,因为文本段from main.o被填充到16个字节的倍数,之后启动代码crt0.o被链接.因此代码大小没有差异.