用于比较未给出正确输出的字符串的汇编程序
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 .
我正在尝试编写一个汇编程序来比较两个字符串并输出它们是否相等,我试图通过一个一个地增加变址寄存器并比较字符来做到这一点。
但是我的代码似乎有错误,因为我期待输出 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
,即