1

假设——出于某种奇怪的原因——ESP某个函数的堆栈指针 , 暂时递减,然后再次递增:

;; ... we're saving registers ...
push EAX
push EBX
push ECX
push EDX

add ESP, 4        ;; Whoops!
sub ESP, 4        ;; Ah, we're fine; we restored it... or are we?

现在,完全有可能在您的指令之前立即触发中断。

如果我理解正确,中断会导致 CPU 将一些值压入堆栈。

这是否意味着您的堆栈现在将被损坏?或者操作系统是否以某种方式(如何?)使用不同的堆栈/内存来存储程序的上下文?还是取决于 CPU 的权限级别?(如果有,怎么做?)

4

4 回答 4

3

减去然后在 x86 上添加就可以了。这就是局部变量的处理方式。但是,如果发生中断,则相反,您可能会损坏数据。add 将释放空间,然后 sub 将再次分配它(不再保证内容相同)。

于 2012-05-21T19:19:53.120 回答
1

如果上述代码位于 ISR 的开头,其中断描述符被标记为“中断门”而不是“陷阱门”,并且您尚未在 ISR 中手动启用中断(使用STIor POPF),则不会问题,因为在这种情况下,CPUFLAGS.IF在进入 ISR 时会自动清除。

此外,如果中断导致保护级别之间的转换,CPU 将内容(EFLAGS、返回地址和 old SS:ESP)推送到新堆栈上,旧堆栈保持不变。

于 2012-05-22T02:08:51.363 回答
1

对于共享堆栈(程序和中断),您绝不希望堆栈指针本身指向您不希望更改或丢失的信息。可能会出现中断并修改该信息。因此,减去,意味着将堆栈指针移离重要数据更远,这很好,当完成该新分配后,您可以返回堆栈指针,同时了解该新数据不再可用。在弄乱堆栈指针本身时,您还需要小心对齐。在这种情况下,一个子然后一个添加是可以的,一个添加然后一个子可能会导致数据丢失。

于 2012-05-21T20:01:49.060 回答
0

这篇文章似乎与上面的答案相矛盾,指出这实际上是安全的:

如果发生中断,您不会搞砸吗?

那些在 DOS 中编程的人可能在这一点上对中断的可能性感到不安。通常,像这样重用堆栈指针是一个非常糟糕的主意,因为您不知道何时可能发生中断,而当一个中断发生时,CPU 会尽职尽责地将当前程序计数器和标志压入堆栈。如果您重用了 ESP,这将导致随机数据结构被丢弃。在这种环境中,ESP 必须始终指向有效且足够的堆栈空间来服务中断,并且当这不成立时,必须禁用中断。长时间禁用中断运行会降低系统响应能力(丢失中断和不良延迟),并且对于大型例程来说不实用。

但是,我们在这里以保护模式运行。

在 Win32 的用户空间中运行时,中断不会压入用户堆栈,而是压入内核堆栈。如果您考虑一下,则不可能使用用户堆栈。如果线程超出堆栈空间,或者甚至只是有一个无效堆栈,当 CPU 尝试推送 EIP 和 EFLAGS 时,它会出现页面错误,并且您不能在中断处理程序中出现页面错误。因此,调度程序可以在无堆栈例程运行时进行任意数量的上下文切换,并且任何指向 ESP 的数据结构都不会受到影响。

于 2013-01-05T03:26:18.047 回答