1. strings命令:
这个命令可以用于扫描ELF文件(可执行程序、动态链接库、编译产生的目标文件)中可打印的字符串。
如果不加任何命令行参数,strings将输出ELF文件头中,位于.data段、.rodata段以及符号表中的常量字符串。
如果添加-a,将对整个ELF文件进行扫描,输出全部字符串,包括段名,比如.data、.bss等字符串。
2. file命令:
这个命令可以用于确定某个文件具体类型。本质上,是根据具体的ELF文件头中的幻数字段(Magic)来确定具体文件类型。
补充:ELF文件头的结构:
typedef struct {
unsigned char e_ident[16]; //幻数,16字节
uint16_t e_type;
uint16_t e_machine;
int32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
int32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
3. nm命令:
这个命令是names的缩写,顾名思义,就是用来查看二进制文件符号表中各个符号的名称、地址及类型。
在ELF文件中,符合分为不同的类型:
1) U:符号未定义,说明该符号在别的文件中定义。这种情况通常发生在主程序调用了某个库函数。
2) D:表明当前符号定义于.data段,即位于已初始化数据段,表示一个初始化全局变量(非static)。
3) B:表明当前符号定义于.bss段,即位于未初始化数据段,表示一个未初始化全局变量(非static)。
其值表示在.bss段中的偏移量,一般情况下,.bss端分配于RAM。
4) C:代表common symbol,本质上也是未初始化数据段。对于gcc编译的程序,未初始化全局变量(可能被别的obj引用)其类型为C。
和B不同的是,该符号表示对应变量只有在链接时才进行内存分配,其值表示该符号需要的字节数。
5) T:表明当前符号定义于.text段,即代码段,比如全局函数(非static)。
6) d: 和D本质上相同,表示当前变量是一个已初始化静态变量(static)。
7) b: 和B本质上相同,表示当前变量是一个未初始化静态变量(static)。
8) R: 只读数据段,即.rodata段。主要存放程序中定义的整型、字符串常量。
9) A: 该符号的值是绝对的,在以后的链接过程中,不允许进行该表。
这样的符号值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量表中的位置。
10) t: 和T本质上相同,表示当前符号定义于.text代码段,比如static函数。
举例:main.c
#include <stdio.h>
static int a = 100;
static int b;
extern int c;
int d = 101;
int e;
int func01()
{
}
static int func02()
{
}
int main()
{
printf("a:%d,b:%d,c:%d,d:%d,e:%d\n",a,b,c,d,e);
}
采用以下命令分别编译:
gcc -c main.c
g++ -c main.c
对产生的main.o目标文件进行nm,得到的结果如下:
1) C目标文件:
0000000000000000 d a
0000000000000000 b b
U c
0000000000000004 D d
0000000000000004 C e
0000000000000000 T func01
0000000000000006 t func02
000000000000000c T main
U printf
2) C++目标文件:
U c
0000000000000004 D d
0000000000000000 B e
000000000000000c T main
U printf
0000000000000000 T _Z6func01v
0000000000000000 d _ZL1a
0000000000000004 b _ZL1b
0000000000000006 t _ZL6func02v
可见:
1) C++会对static变量做名称修饰,对非static全局变量则不会进行名称修饰。
2) 对于未初始化全局变量e,gcc会设置该符号类型为e,g++则会设置该符号类型为B。
3) 非static全局变量/函数,一般符号类型标识为大写,static变量或函数,一般符号类型标识为小写。
4. ldd命令:
该命令是list dynamic dependencies的缩写,用于查看当前可执行程序依赖的所有动态链接库。
该命令很常用,具体用法参见ldd手册。
5.c++filt命令:
该命令主要用于将一个经过C++名称修饰(name mangling)的符号,还原为原始符号。