汇编 MASM 字符串比较
Posted
技术标签:
【中文标题】汇编 MASM 字符串比较【英文标题】:Assembly MASM string comparison 【发布时间】:2017-10-26 22:47:53 【问题描述】:我正在准备汇编语言考试,我正在做我们老师给的例子。可悲的是我遇到了一个我不明白的问题。我的任务是编写一个简短的汇编程序,其中: 有两个字符串仅由拉丁字母的小写字母组成,以 ASCII 编码作为两个字节字符串放置在内存中。两个字符串都以值为 0 的字节结尾,字符串的位置是寄存器 ESI 和 EDI。比较两个字符串并以给定的方式设置标志 CF 和 ZF:
如果 ESI 字符串应该放在字典中的 EDI 字符串之前,则 CF=0 和 ZF=0
如果 ESI 字符串应该放在字典中的 EDI 字符串之后,则 CF=0 和 ZF=1
如果两个字符串相同,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)
编辑:我添加了一些评论
【问题讨论】:
出于某种原因,您正在比较双字而不是字节。你的代码也很难理解,你应该评论它并描述你的算法。 【参考方案1】:如果 ESI 字符串应该放在字典中的 EDI 字符串之前,则 CF=0 和 ZF=0
如果 ESI 字符串应该放在字典中的 EDI 字符串之后,则 CF=0 和 ZF=1
如果两个字符串相同,CF=0 和 ZF=1
这不等同于你在程序最后一行提到的!
; 1 - after(CF=1, ZF=0), 2 - before(CF=0, ZF=0), 3 - identical(CF=0, ZF=1)
让我们假设程序中的行是正确的。无论如何,这是人们对这种操作所期望的更合乎逻辑的标志设置。
下一个 sn-p 中的代码将自动设置所有请求的标志。不需要STC
、CLC
、MOV ECX, 2
DEC ECX
的所有恶作剧。
mov al, [edi + ebx]
cmp al, [esi + ebx]
ja before ;CF=0 ZF=0
jb after ;CF=1 ZF=0
; On equal you continu the loop that compares characters
; if any are left...
请注意,在处理字符串的字符时,您处理的是 bytes,而不是您所写的 dwords。
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:
你没有为你的计数器计算最短字符串的长度!你在做相反的事情。当AL
小于或等于DL
时,会采用jbe
,这意味着您应该将AL
放入ECX
。
这是我设置计数器的版本:
movzx ecx, al ; Optimistically considering 1st text to be shortest
cmp al, dl
jbe compare ; Correct hunch
movzx ecx, dl ; So who's perfect?
compare:
push ecx mov ecx, dword ptr [edi+ebx] cmp dword ptr [esi+ebx], ecx ja after jb before pop ecx
在上面的 sn-p 中,您应该将 pop ecx
放在分支出来的行的上方。这样你就可以保持堆栈平衡。在这个简单的程序中,它会被忽视,但在以后的程序中,这种错误会给你带来很多担忧。
push ecx
mov ecx, dword ptr [edi+ebx]
cmp dword ptr [esi+ebx], ecx
pop ecx ; Keep a balanced stack
ja after
jb before
string1 db 'bies', 0 size1 = $ - string1 string2 db 'bies', 0 size2 = $ - string2
使用这些定义,您可以在长度中包含零终止符。您的代码不需要这个。写得更好:
string1 db 'bies', 0
size1 = $ - string1 - 1
string2 db 'bies', 0
size2 = $ - string2 - 1
push ecx ; remember the counter value, cause **i have no more free registers**
如果您将第一个字符串的长度放入DL
并将第二个字符串的长度放入DH
,您将拥有AL
来存储字符串中的每个字符。
【讨论】:
以上是关于汇编 MASM 字符串比较的主要内容,如果未能解决你的问题,请参考以下文章
需要帮助使用 masm 以 80x86 汇编语言连接两个字符串
在汇编代码 (MASM) 中的字符串中查找子字符串的更好形式?