移植64位发生的问题(跟cltq指令有关)
2014-07-17 17:17
447 查看
原文地址: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这个函数,再让调用该函数的地方包含该头文件就行了。
整个解决问题的过程给我的感觉就是,懂一点汇编,或者说看的懂汇编,对于调试还是挺有帮助的。
同事昨天在群里问了一个问题,大概将一个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这个函数,再让调用该函数的地方包含该头文件就行了。
整个解决问题的过程给我的感觉就是,懂一点汇编,或者说看的懂汇编,对于调试还是挺有帮助的。
相关文章推荐
- 有关代码移植的问题
- linux 32位向64位的移植常见问题
- 有关map压入对象后,对象的数据成员发生改变的问题
- 64位server 2003 架设IIS出现的.NET有关问题
- 64位系统代码移植面临的20个问题(一)
- 前两天刚看书看到的,来这里跟大家分享一下有关C#处理指令的问题
- 【转】一个从32位机器移植到64位机器时的c问题
- 32位程序移植到64位需要考虑的问题
- ok6410平台移植uboot时发生Signal # 8 caught的问题
- 32位程序移植到64位需要考虑的问题
- linux 32位向64位的移植常见问题
- 32位C/C++程序移植到64位系统时需要注意的问题
- Linux 32位向64位移植的一些问题及解决
- tomcat 移植到weblogic session 为null 有关问题
- 32位程序移植到64位需要考虑的问题
- linux 32位向64位的移植常见问题
- 有关本blog 所有补丁 For win7 64位兼容问题
- 有关BOA服务器和CGI程序移植中遇到的问题
- Cocos2d-x(或者应用)第三方类库不支持arm64的有关问题解决(64位架构)
- 32位程序移植到64位需要考虑的问题