MASM32中令人困惑的括号

12

我正在努力学习MASM32,并对以下内容感到困惑:

我以为括号是用于间接引用的,所以如果我有一个预定义变量

 .data
   item dd 42

然后

 mov ebx, item

将'item'的内容,即数字42,存放到ebx寄存器中

 mov ebx, [item]

将“item”的地址,也就是存储42的位置,放入ebx中。

但下面的代码在控制台应用程序中:

 mov ebx, item
 invoke dwtoa, ebx, ADDR valuestr 
 invoke StdOut, ADDR valuestr
 mov ebx, [item]
 invoke dwtoa, ebx, ADDR valuestr 
 invoke StdOut, ADDR valuestr

打印两次42。为了获取“item”的地址,我似乎需要

 mov ebx, [OFFSET item]
 invoke dwtoa, ebx, ADDR valuestr 
 invoke StdOut, ADDR valuestr

有人能解释一下MASM中方括号的作用,或者给我推荐一个好的参考资料吗。


这个问题的副本也指出了var2 dword var1会组合成var1的地址。这是唯一明智的行为,因为var1可能是extern,使得它在编译时不可用。幸运的是,在这种情况下允许使用offset var1,所以您总是可以使用明确的标记。 - Peter Cordes
1个回答

18

MASM在汇编语言中非常不同,因为它具有类型。由于您定义了符号item的方式,MASM知道它是类型为DWORD的内存位置。当您将其用作操作数时,它知道您(可能)意味着您希望获取存储在地址处的值,而不是地址的值。 因此,使用item[item]都可以,MASM假定您指的是后一个。 如果您真的想要项目的地址,那么您需要使用OFFSET item

另一方面,如果您使用item = 42定义item为常量,则mov ebx,item将加载立即值。由于存在歧义,您需要知道item是如何定义的,以确定它是立即操作数还是内存操作数。最好避免使用裸符号作为操作数。

我应该补充说明的是,当您只是使用符号或数字时,方括号[]对于MASM几乎没有任何意义。 它们只在您与寄存器一起使用它们时才有意义。以下是一些例子:

item    DD  42
const   =   43

    mov eax, item             ; memory operand (the value stored at item)
    mov eax, [item]           ; memory operand
    mov eax, OFFSET item      ; immediate operand (the address of item)
    mov eax, [OFFSET item]    ; immediate operand

    mov eax, const            ; immediate operand (43)
    mov eax, [const]          ; immediate operand
    mov eax, ds:[const]       ; memory operand (the value at address 43)
    mov eax, fs:30h           ; memory operand (the value at address 30h + fs base)
    mov eax, OFFSET const     ; immediate operand
    mov eax, [OFFSET const]   ; immediate operand

    mov eax, 42               ; immediate operand
    mov eax, ebx              ; register operand (the value of EBX)
    mov eax, [ebx]            ; indirect operand (the value pointed to by EBX)

如果没有寄存器,方括号只能表达您的意图。 如果您打算将符号用作内存操作数,则应在符号周围放置方括号,并在打算将符号用作立即值时使用OFFSET


如果您使用“mov eax,[esi + OFFSET item]”,MASM会做什么? 有效地址中存在寄存器是否会将其转换为加载而不是“mov r32,imm32”? - Peter Cordes
1
@PeterCordes 寄存器和方括号的组合使其成为内存操作数。因为寄存器与一个值相加,所以需要使用方括号。指令“mov eax, esi + OFFSET item”是非法的,因为它不能被编码为立即操作数或寄存器操作数,我相信你知道这一点。如果您想要该指令隐含的操作,即将item的偏移量添加到 ESI 中并将其存储在 EAX 中,则可以使用lea eax,[esi + OFFSET item]。我还要补充一点,即mov eax. [esi + item]与您的示例几乎具有相同的含义,只是如果 item 是标签,则必须是 DWORD 类型。 - Ross Ridge
我想我本来是想问这是一个加载错误还是语法错误,因为我真的很惊讶[OFFSET item]是一个立即数。当然[esi + OFFSET item]不能是imm32 :P 无论如何,好的,所以这是一个加载错误,需要使用方括号,谢谢。 - Peter Cordes
1
@PeterCordes 我撤销了你的编辑,因为它比你描述的要复杂一些。最近你关闭为重复问题的那个问题的问题在于跳转表标签被定义为 table:,使它成为一个 NEAR 符号(或者 MASM x64 版本称之为其他名称)。如果它被定义为 table QWORD ...,那么它就是一个 QWORD 符号,将使用间接跳转。无论如何,括号不会有任何影响,但符号的类型确实很重要。使用 QWORD PTR 通过更改地址的类型来解决问题,但通常这不是必要的。 - Ross Ridge
1
fs:30h 也是一个内存操作数,对吗?你只展示了 fs:[30h] 的形式。两条指令的区别:mov eax,dword ptr fs:[30h] 和 mov eax,large fs:30h 在解引用 PEB 中? 中有一个 mov eax, large fs:30h(可能是IDA语法),而提问者对于缺少 [] 感到困惑。(因此它可能是这个问题的重复)。 - Peter Cordes
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接