我正在尝试在 asm 中制作一个
strstr
类似物。但我正在挣扎。由于某种原因,代码没有输出任何内容。我想做的是:我将参数传递给堆栈上的 strstr 过程,然后在 strstr 的 inner_loop 中,我将指针指向我想要的第一个字符串的符号搜索,之后我调用 search 过程,在其中迭代两个字符串并比较它们的字符。
关于输入字符串的P.S - 它的第一个字节是它的最大长度;输入后的第二个字节将包含实际长度(输入的字符数)。这就是为什么我写
[bp+6]
和[bp+8]
。
assume cs:code, ds:data
data segment
newline db 0Dh, 0Ah, '$'
string1 db 100, 99 dup (0)
string2 db 100, 99 dup (0)
not_found_message db 'Not found', '$'
data ends
code segment
strstr proc
push bp
mov bp, sp
mov di, [bp+4]
add di, 2
mov si, [bp+6]
add si, 2
inner_loop:
mov al, [di]
cmp al, '$'
jne go_search
je failed1
go_search:
push di
push si
call search
pop ax
cmp ax, 1
je success1
inc di
jmp inner_loop
success1:
mov ax, di
pop bp
pop bx
pop dx
push ax
push bx
ret
failed1:
mov ax, -1
pop bp
pop bx
pop dx
push ax
push bx
ret
strstr endp
search proc
push bp
mov bp, sp
mov di, [bp+10]
mov si, [bp+12]
custom_loop:
mov al, [di]
mov bl, [si]
cmp bl, '$'
je success2
cmp al, '$'
je failed2
cmp al, bl
je match
jmp failed2
match:
inc di
inc si
jmp custom_loop
success2:
mov ax, 1
pop bp
pop bx
pop dx
push ax
push bx
ret
failed2:
pop bp
pop bx
pop dx
push ax
push bx
ret
search endp
start:
mov ax, data
mov ds, ax
mov dx, offset string1
xor ax, ax
mov ah, 0Ah
int 21h
push dx
mov dx, offset newline
mov ah, 09h
int 21h
mov dx, offset string2
xor ax, ax
mov ah, 0Ah
int 21h
push dx
mov dx, offset newline
mov ah, 09h
int 21h
call strstr
pop ax
cmp ax, -1
je not_found
print_result:
mov cx, 10
test ax, ax
jz check_done
check_done:
xor dx, dx
div cx
push dx
test ax, ax
jnz check_done
print_number:
pop dx
add dl, '0'
mov ah, 02h
int 21h
mov ah, 4ch
int 21h
not_found:
mov ah, 09h
mov dx, offset not_found_message
int 21h
mov ah, 4ch
int 21h
code ends
end start
我认为错误在于使用堆栈。
我认为错误在于使用堆栈。
确实,程序中的大多数错误都与您处理堆栈的方式有关。
strstr和search过程都是使用堆栈上的2个参数来调用的,但是这些过程错误地留下了它们的参数之一。这种情况发生在四个不同的场合。作为一个例子,请考虑:
success1: mov ax, di <- No need to transfer beforehand pop bp <- Restore BP pop bx <- Temporary removal of return address pop dx <- Removal of one of the arguments push ax <- Pushing the exit code push bx <- Restoring the return address ret <- The return address gets used
正确的顺序是:
success1:
mov [bp + 6], di ; Overwrite one of the arguments with the exit code
pop bp ; Restore BP
ret 2 ; Return and let the CPU remove the other argument for you
在 search 过程中,您甚至没有正确使用参数!
mov di, [bp+10] <- Return address of 'strstr' ??? mov si, [bp+12] <- One of the arguments of 'strstr' ???
正确的偏移量是:
mov di, [bp + 4] ; The second pushed argument
mov si, [bp + 6] ; The first pushed argument
为了更有意义,最好将两个过程的参数按相同的顺序推送:
push si ; Where to search
push di ; What to search
call search
因为 search 过程将 SI 和 DI 寄存器用于其自身目的,因此返回到 strstr 过程后,您将无法再正确继续 inner_loop!保留这些寄存器是有序的:
search proc
push bp ; Preserve BP
mov bp, sp
push si ; Preserve SI
push di ; Preserve DI
mov si, [bp + 6] ; Where to search
mov di, [bp + 4] ; What to search
custom_loop:
...
success2:
mov ax, 1
failed2:
mov [bp + 6], ax ; Overwrite with the exit code
pop di ; Restore DI
pop si ; Restore SI
pop bp ; Restore BP
ret 2
search endp
请注意,print_number代码忘记迭代堆叠的余数!您的结果是一个 16 位偏移地址,因此您可以预期数字最多有 5 位十进制数字。 使用 DOS 显示数字详细解释了如何转换和显示数字。
使用 DOS.BufferedInput 函数 0Ah 也可以得到改进。在缓冲输入如何工作中阅读所有相关内容。