有什么办法可以缩短 AArch64 程序集中的机器码 Hello World 吗?

Is there any way to shorten this machine code Hello World in AArch64 assembly?

我正在为 Linux.

编写“Hello World”程序的已编译 AArch64 汇编文件

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

当前文件中的机器码(用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

这里有缩短任何内容的说明吗?

如果你不介意写一堆的话,ldp x0, x2, [sp], #16 将栈顶的两个单词 argcargv[0] 弹出到 x0 和 x2 中可能会起作用字符串后的二进制 [=13=] 字节(甚至其他垃圾)。

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

  • argc 将为 1,因此如果 运行 通常来自没有参数的 shell,那么它适用于 stdout fd。
  • argv 是指向堆栈内存的指针,因此是一个比 10 大得多的大整数,因此 write() 将读取字节,直到它到达未映射的页面。
    (Linux write 实际上确实将前面的字节复制到 fd,而不是 returning -EFAULT 如果在发生故障之前可以写入非零数量的字节。看起来它只会在到达后续页面时检查它们的可读性。 这是一个没有记录的实现细节,但是当前 Linux 实际上是这样做的,至少在 x86-64 上是这样。)

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

但没有必要 exit(0) 打印文本;任何退出状态都可以。 (如果你不介意 shell 的噪音,你甚至可以 ar运行ge 你的程序,这样它就会出现段错误,而不是进行退出系统调用,在第一个 [=29] 之后保存所有指令=]!)


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

但是如果你 运行 它带有一个 arg(不计算 shells 隐式传递的 argv[0]),它会打印到 stderr。使用 2 个或更多 args,它将尝试写入未打开的 fd 并写入 return -EBADF,正如您在 strace.

下看到的那样