编写汇编时使用哪个寄存器重要吗?

Does it matter which registers you use when writing assembly?

如果您正在编写汇编,您将值分配给哪个寄存器重要吗?比如,您将 accumulated/intermediate 值存储在 %ebx 而不是 %eax 中,后者通常用于此目的。那是不好的做法吗?会不会影响性能?

换句话说,你能把它们当作存储一样对待吗space,还是应该坚持将它们用于特定目的?

任何只有您的代码 运行ning 的地方,您都可以根据需要使用任何寄存器。然而,有两次前提是错误的:

  1. 您需要将堆栈指针用于其预期目的,或者当诸如信号处理程序之类的东西时 运行,它们会破坏实际上很重要的内存部分。

  2. 您的系统有一个调用约定。每当你调用其他人的库函数(或系统调用)时,你需要将参数放在他们想要的地方,他们会把 return 值放在标准位置,无论你想要它在哪里.

    您的调用约定还将让函数在不保存的情况下销毁某些寄存器:易失性与非易失性寄存器。例如通常 FLAGS、EAX、ECX 和 EDX 在 32 位 x86 调用约定中是易变的,而其余整数寄存器在 call 中保留到 ABI 兼容函数。请参阅 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64 了解系统调用和用户 space 函数调用约定。

If you're writing assembly, does it matter which registers you allocate values to?

对于 80x86;使用哪个 register/s 可能很重要的情况包括:

  • 遵守其他人的调用约定(在正确的寄存器中传递值,通过首选“调用者保存”寄存器避免堆栈用于“被调用者保存”)

  • 使用具有隐含寄存器的指令(MUL、DIV、MOVSQ/D/W/B、STOSQ/D/W/B、XLATB、AAA、CWD、... - 有很多其中)

  • 尝试在段不完全相同时避免段寄存器前缀的成本(例如 mov [ds:bp], ...mov [bx],...)。

  • 避免由于“MOD/RM”字段的限制而无法编码的地址计算(例如mov [di+si], ...)对于32/64位代码大多无关紧要,任何reg 可以是基数或(ESP/RSP 除外)索引。

  • 避免在 64 位代码中使用 REX 前缀(例如 mov ebx,1mov r8d,1

Say, you store an accumulated/intermediate value in %ebx instead of %eax, which was traditionally used for that purpose. Is that bad practice? Will it affect performance?

一般;没关系(这不是坏习惯,也不会影响性能);然而,这可能取决于周围的代码(稍后如何使用该值)并且可能会提高性能或降低性能。

更具体地说,即使所有寄存器都相同,也很难实现最佳寄存器分配(一个 NP 完全问题);和 80x86(在某些情况下所有寄存器都不相同)使得实现最佳寄存器分配变得更加困难。 (并将寄存器分配与指令调度联系起来,比如以不同的顺序执行操作,以最大限度地减少数据进/出寄存器的特定指令需要它们的位置。)

首先,您必须使用支持您要使用的指令的寄存器。 x86 上的许多指令(以及其他架构,虽然较少)对如何支持寄存器有一些限制。

以某双寄存器乘除指令为例,具体涉及到eax和edx的具体用途

接下来,您想要使用高效的寄存器,即寄存器:

  • 编码更短( 是关于 x64 指令长度的一个很好的讨论)。短编码可以更好地利用缓存资源,这可以让更大的程序 运行 更有效。

  • 不受阻碍,即由于调用约定,也就是说它们不会因使用而产生额外的(software/calling-convention 定义的)开销——除非该开销有已经付款了!

  • 这是所产生价值的最终目的地:例如如果是第二个参数,则对应于要传递的第二个值的寄存器(同样根据调用约定)。如果我们可以将值放在正确的寄存器中(根据传递或返回值的需要),那么我们就可以放弃数据移动(又名复制)指令。

Say, you store an accumulated/intermediate value in %ebx instead of %eax, which was traditionally used for that purpose. Is that bad practice? Will it affect performance?

在极少数情况下,它会影响性能。例如,对于 adc eax, imm32 指令,存在比其他寄存器的编码更短的特殊编码(参见 https://www.felixcloutier.com/x86/adc);汇编程序通常使用这种较短的编码。

但是,在最近的 Intel 处理器上,较短的编码需要更多的 µops 并且具有更高的延迟;见