【发布时间】:2023-03-25 15:51:01
【问题描述】:
我正在研究一个 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 替换为 ebx、ecx 或 edx 时,二进制文件会变大:
$ wc -c main
268 main
在比较目标文件的大小时,差异更大(480 对 496 字节)。发生这种情况的eax 寄存器有什么特别之处? NASM 是否在进行某种优化,即使已指定 -O0?
【问题讨论】:
-
你看了一下二进制差异吗?
-
当使用 EAX(有时是 AX 或 AL)作为寄存器时,一些特定的指令组合确实可以编码得更短。
-
如果要缩小尺寸,请改用
-Os -
@LưuVĩnhPhúc 我是创造这个谜题的人,所以我希望人们自己优化代码,而不是依赖一些自动优化:)
-
请注意,对于现代
ld,您还希望-n不将部分与页面边界对齐。
标签: assembly x86 compiler-optimization instruction-encoding