pointers - x86 汇编指针

标签 pointers assembly x86

我试图将我的思绪围绕在 Assembly 中的指针上。
究竟有什么区别:

mov eax, ebx
mov [eax], ebx
什么时候应该dword ptr [eax]应该使用?
同样,当我尝试做 mov eax, [ebx] 时我得到一个编译错误,这是为什么?

最佳答案

如前所述,将括号括在操作数周围意味着该操作数将被取消引用,就好像它是 C 中的指针一样。换句话说,括号意味着您正在从中读取值(或将值存储到)该内存位置,而不是直接读取该值。

所以这:

mov  eax, ebx

只需复制 ebx 中的值进入 eax .在伪 C 符号中,这将是:eax = ebx .

而这:
mov  eax, [ebx]

取消引用 ebx 的内容并将指向的值存储在 eax 中.在伪 C 符号中,这将是:eax = *ebx .

最后,这个:
mov  [eax], ebx

将值存储在 ebx 中进入eax指向的内存位置.同样,在伪 C 符号中:*eax = ebx .

此处的寄存器也可以替换为内存操作数,例如符号变量名称。所以这:
mov  eax, [myVar]

取消引用变量 myVar 的地址并将该变量的内容存储在 eax 中, 喜欢 eax = myVar .

相比之下,这个:
mov  eax, myVar

存储变量myVar的地址进入 eax , 喜欢 eax = &myVar .

至少,这是大多数汇编程序的工作方式。 Microsoft 的汇编器(称为 MASM)和 Microsoft C/C++ 编译器的内联汇编有点不同。它将上述两条指令视为等价的,基本上忽略了内存操作数周围的括号。

要在 MASM 中获取变量的地址,可以使用 OFFSET关键词:
mov  eax, OFFSET myVar

然而,即使 MASM 具有这种宽容的语法并允许您马虎,但您不应该这样做。当您想要取消引用变量并获取其实际值时,请始终包括括号。如果您使用正确的语法明确地编写代码,您将永远不会得到错误的结果,并且它会让其他人更容易理解。另外,它会迫使您养成以其他汇编程序期望的方式编写代码的习惯,而不是依赖 MASM 的“按我的意思做,而不是按我写的”拐杖。

说到“做我的意思,而不是我写的”的关键,MASM 通常还允许您省略操作数大小说明符,因为它知道变量的大小。但同样,我建议为了清晰和一致性而编写它。因此,如果 myVarint ,你会这样做:
mov  eax, DWORD PTR [myVar]    ; eax = myVar

或者
mov  DWORD PTR [myVar], eax    ; myVar = eax

这个符号是 necessary in other assemblers like NASM不是强类型的并且不记得 myVarDWORD -大小的内存位置。

在取消引用寄存器操作数时,您根本不需要这个,因为寄存器的名称表明了它的大小。 alah总是 BYTE -大小,ax总是 WORD -大小,eax总是 DWORD -大小,和 rax总是 QWORD -大小。但无论如何,如果您愿意,为了与您标记内存操作数的方式保持一致,包含它也没有什么坏处。

Also when I try to do mov eax, [ebx] I get a compile error, why is this?



嗯……你不应该。这在 MSVC 的内联汇编中对我来说很好。正如我们已经看到的,它等价于:
mov  eax, DWORD PTR [ebx]

and 表示 ebx 指向的内存位置将被取消引用,并且 DWORD -size 值将加载到 eax .

why I cant do mov a, [eax] Should that not make "a" a pointer to wherever eax is pointing?



不可以。这种操作数组合是不允许的。正如您从 the documentation for the MOV instruction 中看到的,基本上有五种可能性(忽略替代编码和段):
mov  register, register     ; copy one register to another
mov  register, memory       ; load value from memory into register
mov  memory,   register     ; store value from register into memory
mov  register, immediate    ; move immediate value (constant) into register
mov  memory,   immediate    ; store immediate value (constant) in memory

请注意,没有 mov memory, memory ,这就是你正在尝试的。

但是,您可以制作 a指向什么eax通过简单的编码指向:
mov  DWORD PTR [a], eax

现在 aeax具有相同的值(value)。如 eax是一个指针,然后 a现在是指向同一内存位置的指针。

如果要设置aeax 的值指向,那么您需要执行以下操作:
mov  eax, DWORD PTR [eax]    ; eax = *eax
mov  DWORD PTR [a], eax      ; a   = eax

当然,这会破坏指针并将其替换为取消引用的值。如果不想丢失指针,则必须使用第二个“暂存”寄存器;就像是:
mov  edx, DWORD PTR [eax]    ; edx = *eax
mov  DWORD PTR [a], edx      ; a   = edx

我意识到这一切都有些令人困惑。 mov指令在 x86 ISA 中具有大量潜在含义。这是由于 x86 作为 CISC 架构的根源。相比之下,现代 RISC 架构在分离寄存器-寄存器移动、内存加载和内存存储方面做得更好。 x86 将它们全部塞进一个 mov操作说明。现在回去修复已经太晚了;你只需要熟悉语法,有时需要再看一眼。

关于pointers - x86 汇编指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43769467/

相关文章:

assembly - 有条件地清除寄存器的无分支方式

arrays - 如何将数组从程序集传递到 C 函数

c# - 将 C++ 指针结构转换为 C#

带有在退出时自动释放的指针的 C++ 映射,如何处理删除

Linux 上的 C++/汇编 IDE

gcc - 使用 PPC 汇编器时为 "Error: operand out of range"

c - 将CPU和内存管理模型整合在一起

performance - 与缓存预取提示相反

c++ - const、指针、typedef 和星号

c++ - 如何获得指向虚拟成员函数的 "direct"函数指针?