【问题标题】:What's the best way to remember the x86-64 System V arg register order?记住 x86-64 System V arg 寄存器顺序的最佳方法是什么?
【发布时间】:2021-01-01 15:06:02
【问题描述】:

我经常忘记需要为系统调用中的每个参数使用的寄存器,每次忘记时我都会访问this 问题。

整数/指针参数到 x86_64 用户空间函数调用的正确顺序是:
%rdi、%rsi、%rdx、%rcx、%r8 和 %r9。 (可变参数函数取 AL = FP args 的数量,最多 8 个)

或者对于系统调用,%rax(系统调用编号)和相同的参数,除了%r10 而不是%rcx。

记住这些寄存器的最好方法是什么,而不是每次都用谷歌搜索这个问题?

【问题讨论】:

    标签: assembly x86-64 cpu-registers calling-convention abi


    【解决方案1】:

    如果您还记得 C memcpy 的 arg 顺序,以及 rep movsb 的工作原理,那么这就是记住 x86-64 System V 的大部分方法。

    该设计使memcpy(dst, src, size) 与rep movsb 一起实现起来很便宜,除了在更多功能中未使用RCX,因为它更频繁地用于可变计数移位,而不是任何需要RDX。

    那么 R8 和 R9 是前两个“高”寄存器。使用它们需要一个 REX 前缀,这会在指令中花费一个额外字节的代码大小,否则就不需要一个。因此,它们是最后 2 个参数的明智选择。 (Windows x64 同样选择使用 R8、R9 作为最后 2 个寄存器参数)。


    实际的设计过程涉及最小化指令数和代码大小的成本权衡,以使用当时的 AMD64 GCC 端口编译某些东西(可能是 SPECcpu)。我不知道 inlining memcpy as rep movsb 是否相关,或者 glibc 当时是否真的以这种方式实现了它,或者是什么。

    我在Why does Windows64 use a different calling convention from all other OSes on x86-64? 上的回答引用了调用约定设计决策的一些来源。 (来自 GCC 开发人员的早期 x86-64.org 邮件列表帖子,尤其是 Jan Hubicka,他在提出这个之前尝试了一些注册命令。)

    要记住 RDX,RCX 部分订单的特别注意事项是以下引用:

    我们试图在序列的早期避免 RCX,因为它是寄存器 常用于特殊用途,如 EAX,因此具有相同的用途 在序列中丢失。它也不能用于系统调用和 我们想让系统调用序列匹配函数调用序列 尽可能的。


    用户空间与系统调用的区别:

    R10 在系统调用约定中替换了 RCX,因为 syscall 指令本身会破坏 RCX(使用它来保存 RIP,避免使用用户空间堆栈,并且它不能使用内核堆栈,因为它将堆栈切换到软件)。就像它如何使用 R11 来保存 RFLAGS。

    保持它尽可能相似允许 libc 包装器只使用mov %rcx, %r10,而不是在多个 args 上洗牌以填补空白。 R10 是 R8 和 R9 之后的下一个可用寄存器。


    替代方案:助记符:

    Diane's silk dress costs $89

    (the CS:APP blog建议)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-10
      • 2019-02-12
      • 2018-10-17
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多