我刚开始学习汇编,我的朋友和我对以下命令中究竟发生了什么有不同的想法:
推1234h
我们的问题是:第一个数字(12)将在堆栈中的哪个位置?
ss:[sp-2]?
ss:[sp-4]?
* sp =堆栈指针
答案 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个字节)。
第三步是在结果位置上写入数据。因此,如果SS
为0x30
且SP
0xFF
,则:
address = (0x30<<4)+0xFF = 0x3FF
2
:position = 0x3FF - 2 = 0x3FD
*(unsigned char*)position = LOBYTE(0x1234)
,
*((unsigned char*)position+1) = HIBYTE(0x1234)
。所以,byte SS:[SP] = 0x34
和byte SS:[SP+1] = 0x12
。请注意,堆栈会增大/缩小,因此不会SP-x
,而是SP+x
。
在保护模式下,事情有点复杂(我这里只会写一段使用段寄存器的过程):
首先,处理器获取全局描述符表描述符的地址(由LGDT
指令加载)。
处理器将段寄存器的值与GDT的大小进行比较(如果它更大,则抛出异常)。它还检查段寄存器是否未指向空描述符(SS!=0
)
SS*8
)。处理器必须检查一些事情:
4.1。细分是否存在?
4.2。我们是否有足够的权限来访问细分市场?
4.3。是代码段吗?
4.4。它可写吗?
4.5。是ESP*granularity+base < limit
4.6。是系统部分吗?
然后按base_of_segment+ESP
计算地址。
之后它继续类似于真实模式。