在 x86 实模式下选择堆栈指针地址(对齐)
Choose stack pointer address in x86 real mode (alignment)
我了解到应该将堆栈指针对齐到 2 字节边界。换句话说,不应将 SP 设置为以 0xF(或任何其他奇数)结尾的值。
如果我使用 0xFFFF 作为 SP 会发生什么?是所有 64kB 都可用,还是少一个字节?
如果我想要 1024 字节的堆栈大小,我应该将 SP 设置为 0x3FF 还是 0x400?例如SS(堆栈段)指向的字节是要使用的吗?
他们声明here也不应该使用以 0xE 结尾的 SP 地址,“在 0x..E 和 0x..F 处浪费字节” .怎么会?
x86 堆栈完全降序。
Full表示栈指针指向最后被压入的项目。这与 empty descending/ascending 堆栈形成对比,其中堆栈指针指向下一个空闲位置。
基本上,这归结为 push ax
的语义
sub sp, 02h
mov WORD [sp], ax
当你设置堆栈指针sp
到地址X时,X被认为是最后一项的位置已推送,因此不会使用它。
如果将 sp
设置为 0xe,则推送会将 sp
移动到 0xe - 2 = 0xc 并在那里写入其操作数。 0xe及以上内存未动
对 sp
使用奇数地址会对性能产生负面影响,因为未对齐的内存访问的延迟可能是对齐访问的两倍。
对于小于 DRAM 总线宽度(在写入时为 8 字节)的数量,这种损失会有所减少。
考虑到堆栈的使用频率,值得保持对齐。
以sp
的奇数地址开始,当堆栈指针到达1时会导致麻烦。
推送会将 sp
设置为 0xffff,但随后在那里写入一个字会触发 #SS,因为较高字节超出了 ss
限制。
使用混乱的堆栈引发异常将反过来引发另一个 #SS,CPU 将作为 #DF 分派。
但是堆栈仍然一团糟,所以产生了第三个异常,一个三重错误,CPU 将重置。
所以让堆栈指针不对齐没有任何好处。
如果您想要大小为 S 的堆栈,您可以将 sp
设置为 S mod 216 授予 2 <= S <= 64KiB.
您可以通过写下 S(例如 4)的小值的示例来检查这是正确的。
您还可以检查将 sp
设置为 0 会给您一个 64KiB 堆栈,这是实际可用的最大大小 mode.
我了解到应该将堆栈指针对齐到 2 字节边界。换句话说,不应将 SP 设置为以 0xF(或任何其他奇数)结尾的值。
如果我使用 0xFFFF 作为 SP 会发生什么?是所有 64kB 都可用,还是少一个字节?
如果我想要 1024 字节的堆栈大小,我应该将 SP 设置为 0x3FF 还是 0x400?例如SS(堆栈段)指向的字节是要使用的吗?
他们声明here也不应该使用以 0xE 结尾的 SP 地址,“在 0x..E 和 0x..F 处浪费字节” .怎么会?
x86 堆栈完全降序。
Full表示栈指针指向最后被压入的项目。这与 empty descending/ascending 堆栈形成对比,其中堆栈指针指向下一个空闲位置。
基本上,这归结为 push ax
的语义
sub sp, 02h
mov WORD [sp], ax
当你设置堆栈指针sp
到地址X时,X被认为是最后一项的位置已推送,因此不会使用它。
如果将 sp
设置为 0xe,则推送会将 sp
移动到 0xe - 2 = 0xc 并在那里写入其操作数。 0xe及以上内存未动
对 sp
使用奇数地址会对性能产生负面影响,因为未对齐的内存访问的延迟可能是对齐访问的两倍。
对于小于 DRAM 总线宽度(在写入时为 8 字节)的数量,这种损失会有所减少。
考虑到堆栈的使用频率,值得保持对齐。
以sp
的奇数地址开始,当堆栈指针到达1时会导致麻烦。
推送会将 sp
设置为 0xffff,但随后在那里写入一个字会触发 #SS,因为较高字节超出了 ss
限制。
使用混乱的堆栈引发异常将反过来引发另一个 #SS,CPU 将作为 #DF 分派。
但是堆栈仍然一团糟,所以产生了第三个异常,一个三重错误,CPU 将重置。
所以让堆栈指针不对齐没有任何好处。
如果您想要大小为 S 的堆栈,您可以将 sp
设置为 S mod 216 授予 2 <= S <= 64KiB.
您可以通过写下 S(例如 4)的小值的示例来检查这是正确的。
您还可以检查将 sp
设置为 0 会给您一个 64KiB 堆栈,这是实际可用的最大大小 mode.