DrC*_*eal 5 assembly stack real-mode osdev x86-16
我是操作系统开发的新手,我很好奇我在开发自己的bootloader时遇到的问题.我的操作系统将以汇编语言编写,并将以16位实模式运行.
我知道堆栈是什么,我的印象是它向下扩展到内存中.如果我错了,请纠正我.我知道如何从软盘中将基本内核加载到内存中,我不相信这是问题所在.
我遇到的问题是我不确定在哪里放置堆栈并将内核加载到内存中.我试过像这样创建我的堆栈,我遇到了问题:
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
Run Code Online (Sandbox Code Playgroud)
我正在加载我的内核0x1000:0x0000.当我推送并稍后在我的函数中弹出易失性寄存器时print,我的内核只是第二次挂起call print.这是我的print功能:
print:
push ax
push bx
push cx
mov al, [si]
cmp al, 0
je p_Done
cmp al, 9
je p_Tab
mov ah, 0xE
int 0x10
cmp al, 10
je p_NewLine
p_Return:
inc si
jmp print
p_Tab:
xor cx, cx
p_Tab_Repeat:
cmp cx, 8
je p_Return
mov ah, 0xE
mov al, " "
int 0x10
inc cx
jmp p_Tab_Repeat
p_NewLine:
xor bx, bx
mov ah, 0x3
int 0x10
mov dl, 0x00
mov ah, 0x2
int 0x10
jmp p_Return
p_Done:
pop cx
pop bx
pop ax
ret
Run Code Online (Sandbox Code Playgroud)
这些是我想要显示的行:
db "Kernel successfully loaded!", 10, 0
db 9, "Lmao, just a tab test!", 10, 0
Run Code Online (Sandbox Code Playgroud)
这是我内核运行时得到的输出(_是光标):
Kernel successfully loaded!
_
Run Code Online (Sandbox Code Playgroud)
它成功打印第一行,但在打印第二行时挂起.如果我删除PUSH和POP语句就可以了.当我在我的print函数中尝试保存和恢复寄存器时,为什么我的内核会挂起?我应该在哪里放置堆栈以及在哪里加载内核?
这不是一个最小的完全可验证的例子,但你的问题提出了可能需要寻找的东西.通常,如果代码通过在函数序言和结尾中删除PUSH es和POP来工作,通常意味着在执行函数体时堆栈变得不平衡.不平衡的堆栈将导致RET指令返回到堆栈顶部的任何半随机位置.这可能会导致明显的挂起和/或重新启动.行为将是未定义的.
我没有遵循代码中的逻辑,但这很突出:
print:
push ax
push bx
push cx
... snip out code for brevity
jmp print
Run Code Online (Sandbox Code Playgroud)
在某些时候,您print可以在所有推送之前的某个时刻重新启动您的功能.这将导致更多的PUSH进入堆栈,而最后没有相应的POP.我想你可能一直试图得到这样的行为:
print:
push ax
push bx
push cx
.prloop:
... snip out code for brevity
jmp .prloop
Run Code Online (Sandbox Code Playgroud)
该.prloop标签出现在函数的顶部,但推后.这可以防止将多余的值放在堆栈上..prloop可以是您选择的任何有效标签.
堆栈可以放在内存中未被系统使用的任何位置,并且不会干扰引导加载程序和/或内核代码.正如@RossRidge指出的那样,使用0x 0xFF的SP会使堆栈错位,因为它是一个奇数地址(0xFFFF = -1).x86不会抱怨,但它可能会损害某些x86架构上的堆栈性能.
注意:将SS:SP设置为0x1000:0x0000将使堆栈从0x1000:0xFFFF下降到0x1000:0x0000.推送的第一个16位值将为0x1000:0xFFFE.
只要它们不相互冲突,您的内核和堆栈通常在物理地址0x00520和0x90000之间的任何位置都是安全的.在某些系统上,0x90000和0xA0000之间的存储区域的上半部分可能不可用.如果你想使用这个存储区,我会避开0x9C000和0xA0000之间的区域.BIOS可以将此区域用作扩展BIOS数据区(EBDA)的一部分.不应使用0x00000和0x00520之间的区域,因为它包含实模式中断向量表,BIOS数据区(BDA)和被认为保留的32字节内存.
| 归档时间: |
|
| 查看次数: |
230 次 |
| 最近记录: |