x86-64 指令集、AT&T 语法、关于 lea 和括号的混淆 [英] x86-64 instruction set, AT&T syntax, confusion regarding lea and brackets
问题描述
我被告知 lea %rax, %rdx 是无效的语法,因为来源需要在括号中,即 lea (%rax), %rdx
I’ve been told that lea %rax, %rdx is invalid syntax as the source needs to be in brackets, i.e lea (%rax), %rdx
我想我显然误解了 lea 和括号的用途.
I think I’ve clearly misunderstood both lea and the purpose of brackets.
我认为 lea %rax, %rdx 会将存储在 %rax 中的内存地址移动到 %rdx,但显然这就是 lea (%rax), %rdx 所做的?
I thought that lea %rax, %rdx would move the memory address stored in %rax, to %rdx, but apparently this is what lea (%rax), %rdx does?
令我困惑的是,我认为括号表示访问内存中的地址,并获取该地址处的值.因此,通过使用方括号,lea 会将一个值从存储在 %rax 中的内存地址移动到目标寄存器中.
What confuses me is that I thought brackets signify going to an address in memory, and taking the value at that address. So by using brackets lea would be moving a value from the memory address stored in %rax into the destination register.
因此,为什么我认为 lea %rax, %rdx 会被使用,如果您只是想将存储在 %rax 中的地址移动到 %rdx 中
Hence why I thought lea %rax, %rdx would be used if you just wanted to move the address stored in %rax into %rdx
有人可以向我解释在 lea 指令的情况下括号的重要性吗?
Could someone explain to me the significance of brackets in the case of the lea instruction?
推荐答案
从不实际使用 lea (%rax), %rdx
.使用 mov %rax, %rdx
代替,因为 CPU 运行它更有效,并且两种方式都复制寄存器 值(无论该值是否为有效指针).
Never actually use lea (%rax), %rdx
. Use mov %rax, %rdx
instead because CPUs run it more efficiently, and both ways copy a register value (regardless of whether that value is a valid pointer or not).
LEA 只能在内存寻址模式下工作,不能在裸寄存器上工作.LEA 有点撤销"括号中,取地址计算的结果而不是该地址处的内存值.如果一开始就没有内存操作数,就不会发生这种情况.
LEA can only work on a memory addressing mode, not a bare register. LEA kind of "undoes" the brackets, taking the result of the address calculation instead of the value from memory at that address. This can't happen if there wasn't a memory operand in the first place.
这让您可以使用它对任意值进行移位/添加操作,无论它们是否是有效指针:对不是地址/指针的值使用 LEA? LEA 使用 内存操作数语法和机器代码来编码移位/加法操作使用 x86 的正常寻址模式编码,CPU 硬件已经知道如何解码.
This lets you use it to do shift/add operations on arbitrary values, whether they're valid pointers or not: Using LEA on values that aren't addresses / pointers? LEA uses memory-operand syntax and machine code to encode the shift/add operation into a single instruction, using x86's normal addressing-mode encoding that the CPU hardware already knows how to decode.
与 mov
相比,它就像一个 C 的 &
地址运算符.而且你不能取寄存器的地址.(或在 C 中,register
变量.)您只能使用它来撤消取消引用.
Compared to mov
, it's like a C &
address-of operator. And you can't take the address of a register. (Or in C, of a register
variable.) You can only use it to undo a dereference.
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,而不是展示任何东西实际上会或应该如何编译.
Of course if you asked an actual C compiler to compile that, you'd get mov %rax, %rdi
, not lea (%rax), %rdi
, even if it didn't optimize away the code. This is in terms of conceptual equivalents, using C syntax and operators to explain asm, not to show how anything would or should actually compile.
这篇关于x86-64 指令集、AT&T 语法、关于 lea 和括号的混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!