移植64位发生的问题(跟cltq指令有关)

原文地址:http://filwmm1314.blog.163.com/blog/static/218259192012102424024131/

同事昨天在群里问了一个问题,大概将一个32位机器上运行良好的程序,移植到64位机器上之后出现了问题,看了一下core,大概是一个返回指针的函数,在函数内查看返回值还是正确的,但是到调用函数里面,返回值却被截掉了一段,引起了core。

具体代码如下:
char *attach_shm(char *shmstr, int defaultkey, int shmsize)
{
    char *shmptr;
    int shmkey, shmid;
    shmkey = search_shmkey(shmstr);
    if (shmkey < 1024)
        shmkey = defaultkey;
    shmid = shmget(shmkey, shmsize, 0);
    if (shmid < 0) {
    ........
    } else {
    ........
    }
    return shmptr;
}
attach_shm实现很简单,分配一块共享内存,然后返回内存的(首)地址。

调用处的代码:
   char * myTmp =
         attach_shm(shmkey, 5000 + mode * 10,
                            sizeof(struct FILESHM) * maxnum);

有一点要提的是:调用attach_shm和定义attach_shm的不是同一个源文件。(后面会知道,这也是产生问题的原因之一)
这里的问题是,在使用GDB跟踪的时候打印shmptr出来看还是一个64位的值,但是函数返回之后打印myTmp的值确实32位的,这肯定要引起core啊。
可是问题是,这里上下文也不存储缓冲区溢出之类的可能,为什么返回值会被截掉一段呢?
使用GDB跟踪了一下,发现,在attach_shm里面,返回值去%rax的值还是正确的,可是到返回之后%rax的值却变了。这下更郁闷了,难道还有什么东西改变了%rax的值?以我浅薄的知识理解,都是没有这种可能的啊。
实在没办法了,只要将这两个函数反编译出来看看汇编代码了,在调用attach_shm的地方发现了一下代码:
  43063f:       48 89 ca                mov    %rcx,%rdx
  430642:       48 89 c7                mov    %rax,%rdi
  430645:       b8 00 00 00 00          mov    $0x0,%eax
  43064a:       e8 00 c3 fe ff          callq  41c94f <attach_shm>
  43064f:       48 98                    cltq
  430651:       48 89 85 00 ff ff ff    mov    %rax,-0x100(%rbp)
  430658:       48 8b 85 00 ff ff ff    mov    -0x100(%rbp),%rax
注意被标注红色的cltq指令,在函数返回之后为什么会有这个指令?怎么其他函数调用之后没看到这个呢?这条指令我之前没接触过,不知道是干什么用的,于是google了一把,就发现早就有人踩过这个cltq这个坑了。

具体链接在  这里 ,这里说的很详细,我就不太多解释了。不明白cltq指令的意思的同学,可以看文章里面那个pdf 文档。

简单来说就是attach_shm这个函数在调用函数编译的时候没有声明过,于是编译器便将这个函数的返回值默认为32位,这个在32位机器上不会有什么问题,因为在32位机器上指针的长度也是32位,但在64位机器上,指针的长度是64位,默认32位的话,就有问题了。这也就是返回值被截断的原因了。
解决的方法很简单,使用头文件声明一下attach_shm这个函数,再让调用该函数的地方包含该头文件就行了。
整个解决问题的过程给我的感觉就是,懂一点汇编,或者说看的懂汇编,对于调试还是挺有帮助的。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值