Reputation: 3
I wrote a function designed to compare a 4 letter string against the first 4 letters in a buffer:
is_cmd:
; bx is the string address argument
push bx ; Push bx to stack
mov cx, [bx] ; and also move into cx
mov bx, BUFFER ; Reset BUFFER_INDEX
mov [BUFFER_INDEX], bx ; so it points to first 2 characters
mov bx, [BUFFER_INDEX]
cmp cx, [bx] ; Compare
jne is_cmd_no ; Jump if not equal
pop bx ; Retrive bx from stack
inc bx ; Move pointer to next 2 characters
mov cx, [bx] ; Move to cx
mov bx, [BUFFER_INDEX] ; Move BUFFER_INDEX into bx
inc bx ; and move to next 2 characters
cmp cx, [bx] ; Compare
jne is_cmd_no ; Jump if not equal
jmp is_cmd_yes ; Jump if equal both times
is_cmd_no:
mov ax, 1 ; Set ax to 1 so jz will not jump
ret
is_cmd_yes:
mov ax, 0 ; Set ax to 0 so jz will jump
ret
Here is an example of it's usage:
mov bx, REBOOT_CMD
call is_cmd
or ax, ax
jz reboot_cmd
And here are all the variables:
REBOOT_CMD:
db "rset",0
BUFFER_INDEX:
dw BUFFER
BUFFER:
times 80 db 0
BUFFER_END:
However when the string is not equal it causes the emulator (BOCHS) to hang. Why?
Upvotes: 0
Views: 739
Reputation: 2731
use AX for comparing, it's changed anyways; there's no need to clobber anything else; and let the CPU do the "pointer calculation", you can read from [BX+2], there's no need to change it
mov bx, REBOOT_CMD
call is_cmd
or ax, ax
jz reboot_cmd
is_cmd:
mov ax, [bx]
cmp ax, [BUFFER] ; [buffer] with [bx]
jne is_cmd_no
mov ax, [bx+2]
cmp ax, [BUFFER+2] ; [buffer+2] with [bx+2]
jne is_cmd_no
mov ax, 1 ; is_cmd_yes
ret
is_cmd_no:
xor ax, ax
ret
or even better, inline it into the use-case
is_reboot:
mov ax, [REBOOT_CMD]
cmp ax, [BUFFER] ; [buffer] with "rs"
jne no_reboot
mov ax, [REBOOT_CMD+2]
cmp ax, [BUFFER+2] ; [buffer+2] with "et"
jz reboot_cmd
no_reboot:
note: the 2 branches differ, first is a "jne", second a "jz" to the reboot case. it's like an "AND" in C, where the 2nd part of the expression is only evaluated, if the first had TRUE as result
if you feel like obfuscting if, even the "BUFFER db "rset",0" is obsolete, you could compare [BUFFER] with "rs" ( which is "s" + 0x100 * "r" = 0x7372 ) and [BUFFER+2] with "et" ( = "e" + 0x100 * "t" = 0x7465 ):
is_reboot:
cmp word ptr [BUFFER],0x7372 ; [buffer] with "rs"
jne no_reboot
cmp word ptr [BUFFER+2],0x7465 ; [buffer+2] with "et"
jz reboot_cmd
no_reboot:
Upvotes: 1
Reputation: 29052
A suggestion for checking if it is a command. Pay attention to the fact, that I assigned a ' TRUE' value of 1 to a match and a FALSE
value of 0 to a non-matching result. If you really like it the other way, just exchange mov ax,1
and xor ax, ax
in the code below. Also note that using BUFFER_INDEX
is not necessary.
is_cmd:
mov cx, [bx]
mov dx, [bx+2]
lea bx, BUFFER ; Reset BUFFER_INDEX to effective address of BUFFER
; -- mov [BUFFER_INDEX], bx ; so it points to first 2 characters
; -- mov bx, [BUFFER_INDEX] ; is redundant, because BX is already equal to BUFFER_INDEX
cmp cx, [bx] ; compare first two chars
je first_two_match
jmp is_cmd_no
first_two_match:
cmp dx, [bx+2] ; compare the second two chars
jne is_cmd_no
mov ax, 1 ; is_cmd_yes
ret
is_cmd_no:
xor ax, ax
ret
Upvotes: 0