iOS高级强化--005:nm命令

nm命令:打印nlist结构的符号表Symbol Table

常用命令参数

nm -pa a.o

-a:显示符号表的所有内容
-g:显示全局符号
-p:不排序。显示符号表本来的顺序
-r:逆转顺序
-u:显示未定义符号
-U:不显示未定义符号
-m:显示N_SECT类型的符号(Mach-O符号)显示
-n:按照符号值的数字大小排序而不是字母表顺序
-o:输出符号的所有位置,一个符号可能会出现多次
-x:以16进制形式显示符号,后面跟随符号名称
-j:只显示符号,不显示值和类型
-A:显示每个文件的路径和库名称
-P:输出可移植接口格式的符号
-f:按指定格式输出,支持如下bsdsysvposixdarwin四种格式;默认darwin
-t:给输出可移植接口格式的符号按照指定格式输出;-d十进制、-o八进制、-x十六进制;默认-d
-s:仅列出section中的部分符号(segname、sectname),对于lvm-nm(1)选项,必须是命令行的最后一个,并且在文件之后
-l:如果没有符号以section的起始地址为值,则列出一个伪符号.section_start。与上面的-s选项一起使用
-arch:只显示universal file中指定架构的符号;如果指定文件包含这个符号,则显示指定架构的符号,否则显示所有的符号

nlist

定义符号的具体表示含义:

struct nlist {
    // 表示垓符号在string table的索引
    union {
        //在Mach-0中不使用此字段
        char *n_name;
        // 索引
        long n_strx;
    } n_un;
    unsigned char n_type;  /* type flag, see below */
    unsigned char n_sect;  /* section number or NO_ SECT */
    short          n_desc; /* see <mach-o/stab.h> */
    unsigned long n_value; /* value of this symbol (or stab offset) */
};
n_type

n_type1字节,通过四位掩码保存数据:

  • N_STAB0xe0):如果当前的n_type包含这3位中的任何一位,则该符号为调试符号表(stab)。在这种情况下,整个n_type字段将被解释为stab value。请参阅/usr/include/mach-o/stab.h以获取有效的stab value
  • N_PEXT0x10):如果当前的n_type包含此位。则将此符号标记为私有外部符号__private_extern__(visibility=hidden), 只在程序内可引用和访问。当文件通过静态链接器链接的时候,不要将其转换成静态符号(可以通过ld-keep_private_externs关闭静态链接器的这种行为)
  • N_TYPE0x0e):如果当前的n_type包含此位。则使用预先定义的符号类型
  • N_EXT0x01):如果当前的n_type包含此位。则此符号为外部符号。该符号在该文件外部定义或在该文件中定义,但可在其他文件中使用

stab value包括:

#define N_GSYM    0x20 /* 全局符号: name, ,N0_ SECT,type,0 */
#define N_FNAME   0x22 /* procedure name (f77 kludge): name,,N0_ SECT,0,0 */
#define N_FUN     0x24 /* 方法/函数: name,,n_ sect,linenumber , address */
#define N_STSYM   0x26 /* 静态符号: name,,n sect, type , address */
#define N_LCSYM   0x28 /* .lcomm 符号: name,,n sect , type , address */
#define N_BNSYM   0x2e /* nsect符号开始: 0,,n sect,0, address */
#define N_OPT     0x3c /* emitted with gccZ_ compiled and in gcc source */
#define N_RSYM    0x40 /* 寄存器符号: name,NO_ _SECT, type,register */
#define N_SLINE   0x44 /* 代码行数: 0,,n ,sect,linenumber , address */
#define N_ENSYM   0x4e /* nsect符号结束: ø,,n sect,ø, address */
#define N_SSYM    0x60 /* 结构体符号: name,, NO SECT, type,struct_ offset */
#define N_SO      0x64 /* 源码名称: name,,n sect, 0, address */
#define N_OSO     0x66 /* 目标代码名称: name, ,0,0,st_ mtime */
#define N_LSYM    0x80 /* 本地符号: name, ,N0_ SECT,type ,offset */
#define N_BINCL   0x82 /* include file 开始: name,,NO_ SECT,0,sum */
#define N_SOL     0x84 /* #included file 名称: name,,n sect ,0, address */
#define N_PARAMS  0x86 /* 编译器参数: name,,NO_ SECT,0,0 */
#define N_VERSION 0x88 /* 编译器版本: name,,N0_ SECT,0,0 */
#define N_OLEVEL  0x8A /* 编译器-O级别: name,NO_ _SECT,0,0 */
#define N_PSYM    0xa0 /* 参数: name,,No_ _SECT, type,offset */
#define N_EINCL   0xa2 /* include file 结束: name,,NO_ SECT,0,0 */
#define N_ENTRY   0xa4 /* alternate entry: name, ,n. sect,linenumber , address */
#define N_LBRAC   0xc0 /* 左括号: 0,,N0_ SECT,nesting level,address */
#define N_EXCL    0xc2 /* deleted include file: name, ,NO_ SECT,0,sum */
#define N_RBRAC   0xe0 /* 右括号: 0,,N0. _SECT ,nesting level , address */
#define N_BCOMM   0xe2 /* 通用符号开始: name,,NO. SECT,0,0 */
#define N_ECOMM   0xe4 /* 通用符号结束: name,n. sect,0,0 */
#define N_ECOML   0xe8 /* end common (local name): 0,,n_ sect , 0, address */
#define N_LENG    0xfe /* second stab entry with length information */

/*
 * for the berkeley pascal compiler, pC(1):
 */
#define N_ _PC    0x30 /* global pascal symbol: name, ,NO_ SECT, subtype,line */
N_TYPE

N_TYPE字段的值包括:

  • N_UNDF0x0):该符号未定义。未定义符号是在当前模块中引用,但是被定义在其他模块中的符号。n_sect字段设置为NO_SECT
  • N_ABS0x2):该符号是绝对符号。链接器不会更改绝对符号的值。n_sect字段设置为NO_SECT
  • N_SECT0xe):该符号在n_sect中指定的段号中定义
  • N_PBUD0xc):该符号未定义,镜像使用该符号的预绑定值。n_sect字段设置为NO_SECT
  • N_INDR0xa):该符号定义为与另一个符号相同。n_value字段是string table中的索引,用于指定另一个符号的名称。链接该符号时,此符号和另一个符号都具有相同的定义类型和值
n_ sect

n_ sect为整数,用来在指定编号的section中找到此符号;如果在该image的任何部分都找不到该符号,则为NO_SECT。根据sectionLC_SEGMENT加载命令中出现的顺序,这些section1开始连续编号

n_desc

n_desc16-bit值,用来描述非调试符号。低三位使用REFERENCE_TYPE

  • REFERENCE_FLAG_UNDEFINED_NON_LAZY0x0):该符号是外部非延迟(数据)符号的引用
  • REFERENCE_FLAG_UNDEFINED_LAZY0x1):该符号是外部延迟性符号(即对函数调用)的引用
  • REFERENCE_FLAG_DEFINED0x2):该符号在该模块中定义
  • REFERENCE_ FLAG_ PRIVATE_ DEFINED0x3):该符号在该模块中定义,但是仅对该共享库中的模块可见
  • REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY0x4):该符号在该文件的另一个模块中定义,是非延迟加载(数据)符号,并且仅对该共享库中的模块可见
  • REFERENCE_FLAG_PRIVATE_LUNDEFINED_LAZY0x5):该符号在该文件的另一个模块中定义,是延迟加载(函数)符号,仅对该共享库中的模块可见

另外还可以设置如下标识位:

  • REFERENCED_DYNAMICALLY0x10):定义的符号必须是使用在动态加载器中(例如dlsymNSLookupSymbolInImage)。而不是普通的未定义符号引用。strip使用该位来避免删除那些必须存在的符号(如果符号设置了该位,则strip不会剥离它)
  • N_DESC_DISCARDED0x20):在完全链接的image在运行时动态链接器有可能会使用此符号。不要在完全链接的image中设置此位
  • N_NO_DEAD_STRIP0x20):定义在可重定位目标文件(类型为MH_0BJECT)中的符号设置时,指示静态链接器不对该符号进行dead-strip(请注意,与N_DESC_DISCARDED0x20)用于两个不同的目的)
  • N_WEAK_REF0x40):表示此未定义符号是弱引用。如果动态链接器找不到该符号的定义,则将其符号地址设置为0。静态链接器会将此符号设置弱链接标志
  • N_WEAK_DEF0x80):表示此符号为弱定义符号。如果静态链接器或动态链接器为此符号找到另一个(非弱)定义,则弱定义将被忽略。只能将合并部分中的符号标记为弱定义

如果该文件是两级命名two-level namespace image(即如果mach_header中设置了MH_TWOLEVEL标志),则n_desc高8位表示定义此未定义符号的库的编号。使用宏GET_LIBRARY_ORDINAL来获取此值,或者使用宏SET_LIBRARY_0RDINAL来设置此值。0指定当前image1253根据文件中LC_LOAD_DYLIB命令的顺序表明库号。254用于需要动态查找的未定义符号(仅在OS X v10.3和更高版本中受支持)。对于从可执行程序加载符号的插件,255用来指定可执行image。对于flat namespace images高8位必须为0

n_ value

n_ value:符号值。对于symbol table中的每一项,该值的表达的意思都不同(具体由n_type字段说明)。对于N_SECT符号类型,n_value是符号的地址。有关其他可能值的信息,请参见n_type字段的描述。

Common symbols必须为N_UNDF类型,并且必须设置N_EXT位。Common symbolsn_value是符号表示的数据的大小(以字节为单位)。在C语言中,Common symbol是在该文件中声明但未初始化的变量。Common symbols只能出现在MH_OBJECT类型的Mach-0文件中

在LLVM项目中调试nm命令
添加llvm-nm

打开LLVM项目,打开Edit Scheme...弹窗

选择Manage Schemes...

点击+添加

Target选择llvm-nm,填写Name后点击OK

此时llvm-nm添加成功,点击Close关闭弹窗

添加默认参数

打开Edit Scheme...弹窗,左上角选择llvm-nm,左侧选择Run,右侧选择Arguments

Arguments Passed On Launch项中,点击+添加参数-paMach-O路径

参数添加成功,点击Close关闭弹窗

设置断点

TAEGETS中搜索nm关键字,点击llvm-nm,选择Build Phases

展开Compile Sources项,右键llvm-nm.cpp文件,菜单选择Reveal In Project Navigator,将文件显示在左侧

打开llvm-nm.cpp代码,找到main函数并设置好断点

运⾏程序

选择llvm-nm,但不要直接运行,因为编译会非常耗时

使用Run Without Building运⾏程序;第⼀次运⾏时,需要进⾏编译,以重新⽣成调试符号。再次运⾏,当代码没有改变,则不需要重新编译,直接运⾏现有可执⾏⽂件

顺利进入断点,通过下标访问argv,之前设置的默认参数已传入main函数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容