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

Yan*_*Xie 1 c++

如果此类是多态的,我发现类名不能隐藏在共享库中.例如,

// 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;
}
Run Code Online (Sandbox Code Playgroud)

我在Linux上用这样的gcc构建一个共享库

$ g++ -fPIC -shared -fvisibility=hidden ../example.cpp -o libexample.so 
$ strip -R .comment -R .note libexample.so
Run Code Online (Sandbox Code Playgroud)

然后我打开libexample.so在Emacs的一个正常的文件和搜索,类名BaseChild将被发现.

如果我取消注释语句// #define virtual#define virtual,也就是化妆BaseChild不虚方法,我发现类名BaseChild不会在共享库中找到.

剂量类名是否由编译器存储在类vtable中?还是其他一些原因造成了这个问题?

Max*_*kin 5

如果此类是多态的,我发现类名不能隐藏在共享库中.

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

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

$ 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$"
Run Code Online (Sandbox Code Playgroud)

那些字符串5Child4Basetypeinfo返回typeid():

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
Run Code Online (Sandbox Code Playgroud)

您可以使用-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.
Run Code Online (Sandbox Code Playgroud)

  • @BeyelerStudios`mantring`:_GNU字符串打印至少4个字符长的可打印字符序列(或使用下面的选项给出的数字)_. (2认同)
  • @YantaoXie你实际上可以在`.S`程序集输出中更改这些字符串,然后从改变的`.S`文件中构建一个`.o`. (2认同)