ASM空间优化:EAX vs EBX

4

我正在解决一个x86汇编代码高尔夫难题。我正在使用NASM汇编源文件:

nasm -f elf32 -O0 main.s
ld -m elf_i386 -s -O0 -o main main.o

使用-O0,所有优化都应关闭。目标是减小ELF二进制文件的大小。

在为难题编写“参考实现”时,我遇到了奇怪的行为。这是一个简化的代码示例:

section .text
    global _start        ; Must be declared for linker

_start:                  ; Entry point for linker

read_stdin:
    add    esp, 8        ; Ignore argc and argv[0] on stack
    pop    eax           ; Store pointer to 'argv[1]' into EAX
    mov    eax, [eax]    ; Dereference pointer
    and    eax, 0xff     ; We only want the least significant byte
    add    eax, -0x30    ; Subtract ascii offset

exit:
    mov    eax, 1        ; Syscall: sys_exit
    mov    ebx, 0        ; Exit code 0
    int    0x80          ; Invoke syscall

这个二进制文件大小为264字节:

$ wc -c main
264 main

现在,当我只是将read_stdin部分中所有的eax替换为ebxecxedx时,二进制文件变得更大了:

$ wc -c main
268 main

当比较目标文件的大小时,差异更大(480比496字节)。eax寄存器有什么特别之处导致出现这种情况?即使指定了-O0,NASM是否进行了某种优化?


你用二进制差异比较器看了吗? - Devolus
5
当使用EAX寄存器时,确实可以更短地编码一些特定的指令组合(有时也可以使用AX或AL寄存器)。 - 500 - Internal Server Error
1
如果你想要减小文件大小,你应该使用 -Os - phuclv
@LưuVĩnhPhúc 我是创建这个谜题的人,所以我希望人们能够自己优化代码,而不是依赖于某些自动优化 :) - Danilo Bargen
请注意,在现代的 ld 中,您还需要使用 -n 选项来避免将节对齐到页面边界。 - Peter Cordes
1个回答

10

EAX是累加寄存器。它有专门的单字节操作码,用于所有九个基本运算(ADD, ADC, AND, CMP, OR, SBB, SUB, TEST和XOR)。此外,MOV指令还有一个单字节操作码,用于将数据从常量内存位置移动到累加寄存器。

挑选英特尔寄存器的技巧


谢谢,那很有道理。我找到了几个相关的有用链接:http://www.swansontec.com/sregisters.html http://www.swansontec.com/sintel.html http://www.mathemainzel.info/files/x86asmref.html#add - Danilo Bargen
已更新以引用,抱歉。 - spudone
@DaniloBargen:奇怪的是NASM -O0 选择了 add eax, imm32 编码来处理 add eax, -0x30。这仍然比 add r/m32, imm32 更优化。(但是当然,如果你正常汇编,即使对于EAX,你也会得到 add r/m32, imm8,因为它更小。) 当然,如果你想手动优化,你可以使用movzx加载和/或 and al, 0x0f,如果你想假设输入是ASCII 0..9数字。无论如何,除非你希望人们手动编码指令来解决这个挑战,否则需要 -O0 将删除对 r/m32, imm8 编码的访问。 - Peter Cordes
1
还有相关的内容:x86/x64机器码高尔夫技巧,提供了许多关于通过选择寄存器、指令及其编码来节省代码大小的技巧。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接