gpt4 book ai didi

assembly - 在哪里放置堆栈并加载内核

转载 作者:行者123 更新时间:2023-12-04 17:44:54 24 4
gpt4 key购买 nike

我是操作系统开发的新手,我对开发自己的引导加载程序时遇到的问题很好奇。我的操作系统将用汇编语言编写,并将在 16 位实模式下运行。

我知道堆栈是什么,我的印象是它向下生长到内存中。如果我错了,请纠正我。我知道如何从软盘将基本内核加载到内存中,我认为这不是问题所在。

我遇到的问题是我不确定在哪里放置堆栈并将我的内核加载到内存中。我试过像这样创建我的堆栈,但遇到了问题:

mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF

我正在 0x1000:0x0000 加载我的内核.当我 PUSH 和稍后 POP 时,我的 print 中的 volatile 寄存器功能,我的内核只是挂起 第二个我做的时间 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

这些是我想显示的行:
db "Kernel successfully loaded!", 10, 0
db 9, "Lmao, just a tab test!", 10, 0

这是我的内核运行时得到的输出( _ 是光标):
Kernel successfully loaded!
_

它成功打印了第一行,但在打印第二行时挂起。如果我删除 PUSH 和 POP 语句,它就可以正常工作。为什么当我尝试在我的 print 中保存和恢复寄存器时我的内核挂起功能?我应该在哪里放置我的堆栈以及我应该在哪里加载我的内核?

最佳答案

这不是 Minimal Complete Verifiable Example 也无济于事但你的问题表明可能需要寻找的东西。通常,如果代码通过删除函数序言和结尾中的 PUSH 和 POP 来工作,通常意味着堆栈在函数体执行期间变得不平衡。不平衡的堆栈将导致 RET 指令返回到堆栈顶部的任何半随机位置。这可能会导致明显的挂起和/或重新启动。行为将是未定义的。

我没有遵循您代码中的逻辑,但这很突出:

print:
push ax
push bx
push cx

... snip out code for brevity

jmp print

在某些时候,您的 print 是可能的函数在所有推送之前的某个时间点重新启动。这将导致更多的 PUSH 进入堆栈,而最终没有相应的 POP。我认为您可能一直试图获得这样的行为:
print:
push ax
push bx
push cx

.prloop:
... snip out code for brevity

jmp .prloop
.prloop标 checkout 现在函数的顶部,但在推送之后。这可以防止在堆栈上放置过多的值。 .prloop可以是您选择的任何有效标签。

堆栈可以放置在系统未使用的内存中的任何位置,并且不会干扰您的引导加载程序和/或内核代码。正如@RossRidge 指出的那样,使用 0xFFFF 的 SP 会使堆栈错位,因为它是一个奇数地址 (0xFFFF=-1)。 x86 不会提示(没有对齐检查标志),但它会损害某些 x86 架构上的堆栈性能。

注意:将 SS:SP 设置为 0x1000:0x0000 将导致堆栈从 0x1000:0xFFFF 运行到 0x1000:0x0000。推送的第一个 16 位值将位于 0x1000:0xFFFE。

只要它们不相互冲突,您的内核和堆栈通常在物理地址 0x00520 和 0x90000 之间的任何位置都是安全的。在某些系统上,0x90000 和 0xA0000 之间的内存区域的上部可能不可用。如果你想使用这个内存区域,我会避开 0x9C000 和 0xA0000 之间的区域。这个区域可以被 BIOS 用作 Extended BIOS Data Area 的一部分。 (EBDA)。

可以通过调用 ROM-BIOS 的中断 12h 服务或直接读取 0x00413 处的字来了解可用低内存区 (LMA) 空间的确切数量。无论哪种情况,结果都是可用内存的 KiB 量。如果实际内存小于 640 KiB,和/或 LMA 顶部的某些内存被 EBDA 或其他软件使用,则结果将低于 640(即 0x0280)。从技术上讲,结果也可能高于 640。通过乘以或左移以 KiB 为单位的数量,可以计算以段落或字节为单位的等效数量。

不应使用 0x00000 和 0x00520 之间的区域,因为它包含实模式中断向量表 BIOS Data Area (BDA) 和被视为保留的 32 字节内存。

关于assembly - 在哪里放置堆栈并加载内核,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38195589/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com