gpt4 book ai didi

assembly - 如何在 i386 中正确设置 ss 和 sp 寄存器

转载 作者:行者123 更新时间:2023-12-02 08:03:41 25 4
gpt4 key购买 nike

我目前正在编写一个引导加载程序,并且已经开始用完我的 512B 中的空间,所以我开始在 512B 之外编写更多代码,并打算使用引导加载程序将其读入内存。我在代码的末尾添加了:

stack_start:
resb 4096
stack_end:

这样我就可以在操作系统代码的末尾为堆栈分配空间。目前在我的引导加载程序中,我使用从 here 获取的以下内容在引导加载程序之后为堆栈分配 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

但是现在我需要一种方法来将堆栈分配到我的操作系统代码的末尾,这将是一个未知的大小。

我相信我了解如何设置这些 - 类似于使用 es , 我正在使用 ss用于扩展寻址空间,但我找不到任何可以很好地解释我的知识水平的东西。我也不确定如何正确设置它以将我的堆栈放在最后。我用过:
mov ax, stack_start
mov ss, ax
mov sp, 4096

并且没有遇到错误;但是我想知道这是否正确,或者我是否实际上只是为堆栈分配了一些空间,同时用更高的地址填充内存。
ss如何实际工作?以及如何使用它和 sp在我的代码末尾为堆栈分配内存?

这是在 i386 中使用 nasm。

编辑:如果可能的话,验证堆栈是否在正确位置的某种方法也将非常有用。

最佳答案

我知道这对初学者来说很可怕,但是只要满足要求并且没有错误,就没有好的或错误的方法来设置堆栈。
在您拥有一个完全工作的内存管理器之前,您(人类)必须成为内存管理器。
您必须知道如何使用内存。
“分配内存”的整个概念还不存在!你没有内存管理器,你只有一堆 RW RAM 地址。

记录你的假设

首先需要引导加载程序可以安全假设的最小内存量。
由于初始程序加载程序(引导加载程序)位于 0x7c00,因此可以合理地认为系统具有 31.5KiB 的内存。
您还可以假设不存在内存并依赖缓存,但这是高级主题。

当事情出错时,陈述假设是至关重要的。

注意差距

然后你必须知道保留和使用的区域,这是通过标准 memory map 来实现的。 .

摘录:

00000 - 003ff   IVT
00400 - 004ff BDA
00500 - 0052f Dangerous Zone (The Petch Zone :) )
00530 - 07bff Free
07c00 - 07dff IPL

“宠物区” is an inside joke并向 Michael Petch 致敬.

做出完全有意识的决定

通过设置临时堆栈来构建您的最小环境。
在区域上方的片段中 00530 - 07bff是免费的,您可以将其用作 ~29KiB 堆栈。
由于堆栈是全降序的,您可以将堆栈指针 ss:sp07c00 . 07c00是物理地址,将其转换为任何合适的逻辑地址( 0000:7c000001:7bf00002:7be00003:7bd0 ,..., 07c0:0000 ,任何人都会选择你最喜欢的那个)和设置 SS:SP以任何原子方式w.r.t.打断你知道/喜欢。

编辑 当偏移下溢从 0 回绕到 fffe 时,使用带有小偏移部分的逻辑地址会导致问题作为 Ped7g正确指出。
虽然静态行为检查(起始地址相同)动态行为失败,所以最好使用 0000:7c00并且肯定不会有任何高于 0053 的段.

任何其他区域都可以,将堆栈指针设置为 a0000 (常规内存结束)是另一种选择。
没有更好的,只是 意识到 你把什么放在哪里。

编辑 : 如 Michael Petch pointed out在评论中,地址 a0000也是危险的。
更安全的地址是 9c000 .

更新内存映射

使用适合您需要的 block 更新内存映射。
写下你的内核在哪里开始和结束,你的动态数据在哪里等等。

例如
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

到目前为止,您本可以在内存映射中使用静态 block ,但如果您想使用超过 1 MiB 的内存,您需要 query the BIOS获取可用内存的内存映射。
这本质上是动态的,因为每个系统都有不同数量的内存。

该映射只是内存管理器的一个非常小的元数据,所以是时候...

实现一个简单的内存管理器

在您到目前为止设置的基本环境中,编码 简单 该书保存内存块的内存管理器。

陷阱:内存管理器需要一些“元内存”来保存其分配的内存簿,这需要一个假设。

一旦您可以分配和释放内存,您就可以将堆栈移动到更大的区域,从磁盘或等价物加载其他数据等等。
这个想法是您现在可以像在 C 中那样使用 malloc 动态管理内存。和 mfree减轻您在精神上处理内存映射的负担。

更高级的内存管理器

更高级的内存管理器通常是用高级语言编写的,其中数据操作更容易(尤其是在处理诸如分页之类的主题时)。

关于assembly - 如何在 i386 中正确设置 ss 和 sp 寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45283851/

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