Pointers x86汇编指针
我试着把我的思想集中在汇编中的指针上 以下两者之间的具体区别是什么:Pointers x86汇编指针,pointers,assembly,x86,Pointers,Assembly,X86,我试着把我的思想集中在汇编中的指针上 以下两者之间的具体区别是什么: mov eax, ebx 及 什么时候应该使用dword ptr[eax] 另外,当我尝试执行mov eax[ebx]时,我得到了一个编译错误,这是为什么?如前所述,将括号括在操作数周围意味着该操作数将被取消引用,就像它是C中的指针一样。换句话说,括号意味着您正在从中读取值(或将值存储到中)该内存位置,而不是直接读取该值 那么这个, mov eax, ebx 只需将ebx中的值复制到eax。在伪C表示法中,这将是:eax
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通常还允许您忽略操作数大小说明符,因为它知道变量的大小。不过,我还是建议你写得清晰一致。因此,如果myVar
是int
,您将执行以下操作:
mov eax, DWORD PTR [myVar] ; eax = myVar
或
这种表示法不是强类型的,并且不记得myVar
是DWORD
大小的内存位置
在解引用寄存器操作数时,根本不需要这个,因为寄存器的名称指示其大小al
和ah
总是字节大小,ax
总是单词大小,eax
总是DWORD
大小,rax
总是QWORD
大小。但是,如果您愿意的话,为了与内存操作数的注释方式保持一致,无论如何也可以包含它
另外,当我尝试执行moveax,[ebx]
时,我得到了一个编译错误,为什么会这样
嗯…你不应该。在MSVC的内联汇编中,这个汇编对我来说很好。正如我们已经看到的,这相当于:
mov eax, DWORD PTR [ebx]
这意味着ebx
指向的内存位置将被取消引用,并且DWORD
大小的值将被加载到eax
中
为什么我不能mova,[eax]
这不应该使“a”成为指向eax指向的任何地方的指针
不允许。不允许这种操作数组合。从中可以看出,基本上有五种可能性(忽略替代编码和段):
请注意,没有mov内存,内存,这正是您所尝试的
但是,您可以通过简单的编码使a
指向eax
所指向的内容:
mov DWORD PTR [a], eax
现在a
和eax
具有相同的值。如果eax
是指针,那么a
现在是指向同一内存位置的指针
如果要将a
设置为eax
所指向的值,则需要执行以下操作:
mov eax, DWORD PTR [eax] ; eax = *eax
mov DWORD PTR [a], eax ; a = eax
当然,这会重击指针,并将其替换为取消引用的值。如果您不想丢失指针,则必须使用第二个“scratch”寄存器;比如:
mov edx, DWORD PTR [eax] ; edx = *eax
mov DWORD PTR [a], edx ; a = edx
我意识到这一切都有点令人困惑。在x86 ISA中,mov
指令因大量潜在含义而过载。这是因为x86源于CISC体系结构。相比之下,现代RISC体系结构在分离寄存器移动、内存加载和内存存储方面做得更好。x86将它们全部塞进一条mov
指令中。现在回去修理已经太晚了;您只需熟悉语法,有时还需要再看一眼。mov eax,ebx
将寄存器ebx中的值移动到eax。mov[eax],ebx
将ebx中的32位值移动到eax指向的内存位置。好的,为了确保我正确理解这一点。以下代码:inta_asm{mov[a],eax
将存储在eax中的值复制到int a指向的内存位置?如果我继续打印a的值,我会看到存储在eax中的值吗?如果我改为执行以下操作:int a=5;_asm{mov[eax],a
那里发生了什么?eax是存储a的内存位置?还是存储5?@Duxa:没那么简单。如果我们假设a
amov DWORD PTR [a], eax
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