nasm 无法在函数中调用函数

nasm can't call function in function

所以我最近又搬到 nasm 并尝试构建一些基本的东西(putc 和 puts)。

Putc 工作正常但问题是在我调用 puts 中的 putc 之后,putc 中的 ret 没有 return 到 puts 推入堆栈的 ip,因此在 puts 中不再执行更多指令(在 gdb 中调试了该部分)。

msg db "Welcome!", 0ah, 0dh, 0h

putc:
    push ebp
    mov esp, ebp
    
    mov ah, 0ah
    ; al is set before
    mov bh, 0
    mov bl, 0
    mov cx, 1

    int 10h
    ret

puts:
    push ebp
    mov esp, ebp
    
    mov ebx, msg
    dec ebx
puts_l:
    inc ebx
    
    mov al, [ebx]
    call putc

    cmp al, 0h
    jne puts_l

    ret

这显然不是最好的,但我想我在某处有误解。我可以想象寄存器会被 putc 覆盖,但这并不能说明为什么 putc 中的 ret 不会 return 到 puts

我还应该提到我正在使用 x86。

当你这样做时

push ebp
mov esp, ebp

esp不再指向被压入的ebpreturn地址,这是无法解决的问题通过使用 LEAVE in the function epilogue. BTW LEAVE should be paired with ENTER.

如果您确实需要堆栈帧(例如定义一个本地内存变量),框架可能如下所示:

Function:
    PUSH EBP    
    MOV EBP,ESP 
    SUB ESP,4   ; The local variable is now addressable as [ESP] alias [EBP-4].

    ; Here is the Function body which can use local variable(s).

    MOV ESP,EBP ; Discard local variable, ESP will point to the saved EBP. 
    POP EBP     ; Restore EBP which might be used as parent's frame pointer.
    RET

由于您的程序不使用局部变量,因此可能

mov esi, msg       ; Address of the ASCIIZ string.
call puts          
jmp $              ; Program ends here.

puts: ; Function which displays ASCIIZ string at ESI.
    lodsb         ; Load AL from [DS:ESI], increment ESI.
    cmp al, 0h
    je puts_2
    call putc     ; Display a nonzero character in AL.
    jmp puts
puts_2: ret

putc:  ; Function which displays a character in AL.
    mov ah, 0ah ; WRITE CHARACTER.   
    mov bh, 0   ; Videopage 0.
    mov bl, 0   ; Colour in graphic mode.
    mov cx, 1   ; Number of times to write character
    int 10h     ; Invoke BIOS videofunction.
    ret

msg db "Welcome!", 0ah, 0dh, 0h ; The displayed ASCIIZ string.