C 在汇编中的 strstr() 类似物

问题描述 投票:0回答:1

我正在尝试在 asm 中制作一个

strstr
类似物。但我正在挣扎。由于某种原因,代码没有输出任何内容。我想做的是:我将参数传递给堆栈上的 strstr 过程,然后在 strstrinner_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

我认为错误在于使用堆栈。

string assembly search x86 tasm
1个回答
0
投票

我认为错误在于使用堆栈。

确实,程序中的大多数错误都与您处理堆栈的方式有关。

  • strstrsearch过程都是使用堆栈上的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 也可以得到改进。在缓冲输入如何工作中阅读所有相关内容。

© www.soinside.com 2019 - 2024. All rights reserved.