原文网址:http://www.jiancool.com/article/96402954887/

最近工作中遇到了一个讨厌的问题,在32位机器上运行的好好的,但是在64位机器上,出现了诡异的 Segmental fault。

于是调试分析,一切似乎都很正常。开始怀疑是否由于使用了变参。因为proc不支持...形式的变参,所以,不得已自己写了一个类似printf这样的变参,和proc程序分开。这个函数如下:

  1. const char * get_fmt_str(const char * fmt, ...)
  2. {
  3. #define SHARE_BUF_STR_LEN 4096
  4. static char str_buf[SHARE_BUF_STR_LEN];
  5. va_list arg_ptr;
  6. va_start(arg_ptr, fmt);
  7. vsnprintf(str_buf, SHARE_BUF_STR_LEN, fmt, arg_ptr);
  8. va_end(arg_ptr);
  9. return str_buf;
  10. }

调用的语句为

get_fmt_str("%s", get_last_error());

  使用GDB调试,打印函数get_last_error(),返回正确的错误信息。
可是接着运行,Segmentation fault 出来了。
由于怀疑变参,于是找到一些关于x64的机器上变参的一些资料。在x64上的 参数入栈,一般是先入寄存器,大概有6个寄存器,顺序为:rdi,rsi,rdx,rcx,r8,r9。如果参数大于6个,那么就使用栈保存。这时的 va_list 不再是一个简单的char *指针,而是一个结构体:
  1. <span style="font-weight: normal;">typedef struct{
  2. unsigned int gp_offset;
  3. unsigned int fp_offset;
  4. char *overflow_arg_area;
  5. char *reg_save_area;
  6. }va_list;</span>
  由于gp_offset不到6*8=48,所以,变参就通过 gp_offset + reg_save_area 获取。
根据这些信息,又调试,发现,gp_offset + reg_save_area  根本不对。
于是继续调试。也许这时,大家想知道get_last_error()返回什么了。
  1. char *get_last_error()
  2. {
  3. return _error_;
  4. }
  其实 _error_就是一个全局变量。一切都很正常。
实在是没有什么眉目了,于是只好根据x64位参数的分配方式,查看寄存器了。
使用 info register
  1. rax            0x2ba3320526c0   47979918862016
  2. rbx            0x2ba331e6f5e8   47979916883432
  3. rcx            0x0      0
  4. rdx            0x0      0
  5. rsi             0x320526c0       839198400
  6. rdi             0x2ba33201c036   47979918639158
这是在get_last_error()返回以后的寄存器情况。细心的人可能已经发现问题了。
get_last_error()返回值作为参数,首先放在了rax,然后被放到rsi作为参数,这是gcc x64上的变参调用时参数保存方式。而我们在rsi里看到什么了?
这个值正好是rax里的低32位,这就是说,返回get_last_error()时,返回的char * ,在x64机器上应该为64位的char *,居然变成了32位的值。为什么?为什么?
我们也可以看到,get_last_error()的返回值,确实是char * 啊。
这种疑惑,我又做了无数的猜疑,但是突然想到一点,c语言中,如果没有函数原型的声明,那么,返回值会被默认为int型,而int在x64的机器上是32位的!
肯定就是这个原因,于是打开get_last_error()这个函数的c文件,果然没有包含一个头文件,而头文件的作用,也就是声明函数原型。当然,调用语句所在的c文件,也没有用到声明get_last_error()的头文件。
于是加上原型函数声明,再试,好了。纠结了近两天的问题圆满解决!

【转】一个从32位机器移植到64位机器时的c问题的更多相关文章

  1. 【转】将 Linux 应用程序移植到 64 位系统上

    原文网址:http://www.ibm.com/developerworks/cn/linux/l-port64.html 随着 64 位体系结构的普及,针对 64 位系统准备好您的 Linux® 软 ...

  2. <转>32位移植到64位 注意事项

    32bit-64bit porting work注意事项 64位服务器逐步普及,各条产品线对64位升级的需求也不断加大.在本文中,主要讨论向64位平台移植现有32位代码时,应注意的一些细小问题. 什么 ...

  3. [百度空间] [转]将程序移植到64位Windows

    from : http://goooder.bokee.com/2000373.html (雷立辉 整理) 简介:本文对如何将32位Windows程序平滑的支持和过渡到64位Windows操作系统做出 ...

  4. SWMM代码移植到64位平台

    在32位平台上运行SWMM模型,当节点数量到达60万以上的时候,模型运行占用内存接近1.85G的时候就会因为内存不够而无法计算.这种情况还是单独运行SWMM.exe的时候出现,如果采用SWMM.DLL ...

  5. 模块XXXX可能与您正在运行的Windows版本不兼容。检查该模块是否与regsvr32.exe的x86(32位)x64(64位)版本兼容。

    最近自己在编写ActiveX控件.遇到的麻烦事不少. 今天遇到了这个问题“模块XXXX可能与您正在运行的Windows版本不兼容.检查该模块是否与regsvr32.exe的x86(32位)x64(64 ...

  6. Qt5.8 下链接 Mysql 错误以及解决方法(无论 Mysql 是什么版本的,64 位 Qt 要用 64 位的 Mysql 驱动,32 位的 Qt 要用 32 位的Mysql 驱动)

    Qt 5.8 下链接 Mysql(Windows 平台下),有朋友会出现一个这个无法连接的错误 QSqlDatabase: QMYSQL driver not loaded QSqlDatabase: ...

  7. Oracle 11g R2 32位 & Oracle 11g R2 64位 -百度云下载

    Oracle 11g R2 32位 & Oracle 11g R2 64位 -百度云下载 https://pan.baidu.com/s/1fuzy67Olfxzsy3WJMCrCnQ 提取码 ...

  8. 64位windows上访问64位oracle 12c

    64位windows上访问64位oracle 12c,这会有啥问题? 没啥问题.问题是,我64位操作系统的机器上装了个oracle 10g.而oracle 10g好像是不区分啥32位.64位的,一律3 ...

  9. VS2010在64位系统中连接64位Oracle出现的问题和解决方法

    C#使用System.Data.OracleClient连接Oracle数据库.我的是window7/64位系统,装了一个64位的oralce 11G r2 客户端是64位的 用VS10调试错误信息如 ...

随机推荐

  1. C#实现目录复制

     摘自:http://www.cnblogs.com/zxjay/archive/2008/10/29/1322517.html FCL提供了文件移动.文件复制.目录移动的方法,但没提供目录复制的 ...

  2. 如何从Linux系统中获取带宽、流量网络数据

    引入 国外的云主机厂商,例如AWS提供的网络数据是以流量为单位的,例如下面的图片: 从上图来看,其取值方式为 每隔5分钟取值1次,(每次)每个点显示为1分钟内的流量字节数(Bytes) 带宽与流量 我 ...

  3. Window vagrant 安装部署【转】

    回想以前,想要安装个虚拟机是多么的麻烦.先要费尽心机找到想要的操作系统镜像文件,然后安装虚拟化软件,按照其提供的GUI界面操作一步步创建,整个过程费时费力.但是,自从使用了Vagrant以后,咱腰不酸 ...

  4. this关键字的解析

    this关键字的作用: 1.表示类中的属性. class Person{ // 定义Person类 private String name ; // 姓名 private int age ; // 年 ...

  5. Android自定义控件(四)——让每一个Activity UI都具有弹性

    前面我们已经介绍了如何让你的ScrollView,ListView具有弹性, 今天,我们在前面的基础上,做一下适当的修改,让那些既不是ScrollView,也不是ListView的Activity页面 ...

  6. HDOJ 4937 Lucky Number

    当进制转换后所剩下的为数较少时(2位.3位),相应的base都比較大.能够用数学的方法计算出来. 预处理掉转换后位数为3位后,base就小于n的3次方了,能够暴力计算. . .. Lucky Numb ...

  7. iOS中AutoLayer自动布局流程及相关方法【转】

    转自:http://my.oschina.net/w11h22j33/blog/208574 关于UIView的Layer,IOS提供了三个方法: 1.layoutSubviews 在iOS5.1和之 ...

  8. 转载--DEV GridControl 的一些基本操作

    1. 如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 2. 如何新增一条记录 (1).gridView.Ad ...

  9. 关于IE11

    最近,一个开发代号为Windows Blue的Windows操作系统泄漏到了互联网上,该操作系统的内置浏览器为IE11,本文将介绍一下这个泄漏版的IE11中有哪些关键的新变化和新特性. 预先声明: 本 ...

  10. easyUI的doCellTip 就是鼠标放到单元格上有个提示的功能

    1:这个东西是我抄的(抄的哪儿的我就想不起来了- -)弹出的窗没有样式  不是很好看 //扩展 $.extend($.fn.datagrid.methods, { /** * 开打提示功能 * @pa ...