深入理解Symbol[通俗易懂]

深入理解Symbol[通俗易懂]这里是引用前言符号(Symbol)是日常开发中经常接触的一个概念,虽然日常开发中直接应用的场景比较少,但符号编译期和运行时都扮演了重要的角色。符号是什么维基百科的定义Asymbolincomputerprogrammingisaprimitivedatatypewhoseinstanceshaveauniquehuman-readableform…._c++动态库symbol怎么理解

前言

符号(Symbol)是日常开发中经常接触的一个概念,虽然日常开发中直接应用的场景比较少,但符号编译期和运行时都扮演了重要的角色。

符号是什么

维基百科的定义

A symbol in computer programming is a primitive data type whose instances have a unique human-readable form.

直观理解,符号是一个数据结构,包含了名称(String)和类型等元数据,符号对应一个函数或者数据的地址。

Symbol Table

符号表存储了当前文件的符号信息,静态链接器(ld)和动态链接器(dyld)在链接的过程中都会读取符号表,另外调试器也会用符号表来把符号映射到源文件。

如果把调试符号裁剪掉(Deployment Postprocessing选择为YES),那么文件里的断点会失效:

在这里插入图片描述

Release模式下是可以裁剪掉符号的,因为release模式下默认有dsym文件,调试器仍然可以从中获取到信息正常工作。

符号表中存储符号的数据结构如下:

struct nlist_64 {
    union {
        uint32_t  n_strx; /* index into the string table */
    } n_un;
    uint8_t n_type;        /* type flag, see below */
    uint8_t n_sect;        /* section number or NO_SECT */
    uint16_t n_desc;       /* see <mach-o/stab.h> */
    uint64_t n_value;      /* value of this symbol (or stab offset) */
};

字符串存储在String Table里,String Table的格式很简单,就是一个个字符串拼接而成。符号的n_strx字段存储了符号的名字在String Table的下标。

在这里插入图片描述

Dynamic Symbol Table

Dynamic Symbol Table是动态链接器(dyld)需要的符号表,是符号表的子集,对应的数据结构很简单,只存储了符号位于Symbol Table的下标:

➜ otool -I main 
main:
...
Indirect symbols for (__DATA,__la_symbol_ptr) 1 entries
address            index
0x000000010000c000     4 //对应符号表的idx为4的符号
....

在这里插入图片描述

感兴趣的同学可能会问,既然Dynamic Symbol Table只存储了下标,这里otool是如何知道这个Indirect symbol属于__DATA,__la_symbol_ptr

答案是用section_64的reserved字段:如果一个section是__DATA,__la_symbol_ptr,那么它的reserved1字段会存储一个Dynamic Symbol Table下标。

struct section_64 { /* for 64-bit architectures */
  char    sectname[16]; /* name of this section */
  char    segname[16];  /* segment this section goes in */
  uint64_t  addr;   /* memory address of this section */
  uint64_t  size;   /* size in bytes of this section */
  uint32_t  offset;   /* file offset of this section */
  uint32_t  align;    /* section alignment (power of 2) */
  uint32_t  reloff;   /* file offset of relocation entries */
  uint32_t  nreloc;   /* number of relocation entries */
  uint32_t  flags;    /* flags (section type and attributes)*/
  uint32_t  reserved1;  /* reserved (for offset or index) */
  uint32_t  reserved2;  /* reserved (for count or sizeof) */
  uint32_t  reserved3;  /* reserved */
};

所以,对于位于__la_symbol_ptr的指针,我们可以通过如下的方式来获取它的符号名:

  1. 遍历load command,如果发现是__DATA,__la_symbol_ptr,那么读取reserved1,即__la_symbol_ptr的符号位于Dynamic Symbol Table的起始地址。
  2. 遍历__DATA,__la_symbol_ptr处的指针

今天的文章深入理解Symbol[通俗易懂]分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/58384.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注