- SDM指令功能描述(PUSH)
总体描述:
先递减栈指针,然后把指令中的SRC操作数的内容放在栈顶(也就是ss:(r/e)sp),关于地址和操作数等的宽度规则如下:
地址宽度:取决于当前cs指向的代码段的D flag,可以被prefix 0x67重载。
操作数宽度:取决于当前cs指向的代码段的D flag,可以被prefix 0x66或REX.W重载。操作数的宽度同时决定了栈指针的递减值。
栈地址宽度:除了64bit-mode,B flag决定了栈地址宽度;64bit-mode的地址宽度永远是64。
补充:
如果要把立即数压到栈中,则默认使用符号填充的方式,如果要把段选择符压到栈中比如cs,则会用0填充宽度的不足。
如果操作数宽度小于栈地址宽度,PUSH指令会造成栈的不对齐,会引发异常。
如果要压入(R/E)SP,那么压入的值是执行PUSH之前的值。
如果(R/E)SP的值为1,在实地址模式下执行PUSH会引发#SS异常。而进入异常服务函数的时候明显又会引发一次异常,就会引发#DF,然后又进入异常的过程中再次引发了第三次#SS,然后基本就进入shutdown了。
注:D/B flag在代码段中表示指令引用有效地址和操作数的长度
伪代码:
栈地址宽度==64:
if(操作数宽度==64) //push qword
{
RSP = RSP - 8;
*(SS:RSP) = SRC;
}
else if(操作数宽度==32) //push dword
{
RSP=RSP - 4;
*(SS:RSP) = SRC;
}
else if(操作数宽度==16) //push word
{
RSP=RSP - 2;
*(SS:RSP) = SRC;
}
栈地址宽度==32:
if(操作数宽度==64) //push qword
{
ESP = ESP - 8;
*(SS:ESP) = SRC;
}
else if(操作数宽度==32) //push dword
{
ESP=ESP - 4;
*(SS:ESP) = SRC;
}
else if(操作数宽度==16) //push word
{
ESP=ESP - 2;
*(SS:ESP) = SRC;
}
栈地址宽度==16:
else if(操作数宽度==32) //push dword
{
SP=SP - 4;
*(SS:SP) = SRC;
}
else if(操作数宽度==16) //push word
{
SP=SP - 2;
*(SS:SP) = SRC;
}
- 示例代码
__asm__ volatile
(
"pushw %0\t\n"
"pushl %1\t\n"
"movl $0, %%eax\t\n"
"pushw (%%eax)\t\n"
"pushl (0x30)\t\n"
"pushw %%ax\t\n"
"pushl %%eax\t\n"
"pushw $1\t\n"
"pushl $1\t\n"
"pushw %%cs\t\n"
"pushl %%cs\t\n"
"pushw %%fs\t\n"
"pushw %%gs\t\n"
"addl $38, %%esp\t\n"
::"m"(i16), "m"(i32), "m"(i64)
);
反汇编结果