当我们编写PUSH命令时,堆栈和sp会发生什么? (部件)

时间:2013-07-12 10:25:25

标签: assembly

我刚开始学习汇编,我的朋友和我对以下命令中究竟发生了什么有不同的想法:

推1234h

我们的问题是:第一个数字(12)将在堆栈中的哪个位置?  ss:[sp-2]?
 ss:[sp-4]?

* sp =堆栈指针

3 个答案:

答案 0 :(得分:2)

假设您正在谈论x86硬件(因为您指定了ss寄存器),字节将被推送到最高阶(最重要)到最低阶(最低有效)。在这种情况下,它将推送字节12h,然后是字节34h。由于在推送项目时x86堆栈指针会减少,因此内存布局如下所示:

[sp+1] = 12h
[sp]   = 34h

如果您将[sp]作为一个单词(两个字节)访问,您将获得原始值:

[sp] = 1234h

答案 1 :(得分:1)

信不信由你,但你们两个都是对的。字节排序取决于您机器的endianness

答案 2 :(得分:0)

在实模式下(看起来你正在尝试为它制作程序),首先计算地址。公式非常简单:

address = (segment<<4)+offset

然后,此地址被您尝试推送的元素的大小减去(word:2个字节,dword:4个字节,qword:8个字节)。 第三步是在结果位置上写入数据。因此,如果SS0x30SP 0xFF,则:

  1. address = (0x30<<4)+0xFF = 0x3FF
  2. 元素是单词,因此我们减去2position = 0x3FF - 2 = 0x3FD
  3. 在结果位置上写入数据(作为C指针):*(unsigned char*)position = LOBYTE(0x1234)*((unsigned char*)position+1) = HIBYTE(0x1234)
  4. 所以,byte SS:[SP] = 0x34byte SS:[SP+1] = 0x12。请注意,堆栈会增大/缩小,因此不会SP-x,而是SP+x

    在保护模式下,事情有点复杂(我这里只会写一段使用段寄存器的过程):

    1. 首先,处理器获取全局描述符表描述符的地址(由LGDT指令加载)。

    2. 处理器将段寄存器的值与GDT的大小进行比较(如果它更大,则抛出异常)。它还检查段寄存器是否未指向空描述符(SS!=0

    3. 然后处理器获取指向GDT条目的指针,并计算从GDT开始的偏移量(使用SS*8)。
    4. 处理器必须检查一些事情:

      4.1。细分是否存在? 4.2。我们是否有足够的权限来访问细分市场? 4.3。是代码段吗? 4.4。它可写吗? 4.5。是ESP*granularity+base < limit 4.6。是系统部分吗?

    5. 然后按base_of_segment+ESP计算地址。

    6. 之后它继续类似于真实模式。