移动字节指针和移动字指针有什么区别?
What is difference between move byte ptr, move word ptr?
我阅读了一些关于
的早期帖子
'What ptr does?'
'What [ ] does?'
但我发现对理解以下问题没有任何帮助?
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'??
在汇编中,语法取决于特定的汇编器。 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 06
是 MOV [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.[=13=]d. $"
这个词确实覆盖了两个字节,'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
这是 add r/m,imm
variants 中的一个,具体取决于数据大小)。
所以mov msg+1,...
只能是内存地址msg + 1
,在x86指令集中没有其他有意义的可能性。而数据大小byte
是从标签msg:
后使用的db
指令中扣除的,这是MASM和emu8086汇编器的特长,其他大多数汇编器不会link任何定义的标签(符号),其后使用指令,即普通汇编程序中没有 "types" 符号。对于那些 mov msg+1,'R'
可能以语法错误结尾,但不是因为左侧有问题,而是他们不知道 'R'
值应该有多大(多少字节)。
我个人最喜欢的 NASM 会报告另一个错误,因为它需要围绕内存访问的括号,所以在 NASM 中只有 mov [msg+2],...
是有效的(大小修饰符如"byte ptr" 在 MASM 中允许,但没有 "ptr":mov byte [msg+2],...
。但是在 MASM/emu8086 中,您使用的所有变体都是具有相同含义的有效语法,通过 16b 偏移产生内存引用。
汇编器也不会产生两条指令而不是一条指令(在某些汇编器中可能会有特殊的例外情况 "pseudo-instructions",它们被编译为多个本机指令,但这在 x86 汇编中并不常见)。
一旦你知道了目标CPU指令集,确实存在哪些指令,你就可以很容易地从模糊的语法中猜测出将产生哪条目标指令。
或者您可以轻松检查调试器反汇编 window,因为反汇编器将仅对特定指令使用单一语法方式,而不会意识到源格式的歧义。
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/memory 状态做什么,只需使用 emu8086 调试器即可。如果你在这种情况下这样做,你会在反汇编 window 中看到 msg+x
的所有这些变体确实编译到在原始 msg
内存上逐字节移动的内存地址。此外,如果您在 msg
地址打开一些内存视图(我希望 emu8086 有一个,我不使用它),您可以观察每次写入内存,它如何改变原始值,以及 WORD PTR
有效,因为你不确定。在调试器中观察通常比阅读这些关于堆栈溢出的长答案要容易得多...
关于PTR是干什么的: ... 不好解释,不好解释,整个"BYTE PTR"是MASM用的术语,不是解析它作为 BYTE,然后对 BYTE 执行一些 PTR,但它会将其解析为 "BYTE PTR" 并类似于 "okay, he want to address byte"。这就像单个关键字,但带有 space.
我阅读了一些关于
的早期帖子
'What ptr does?'
'What [ ] does?'
但我发现对理解以下问题没有任何帮助?
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'??
在汇编中,语法取决于特定的汇编器。 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 06
是 MOV [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.[=13=]d. $"
这个词确实覆盖了两个字节,'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
这是 add r/m,imm
variants 中的一个,具体取决于数据大小)。
所以mov msg+1,...
只能是内存地址msg + 1
,在x86指令集中没有其他有意义的可能性。而数据大小byte
是从标签msg:
后使用的db
指令中扣除的,这是MASM和emu8086汇编器的特长,其他大多数汇编器不会link任何定义的标签(符号),其后使用指令,即普通汇编程序中没有 "types" 符号。对于那些 mov msg+1,'R'
可能以语法错误结尾,但不是因为左侧有问题,而是他们不知道 'R'
值应该有多大(多少字节)。
我个人最喜欢的 NASM 会报告另一个错误,因为它需要围绕内存访问的括号,所以在 NASM 中只有 mov [msg+2],...
是有效的(大小修饰符如"byte ptr" 在 MASM 中允许,但没有 "ptr":mov byte [msg+2],...
。但是在 MASM/emu8086 中,您使用的所有变体都是具有相同含义的有效语法,通过 16b 偏移产生内存引用。
汇编器也不会产生两条指令而不是一条指令(在某些汇编器中可能会有特殊的例外情况 "pseudo-instructions",它们被编译为多个本机指令,但这在 x86 汇编中并不常见)。
一旦你知道了目标CPU指令集,确实存在哪些指令,你就可以很容易地从模糊的语法中猜测出将产生哪条目标指令。
或者您可以轻松检查调试器反汇编 window,因为反汇编器将仅对特定指令使用单一语法方式,而不会意识到源格式的歧义。
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/memory 状态做什么,只需使用 emu8086 调试器即可。如果你在这种情况下这样做,你会在反汇编 window 中看到 msg+x
的所有这些变体确实编译到在原始 msg
内存上逐字节移动的内存地址。此外,如果您在 msg
地址打开一些内存视图(我希望 emu8086 有一个,我不使用它),您可以观察每次写入内存,它如何改变原始值,以及 WORD PTR
有效,因为你不确定。在调试器中观察通常比阅读这些关于堆栈溢出的长答案要容易得多...
关于PTR是干什么的: