程序集 8086 - 从堆栈中压入和弹出寄存器不起作用

Assembly 8086- Pushing and popping registers from stack not working

我是初学者,出于某种原因,推动和弹出堆栈对我不起作用。我的引导程序:

org 0x7c00
bits 16
jmp main
print:
    pop bx
    mov al, [bx]
    mov ah, 0eh
    int 10h
    ret
main:
    mov bx, msg
    push bx
    call print

    cli
    hlt

    msg: db 'Hello World!', 0
    times 510 - ($-$$) db 0
    dw 0xAA55

我认为这应该做的是,将地址 msgbx 压入堆栈,然后将其检索到 bx。然而,情况似乎并非如此。 'H' 未打印。而是打印 '-'。如果我使用 msg 作为有效地址,它会起作用。

Edit:正如 Duncan 所指出的,call 指令将 return 地址压入我的堆栈顶部,这使得上述程序使用return BIOS 中断地址!我现在 pop return 地址变成 dx 然后 pop 变成 bx,使用 bxjmp 的值 dx完成后!

org 0x7c00
bits 16
jmp main
print:
    pop dx
    pop bx
    mov al, [bx]
    mov ah, 0eh
    int 10h
    jmp dx
main:
    mov bx, msg
    push bx
    call print

    cli
    hlt

    msg: db 'Hello World!', 0
    times 510 - ($-$$) db 0
    dw 0xAA55

call指令将程序计数器压入堆栈,ret从堆栈弹出顶部值并跳转到它。

因此您不能通过在调用之前将参数压入并在调用中弹出它们来将参数传递给函数,因为保存的 pc 会妨碍。

选项可能包括设置帧指针,以便您可以访问仍在堆栈中的参数,然后将它们作为 return 的一部分弹出。

或者对于这么简单的事情,您可以将 return 地址弹出到另一个寄存器中,而不是 return 您只需跳转到它。

jmp far 0:main 开始,规范化 cs:ip,因为有些 BIOS 会用 cs=0 调用你,有些会用 cs=0x07c0

print:
    pop bx
    mov al, [bx]
    mov ah, 0eh
    int 10h
    ret

也许你在 shell 漏洞中看到过类似的东西,但正确的用法是这样的:

    call print  ; this will put `msg` at top of stack!
msg: db 'H'
print:
    pop bx      ; load `msg` address
    ... no RET !! (there's nowhere to return to)

当你不知道你的代码将位于何处时,这是一个如何将正确的偏移量放入堆栈的技巧(shell exploit lands 通常进入一些缓冲区溢出区域,具有一些随机地址)。

这在引导加载程序中不需要,因为您处于固定位置 0000:7C00 并且您可以 assemble 那样,因此使用一些自定义 "pass argument value by register" 调用约定来调用自定义过程,例如 print 很好,根本不涉及堆栈(除了用它来存储 call + ret 对的 return 地址)。


在使用之前也初始化堆栈,即在 main 的开头你可能想要做的例子:

main:
    ; set ss:sp to 0000:7C00 (so you have about ~29kB of RAM for stack)
    xor ax,ax
    mov ss,ax       ; disables interrupts for 1 more instruction
    mov sp,0x7C00   ; so sp set must follow the `ss` setup

当然不要将它用于任何深度递归,29kB 是小堆栈(但足够用于合理编写的引导加载程序,从磁盘加载一些内核,实际上 100-200B 的堆栈应该足够了)。

当然还要设置 ds!正如您所做的 mov al,[bx] 一样,ds 已经设置好了。在您的情况下,最简单的方法是将所有内容保持在 0000:7C00,因此在 mov ss,ax 之前您也可以执行 mov ds,ax