gpt4 book ai didi

assembly - 常规使用 r10 和 r11 的可接受性

转载 作者:行者123 更新时间:2023-12-04 13:21:55 25 4
gpt4 key购买 nike

我最近做了很多 x64 汇编编程(在 Linux 上)
用于与我的 C/C++ 程序集成。

因为我最关心的是效率,所以我喜欢尽可能少地使用不同的 regs/内存地址,并且尽量不创建任何堆栈帧或保留寄存器(每个周期计数)。

根据 cdecl r10 和 r11 寄存器未保留,我希望将它们用作函数中的临时变量,最好不保留。
它是否会导致任何编译器的不可比性问题/错误(到目前为止还没有遇到任何问题,但这是一个问题)?

最佳答案

x86-64 System V ABI 不会将其调用约定称为“cdecl”。这只是 x86-64 SysV 调用约定。字符串“cdecl”没有出现在 the ABI doc 中.
r11是一个临时的,又名调用破坏的寄存器。
r10也是一个被调用破坏的寄存器。 ABI 说“用于传递函数的静态链指针”,但 C 不使用它,gcc 和 clang 生成的代码可以自由使用 r10不保存/恢复它。 ABI 的寄存器使用列表表 r10未跨函数调用保留 所以叶函数总是可以破坏它。 ( Which registers to use as temporaries when writing AMD64 SysV assembly? )

gcc 确实使用 r10作为其 trampoline for function pointers to GNU C nested functions 的一部分, 用于指向外部作用域的堆栈帧的指针。栈上机器码的蹦床是hack,但这确实是一个静态链指针;适当支持嵌套函数的语言可能会让调用者意识到它(如 lambda/闭包)并在 r10 中传递一个值。使用指向嵌套函数的指针时。

非叶函数不需要传递它们的传入 r10给他们的 child ,除非他们是支持那种东西的语言(不是 C 或 C++)中的“嵌套函数”。 因此 r10也是纯临时在正常情况下。
r10r11不是传递参数的寄存器,与其他调用破坏的寄存器不同,因此“包装器”函数可以使用它们(尤其是 r11 )而无需保存/恢复任何内容。

在正常功能中,RBX、RBP 和 RSP 与 R12..R15 一起是调用保留的。所有其他人都可以在不保存/恢复的情况下被破坏。 (这包括 xmm/ymm0..15 和 zmm0..31、x87 堆栈以及 RFLAGS 中的条件代码)。

请注意 r8..15需要一个 REX 前缀,即使是 32 位操作数大小(如 xor r10d, r10d )。如果您有一些 64 位非指针整数,请确保将它们保存在 r8..r11 中,因为无论何时使用这些值,您总是需要一个 REX 前缀来表示 64 位操作数大小。

较小的代码大小通常不会更糟,有时有助于解码和 uop 缓存密度,以及 L1i 缓存密度。 RAX、RCX、RDX、RSI、RDI 应该是您临时注册的首选。 (除非您需要 64 位,否则请使用 32 位操作数大小。例如 xor eax,eax 是将 RAX 归零的正确方法。Silvermont 不将 xor r10,r10 识别为归零习语,因此使用 xor r10d,r10d 即使它没有'不节省代码大小。)

如果您确实用完了低寄存器,最好使用 r10/r11对于通常会与 64 位操作数大小(或 VEX 前缀)一起使用的东西。例如指向 64 位数据的指针或指向指针的指针。 mov eax, [r10]需要一个 REX 前缀,而 mov eax, [rdi]没有。但是mov rax, [rdi]mov r8, [r10]大小相同。

很难获得太多 yield ,因为您经常需要在不同的组合中同时使用不同的值,例如最终使用 cmp eax, r10d或者其他什么,但如果你想全力以赴优化,那么考虑代码大小。也许还要考虑指令边界在哪里以及它将如何适应 uop 缓存。

x86 tag wiki ,尤其是 http://agner.org/optimize/有关编写高效代码的提示。

关于assembly - 常规使用 r10 和 r11 的可接受性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49928950/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com