Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pointers x86汇编指针_Pointers_Assembly_X86 - Fatal编程技术网

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