x86-64 指令集,AT&T 语法,关于 lea 和括号的混淆
x86-64 instruction set, AT&T syntax, confusion regarding lea and brackets
有人告诉我 lea %rax, %rdx 是无效语法,因为源代码需要放在括号中,即 lea (%rax), %rdx
我想我显然误解了 lea 和方括号的用途。
我以为 lea %rax, %rdx 会将存储在 %rax 中的内存地址移动到 %rdx,但显然这就是 lea (%rax), %rdx 的作用?
让我感到困惑的是,我认为括号表示转到内存中的一个地址,并获取该地址的值。因此,通过使用括号,lea 会将存储在 %rax 中的内存地址中的值移动到目标寄存器中。
因此我认为如果您只是想将存储在 %rax 中的地址移动到 %rdx 中,将使用 lea %rax、%rdx
有人可以向我解释括号在 lea 指令中的意义吗?
永远不要真正使用 lea (%rax), %rdx
。使用 mov %rax, %rdx
因为 CPUs 运行 它更有效,并且两种方式都复制寄存器 value (不管该值是否是有效指针或不)。
LEA只能工作在内存寻址模式下,不能工作在裸寄存器上。 LEA 有点“撤消”括号,采用地址计算的结果而不是该地址内存中的值。如果一开始就没有内存操作数,就不会发生这种情况。
这使您可以使用它对任意值执行 shift/add 操作,无论它们是否为有效指针: LEA 使用 内存-使用 x86 的正常寻址模式编码将 shift/add 操作编码为单个指令的操作数语法和机器代码 CPU 硬件已经知道如何解码。
与mov
相比,它就像一个C &
寻址运算符。而且您不能获取寄存器的地址。 (或者在 C 语言中,register
变量。) 你只能用它来取消引用。
register char *rax = ...;
register char dl = *rax; // mov (%rax), %dl
register char *rcx = rax; // mov %rax, %rcx
register char *rdi = &rax[0]; // lea (%rax), %rdi // never do this, mov is more efficient
register char *rbx = &rax[rdx*4 + 1234]; // lea 1234(%rax, %rdx, 4), %rbx // a real use-case
register char **rsi = &rax; // lea %rax, %rsi // ERROR: can't take the address of a register
当然,如果您要求实际的 C 编译器编译它,您会得到 mov %rax, %rdi
,而不是 lea (%rax), %rdi
,即使它没有优化代码。 这是概念上的等价物,使用 C 语法和运算符来解释 asm,而不是说明任何东西将或应该如何实际编译。
有人告诉我 lea %rax, %rdx 是无效语法,因为源代码需要放在括号中,即 lea (%rax), %rdx
我想我显然误解了 lea 和方括号的用途。
我以为 lea %rax, %rdx 会将存储在 %rax 中的内存地址移动到 %rdx,但显然这就是 lea (%rax), %rdx 的作用?
让我感到困惑的是,我认为括号表示转到内存中的一个地址,并获取该地址的值。因此,通过使用括号,lea 会将存储在 %rax 中的内存地址中的值移动到目标寄存器中。
因此我认为如果您只是想将存储在 %rax 中的地址移动到 %rdx 中,将使用 lea %rax、%rdx
有人可以向我解释括号在 lea 指令中的意义吗?
永远不要真正使用 lea (%rax), %rdx
。使用 mov %rax, %rdx
因为 CPUs 运行 它更有效,并且两种方式都复制寄存器 value (不管该值是否是有效指针或不)。
LEA只能工作在内存寻址模式下,不能工作在裸寄存器上。 LEA 有点“撤消”括号,采用地址计算的结果而不是该地址内存中的值。如果一开始就没有内存操作数,就不会发生这种情况。
这使您可以使用它对任意值执行 shift/add 操作,无论它们是否为有效指针:
与mov
相比,它就像一个C &
寻址运算符。而且您不能获取寄存器的地址。 (或者在 C 语言中,register
变量。) 你只能用它来取消引用。
register char *rax = ...;
register char dl = *rax; // mov (%rax), %dl
register char *rcx = rax; // mov %rax, %rcx
register char *rdi = &rax[0]; // lea (%rax), %rdi // never do this, mov is more efficient
register char *rbx = &rax[rdx*4 + 1234]; // lea 1234(%rax, %rdx, 4), %rbx // a real use-case
register char **rsi = &rax; // lea %rax, %rsi // ERROR: can't take the address of a register
当然,如果您要求实际的 C 编译器编译它,您会得到 mov %rax, %rdi
,而不是 lea (%rax), %rdi
,即使它没有优化代码。 这是概念上的等价物,使用 C 语法和运算符来解释 asm,而不是说明任何东西将或应该如何实际编译。