Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5760900
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: C/C++

2008-05-06 10:30:38

昨天同事调试的时候,发现的一个问题,比较有意思,拿来与大家分享:
pop (%esp)指令的执行结果是怎么样的?

先测试一下:
#include

int main()
{
        __asm__("pop (%esp)");

        return 0;
}


我们用gdb调试一下:
(gdb) b main
Breakpoint 1 at 0x8048352: file t_esp.c, line 5.
(gdb) r
Starting program: /home/wangyao/a.out

Breakpoint 1, main () at t_esp.c:5
5               __asm__("pop (%esp)");
(gdb) x $esp
0xbf876f64:     0xbf876f80
(gdb) x $esp+4
0xbf876f68:     0xbf876fd8
(gdb) x $esp+8
0xbf876f6c:     0xb7de1050
(gdb) s
8               return 0;
(gdb) x $esp
0xbf876f68:     0xbf876f80
(gdb) x $esp+4
0xbf876f6c:     0xb7de1050
(gdb) q

结果,我们发现原来%esp中的内容,被弹到了%esp+4中了。

刚开始的时候,我感到很诧异,但是在VC6和gdb下调试都是一个样子的结果,已经不是OS的原因了。那只有是CPU硬件的原因了。

本来以为是CPU的BUG,时序有问题,但是同事讲了一下他的理解,才恍然大悟。
pop (%esp)终归是一个内存操作指令,需要地址线和数据线。
pop (%esp)的微码操作:
1、将(%esp)送到数据线上
2、将%esp+4,送到地址线上
3、接收到Ready信号,写内存

也就是说这完全没有违背我们所学的计算机理论,只不过凑巧pop指令和%esp寄存器凑到了一块。
从字面上理解这条指令的意思:将栈顶pop到栈顶,不过栈顶在pop之后发生了+4操作,也就是说将(%esp)移动到了4(%esp)。

如果单单是普通的pop指令的话,这是没有问题的;如果是movl $0x1234, %esp的话也是没有问题的。

pop (%eax)的话:
1、将(%esp)送到数据线上
2、将%esp+4
3、将(%eax),送到地址线上
4、接收到Ready信号,写内存

也就是说pop和push操作都是要加减%esp的,如果是要操作内存的话,加减esp操作要早于写内存操作。为什么会这样子,只能够问intel了。
BTW:我认为CPU可以先写内存再加减esp。

顺便练手gnu的内嵌汇编:
#include

int main()
{
        int temp = 0x1234;
        int temp0,temp1,temp2,temp3;

        __asm__ __volatile__("push %4\n\t"
                             "movl 4(%%esp),%0\n\t"
                             "movl -4(%%esp),%1\n\t"
                             "pop (%%esp)\n\t"
                             "movl (%%esp),%2\n\t"
                             "movl -4(%%esp),%3\n\t"
                             :"=r"(temp0),"=r"(temp1),"=r"(temp2),"=r"(temp3)
                             :"g"(temp));

        printf("---------------\n");
        printf("esp+4:0x%08x\n", temp0);
        printf("esp:0x%08x\n", temp);
        printf("esp-4:0x%08x\n", temp1);
        printf("----- pop -----\n");
        printf("esp:0x%08x\n", temp2);
        printf("esp-4:0x%08x\n", temp3);

        return 0;
}

阅读(2566) | 评论(0) | 转发(0) |
0

上一篇:[zz]cgdb - curses gdb

下一篇:scanf() sscanf() Usage

给主人留下些什么吧!~~