x86计算机启动时的默认寄存器和段值

6

我发现通常程序员会在引导程序的最开始修复寄存器(有时也会修复段寄存器),并且他们通常建议养成这种习惯。例如:

inc cx
dec bx
inc bp
dec di
xor ax, ax

我知道的是:BIOS在启动过程中会清除所有寄存器!在引导加载程序中初始化寄存器和段是一个好习惯吗?为什么?默认的寄存器、段和指针值是什么(可能与芯片组有关)?

3
英特尔文档确实指定了CPU上电时每个寄存器包含的值。但是你正在询问BIOS交接给引导加载程序后的状态,所以谁知道呢... - Nayuki
谢谢@Nayuki。你是对的。 - محمد جعفر نعمة
8
当启动引导程序执行时,除了一些不太兼容的20世纪80年代计算机之外,你只能做出一个假设,那就是BIOS引导的驱动器号码在_DL_寄存器中。除此之外,你不应该对标志位、段寄存器的状态以及任何通用寄存器的状态做出任何假设。 - Michael Petch
1
谢谢@MichaelPetch。总是很有帮助。 - محمد جعفر نعمة
@MichaelPetch,我认为那应该是一个答案。 - Johan
显示剩余3条评论
1个回答

9

由于你提到了分段寄存器的设置,以及你的代码似乎是16位代码,我将假设你正在讨论古老的IBM-PC启动加载程序(PC-BIOS),而不是(EFI/UEFI)。对于绝大多数已经制造过的设备,在PC-BIOS加载引导扇区并将控制权传递给它时,除了一个寄存器外,所有寄存器的状态都有可用的值。除了80年代和90年代的一些非标准(并且不是100%兼容的BIOS)之外,寄存器DL将包含BIOS引导的驱动器号码。这个值也被用于调用Int 13h磁盘服务例程

SS:SP可能指向内存中的某个位置,但是从BIOS到BIOS它所指向的位置是不同的。如果你打算加载数据到内存中,应当自己设置栈指针(SSSP)。否则你可能会无意中用数据覆盖栈。

有些人认为当控制权传递给你的引导程序时(通常通过),CS:IP总是设置为0x0000:0x7c00(CS=0x0000,IP=0x7c00)。不幸的是这并不能保证。一些启动加载程序已知使用0x07c0:0x0000,这也指向物理地址0x07c00(0x07c0<<4+0x0000)。这是因为不同的段:偏移寻址可以表示相同的物理地址(如0x07c00)。我写了一个Stackoverflow问题/答案,记录了一种情况,即假设CS始终为0x0000可能会导致根据环境的不同出现一些有趣的错误。

字符串指令(如CMPSMOVS)中使用的方向标志(FLAGS寄存器中的DF)不应假定为特定方向。大多数代码使用向前移动(DF=0),但不能保证BIOS在跳转到引导加载程序之前设置了该方向。因此,应显式地使用CLD清除它以进行向前移动,或使用STD设置它以进行向后移动。
除了上述的DL寄存器外,不应假定任何通用寄存器都已初始化。经常看到引导加载程序假定它们为零。这几乎从来不是真实情况。
关于许多这些内容,可以在我的Stackoverflow 通用引导加载程序提示中进行讨论。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接