【问题标题】:Is there any way to shorten this machine code Hello World in AArch64 assembly?有没有办法在 AArch64 程序集中缩短这个机器代码 Hello World ?
【发布时间】:2021-11-09 11:12:52
【问题描述】:

我正在为 Linux 编写“Hello World”程序的已编译 AArch64 程序集文件。

我已经成功地将它从 504 字节缩短到 124 字节。我能想到的唯一更“优化”的就是找到一些在一条指令中执行两个或多个任务的指令。

目前文件中的机器码(以asm表示)是这样的:

  mov x8, 64     // __NR_write
  adr x1, hello  //the string, I know the exact address
  mov x2, 10     //string length (actually only "HelloWorld")

j:
  mov x0, 0      // write to stdin happens to work
  svc 0
  mov x8, 93     // __NR_exit
  b j    //the branching saves me one instruction to exit with status = 0

这里有什么缩短的说明吗?

【问题讨论】:

  • 这是针对 Linux 的,对吧?构建到 ELF 可执行文件中?您是否将此代码打包到 ELF 标头或其他内容中,例如 muppetlabs.com/~breadbox/software/tiny/teensy.html
  • 是的,有很多重叠和写入标题
  • 如果您至少使用构建命令链接完整源代码,一些未来的读者可能会喜欢它。
  • 好吧,我不是在构建它,我是从手动创建的 hexdump 将原始字节写入文件
  • 这听起来不方便与使用 as 构建它(来自包括一些 .byte.word 指令的源)并使用 objcopy 将 .text 部分单独放入文件中。就像那个 x86 教程/文章是用 NASM 做的一样,它可以直接组装成一个平面二进制文件。

标签: assembly optimization arm64 code-size


【解决方案1】:

如果您不介意编写一堆二进制 \0 字节(或甚至其他垃圾)在你的字符串之后。

Linux 进程启动环境有指向argc 的堆栈指针,在其上方是argv[] 数组值。 (不是像main 那样指向argv 的指针;它的第一个双字是argv[0]argv[] 上方是env[]。)

  • argc 将为 1,因此它适用于 stdout fd,如果从没有参数的 shell 正常运行。
  • argv 是指向堆栈内存的指针,因此是一个比 10 大得多的大整数,因此 write() 将读取字节,直到它到达未映射的页面。
    (Linux write 实际上确实将前面的字节复制到 fd,如果在遇到错误之前可以写入非零数量的字节,则不返回 -EFAULT。它似乎只在到达后面的页面时检查它们的可读性. 这是一个没有记录的实现细节,但它是当前 Linux 实际所做的,至少在 x86-64 上是这样。)

假设它在没有参数的情况下运行,它甚至可能仍然以 0 状态退出。后增量寻址将使ldp 下一次迭代加载 x0 = argv[1] = NULL。 (env[0] 进入 x2;我们知道我们不会因为 env[] 就在堆栈区域的顶部读取,所以不会出现段错误。)

但不需要exit(0) 来打印文本;任何退出状态都可以工作。 (如果你不介意 shell 的噪音,你甚至可以安排你的程序,让它发生段错误而不是进行退出系统调用,在第一个 svc 0 之后保存所有指令!)


如果您通过手动 execve 运行没有 args 的程序,因此 argv[0] = 0,它将调用 write(0, hello, 0),因此不会打印任何内容。

但是如果你用一个 arg 运行它(不包括 shell 隐式传递的 argv[0]),它会打印到 stderr。如果有 2 个或更多 args,它会尝试写入未打开的 fd,并且 write 会返回 -EBADF,正如您在 strace 下看到的那样。

【讨论】:

  • 这个想法很好,但是,1)我将字符串存储在文件头中,没有更多字节空间,2)我必须以状态码 0 退出,这是条件,我为自己指定了
  • @gXLg:啊,那么你会被尾随垃圾卡住,除非你可以将它放在 FILESZ 在字符串末尾结束的段中,所以页面的其余部分被填充像 BSS 这样的零。但大概您的 ELF 程序标头中只有一个条目涵盖了该条目和可执行代码,而另一个条目会增加总大小。
  • 是的,我是,只有一个程序头,没有节头,程序头和文件头有16个字节重叠。仍然感谢您的时间,您投入其中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-01
  • 2020-11-17
  • 1970-01-01
相关资源
最近更新 更多