汇编MASM字符串比较

问题描述 投票:0回答:1

我正在准备汇编语言考试,正在做我们老师给的例子。可悲的是我遇到了一个我不明白的问题。我的任务是编写一个简短的汇编程序,其中: 有两个字符串仅由拉丁字母的小字母组成,以 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)

编辑:我添加了一些评论

assembly x86 masm eflags
1个回答
0
投票

首先,术语“双字节字符串”有点模糊。

这可能意味着每个字符应该是 16 位宽;如果是这种情况,那么您需要更改几件事:

  1. 使用
    dw
    而不是
    db
    存储字符串。
  2. 表达式
    $ - string1
    可能会为您提供字节,因此您必须将其除以 2 才能获取字符。
  3. 比较字符时,不能使用
    ecx
    ,因为这是一个32位寄存器。 你必须使用16位寄存器,例如
    cx
    。 (如果您要比较单字节字符,则必须使用 8 位寄存器,例如
    cl
    。)
  4. 从内存中获取字符时,您必须使用
    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
的意思是“如果设置了零标志并且未设置进位标志则跳转”,所以你已经准确地获得了标志如您所愿。

© www.soinside.com 2019 - 2024. All rights reserved.