`
airu
  • 浏览: 270771 次
  • 性别: Icon_minigender_1
  • 来自: 云南
社区版块
存档分类
最新评论

一个从32位机器移植到64位机器时的c问题

 
阅读更多

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

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

 

 

const char * get_fmt_str(const char * fmt, ...)
{
#define SHARE_BUF_STR_LEN 4096
  static char str_buf[SHARE_BUF_STR_LEN];

  va_list arg_ptr;
  va_start(arg_ptr, fmt);
  vsnprintf(str_buf, SHARE_BUF_STR_LEN, fmt, arg_ptr);
  va_end(arg_ptr);
  return str_buf;
}

 

 调用的语句为

 

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 *指针,而是一个结构体:
typedef struct{
unsigned int gp_offset;
unsigned int fp_offset;
char *overflow_arg_area;
char *reg_save_area;
}va_list;
 
 由于gp_offset不到6*8=48,所以,变参就通过 gp_offset + reg_save_area 获取。
根据这些信息,又调试,发现,gp_offset + reg_save_area  根本不对。
于是继续调试。也许这时,大家想知道get_last_error()返回什么了。
char *get_last_error()
{
   return _error_;
}
 其实 _error_就是一个全局变量。一切都很正常。
实在是没有什么眉目了,于是只好根据x64位参数的分配方式,查看寄存器了。
使用 info register
rax            0x2ba3320526c0   47979918862016
rbx            0x2ba331e6f5e8   47979916883432
rcx            0x0      0
rdx            0x0      0
rsi             0x320526c0       839198400
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()的头文件。
于是加上原型函数声明,再试,好了。纠结了近两天的问题圆满解决!

 

分享到:
评论

相关推荐

    C语言编程需要注意的64位和32机器的区别.doc

    ### C语言编程中64位和32位机器的区别 #### 一、数据类型差异 在C语言编程中,理解不同类型在不同平台上的表现是非常重要的。C99标准并未明确规定各种基本数据类型的精确大小,而是提供了最低界限的要求。在16位、...

    Python-OpenNMT开源神经机器翻译系统OpenNMT的Pytorch一个移植

    标题“Python-OpenNMT开源神经机器翻译系统OpenNMT的Pytorch一个移植”揭示了我们讨论的主题——OpenNMT,这是一个基于Python的开源神经机器翻译框架,其移植版是用PyTorch实现的。PyTorch是Facebook人工智能研究...

    将Cocos2dx从win32移植到android平台 不用cygwin

    本篇文章将详细讲解如何在不使用Cygwin的情况下,将一个基于Cocos2d-x的Win32项目成功地移植到Android平台。Cygwin是一个在Windows上模拟Linux环境的工具,但在某些情况下,我们可能希望避免它的使用,例如为了减少...

    解析gcc编译器的移植方法

    本文旨在提供一个关于如何将GCC移植到新平台的指南,特别是针对i386架构的移植过程。 #### 方法概述 ##### ABI(应用二进制编程接口)的规范化 ABI定义了程序与操作系统之间交互的基本规则,包括数据类型的内存分配...

    视频图像处理算法opencv在esp32及esp32s3上面的移植,可以移植openmv

    OpenCV是一个强大的计算机视觉库,广泛应用于图像处理和机器学习任务,而ESP32和ESP32S3则是专为物联网应用设计的高性能SoC,它们集成了Wi-Fi和蓝牙功能,适用于各种智能设备。 首先,OpenCV库包含了丰富的C++类和C...

    GRBLF407.rar_G代码_grbl_stm32 grbl 1.1_stm32f407_stm32f407移植GRBL

    标题"GRBLF407.rar_G代码_grbl_stm32 grbl 1.1_stm32f407_stm32f407移植GRBL"指出,这个压缩包包含了将GRBL 1.1版本移植到STM32F407微控制器上的相关资源。STM32F407是一款高性能、低功耗的ARM Cortex-M4内核的微...

    你必须知道的495个C语言问题

    1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取不到数组的大小? 声明问题 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 *1.26 main的正确定义是什么...

    stm32f103 GRBL代码移植

    STM32F103 GRBL代码移植是一个将开源的GRBL固件适配到STM32F103微控制器上的过程。GRBL是一种基于Arduino的、用于控制CNC机器(如3D打印机、激光切割机等)的固件,它实现了G代码解释器,能够将G代码指令转化为电机...

    阿里云oss c-sdk交叉编译移植 oss-demo.tar.gz

    阿里云OSS(Object Storage Service)C-SDK交叉编译移植是将阿里云提供的C语言SDK在非目标系统上进行编译,以便在特定的目标硬件或操作系统上运行OSS相关的应用,例如物联网设备、嵌入式系统等。在这个过程中,我们...

    grbl0.8源码移植

    总的来说,这个项目涉及的知识点包括但不限于:GRBL固件的工作原理、G代码解析、STM32微控制器的架构与编程、嵌入式系统的开发流程、C语言编程、硬件接口设计、实时操作系统(RTOS)概念、以及嵌入式软件调试技术。...

    OpenCV2.1在s3c2440linux上的移植方法与资源

    对于s3c2440这样的嵌入式设备,你需要一个交叉编译环境,这通常意味着在宿主机(如Linux或Windows系统)上搭建一个能够生成适用于目标板(s3c2440)的二进制文件的环境。 1. **环境准备** - 安装交叉编译工具链:...

    移植linux内核到2440

    【移植Linux内核到2440】是一个涉及嵌入式Linux系统开发的过程,主要针对友善之臂2440开发板。以下是移植步骤及关键知识点的详细说明: 1. **准备阶段** - **系统环境**:Ubuntu 9.04作为开发环境,内核版本为...

    S3C6410的linux内核移植

    【S3C6410的Linux内核移植】是一个涉及嵌入式系统开发的重要环节,主要用于在三星S3C6410处理器上运行Linux操作系统。S3C6410是一款高性能的ARM Cortex-A8核心的微处理器,常用于高端的嵌入式设备,如智能手机、平板...

    GCC编译器后端移植技术.pdf

    这个过程需要解决三个根本问题:设计一种较好的中间语言,设计一种对目标机恰当的机器描述,在机器描述与编译主体之间设计一种统一接口。 RTL(Register Transfer Language)是一种中间语言,用于描述计算机行为。...

    C语言矩阵库,在STM32上使用,可移植到其他场合.zip

    在本文中,我们将深入探讨如何使用C语言矩阵库在STM32微控制器上进行操作,并了解如何将此类库轻松地移植到其他应用场景。C语言是一种广泛应用于嵌入式系统编程的强大语言,尤其在处理数学计算和实时控制时,如STM32...

Global site tag (gtag.js) - Google Analytics