gcc 升级导致模板函数的静态局部变量变得未知

Posted

技术标签:

【中文标题】gcc 升级导致模板函数的静态局部变量变得未知【英文标题】:gcc upgrade caused static local variable of template function to become unknow 【发布时间】:2017-07-04 07:23:14 【问题描述】:

我正在将我们的 gcc 从 gcc 4.1.2 升级到 gcc 4.9.4。

我先用gcc4.9编译,然后启动程序,看到如下错误:

user@machine:~/bin> Load BusinessSoCfg, Name GameSvr, Dll ../SO/so, CreateFunc CreateBusinessSo
Open Dll ../SO/so failed, ../SO/so: undefined symbol: _ZZN6CTable24IsGameTableSOSupportFuncIM5IGameFiisiiP13tagSOItemInfoEEEbT_E7pHandle

pHandle 是模板函数中定义的静态变量。 代码是这样的:

template<class TPMF>
bool CTable::IsGameTableSOSupportFunc(TPMF pfunc)

     static void *pHandle = NULL;
     // somethign todo
     return true;

在我们的测试环境(gcc4.1.2)中,nm -C 显示如下,表示符号是未知类型

0000000004d1d9d0 ? bool CTable::IsGameTableSOSupportFunc<int (IGame::*)(int, short, int, int, tagSOItemInfo*)>(int (IGame::*)(int, short, int, int, tagSOItemInfo*))::pHandle

但在编译 env(gcc4.9.4) nm -C 时显示如下,显示符号已定义

0000000004d1d9d0 u bool CTable::IsGameTableSOSupportFunc<int (IGame::*)(int, short, int, int, tagSOItemInfo*)>(int (IGame::*)(int, short, int, int, tagSOItemInfo*))::pHandle

更重要的是,gcc4.9.4 是使用 gcc4.1.2 从源代码编译而来的,配置如下:

$ ./configure --prefix=/data/gcc-4.9.4/ --enable-languages=c,c++ --enable-lto --enable-vtable-verify --disable-libquadmath-support --disable-libada

原因:以下示例显示的结果与上述不同

示例:

//singleton.hpp, must be a hpp
// if singleton was defined in the same file with main,everything goes fine
#include <stdio.h>
#include <stdlib.h>


template <class TYPE>
class CSingleton

public:
    static TYPE* Instance(void)
    
        if(m_pSingleton == NULL)
        
            CSingleton *pTmpCSingleton = new CSingleton;
            m_pSingleton = pTmpCSingleton;
        
        return &m_pSingleton->m_stInstance;
    
protected:
    TYPE m_stInstance;
    static CSingleton<TYPE>* m_pSingleton;
;

template <class TYPE>
CSingleton<TYPE>* CSingleton<TYPE>::m_pSingleton = NULL;

// main.cpp
// if singleton was defined in the same file with main,everything goes fine
#include "singleton.hpp" 
#include <stdio.h>
typedef CSingleton<int> s;
int main()
    printf("%d\n", *s::Instance());
    return 0;

用gcc4.9编译,运行结果为:0

但是当我将二进制文件复制到 gcc4.1.2 机器时,执行将成为核心。

Floating point exception (core dumped)

fathermore nm -C 会显示一些错误:

nm: a.out: File format not recognized

但两台机器上的 readelf 都可以正常工作:

ELF Header:
Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
Class:                             ELF64
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              EXEC (Executable file)
Machine:                           Advanced Micro Devices X86-64
Version:                           0x1
Entry point address:               0x400520
Start of program headers:          64 (bytes into file)
Start of section headers:          3072 (bytes into file)
Flags:                             0x0
Size of this header:               64 (bytes)
Size of program headers:           56 (bytes)
Number of program headers:         8
Size of section headers:           64 (bytes)
Number of section headers:         30
Section header string table index: 27

【问题讨论】:

编译器的错误? 因为我不确定如何从源代码升级 gcc。我仍然想知道它是否是由坏的 gcc/g++ 工具链引起的。 你能创建一个SSCCE吗? 添加了一个简单的sscce,它将在旧机器上核心 你的例子和你上面写的不一样 【参考方案1】:

这是由 gcc 升级引起的。从更高版本的 gcc 编译的二进制文件使用 gnu 哈希。但是正在运行的计算机的 binutil 无法识别这一点。用-Wl,--hash-style=both-Wl,--hash-style=sysv重新编译可以解决这个问题。

如果我早点查看核心文件,我可以更快地解决这个问题。

【讨论】:

以上是关于gcc 升级导致模板函数的静态局部变量变得未知的主要内容,如果未能解决你的问题,请参考以下文章

c++ int类型默认值是多少?

C++11:在多线程程序中使用局部静态变量导致 coredump

C语言中定义int变量,默认值是多少

局部静态的线程安全初始化:MSVC [重复]

内联函数的局部静态/线程局部变量?

习题5-15