Assembly 16位实模式下的堆栈内存布局
我正在使用NASM和qemu进行实模式裸机编程。我试图理解堆栈是如何工作的,尤其是它是如何存储在内存中的 我的代码位于512字节的引导扇区中,末尾是“magic byte”Assembly 16位实模式下的堆栈内存布局,assembly,x86,real-mode,Assembly,X86,Real Mode,我正在使用NASM和qemu进行实模式裸机编程。我试图理解堆栈是如何工作的,尤其是它是如何存储在内存中的 我的代码位于512字节的引导扇区中,末尾是“magic byte”0xaa55,它被加载到内存地址0x7c00 我已将堆栈基指针设置为0x7cfe。我知道我必须注意不要用堆栈覆盖我的代码,但事实并非如此。我的代码只占用几个字节。这是我的代码: [BITS 16] org 0x7c00 mov bp, 0x7cfe mov sp, bp push 'A' jmp $ times 510
0xaa55
,它被加载到内存地址0x7c00
我已将堆栈基指针设置为0x7cfe
。我知道我必须注意不要用堆栈覆盖我的代码,但事实并非如此。我的代码只占用几个字节。这是我的代码:
[BITS 16]
org 0x7c00
mov bp, 0x7cfe
mov sp, bp
push 'A'
jmp $
times 510-($-$$) db 0
dw 0xaa55
程序设置堆栈指针,将字符“A”推入堆栈,然后启动无限循环。我使用以下命令对其进行组装和tun:
nasm -f bin boot.asm -o boot.bin
&& qemu-system-i386 -drive file=boot.bin,index=0,media=disk,format=raw -monitor stdio
在emulator运行时,我按以下方式转储内存:
qemu> pmemsave 0x7c00 512 medump.bin
当我打开文件memdump.bin
时,我在基址处看到字符“A”(41 00
,因为它是小尾端),在此之前(如果我们从堆栈的角度考虑,它位于顶部),我看到很多“垃圾”,即:
这些字节是什么
如果我没有设置堆栈指针基数,则代码后面和字节之前的所有字节0xaa55
都是零
你能提供一些信息或至少一些建议吗
谢谢为了处理中断,CPU需要一个正确设置的堆栈。
仅为了通过向ISR(中断服务路由)传递控制来服务中断,CPU按下
标志
、CS
和IP
然后,ISR可能,而且通常需要更多的堆栈
堆栈背后的基本假设是SS:SP
下面的所有内容都被认为是空闲的、可用的内存。当您将
SP
设置为7cfeh时,您只是说7cfeh以下的每个内存位置都是空闲的,其他人可以将其用作堆栈内存。这就是你看到的垃圾。
请注意,列为200、220和240的地址位于堆栈指针的下方,在我看来,对这些地址使用“在顶部”虽然在比喻上是正确的,但有点混乱 如果您想确保自己是唯一一个干扰堆栈的人,请尽早(绝对在设置堆栈之前)发出
cli
。这在UP系统中就足够了
编辑 不要假设
SS
为零,显式设置它,用
mov ax, <ss_value>
;cli Decomment for very old 8088 compatibility
;Use these instructions in this order in pair
;Interrupts are disabled for 1 inst after mov ss, ...
mov ss, ax
mov sp, <sp_value>
;sti Decomment for very old 8088 compatibility
mov-ax,
;cli取消对非常旧的8088兼容性的限制
;按此顺序成对使用这些说明
;在mov ss…之后,中断被禁用1次。。。
mov-ss,ax
mov sp,
;sti Decomment可实现非常古老的8088兼容性
为了处理中断,CPU需要一个正确设置的堆栈。仅为了通过向ISR(中断服务路由)传递控制来服务中断,CPU按下
标志
、CS
和IP
然后,ISR可能,而且通常需要更多的堆栈
堆栈背后的基本假设是SS:SP
下面的所有内容都被认为是空闲的、可用的内存。当您将
SP
设置为7cfeh时,您只是说7cfeh以下的每个内存位置都是空闲的,其他人可以将其用作堆栈内存。这就是你看到的垃圾。
请注意,列为200、220和240的地址位于堆栈指针的下方,在我看来,对这些地址使用“在顶部”虽然在比喻上是正确的,但有点混乱 如果您想确保自己是唯一一个干扰堆栈的人,请尽早(绝对在设置堆栈之前)发出
cli
。这在UP系统中就足够了
编辑 不要假设
SS
为零,显式设置它,用
mov ax, <ss_value>
;cli Decomment for very old 8088 compatibility
;Use these instructions in this order in pair
;Interrupts are disabled for 1 inst after mov ss, ...
mov ss, ax
mov sp, <sp_value>
;sti Decomment for very old 8088 compatibility
mov-ax,
;cli取消对非常旧的8088兼容性的限制
;按此顺序成对使用这些说明
;在mov ss…之后,中断被禁用1次。。。
mov-ss,ax
mov sp,
;sti Decomment可实现非常古老的8088兼容性
您可以演示如何生成二进制文件吗?@MargaretBloom我添加了更多信息在最开始时使用cli
清除中断标志,而不将其设置回原位如何?我的意思是:SP以下以及堆栈末尾的所有内容都被认为是可以被需要覆盖的。而ISR需要。与你的问题无关。您可以使用将值0x7cfe
直接移动到SPmov sp,0x7cfe
。设置SS时需要使用寄存器。在设置SP时显式设置SS段是一个非常好的主意。它们作为一对SS:*SP*。某些环境(真实硬件)可能没有将SS设置为0。你似乎很依赖这个。如果希望堆栈从0x0000:0x7cfe(物理地址0x07cfe)向下扩展,则将其设置为该方式。这将执行异或ax,axmov-ss,ax
mov-sp,0x7cfe
。为了不限制你的代码,你可以把它放在下面0x07c00@MichaelPetch我刚刚开始学习这些东西,我需要一些时间来完全理解你的评论。不需要设置基本指针bp
?感谢您展示了如何生成二进制文件?@MargaretBloom我添加了更多信息如何在最开始时用cli
清除中断标志,而不将其设置回原位?我的意思是:SP以下以及堆栈末尾的所有内容都被认为是可以被需要覆盖的。而ISR需要。与你的问题无关。您可以使用将值0x7cfe
直接移动到SPmov sp,0x7cfe
。设置SS时需要使用寄存器。在设置SP时显式设置SS段是一个非常好的主意。它们作为一对SS:*SP*。某些环境(真实硬件)可能没有将SS设置为0。你似乎很依赖这个。如果希望堆栈从0x0000:0x7cfe(物理地址0x07cfe)向下扩展,则将其设置为该方式。这将执行xor ax,ax