Fra*_*kH. 5 assembly code-golf
以下32位x86 Linux程序打印一个任意长度的字符串(只要程序可以,无论如何),exit(0)然后执行:
.global _start ; notice on entry here, all regs but %esp are zero
_start:
call .L0 ; offset == strlen, provided by your assembler
.byte 'H','e','l','l','o',',',' ','W','o','r','l','d'
.L0:
pop %ecx ; ret addr is starting addr of string
mov -4(%ecx),%edx ; argument to `call`, 4 bytes: strlen
inc %ebx ; stdout == 1
movb $4, %al ; SYS_write == 4
int $0x80
xchg %eax,%ebp ; %ebp is still zero
xchg %eax,%ebx ; SYS_exit == 1, return value == 0
int $0x80
Run Code Online (Sandbox Code Playgroud)
如果一个人愿意牺牲位置独立性(相反,强制链接器插入字符串地址),而不关心程序返回零,可以将其归结为:
.global _start
_start:
movb $4, %al
inc %ebx
mov $.L0, %ecx ; this address is calculated when linking
movb $.Lend-.L0, %dl ; strlen, calculated by assembler
int $0x80
xchg %eax,%ebx
int %0x80
.L0:
.byte 'H','e','l','l','o',',',' ','W','o','r','l','d'
.Lend:
Run Code Online (Sandbox Code Playgroud)
这两个都可以通过组装/链接as --32 -o x.o x.S; ld -s -m elf_i386 x.o,并运行得很好.第二个是26字节的代码.如果您在打印后允许崩溃,Hello, World则保留最后两条指令,即23字节.那是我能走的最低点.
一直困扰着我的问题,是否有可能从中挤出几个字节?对我的纯粹猜测给出了这些可能的线索:
movw $.L0, %cx可以使用(保存一个字节)?jmp对已知(或通过汇编程序/链接器调用魔术创建)的位置执行8位偏移以包含exit(...)系统调用的必要指令,从而在xchg; int序列上保存一个字节?或者,可以证明这实际上是最小的表现良好(没有崩溃/返回代码为零)Linux/x86"Hello,World"?
澄清一下,问题不在于最小化ELF可执行文件的大小; 这方面的技术是众所周知的.我明确询问Linux 32位x86汇编程序的大小,该程序执行的编译代码与以下代码相同:
int main(int argc, char **argv)
{
puts("Hello, World");
exit(0); /* or whatever code */
}
Run Code Online (Sandbox Code Playgroud)
会做.
事实上,我会对任何不需要手动编辑ELF标题的事情感到高兴.如果你找到一种方法来填充"Hello, World"某些ELF对象并从汇编源引用它,只使用汇编器/链接器命令行和/或mapfile输入,我认为它足够有效,即使这增加了大小ELF可执行文件.我只是想知道打印"Hello,World"以及exit()之后的指令序列是否可以缩小.
问题是关于代码大小,而不是可执行文件大小.