用于比较未给出正确输出的字符串的汇编程序

Assembly program to compare strings not giving correct output

我正在尝试编写一个汇编程序来比较两个字符串并输出它们是否相等,我试图通过一个一个地增加变址寄存器并比较字符来做到这一点。

但是我的代码似乎有错误,因为我期待输出 Equal

但实际输出是:

Equal
NotEqual

代码:

%include "asm_io.inc"
segment .data
str1: db "ThisIsSomeString", 0
str2: db "ThisIsSomeString", 0
msg_eq: db "Equal", 10, 0
msg_neq: db "NotEqual", 10, 0

segment .text
        global  asm_main
asm_main:
    mov esi, str1
    mov edi, str2
    xor edx, edx              ; to clear edx for index addressing
loop:
    mov al, [esi + edx]
    mov bl, [edi + edx]
    inc edx
    cmp al, bl
    jne not_equal
    cmp al, 0                 ; check if we're at the end of string
        je equal
    jmp loop
not_equal:
    mov eax, 4                ; system call number (sys_write = 4)
    mov ebx, 1                ; stdout = 1
    mov ecx, msg_neq          ; message to print
    int 0x80                  ; issue a system call
    jmp exit
equal:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg_eq
    int 0x80
    jmp exit
exit:
    mov eax, 1                ; system call number (sys_exit = 1)
    mov ebx, 0                ; exit code
    int 0x80

您没有为 sys_write 提供长度。它需要写入edx中的字节数。它并不关心您尝试打印的字符串是一个以 nul 结尾的字符串。您可以通过保存您希望输出的消息的长度来解决问题,例如

segment .data
str1: db "ThisIsSomeString", 0
str2: db "ThisIsSomeString", 0
msg_eq: db "Equal", 10, 0
len_eq   equ $ - msg_eq
msg_neq: db "NotEqual", 10, 0
len_neq  equ $ - msg_neq

nasm中,$是当前语句之前的当前堆栈地址。因此,只需在声明字符串的地方使用 $ - string_before,就可以保存长度供以后使用 sys_write,例如

segment .data
str1: db "ThisIsSomeString", 0
str2: db "ThisIsSomeString", 0
msg_eq: db "Equal", 10, 0
len_eq   equ $ - msg_eq
msg_neq: db "NotEqual", 10, 0
len_neq  equ $ - msg_neq

segment .text
        global  _start
_start:

    mov esi, str1
    mov edi, str2
    xor edx, edx              ; to clear edx for index addressing
loop:
    mov al, [esi + edx]
    mov bl, [edi + edx]
    inc edx
    cmp al, bl
    jne not_equal
    cmp al, 0                 ; check if we're at the end of string
        je equal
    jmp loop
not_equal:
    mov eax, 4                ; system call number (sys_write = 4)
    mov ebx, 1                ; stdout = 1
    mov ecx, msg_neq          ; message to print
    mov edx, len_neq          ; length in edx
    int 0x80                  ; issue a system call
    jmp exit
equal:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg_eq
    mov edx, len_eq           ; length in edx
    int 0x80
    jmp exit
exit:
    mov eax, 1                ; system call number (sys_exit = 1)
    mov ebx, 0                ; exit code
    int 0x80

注意:不需要你的%include "asm_io.inc"声明)

另请注意,我已将您的 asm_main 替换为 _start 进行编译,并在我的盒子上将 运行 替换为 asm_main,只需根据需要将其改回即可。

示例输出

$ ./bin/strcmp32
Equal

正如 David C. Rankin 所说,sys_write 系统调用不像 C 中的 puts 那样工作——它不会写出以 NUL 结尾的字符串。相反,它需要您明确告诉它要写入多少个字符。它在 EDX 寄存器中接受这个参数。当您在 equal 处调用 sys_write 时,EDX 将等于被检查字符串中的字符数。由于测试字符串的长度为 16 个字符,并且您已经告诉 sys_write 在地址 msg_eq 开始打印字符,它会打印以下字符:

E
q
u
a
l
10
0
N
o
t
E
q
u
a
l
10

所见即所得!这里的关键是汇编程序将 msg_neq 紧跟在 msg_eq 之后,因此当 sys_write 跑完 msq_eq 的末尾时,它会继续进入 msg_neq .

我建议按如下方式修改您的代码:

%include "asm_io.inc"
segment .data
str1:    db "ThisIsSomeString", 0
str2:    db "ThisIsSomeString", 0
msg_eq:  db "Equal", 10, 0
msg_neq: db "NotEqual", 10, 0

segment .text
global  asm_main
asm_main:
    mov  esi, str1
    mov  edi, str2
    xor  edx, edx              ; to clear edx for index addressing
    ; Set up output assuming the strings are not equal:
    mov  ecx, msg_neq          ; message to print
    mov  edx, 9                ; number of characters to print (length of string)
loop:
    mov  al, [esi + edx]
    mov  bl, [edi + edx]
    inc  edx
    cmp  al, bl
    jne  print                 ; if string is not equal, skip straight to print
    test al, al                ; check if we're at the end of string
    jne  loop
    ; The strings were actually equal, so change output setup:
    mov  ecx, msg_eq           ; message to print
    mov  edx, 6                ; number of characters to print (length of string)
print:
    mov  eax, 4                ; system call number (sys_write = 4)
    mov  ebx, 1                ; stdout = 1
    int  0x80                  ; issue a system call
exit:
    mov  eax, 1                ; system call number (sys_exit = 1)
    xor  ebx, ebx              ; exit code
    int  0x80

除了通过在 EDX 中设置显式长度来修复此错误之外,我还重新安排了您的代码以减少分支数。这应该使它稍微更有效率,但更重要的是,它使它更具可读性。另请注意,我已将 cmp reg, 0 更改为 test reg, reg,即 . Similarly for .

Try it online!