WOR*_*559 5 assembly operating-system nasm bootloader i386
我目前正在编写一个bootloader并且已经开始耗尽我的512B空间,所以我开始在512B之外编写更多代码并打算使用bootloader将其读入内存.我添加到我的代码的末尾:
stack_start:
resb 4096
stack_end:
Run Code Online (Sandbox Code Playgroud)
这样我就可以在操作系统代码的末尾为堆栈分配空间.目前在我的引导程序中,我在引导加载程序之后为堆栈分配4KiB,使用以下我从这里获取:
mov ax, 07c0h ; 4K stack space after the bootloader -- code is running at 0x07c0
add ax, 288 ; (4096 + 512)/16 bytes per paragraph (288 paragraphs)
mov ss, ax
mov sp, 4096 ; moves the stack pointer
Run Code Online (Sandbox Code Playgroud)
但是现在我需要一种方法来将堆栈分配到我的操作系统代码的末尾,这将是一个未知的大小.
我相信我理解这些是如何建立的 - 类似于使用es,我ss用于扩展寻址空间,但我找不到任何能够很好地解释我的知识水平的东西.我也不确定如何正确设置它以使我的堆栈结束.我用过:
mov ax, stack_start
mov ss, ax
mov sp, 4096
Run Code Online (Sandbox Code Playgroud)
并没有遇到过错误; 但是我想知道这是否正确,或者我是否真的只为堆栈分配了一些空间,同时用更高的地址填充内存.
ss实际上如何运作?我如何使用它并sp在代码末尾为堆栈分配内存?
这是在使用nasm的i386中.
编辑:如果可能的话,某些方法来验证堆栈是否在正确的位置也非常有用.
我知道这对于初学者来说很可怕,但是只要满足要求并且没有错误,设置堆栈的方法就没有好坏之分。
在拥有一个完全正常工作的内存管理器之前,您(人类)必须成为内存管理器。
您必须了解如何使用内存。
“分配内存”的整个概念还不存在!你没有内存管理器,你只有一堆 RW RAM 地址。
首先需要引导加载程序可以安全地占用的最小内存量。
由于初始程序加载器(引导加载器)位于 0x7c00,因此有理由相信系统具有 31.5KiB 内存。您还可以假设不存在内存并依赖缓存,但这是高级主题。
当事情出错时,陈述假设至关重要。
然后您必须了解保留和使用的区域,这是通过标准内存映射来实现的。
摘录:
00000 - 003ff IVT
00400 - 004ff BDA
00500 - 0052f Dangerous Zone (The Petch Zone :) )
00530 - 07bff Free
07c00 - 07dff IPL
Run Code Online (Sandbox Code Playgroud)
“Petch Zone”是一个内部笑话,也是对Michael Petch 的致敬。
通过设置临时堆栈来构建您的最小环境。
在上面的片段中,该区域00530 - 07bff是空闲的,您可以将其用作 ~29KiB 堆栈。
由于堆栈是完全降序的,因此您可以将堆栈指针ss:sp放在07c00。
07c00是一个物理地址,将其转换为任何合适的逻辑地址(0000:7c00, 0001:7bf0, 0002:7be0, 0003:7bd0, ..., 07c0:0000,任何都可以选择您最喜欢的地址)并SS:SP以您知道/喜欢的任何原子方式设置它。
编辑当偏移下溢从 0 到Ped7gfffe正确记录的位置时,使用带有小偏移部分的逻辑地址会导致问题。
虽然静态行为检查(起始地址相同),但动态行为失败,因此最好使用上面的段,并且肯定不要使用任何内容。 0000:7c000053
任何其他区域都可以,将堆栈指针设置为a0000(常规内存的末尾)是另一种选择。
没有哪个更好,只要注意你把什么放在哪里就可以了。
编辑:正如迈克尔·佩奇在评论中指出的a0000那样,该地址也很危险。
更安全的地址是9c000.
使用适合您需要的块更新内存映射。
记下内核的开始和结束位置、动态数据所在位置等等。
例如
00000 - 003ff IVT
00400 - 004ff BDA
00500 - 0052f Dangerous Zone (The Petch Zone :) )
00530 - 07bff Stack
07c00 - 07dff IPL
07e00 - 08fff Kernel
09000 - 10000 Other kernel stuff
Run Code Online (Sandbox Code Playgroud)
到目前为止,您可以在内存映射中使用静态块,但如果您想使用超过 1 MiB 的内存,则需要查询BIOS以获取可用内存的内存映射。
这本质上是动态的,因为每个系统都具有不同的内存量。
该映射只不过是内存管理器的一个非常小的元数据,所以是时候......
在您目前设置的基本环境中,编写一个简单的内存管理器来保存内存块。
陷阱:内存管理器需要一些“元内存”来保存其分配的内存簿,这需要一个假设。
一旦您可以分配和释放内存,您就可以将堆栈移动到更大的区域,从磁盘或等效文件加载其他数据等等。
这个想法是,您现在可以像在 C 中一样动态管理内存malloc,并将mfree您从精神上处理内存映射的负担中解放出来。
更高级的内存管理器通常是用高级语言编写的,其中数据操作更容易(特别是在处理诸如分页之类的主题时)。