【问题标题】:Function is run multiple times, but only called once函数多次运行,但只调用一次
【发布时间】:2015-06-23 18:03:33
【问题描述】:

我正在编写一个 16 位实模式汇编应用程序。

这是代码的顶部:

org 100h
jmp start

%include "memory.asm"

str: db "aBc", 0
outstr: times 100 db 0

start:
    mov si, str
    mov di, outstr
    call english_to_morse
    jmp $

如你所见,我只给english_to_morse打了一次电话。

这是english_to_morse函数:

english_to_morse:
    pusha
    call str_to_lower

    pusha;             BREAKPOINT
    mov ah, 0Eh
    mov al, 'a'
    int 10h
    popa

.next:
    lodsb
    push si;                get_morse_from_alpha will trash SI

    cmp al, 0
    je .end
    cmp al, 'a'
    jl .next
    cmp al, 'z'
    jg .next

    call get_morse_from_alpha
    call print_morse_letter

    pop si
    jmp .next

.end:
    ret

正如您在此处看到的,此处完成的唯一循环是在.next 标签上;不是整个子程序。

但是,当我运行它时,输出如下:

a._  _..._._.

大约一百次(基本上,这只是一遍又一遍地打印,直到突然停止)。

我的目标是让这个函数只运行一次。


这是用 NASM 汇编器汇编并在 DOSBOX 中执行的。

【问题讨论】:

  • 我不能买两个 pusha 和一个 popa。不太合乎逻辑。

标签: assembly nasm


【解决方案1】:

english_to_morse 的开头有一个pusha,但在ret 之前没有对应的popa

【讨论】:

    【解决方案2】:

    我发现您的代码存在 2 个问题。

    • 正如 Michael 指出的那样,pushapopa 不匹配。
    • 你推 SI 寄存器太早了。

      1. jl .nextjg .next 都将继续推送一个永远不会弹出的额外 SI 寄存器!
      2. je .end 忘记弹出 SI 寄存器。

    既然您知道 get_morse_from_alpha 会破坏 SI,只需将 push si 直接放在它的调用上方即可。

    .next:
     lodsb
     cmp al, 0
     je .end
     cmp al, 'a'
     jl .next
     cmp al, 'z'
     jg .next
     push si;                get_morse_from_alpha will trash SI
     call get_morse_from_alpha
     call print_morse_letter
     pop si
     jmp .next
    .end:
     popa
     ret
    

    我不禁注意到您使用了签名比较。在这个小代码中,sn-p 并没有什么坏处,但如果你想考虑完整的 ASCII 范围 [0,255],这个习惯会给你带来麻烦。最好使用jbja

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2021-03-04
      • 2015-01-01
      相关资源
      最近更新 更多