我正在准备汇编语言考试,正在做我们老师给的例子。可悲的是我遇到了一个我不明白的问题。我的任务是编写一个简短的汇编程序,其中: 有两个字符串仅由拉丁字母的小字母组成,以 ASCII 编码为两个字节字符串放置在内存中。两个字符串都以值为 0 的字节结束,字符串的位置是寄存器 ESI 和 EDI。比较两个字符串并以给定方式设置标志 CF 和 ZF:
CF=0 且 ZF=0 如果 ESI 字符串应放在字典中的 EDI 字符串之前
CF=0 且 ZF=1 如果 ESI 字符串应放置在字典中的 EDI 字符串之后
如果两个字符串相同,则 CF=0 且 ZF=1
在我的代码中,它工作正常,直到我给出相同的字符串。我不知道为什么,但是当我给出相同的字符串时,程序说我的字符串不相同。我尝试过调试,所以我知道当我比较这些字符串的第三个元素时会发生这种情况,但我不明白为什么它假设它们不同,因为它们是相同的。我的条件似乎工作正常,因为如果我写 cmp [esi+counter] 和 [esi+counter] 它可以工作并输出数字 3,但对于 cmp [esi+counter] 和 [edi+counter] 它说它们是不同的(在我的案例输出数字 1)。我不知道问题出在哪里。有人可以解释一下发生了什么事吗?我必须与 MASM 合作。我使用的是VS17,程序是32位的。
这是我的代码:
.686
.model flat
public _main
extern _ExitProcess@4 : PROC
extern _MessageBoxA@16 : PROC
.data
window_title db 'Example 42', 0
string1 db 'bies', 0
size1 = $ - string1
string2 db 'bies', 0
size2 = $ - string2
output db 80 dup(?), 0 ; variable to output result
.code
_main PROC
mov esi, OFFSET string1
mov edi, OFFSET string2
mov al, OFFSET size1
mov dl, OFFSET size2
xor ebx, ebx ; set ebx = 0
cmp al, dl ; compare sizes i want shorter to be counter for comparsion loop
jbe second_as_counter ; case when bl is shorter - bl is counter
movzx ecx, al
jmp compare
second_as_counter:
movzx ecx, dl
compare:
cmp ecx, ebx ; im checking if strings are the same size, ebx starts as 0
je same ; if none of the others condition were fullfilled it means all the letter were the same
push ecx ; remember the counter value, cause i have no more free registers
mov ecx, dword ptr [edi+ebx] ; compare x element of both strings
cmp dword ptr [esi+ebx], ecx
ja after ; if letter in esi is bigger than letter in edi, it will be placed after edi in dictionary
jb before ; else edi is first
pop ecx ; return ecx previous value
inc ebx ; increment counter, to check next elemnt of string
jmp compare
after:
stc ; set carry flag
mov ecx, 2
dec ecx ; clear zero flag
mov byte ptr output, byte ptr '1' ; just an output to have a proof it works
jmp koniec
before:
clc ; clear carry flag
mov ecx, 2
dec ecx ; clear zero flag
mov byte ptr output, byte ptr '2'
jmp koniec
same:
cmp al, dl ; check if lenghts are the same
je identical
ja after
jmp before
identical:
clc ; clear carry flag
mov ecx, 1
dec ecx ; set zero flag
mov byte ptr output, byte ptr '3'
koniec:
push 0; MB_OK
push OFFSET window_title
push OFFSET output
push 0
call _MessageBoxA@16
push 0
call _ExitProcess@4
_main ENDP
END
; 1 - after(CF=1, ZF=0), 2 - before(CF=0, ZF=0), 3 - identical(CF=0, ZF=1)
编辑:我添加了一些评论
这可能意味着每个字符应该是 16 位宽;如果是这种情况,那么您需要更改几件事:
dw
而不是 db
存储字符串。$ - string1
可能会为您提供字节,因此您必须将其除以 2 才能获取字符。ecx
,因为这是一个32位寄存器。 你必须使用16位寄存器,例如cx
。 (如果您要比较单字节字符,则必须使用 8 位寄存器,例如 cl
。)mov ecx, dword ptr [edi+ebx*2]
。CF=0 且 ZF=0 如果 ESI 字符串应放在字典中的 EDI 字符串之前
CF=0 且 ZF=1 如果 ESI 字符串应放在字典中的 EDI 字符串之后
如果两个字符串相同,CF=0 且 ZF=1
最后两行都要求 CF=0 和 ZF=1,因此它们无法区分,因此问题陈述没有意义。
会有意义的是:
CF=0 且 ZF=0 如果 ESI 字符串应放在字典中的 EDI 字符串之前
CF=1 且 ZF=?字典中 ESI 字符串是否应放在 EDI 字符串之后
如果两个字符串相同,CF=0 且 ZF=1
(请注意,“?”我的意思是“不关心”。无论如何,这并不重要;如果设置了 CF,则 ZF 将not为零。)
比较后,CPU 设置 CF 和 ZF 标志如下:
CF = 1 如果无符号操作数 2 > 无符号操作数 1
如果操作数 1 = 操作数 2,则 ZF = 1
如您所见,
cmp
指令的行为与更正后的问题陈述的要求相匹配。太方便了!
因此,在比较两个字符之后,您可以使用“jump-if-zero”(
jz
)跳转到same:
,比较字符串的长度,否则您可以无条件跳转到末尾,因为标志已经包含您想要的值。
比较
same:
中字符串的长度时,不需要 je identical
,因为 je
的意思是“如果设置了零标志并且未设置进位标志则跳转”,所以你已经准确地获得了标志如您所愿。