栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

控制目标文件符号可见性

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

控制目标文件符号可见性

控制符号可见性实验环境

系统:  16.04.1-Ubuntu
编译器:gnu 5.4.0

参考

第 1 部分 - 符号可见性简介

nm工具使用

使用NM查看目标文件的符号列表

// file : symtest.hppclass SymTest{
    SymTest();
    SymTest(int x);
    ~SymTest();    void foo();
};// file : symtest.cc#include "symtest.hpp"SymTest::SymTest()       {}
SymTest::SymTest( int x) {}
SymTest::~SymTest()      {}void SymTest::foo()      {}

> g++ -g -shared -o libsymtest.so symtest.cc // 编译动态库> g++ -g -c symtest.cc -o libsymtest.o; ar rvs libsymtest.a libsymtest.o // 编译静态库
  • so 编译时,加上 -g 编译信息

  • -g 仅显示外部符号 -C 显示用户级名字

$ nm -g libsymtest.a 

libsymtest.o:0000000000000026 T _ZN7SymTest3fooEv000000000000000c T _ZN7SymTestC1Ei0000000000000000 T _ZN7SymTestC1Ev000000000000000c T _ZN7SymTestC2Ei0000000000000000 T _ZN7SymTestC2Ev000000000000001a T _ZN7SymTestD1Ev000000000000001a T _ZN7SymTestD2Ev
$ nm -C libsymtest.a 

libsymtest.o:0000000000000026 T SymTest::foo()000000000000000c T SymTest::SymTest(int)0000000000000000 T SymTest::SymTest()000000000000000c T SymTest::SymTest(int)0000000000000000 T SymTest::SymTest()000000000000001a T SymTest::~SymTest()000000000000001a T SymTest::~SymTest()

ps. 构造函数和系够函数会出现两次,见使用NM查看目标文件的符号列表

  • -A 符号前显示二进制文件名称

$ nm -C -A libsymtest.a

libsymtest.a:libsymtest.o:0000000000000026 T SymTest::foo()
libsymtest.a:libsymtest.o:000000000000000c T SymTest::SymTest(int)
libsymtest.a:libsymtest.o:0000000000000000 T SymTest::SymTest()
libsymtest.a:libsymtest.o:000000000000000c T SymTest::SymTest(int)
libsymtest.a:libsymtest.o:0000000000000000 T SymTest::SymTest()
libsymtest.a:libsymtest.o:000000000000001a T SymTest::~SymTest()
libsymtest.a:libsymtest.o:000000000000001a T SymTest::~SymTest()
  • -l 显示行号,需要配合 -g 调试选项使用

$ nm -C -A -l libsymtest.a
 
libsymtest.a:libsymtest.o:0000000000000026 T SymTest::foo()
libsymtest.a:libsymtest.o:000000000000000c T SymTest::SymTest(int)  /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:4libsymtest.a:libsymtest.o:0000000000000000 T SymTest::SymTest() /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:3libsymtest.a:libsymtest.o:000000000000000c T SymTest::SymTest(int)
libsymtest.a:libsymtest.o:0000000000000000 T SymTest::SymTest()
libsymtest.a:libsymtest.o:000000000000001a T SymTest::~SymTest()    /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:5libsymtest.a:libsymtest.o:000000000000001a T SymTest::~SymTest()
符号类型

符号类型一列有两个字母时,小写字母代表局部符号,大写则为全局/外部符号。

‘A’   - 符号的值为连接期间不能改变
‘B b’ - BSS 段, 存放未初始化的数据
‘C’   - comm symbols ?
'D d' - 初始化的数据段
‘G g’ - 存放小对象的初始化数据段,某些目标文件格式支持小对象的快速访问,比如全局的 int 类型可以存放在此处,而大型全局数组不能存放在这里
'i'   - 看不懂 ?
"N"   - 调试相关的符号
"p"   - 该符号在堆栈展开部分
"R r" - 常量,只读数据段
"S s" - 存放小对象的未初始化数据段
"T t" - text段,代码段
"U"   - 未定义符号
"u"   - 独占的全局符号,GNU对ELF标准的拓展,链接过程需要保证该符号是独占的
"V v" - 看不懂?
"W w" - 看不懂?
"-"   - a.out 文件中的调试信息相关
"?"   - 看不懂?

符号及符号可见性是什么?

符号概念与对象文件(.o)、链接等概念相关,对于 C/C++ 语言,用户定义的变量、函数名称、及命名空间、类/结构/名称等,都会在对象文件中生成符号,这些符号对于链接器(linker)确定不同模块(对象文件、动态共享库、可执行文件)是否会共享相同的数据或代码很有用。 ps. 水平有限,此处只关注函数的符号可见性

举例

nm命令中符号类型详解

// file : demo.cc// description : demo symbol of elements in Cint a1;int a2 = 1;const int a3 = 1;static int sa = 1;static int funA() {return 1;}int funB() {return 2;}


$ g++ -g -c demo.cc 
$ nm -C -A -l demo.o 
demo.o:0000000000000000 B global BBS段-未初始化变量   a1   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:1demo.o:0000000000000000 D global 数据段-初始化变量    a2    /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:5demo.o:000000000000000b T global 代码段             funB() /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:6demo.o:0000000000000000 r local  常量               a3    /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:5demo.o:0000000000000004 d local  数据段-初始化变量    sa    /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:5demo.o:0000000000000000 t local  代码段             funA() /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:5> readelf -s demo.o
Symbol table '.symtab' contains 20 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name     6: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL2a3     7: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    2 _ZL2sa     8: 0000000000000000    11 FUNC    LOCAL  DEFAULT    1 _ZL4funAv    17: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 a1    18: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    2 a2    19: 000000000000000b    11 FUNC    GLOBAL DEFAULT    1 _Z4funBv
为什么控制符号可见性?

编译器默认导出所有的符号,存在很高的风险,链接时可能会导致符号冲突,只要有人链接一个跟您的库具有相同符号名称的库,当进行链接器解析时,该库就可能会意外地覆盖您自己的符号。

导出所有的符号,会增加动态库的加载和链接时间。

举例
> g++ -c demo.cc                          // 生成目标文件 demo.o> cp demo.cc demo1.cc                     // 此时 demo1.cc 同样具有符号 a、sa、funA 和 funB> g++ -c demo1.cc                         // 生成目标文件 demo1.o> g++ -shared -o demo.so demo.o demo1.o   // 链接生成动态库 demo.so, 产生符号冲突demo1.o:(.data+0x0): `a'被多次定义
demo.o:(.data+0x0):第一次在此定义
demo1.o:在函数‘funB()’中:
demo1.cc:(.text+0xb): `funB()'被多次定义
demo.o:demo.cc:(.text+0xb):第一次在此定义
collect2: error: ld returned 1 exit status
题外话 - 头文件中放置函数的定义引起符号冲突
// file: demo1.hpp#ifndef __demo1_hpp_#define __demo1_hpp_int test1() { return 1; }#endif//#ifndef __demo1_hpp_// file: demo2.cc#include "demo1.hpp"int test2(){ return test1(); }// file: demo3.cc#include "demo1.hpp"int test3(){ return test1(); }

> g++ -fPIC -shared -o demo.so demo2.cc demo3.cc
/tmp/cchKMCYz.o:在函数‘test1()’中:
demo3.cc:(.text+0x0): `test1()'被多次定义
/tmp/ccLp8ynr.o:demo2.cc:(.text+0x0):第一次在此定义
collect2: error: ld returned 1 exit status

// 1, demo1.hpp 中的 `#ifndef ... #define ...#endif` 不能阻止此类符号冲突
// 2, 将 demo1.hpp 中的函数 test1 改为 inline  可以修复该编译错误
// 3, 也可以将 demo1.hpp 中的函数 test1 改为 static [inline], 会生成两个版本的 test1
控制符号可见性的方式1, static 关键字

如上所示 demo.cc 中, static 改变可见性

2, (仅针对gnu)visibility属性
// file : demo.cc// description : demo visibility change the visiable of symbol#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default")))#else#define NP_VISIBILITY_DEFAULT#endif#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __typeint a1; 
int a2 = 1;const int a3 = 1;int sa = 1;int funA() {return 1;} 
NP_EXPORT(int) funB() {return 2;} 

$ g++ -g -shared -o libdemo.so -fvisibility=hidden demo.cc 
$ nm -C -a -l libdemo.so 

000000000020102c b a1   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:90000000000201020 d a2   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:100000000000201024 d sa   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:120000000000000600 t funA()   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:13000000000000060b T funB()   /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/demo.cc:140000000000000624 r a3
3, 使用导出列表
// file : demo.cc// description : demo version-script change the visiable of symbolint a = 1;int sa = 1;int funA() {return 1;}int funB() {return 2;}> g++ -shared -o demo.so  demo.cc -fPIC -Wl,--version-script=exportmap 
> nm demo.so0000000000201020 D a0000000000201024 d sa0000000000000570 T _Z4funAv000000000000057b t _Z4funBv
cpp 文件
// file : symtest.hpp#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))#define NP_EXPORT __attribute__((visibility("default")))#else#define NP_EXPORT#endifclass SymTest{
    SymTest() ;    NP_EXPORT SymTest(int x); 
    ~SymTest();    void foo();
};// file : symtest.cc#include "symtest.hpp"SymTest::SymTest()       {}
SymTest::SymTest( int x) {}
SymTest::~SymTest()      {}void SymTest::foo()      {}

$ g++ -g -fvisibility=hidden -shared -o libsymtest.so symtest.cc
$ nm -C -A -l libsymtest.so 

libsymtest.so:0000000000000656 t SymTest::foo() /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:6libsymtest.so:000000000000063c T SymTest::SymTest(int)  /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:4libsymtest.so:0000000000000630 t SymTest::SymTest() /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:3libsymtest.so:000000000000063c T SymTest::SymTest(int)
libsymtest.so:0000000000000630 t SymTest::SymTest()
libsymtest.so:000000000000064a t SymTest::~SymTest()    /home/zhanghl/001_cpp/005_snipts/0004_gnu_symbol_visiable/with_cpp/symtest.cc:5libsymtest.so:000000000000064a t SymTest::~SymTest()



作者:呆呆的张先生
链接:https://www.jianshu.com/p/82e1ef7a23f5


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/221907.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号