文章目录
- 前言
- 一、strip
- 1.1 GNU Binutils
- 1.2 strip
- 二、使用步骤
- 1.1 demo
- 1.2 strip –strip-debug
- 1.3 符号信息
- 1.3.1 查看模块的符号信息
- 1.3.2 符号表
- 1.3.3 strip -s
- 总结
- 参考资料
前言
最近学习了Linux内核模块的符号信息和 strip 命令,总结一下。
一、strip
1.1 GNU Binutils
GNU Binutils 是二进制工具的集合。 主要有:
ld - the GNU linker.as - the GNU assembler.
其他常用的一些工具:
ar - A utility for creating, modifying and extracting from archives.nm - Lists symbols from object files.objcopy - Copies and translates object files.objdump - Displays information from object files.readelf - Displays information from any ELF format object file.size - Lists the section sizes of an object or archive file.strings - Lists printable strings from files.strip - Discards symbols.......
binutils 已被移植到大多数主要的 Unix variants 中,是为GNU系统(以及GNU/Linux)提供编译和链接程序的工具。
本文主要介绍strip命令的使用。
1.2 strip
(1)
strip - Discard symbols from object files.
Discard 目标文件 objfile 中的符号。
(2)
-s --strip-allRemove all symbols. -g -S -d --strip-debug Remove debugging symbols only.
(3)
--info Display a list showing all architectures and object formats available.
二、使用步骤
1.1 demo
我以一个简单的内核模块为例子:
#include #include //内核模块初始化函数static int __init hello_init(void){printk(KERN_EMERG "Hello World\n");return 0;}//内核模块退出函数static void __exit hello_exit(void){printk(KERN_DEBUG "exit\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");
编译出来的内核模块:
可以看出内核模块带有debug_info信息,所以导致文件大小比较大。
readelf -S helloworld.ko
有很多带debug的Section。
1.2 strip –strip-debug
我用 strip –strip-debug 命令去除内核模块的调试信息:
strip --strip-debug helloworld.ko
可见调试信息没有了,内核模块一下小了很多。
readelf -S helloworld.ko
没有带有debug的Section。
依然能够正常使用内核模块:
1.3 符号信息
1.3.1 查看模块的符号信息
readelf -s helloworld.ko-s--symbols --syms Displays the entries in symbol table section of the file, if it has one.
nm helloworld.ko
1.3.2 符号表
(1)
symtab 保存了二进制文件的符号表,符号表保存了查找程序符号、为符合赋值,重定位符号所需要的全部信息。有一个专门的section来保存符号表。符号表表项的格式由下列数据结构表示:
/* Symbol table entry.*/typedef struct{Elf64_Wordst_name;/* Symbol name (string tbl index) */unsigned charst_info;/* Symbol type and binding */unsigned char st_other;/* Symbol visibility */Elf64_Sectionst_shndx;/* Section index */Elf64_Addrst_value;/* Symbol value */Elf64_Xwordst_size;/* Symbol size */} Elf64_Sym;
符号的主要任务是将一个字符串和一个值关联起来。
(2)
一个符号的确切用途由st_info定义,由两部分组成:Symbol type 和 Symbol binding。
/* How to extract and insert information held in the st_info field.*/#define ELF32_ST_BIND(val)(((unsigned char) (val)) >> 4)#define ELF32_ST_TYPE(val)((val) & 0xf)#define ELF32_ST_INFO(bind, type)(((bind) << 4) + ((type) & 0xf))/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.*/#define ELF64_ST_BIND(val)ELF32_ST_BIND (val)#define ELF64_ST_TYPE(val)ELF32_ST_TYPE (val)#define ELF64_ST_INFO(bind, type)ELF32_ST_INFO ((bind), (type))
(3)
Symbol type:
/* Legal values for ST_TYPE subfield of st_info (symbol type).*/#define STT_NOTYPE0/* Symbol type is unspecified */#define STT_OBJECT1/* Symbol is a data object */#define STT_FUNC2/* Symbol is a code object */#define STT_SECTION3/* Symbol associated with a section */#define STT_FILE4/* Symbol's name is file name */#define STT_COMMON5/* Symbol is a common data object */#define STT_TLS6/* Symbol is thread-local data object*/#defineSTT_NUM7/* Number of defined types.*/#define STT_LOOS10/* Start of OS-specific */#define STT_GNU_IFUNC10/* Symbol is indirect code object */#define STT_HIOS12/* End of OS-specific */#define STT_LOPROC13/* Start of processor-specific */#define STT_HIPROC15/* End of processor-specific */
主要说明三个:
STT_NOTYPE:表示符号的类型未指定,用于未定义引用。
STT_OBJECT:表示符号关联到一个数据对象,比如变量、数组或指针。
STT_FUNC:表示符号关联到一个代码对象,比如函数或过程。
(4)
Symbol binding:
/* Legal values for ST_BIND subfield of st_info (symbol binding).*/#define STB_LOCAL0/* Local symbol */#define STB_GLOBAL1/* Global symbol */#define STB_WEAK2/* Weak symbol */#defineSTB_NUM3/* Number of defined types.*/#define STB_LOOS10/* Start of OS-specific */#define STB_GNU_UNIQUE10/* Unique symbol.*/#define STB_HIOS12/* End of OS-specific */#define STB_LOPROC13/* Start of processor-specific */#define STB_HIPROC15/* End of processor-specific */
主要说明三个:
STB_LOCAL:局部符号,只在目标文件内部可见,在与其它程序的其它部分合并时,是不可见的。如果一个程序的几个目标文件都定义相同的符号名,也不会有问题。局部符号互不干扰。
STB_GLOBAL:全局符号,在定义的目标文件内部可见,也可以由构成的其他目标文件引用。每个全局符号在一个程序内部都只能定义一次,否则链接器将报告错误。
指向符号的未定义引用,将在重定位期间确定相关符号的位置。如果对全局符号的未定义引用无法解决,则拒绝程序执行或静态绑定。
STB_WEAK:整个程序内可见,但可以有多个定义。如果程序中一个全局符号和一个局部符号名字相同,全局符号优先处理。
即使一个弱符号未定义,程序也可以静态或动态链接,并将符号指定为0值。
1.3.3 strip -s
strip -s helloworld.ko
去除模块的所有符号:
二进制模块的符号信息全部被strip,如下所示:
去除所有模块后,内核模块不能正常加载:
总结
本文是内核模块符号表的一些内容以及strip命令的使用。
参考资料
深入Linux内核架构
https://www.gnu.org/software/binutils/