没有使用libstdc++,能否实现C++的运行时类型识别(RTTI)?

4
我想探讨如何在不依赖libstdc++的情况下,支持rtti并链接C++程序。我尝试按照以下方式进行编译。如果有必要但缺失的符号,可以像示例中的strcmp函数一样进行定义,但是是否可以在没有显式mangle/demangle魔法的情况下定义typeinfo符号呢? 如果可能的话,该怎么做?

cd /tmp && cat << 'eof' >rtti.cpp && g++ -nodefaultlibs -lc rtti.cpp

extern "C" int strcmp(const char *s1, const char *s2) { return 0; };
#include "typeinfo"

int main(){
    return typeid(int) == typeid(char);
}

Linker说:
/tmp/cc6rBAef.o: 在函数 `main' 中:
rtti.cpp:(.text+0x18): undefined reference to `typeinfo for char'
rtti.cpp:(.text+0x1d): undefined reference to `typeinfo for int'
collect2: error: ld returned 1 exit status

那么,我该如何使用g++或clang++在源文件中定义'char的typeinfo'(_ZTIc@@CXXABI_1.3)呢?
注:不要问我为什么需要它,只是好奇。

我不知道选项“-nostartfiles”在这种情况下是否有帮助。 - RedX
无论是否使用它,问题都在于 ELF 符号。如果你愿意,可以想象我使用了 "g++ ./ti.cc -nodefaultlibs -lc"。 - Spoonwalker Highwater
1
你应该包含 <typeinfo> 而不是 "typeinfo",对吗? - Morwenn
是的,我应该这样做,但不是必须的。编译器会找到正确的头文件。证明 - Spoonwalker Highwater
@SpoonwalkerHighwater,那不是证明,这只是意味着它恰好适用于GCC,但并不被标准保证。标准有一个非规范性注释,它说:“尽管实现可能提供一种机制来使任意源文件可用于< >搜索,但通常程序员应该使用< >形式的头文件,以及" "形式的超出实现控制范围的源文件。” - Jonathan Wakely
显示剩余2条评论
2个回答

4

由于RTTI所需的符号似乎在libstdc++库中,因此您无法完全不使用它。请注意,我是通过运行以下命令找到这个信息的:

readelf -Ws `g++ -print-file-name=libstdc++.so` | awk '{print $8}' | c++filt | grep 'typeinfo for'

然而,你可以通过静态链接 libstdc++ 来实现:

g++ -static-libstdc++ rtti.cpp

通过这种方式,您不会在libstdc++上有任何动态依赖关系,并且只有实际需要的符号被引入到可执行文件中。 (好吧,我想您的示例中包含所需符号的对象文件fundamental_type_info.o中的所有符号。)


你引用了一篇2005年的博客文章。现在,你可以使用“-static-libstdc++”选项。 - user743382
谢谢您的回答,我也找到了 fundamental_type_info.o。但是文件 gcc-4.8.0/libstdc++-v3/libsupc++/fundamental_type_info.cc 是空的。看起来基本类型是在文件 gcc-4.8.0/gcc/cp/rtti.c 中生成的,但我不确定。我会继续尝试。 - Spoonwalker Highwater
@SpoonwalkerHighwater:最终,包含这些符号的.o文件并不重要,因为在静态链接时会自动引入正确的文件。或者你是想自己实现RTTI吗?如果是这样,请查看Itanium C++ ABI中相关部分。 - mtvec
我真的想知道编译器如何定义fundamental_type_info。我阅读了Itanium ABI,但它没有提供理解变量实现方式的关键。用户类的Typeinfo是由g++生成的,但基本类型的typeinfo位于libstdc++中。只要libstdc++被编译和链接为普通库,就存在一种方法在用户库中生成基本类型的typeinfo。我想找到它。 - Spoonwalker Highwater
如果你能公开你的实现,那将非常有趣。我相信不仅仅是对我而言如此。所以请发布它,提前感谢你。 - Spoonwalker Highwater
显示剩余2条评论

2
感谢gcc社区提供的提示。
答案是:
“gcc使用一些魔法将__fundamental_type_info的析构函数替换为一组typeinfo符号”
替换代码位于文件:gcc-4.7.2/gcc/cp/rtti.c中的void emit_support_tinfos(void);
rtti.cc:
#include <typeinfo>
namespace __cxxabiv1 {
class __fundamental_type_info:public std::type_info{
public:
     explicit __fundamental_type_info(const char* __n) : std::type_info(_n) { } 
     virtual ~__fundamental_type_info(){}; 
};
}
int main(){
    return typeid(int) == typeid(char);
}

编译期间,所有基本类型信息都会插入到目标文件中。

$g++ -c ./rtti.cc;readelf -sW ./rtti.o |c++filt|grep typeinfo|wc -l

$153

因此问题已经得到解答。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接