程序集 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
我认为这应该做的是,将地址 msg
从 bx
压入堆栈,然后将其检索到 bx
。然而,情况似乎并非如此。 'H'
未打印。而是打印 '-'
。如果我使用 msg
作为有效地址,它会起作用。
Edit:正如 Duncan 所指出的,call
指令将 return 地址压入我的堆栈顶部,这使得上述程序使用return BIOS 中断地址!我现在 pop
return 地址变成 dx
然后 pop
变成 bx
,使用 bx
和 jmp
的值 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
。
我是初学者,出于某种原因,推动和弹出堆栈对我不起作用。我的引导程序:
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
我认为这应该做的是,将地址 msg
从 bx
压入堆栈,然后将其检索到 bx
。然而,情况似乎并非如此。 'H'
未打印。而是打印 '-'
。如果我使用 msg
作为有效地址,它会起作用。
Edit:正如 Duncan 所指出的,call
指令将 return 地址压入我的堆栈顶部,这使得上述程序使用return BIOS 中断地址!我现在 pop
return 地址变成 dx
然后 pop
变成 bx
,使用 bx
和 jmp
的值 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
。