【问题标题】:What is difference between move byte ptr, move word ptr?移动字节ptr,移动字ptr有什么区别?
【发布时间】:2017-10-30 14:04:14
【问题描述】:

我阅读了一些关于
的早期帖子 “ptr 做什么?”
“[]做什么?”
但我发现对理解以下问题没有任何帮助?

Title : Program failed to comprehend
.model small
.stack 100h
.data
     Msg db 10,13, 'Zahid. $'   
.code
.startup
     ; Initialising data segment
      mov ax, @data
      mov dx, ax
    ;Before operation displaying message
     mov dx, offset msg
     mov ah,09h
     int 21h

      mov msg , 'A'          ; Writing on memory specified by msg thats OK -> A
      mov msg+1 , 'R'     ; Confusion as writing on memory specified by msg then add 1(not 8bits next address write) -> A
      mov [msg]+2, 'I'     ; confusion: Writing on memory specified by msg then add 2 value to that address write-> I
      mov byte ptr [msg+3] , 'F'      ; Ok with me, writing on byte memory specified by msg+3 -> F 
      mov word ptr [msg + 4], '.'      ; Confused again as writing on word memory specified by msg+4, '.' Will it write ascii on the two bytes-> .
      mov msg[5] , '$'   ; Not confused on this.

   ;Print var
    mov dx, offset msg
    mov ah,09h
    int 21h
 
    ;Exit Code.
    mov ah,04ch
    xor al,al
    int 21h
     
Ends

Output : Zahid. ARIF.

请解释一下操作,因为我认为它不应该打印'ARIF'??

【问题讨论】:

  • 您希望它打印什么?仅通过查看代码和 cmets 就很清楚,它应该打印类似 'Arif' 的内容(虽然我希望它是大写的)。甚至在代码中包含字符ARIF.
  • 输出应该是\n\rZahid. ARIF. 你要么没有发布确切的输出,要么是代码。编辑:实际上,您的 DOS 换行符 13,10 字节的顺序错误,因此输出将开始 \n\r,而不是 \r\n。你的问题到底是什么?
  • 为什么 mov [msg] +2 , 'I' 没有产生错误。因为 [msg] 将返回变量的地址,然后将其增加 2 并将该地址初始化为某个值不应在执行时产生 'i'
  • emu8086 和 MASM(以及 MASM 仿真模式下的 TASM)语法相当宽松,所有这些在 MASM 中都是等价的:mov msg+2,'I'mov [msg+2],'I'mov [msg]+2,'I'mov byte ptr [msg+2],'I'、@987654334 @,mov msg[2],'I'(不确定这个,我没有emu8086来验证)......基本上只要一侧是内存操作数,它就是内存操作数。查看 Intel 指令参考指南以查看有效的内存操作数,尤其是在 16 位实模式下,它们非常有限。 (不需要byte ptr,因为msg 是由db 定义的,MASM 承认这一点)
  • 相关:stackoverflow.com/questions/25129743/…。 “方括号[] 在您仅使用符号时对 MASM 几乎没有任何意义。它们仅在您将它们与寄存器一起使用时才有意义。” (MASM / TASM / emu8086 在这方面都一样,AFAIK)。

标签: assembly tasm emu8086


【解决方案1】:

在汇编中,语法取决于特定的汇编器。 Emu8086主要遵循MASM方言,规则相当宽松,允许多个不同的options (with same output)

如果你习惯了一些高级编程语言,这可能会让人感到困惑,为什么语法不是一成不变的以及如何在 asm 中忍受这种混乱。

但是对于 asm 程序员来说,这几乎不是问题,因为在汇编中您不会使用运算符和不同的值构建一些运行时表达式,来自源的指令通常 1:1 映射到 CPU 指令之一,具有确切的参数和CPU中存在的特定指令的选项。

x86 上的 MOV instruction 本身有点混乱,因为它是用于许多不同指令操作码的单个助记符“MOV”,但在您的示例中只使用了两条指令:MOV r/m8,imm8 和操作码 C6 用于存储字节值,MOV r/m16,imm16 使用操作码 C7 存储字值。在所有情况下,r/m 部分都是绝对偏移量的内存引用,这是在编译时计算的。

所以如果msg 是内存地址0x1000 的符号,那么您问题中的这些行编译为:

; machine code  | disassembled instruction from machine code

C606001041        mov byte [0x1000],0x41

将字节值0x41 ('A') 存储到地址ds:0x1000 的内存中。 C6 06MOV [offset16],imm8 指令操作码,00 10 字节是 0x1000 offset16 本身(小端序),最后 41 是 imm8 值 0x41。默认情况下,段ds 将用于计算完整的物理内存地址,因为该指令之前没有段覆盖前缀。

C606011052        mov byte [0x1001],0x52
C606021049        mov byte [0x1002],0x49
C606031046        mov byte [0x1003],0x46
C70604102E00      mov word [0x1004],0x2e
C606051024        mov byte [0x1005],0x24

剩下的行是同一个故事,在特定的内存偏移处写入字节值,在内存中逐个字节,覆盖它们中的每一行。

mov word ptr [msg + 4], '.'的细微差别,它的目标内存地址ds:0x1004与其他行类似,但存储的值为imm16,即word值,等于0x002E'.') ,所以使用了不同的操作码C7,立即数需要两个字节2E 00。这将用字节2E覆盖地址ds:0x1004的内存,用字节00覆盖ds:0x1005

因此,如果地址msg(在我的示例中为ds:0x1000)的内存位于开头:

0x1000: 0A 0D 5A 61 68 69 64 2E 20 24  ; "\n\rZahid. $"

每执行一次MOV 就会变成这个:

0x1000: 41 0D 5A 61 68 69 64 2E 20 24  ; "A\rZahid. $"
0x1000: 41 52 5A 61 68 69 64 2E 20 24  ; "ARZahid. $"
0x1000: 41 52 49 61 68 69 64 2E 20 24  ; "ARIahid. $"
0x1000: 41 52 49 46 68 69 64 2E 20 24  ; "ARIFhid. $"
0x1000: 41 52 49 46 2E 00 64 2E 20 24  ; "ARIF.\0d. $"

那个词确实覆盖了两个字节,'h'(带点)和'i'(带零)。

0x1000: 41 52 49 46 2E 24 64 2E 20 24  ; "ARIF.$d. $"

并且该零被再次覆盖为美元符号(DOS int 21h 服务 ah=9 的字符串终止符)。

通常宽松的语法不是问题,因为您无法构建自己的指令,汇编器会猜测现有的哪一个适合,并将您拥有的任何表达式编译到其中。 x86 上没有指令,例如 mov [address1] and [address2], value 在两个不同的内存位置存储相同的值,或者 mov [address]+2 会在 address 的内存值上加二(这可能与 add [address], 2 相关,这是 @987654323 中的一个@,取决于数据大小)。

所以mov msg+1,...只能是内存地址msg + 1,在x86指令集中没有其他有意义的可能性。并且数据大小byte 是从标签msg: 之后使用的db 指令中扣除的,这是MASM 和emu8086 汇编程序的特性,大多数其他汇编程序不会将任何定义的标签(符号)与之后使用的指令链接它,即普通汇编程序中没有符号的“类型”。对于那些mov msg+1,'R' 可能以语法错误结尾,但不是因为左侧有问题,而是他们不知道'R' 的值应该有多大(多少字节)。

我个人最喜欢的 NASM 会报告另一个错误,因为它需要围绕内存访问的括号,所以在 NASM 中只有 mov [msg+2],... 是有效的(在 MASM 中允许使用像“byte ptr”这样的大小修饰符,但没有“ptr ": mov byte [msg+2],...。但是在 MASM/emu8086 中,您使用的所有变体都是具有相同含义的有效语法,产生 16b 偏移量的内存引用。

汇编器也不会产生两条指令而不是一条指令(在某些汇编器中可能是特殊的“伪指令”,它们被编译成几条本机指令,但这在 x86 汇编中并不常见)。

一旦你知道了目标CPU指令集,存在哪些指令,你就可以很容易地从模糊的语法中猜出,会产生哪条目标指令。

或者您可以轻松地检查调试器反汇编窗口,因为反汇编器将只对特定指令使用单一的语法方式,而不知道源格式的歧义。

 mov word ptr [msg + 4], '.'
   ; Confused again as writing on word memory specified by msg+4,
     '.' Will it write ascii on the two bytes-> .

它将写入两个字节,这就是 MASM 中的WORD PTR 指定的。但值只有'.' = 0x2E。但是0x2E 即使作为 16 位值也是完全有效的,只需用零扩展为 0x002E,这就是汇编程序在这一行中使用的值。

将来,如果您不确定具体的组件如何组装,以及它将对 CPU/内存状态产生什么影响,请使用 emu8086 调试器。在这种情况下,您会在反汇编窗口中看到msg+x 的所有这些变体确实编译到原始msg 内存上逐字节的内存地址。另外,如果您要在msg 地址打开一些内存视图(我希望emu8086 有一个,我不使用它),您可以观察每次写入内存,它如何改变原始值,以及WORD PTR工作,因为你不确定。在调试器中观看通常比在堆栈溢出时阅读这些长答案要容易得多...

关于 PTR 的作用:In assembly, what does `PTR` stand for? ... 没有很好地解释它,因为很难很好地解释它,整个“BYTE PTR”是 MASM 使用的术语,它不会将其解析为 BYTE 然后对 BYTE 做一些 PTR 操作,但它会将其解析为“BYTE PTR”并且就像“好的,他想寻址字节”。这就像单个关键字,但带有空格。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2013-01-16
    • 1970-01-01
    • 2022-01-15
    • 2021-02-28
    相关资源
    最近更新 更多