我可以隐藏或删除共享库中的类名吗

Can I hide or remove the class name in the shared library?

本文关键字:隐藏 删除 共享 我可以      更新时间:2023-10-16

我发现如果这个类是多态的,那么类名就不能隐藏在共享库中。例如,

// example.cpp
#include <stdio.h>
#include <string.h>
// #define virtual 
class Base
{
  public:
    virtual const char* whatiam()
    {
        return "Papa";
    }
};
class Child : public Base
{
  public:
    virtual const char* whatiam()
    {
        return "Son";
    }
};
const char* whatiam(Base* obj)
{
    return obj->whatiam();
}
__attribute__((visibility("default"))) const char* TheAPI(int n)
{
    static char buf[64];
    Child t;
    sprintf(buf, "I'm %s.", whatiam(&t));
    return buf;
}

我用gcc在Linux上构建了一个共享库,比如这个

$ g++ -fPIC -shared -fvisibility=hidden ../example.cpp -o libexample.so 
$ strip -R .comment -R .note libexample.so

然后我在Emacs中将libexample.so作为一个普通文件打开并搜索,会找到类名BaseChild

如果我将语句// #define virtual取消注释为#define virtual,也就是说使BaseChild没有虚拟方法,我会发现在共享库中找不到类名BaseChild

编译器是否将类名存储在类vtable中?还是其他原因导致了这个问题?

我发现如果这个类是多态的,那么这个类名就不能隐藏在共享库中。

不清楚你指的是什么样的隐藏。

从链接器符号可见性的角度来看,所有具有内部链接的名称都是隐藏的。类根本没有链接,函数和变量有:

$ nm -C libexample.so
nm: libexample.so: no symbols
$ nm -D -C libexample.so
0000000000201030 B __bss_start
                 w __cxa_finalize
0000000000201030 D _edata
00000000002010a0 B _end
0000000000000944 T _fini
                 w __gmon_start__
0000000000000728 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U sprintf
0000000000000899 T TheAPI(int)
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

$ strings libexample.so | c++filt 
__gmon_start__
_init
_fini
_ITM_deregisterTMCloneTable
_ITM_registerTMCloneTable
__cxa_finalize
_Jv_RegisterClasses
TheAPI(int)
sprintf
vtable for __cxxabiv1::__si_class_type_info
vtable for __cxxabiv1::__class_type_info
libstdc++.so.6
libm.so.6
libgcc_s.so.1
libc.so.6
_edata
__bss_start
_end
CXXABI_1.3
GLIBC_2.2.5
fffff.
Papa
I'm %s.
5Child
4Base
;*3$"

这些字符串5Child4Basetypeid():返回的typeinfo

typeinfo name for Child:
    .string "5Child"
    .hidden typeinfo for Child
    .weak   typeinfo for Child
    .section    .data.rel.ro._ZTI5Child,"awG",@progbits,typeinfo for Child,comdat
    .align 16
    .type   typeinfo for Child, @object
    .size   typeinfo for Child, 24
typeinfo name for Base:
    .string "4Base"
    .hidden typeinfo for Base
    .weak   typeinfo for Base
    .section    .data.rel.ro._ZTI4Base,"awG",@progbits,typeinfo for Base,comdat
    .align 16
    .type   typeinfo for Base, @object
    .size   typeinfo for Base, 16

您可以使用-fno-rtti编译器开关禁用typeinfo:

       -fno-rtti
           Disable generation of information about every class with virtual
           functions for use by the C++ run-time type identification features
           (dynamic_cast and typeid).  If you don't use those parts of the
           language, you can save some space by using this flag.  Note that
           exception handling uses the same information, but G++ generates it
           as needed. The dynamic_cast operator can still be used for casts
           that do not require run-time type information, i.e. casts to "void
           *" or to unambiguous base classes.