在Assembly中,比较两个字符串只需要一半的时间

deyfvvtc  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(117)

我做了一个程序,它可以比较用户输入和字符串。第一次输入ping时,它成功地完成了比较,并返回pong,但第二次它没有输出任何内容。第三次它再次开始工作,然后第四次它再次停止工作。可能是什么问题呢?下面是相关代码:

key_press:
  mov ah, 0x00
  int 0x16
  cmp al, 0x21
  jge compare
  jl other_chars
  jmp key_press

compare:
  cmp al, 0x7e
  jl print

print:
  pusha
  mov ah, 0x0e
  int 0x10
  popa
  mov [si], al
  inc si
  jmp key_press

other_chars:
  cmp ah, 0x1C
  je enter
  cmp ah, 0x39
  je space
  cmp al, 0x8
  je backspace
  jmp key_press

enter:
  pusha
  mov ah, 0x0e
  mov al, 0x0a
  int 0x10
  mov al, 0x0d
  int 0x10
  popa
  mov di, reserved
  mov bx, ping_command
  jmp loop1

loop1:
  cmp di, si
  je middle_loop1
  cmp byte [bx], 0
  je go_back_loop1
  mov ch, [di]
  cmp ch, [bx]
  jne go_back_loop1
;  pusha
;  mov ah, 0x0e
;  mov al, [di]
;  int 0x10
;  popa
  inc di
  inc bx
  jmp loop1

go_back_loop1:
  mov si, reserved
  mov bx, ping_command
  jmp key_press

middle_loop1:
  mov bx, pong
  pusha
  jmp print_ping

print_ping:
  cmp byte [bx], 0
  je go_back_print_ping
  mov ah, 0x0e
  mov al, [bx]
  int 0x10
  inc bx
  jmp print_ping

go_back_print_ping:
  mov al, 0x0a
  int 0x10
  mov al, 0x0d
  int 0x10
  popa
  jmp key_press

这是完整的代码:

org 0x7c00
bits 16

init:
  mov ah, 0x0e
  mov bx, string
  mov si, reserved
  jmp loop

loop:
  mov al, [bx]
  cmp al, 0
  je key_press
  int 0x10
  inc bx
  jmp loop

key_press:
  mov ah, 0x00
  int 0x16
  cmp al, 0x21
  jge compare
  jl other_chars
  jmp key_press

compare:
  cmp al, 0x7e
  jl print

print:
  pusha
  mov ah, 0x0e
  int 0x10
  popa
  mov [si], al
  inc si
  jmp key_press

other_chars:
  cmp ah, 0x1C
  je enter
  cmp ah, 0x39
  je space
  cmp al, 0x8
  je backspace
  jmp key_press

enter:
  pusha
  mov ah, 0x0e
  mov al, 0x0a
  int 0x10
  mov al, 0x0d
  int 0x10
  popa
  mov di, reserved
  mov bx, ping_command
  jmp loop1

loop1:
  cmp di, si
  je middle_loop1
  cmp byte [bx], 0
  je go_back_loop1
  mov ch, [di]
  cmp ch, [bx]
  jne go_back_loop1
;  pusha
;  mov ah, 0x0e
;  mov al, [di]
;  int 0x10
;  popa
  inc di
  inc bx
  jmp loop1

go_back_loop1:
  mov si, reserved
  mov bx, ping_command
  jmp key_press

middle_loop1:
  mov bx, pong
  pusha
  jmp print_ping

print_ping:
  cmp byte [bx], 0
  je go_back_print_ping
  mov ah, 0x0e
  mov al, [bx]
  int 0x10
  inc bx
  jmp print_ping

go_back_print_ping:
  mov al, 0x0a
  int 0x10
  mov al, 0x0d
  int 0x10
  popa
  jmp key_press

space:
  pusha
  mov ah, 0x0e
  mov al, ' '
  int 0x10
  popa
  mov byte [si], ' '
  inc si
  jmp key_press

backspace:
  pusha
  mov ah, 0x0e
  int 0x10
  mov al, ' '
  int 0x10
  mov al, 0x8
  int 0x10
  popa
  dec si
  jmp key_press

halt:
  hlt
  jmp halt

reserved resb 256
ping_command db "ping", 0
pong db "pong", 0
string db "Hello, World!", 0
times 510-($-$$) db 0
dw 0xAA55
tyu7yeag

tyu7yeag1#

在 * 函数 * go_back_print_ping中,jmp key_press应更改为jmp go_back_loop1,以便将si设置回reserved

This is the memory at `reserved` in the first/third/odd runs.

  di              si
|---|---|---|---|---|-----
| p | i | n | g | X | ...
|---|---|---|---|---|-----

X只是一个垃圾值,不管它是什么。
si直接指向“ping”的“g”之后的第一个字节,即X
di将不断递增,直到等于si。在这种情况下会发生什么?我们将得到一个je middle_loop1。如果您遵循middle_loop1的代码序列,您会注意到,在任何时间点si都不会被设置回reserved
因此,在第二次/第四次/偶数次运行中,这是reserved之后内存区域的状态

di                              si
|---|---|---|---|---|---|---|---|---|-----
| p | i | n | g | p | i | n | g | X | ...
|---|---|---|---|---|---|---|---|---|-----

si继续递增,将我们写入的第二个ping放在第一个之后。
现在,di将继续递增,但我们实际上是在比较上次写入的第一个ping,在这种情况下,cmp byte [bx], 0di等于si之前为真,使程序跳到go_back_loop1,这一次将si设置回reserved,但它不会打印任何内容,并将程序置于这样一种状态,即即使运行,bug也会继续发生。
实际上有多种方法可以解决这个问题,除了我建议的方法,还有其他问题。拿一张纸,了解所有寄存器的状态,看看会发生什么,这是一个非常有趣的练习,我认为这是理解问题的最好方法。祝你的项目好运。

相关问题