在 x86-CPU 上,堆栈指针究竟指向(!)哪里?到顶部元素还是在它后面?

Where exactly(!) does the stack pointer point to on x86-CPUs? TO the top element or RIGHT BEHIND it?

在一些教程中说栈指针指向栈顶元素:

+-------------+
|    stack    |
+-------------+
| top element |  <-- esp
+-------------+

在其他人中,它指向它的右后方,因此指向堆栈增长时可以写入的第一个内存地址。

+-------------+
|    stack    |
+-------------+
| top element | 
+-------------+  <-- esp

在这个德国维基百科网站上 https://de.wikipedia.org/wiki/Register_(Computer)#Stapelregister 据说这两个版本都存在,而且它依赖于CPU架构。

我的问题是,它在 x86-CPUs 上怎么样?它也取决于操作系统吗?

假设您处于 32b x86 模式,并且您将地址 100 到 200 的内存保留为堆栈(不真实,太低,会与 IVT 冲突,但在本示例中会这样做)。堆栈中已经有一些值,所以 esp 是 160.

现在"top of the stack value"在地址160、161、162和163处占用内存(四个字节,因为在32b模式下,堆栈中的单个值是32b = 4B大),假设有存储值0xaabbccdd.

如果您现在执行 push 0x12345678,CPU 将首先从 esp 中减去 4 -> 新的 esp = 156; (160-4)。然后它将写入 32b 值,以小端方式分解为四个字节:mem[156] = 0x78, mem[157] = 0x56, mem[158] = 0x34, mem[159] = 0x12.

现在如果你要执行mov eax,[esp],它会从地址156加载32位值,这意味着它将把地址156、157、158、159的四个字节组成32b值到dword 值 0x12345678.

最后,当您在推送后查看调试器中的内存时,从 ss:esp 地址查看,它将包含这些字节(十六进制):

0000009C:  78 56 34 12 DD CC BB AA ....

(0x9C = 156 = 内存视图开始的地址)。 esp 指向值的第一个字节,被认为是 "top of stack".

或者切换内存视图显示dword值时,为了避免head中的little-endian组合,它会显示:

0000009C:  12345678 AABBCCDD ....