【问题标题】:nasm can't call function in functionnasm 不能在函数中调用函数
【发布时间】:2023-12-28 10:42:01
【问题描述】:

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

Putc 工作正常,但问题是在我在puts 中调用putc 后,putc 中的ret 不会返回到由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 不会返回到 puts

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

【问题讨论】:

  • 您可能过于频繁地推送 ebp 几次。这可能会破坏ret 的期望,即ip 在某种程度上是堆栈中的下一个项目
  • 这实际上是有道理的。 Tho,如果我想创建堆栈帧,我该怎么办?据我所知,这就是这样做的方法。我认为 ret 会为我完成清除堆栈框架的工作。如果没有,我可能不得不使用leave
  • ret 就是 x86 拼写 pop ip(或 32 位代码中的 pop eip)的方式。它并不神奇地知道返回哪里,[E/R]SP 必须已经指向一个返回地址。
  • 是的,但不应该调用push当前ip然后将ip更改为新地址?这就是你的评论让我有点困惑的地方。
  • 是的,call 推送当前的eip(所谓的返回地址)并跳转到被调用的地址,但是这个地址的第一件事就是你的@987654340 @,所以当你执行ret 时,eip 是从这个推送的ebp 加载的,而不是上面预期的返回地址

标签: assembly x86 nasm


【解决方案1】:

当你这样做时

push ebp
mov esp, ebp

esp 不再指向推送的ebp返回地址,这是在函数尾声中使用LEAVE 无法解决的问题。顺便说一句,LEAVE 应该与 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.

【讨论】: