pushad与popad的神奇问题(从未见过)

harry_1523 2009-01-15 08:22:55
参考资料:
PUSHAD: 依次把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI等压入栈中
POPAD: 把栈中的值依次弹到EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX等寄存器中

==========================================================================================================
; 这里开始
mov esp,0x00300000

pushad
mov dword [esp + 12],0x00500000 ; 婉转地修改esp的值
popad

; 这里结束

==========================================================================================================
问题:
popad后我发现esp的值还是没有改变,请问这是为什么?
多谢!
...全文
2082 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
s393658806 2009-08-06
  • 打赏
  • 举报
回复

不错,答案找到了
harry_1523 2009-01-16
  • 打赏
  • 举报
回复
寄存器的值被覆盖了,所以影响ebx,edx

ls,你是问这个吗?
vamking_boy 2009-01-16
  • 打赏
  • 举报
回复
执行后怎么会影响EBX 和 EDX 呢?搞不懂
cnzdgs 2009-01-15
  • 打赏
  • 举报
回复
其实也没什么道理好说,这条指令就是这样设计的,可能这样设计的初衷是为了设计处理器更方便一些,假设pop中途改变了esp的值,后面的pop操作就不好处理了。
xtdumpling 2009-01-15
  • 打赏
  • 举报
回复

push是为了保存,保存EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI
pop 是为了恢复,恢复...

而pop也直接地恢复了SP/ESP,通过 堆栈弹出,和 直接加10h/20h 都是可以恢复SP/ESP,
相比来说,后者更安全!!

再次推测...
harry_1523 2009-01-15
  • 打赏
  • 举报
回复
回12楼.

哦,果然是cnzdgs说的那样,"执行popad指令后,其它寄存器是从栈中pop出来,但esp=esp+0x20".
harry_1523 2009-01-15
  • 打赏
  • 举报
回复
"increment ESP by 4 (* skip next 4 bytes of stack *)"
我晕了,原来直接跳过esp!

嗯,基本可以给分了.但还是想问问怎么pushad的时候要把esp也一同压进去?有什么意义?
xtdumpling 2009-01-15
  • 打赏
  • 举报
回复
The value on the stack for the ESP or SP register is ignored. Instead, the ESP or SP register is
incremented after each register is loaded.
xtdumpling 2009-01-15
  • 打赏
  • 举报
回复
翻了一下Intel的指令手册,
IF OperandSize = 32 (* instruction = POPAD *)
THEN
EDI ¬ Pop();
ESI ¬ Pop();
EBP ¬ Pop();
increment ESP by 4 (* skip next 4 bytes of stack *)
EBX ¬ Pop();
EDX ¬ Pop();
ECX ¬ Pop();
EAX ¬ Pop();
ELSE (* OperandSize = 16, instruction = POPA *)
DI ¬ Pop();
SI ¬ Pop();
BP ¬ Pop();
increment ESP by 2 (* skip next 2 bytes of stack *)
BX ¬ Pop();
DX ¬ Pop();
CX ¬ Pop();
AX ¬ Pop();
FI;

FYI.
xtdumpling 2009-01-15
  • 打赏
  • 举报
回复
Windows XP下debug32试的,
harry_1523 2009-01-15
  • 打赏
  • 举报
回复
我问了下开发麒麟操作系统的无心兄,他也是说popad不pop esp,但个中原因没有详细说明.
在此我想请教一下cnzdgs,为什么pushad的时候push了esp,但popad的时候不用pop出esp,那它pushad的时候push esp有什么用?
cnzdgs 2009-01-15
  • 打赏
  • 举报
回复
popad指令是不pop esp的。执行popad指令后,其它寄存器是从栈中pop出来,但esp=esp+0x20。
harry_1523 2009-01-15
  • 打赏
  • 举报
回复 1
回6楼.

1: pushad时候把esp压入堆栈了,我修改esp被压入到的相应地址的值.然后等待popad把esp弹出,从而修改esp的值.
2: 汗一下!你不说我也没发现我的结帖率居然这么牛!
harry_1523 2009-01-15
  • 打赏
  • 举报
回复
回4楼的.

我这代码是在32位保护模式下运行(虚拟机:VirtualBox).
你调试的ESP最后是什么值,在什么环境下调试?
还有就是我刚才用emu8086做了一个16位的pusha和popa的实验,发现修改[sp+6]的值然后再popa也是不能修改sp的值,只能push sp再pop sp.
xtdumpling 2009-01-15
  • 打赏
  • 举报
回复
另外:
1: mov dword [esp + 12],0x00500000 ; 婉转地修改esp的值 ,这个能修改esp的值吗??

2: 结帖率:125.00% ??!!!


xtdumpling 2009-01-15
  • 打赏
  • 举报
回复
用debug32试了,的确,ESP最后的值不是0x00300000!

请问LZ,你的这段代码执行的环境CPU是实模式还是保护模式?代码是16位还是32位?

在实模式下,是把ESP的低16位SP作为指向栈顶的指针,可以认为堆栈顶由SS和SP指定;
在保护模式下,32位堆栈段的堆栈指针是ESP,16位的堆栈指针是SP。

据此推测,你的代码可能是在实模式的32位环境下的,所以只看ESP的低16位就可以啦.

  mov esp,0x00300000 ;sp=0

pushad ;sp=0 - 20h
mov dword [esp + 12],0x00500000 ; 婉转地修改esp的值
popad ;sp=(0 - 20h) + 20h


仅仅是推测...
harry_1523 2009-01-15
  • 打赏
  • 举报
回复
多谢ls的回答.

是这样的.我的代码是在没有操作系统的环境下运行的,所以怎么也要先mov一个值到esp进行初始化.
另外你这个异常是指操作系统保护所以产生异常还是cpu的异常?
killbug2004 2009-01-15
  • 打赏
  • 举报
回复
不要mov esp,0x00300000
pushad
mov dword [esp + 12],0x00500000 ; 婉转地修改esp的值
popad
执行后EDX和EBX部分位被修改

应该可以肯定lz的代码也出现异常而没有执行
killbug2004 2009-01-15
  • 打赏
  • 举报
回复
lz确认代码可以正确执行 我这里
(19c.4ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=7ffde000 ecx=0013ffb0 edx=7c92eb94 esi=00000000 edi=00000000
eip=004012a0 esp=00300000 ebp=0013fff0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
test+0x12a0:
004012a0 60 pushad

21,500

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧