objdump命令
在 Linux 中,可以使用 objdump 命令来反汇编 ko 文件并查看其中的宏定义值。
以下是如何使用 objdump 命令查看 ko 文件中的宏定义值的示例:
objdump -d <ko文件> | grep '<宏名称>'
其中,-d 参数表示反汇编目标文件,grep 命令用于查找特定的宏定义。
例如,如果您想查看 ko 文件中 MODULE_LICENSE 宏的定义值,可以使用以下命令:
objdump -d hello.ko | grep '<MODULE_LICENSE>'
这将输出类似以下内容的结果:
ffffffffa0000f3c <init_module>:
ffffffffa0000f52: 48 8b 15 a5 11 00 00 mov 0x11a5(%rip),%rdx # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f59: 48 8b 0d 9a 11 00 00 mov 0x119a(%rip),%rcx # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f60: 48 8b 05 95 11 00 00 mov 0x1195(%rip),%rax # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f67: 48 8b 35 90 11 00 00 mov 0x1190(%rip),%rsi # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f6e: 48 8b 2d 8b 11 00 00 mov 0x118b(%rip),%rbp # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f75: 48 8d 15 84 11 00 00 lea 0x1184(%rip),%rdx # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f7c: 48 8d 0d 7d 11 00 00 lea 0x117d(%rip),%rcx # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f83: 48 8d 05 76 11 00 00 lea 0x1176(%rip),%rax # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f8a: 48 8d 35 71 11 00 00 lea 0x1171(%rip),%rsi # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f91: 48 8d 2d 6c 11 00 00 lea 0x116c(%rip),%rbp # ffffffff815e1f00 <__this_module+0x80>
ffffffffa0000f98: 48 81 ec b8 00 00 00 sub $0xb8,%rsp
ffffffffa0000f9f: 48 8b 05 1e 11 00 00 mov 0x111e(%rip),%rax # ffffffff815e1f00 <__this_module+0x80>
...
nm命令
在这个示例中,可以看到 MODULE_LICENSE 宏定义值在 ffffffff815e1f00 地址中,可以根据需要进一步查看这个地址的内容。
在Linux系统中,可以使用nm命令查看目标文件或共享库中的符号表信息。nm命令可以列出目标文件或共享库中定义的符号名以及每个符号名对应的地址、类型和其他属性。
下面是使用nm命令查看ko文件中符号表信息的示例:
nm -g <ko文件>
其中,-g参数表示只显示全局符号表,即在模块中定义并且可以被其他模块引用的符号。
例如,假设我们有一个名为hello.ko的内核模块文件,可以使用以下命令查看hello.ko文件中的符号表信息:
nm -g hello.ko
这将列出hello.ko文件中定义的所有全局符号及其地址,例如:
0000000000000000 T hello_init
0000000000000010 T hello_exit
其中,T表示符号类型为Text段,即代码段。hello_init和hello_exit是在hello.ko模块中定义的函数名。
需要注意的是,nm命令只能查看已编译的目标文件或共享库中的符号表信息,不能查看源代码中的符号定义。如果您需要查看源代码中的符号定义,可以使用grep等工具进行搜索。
U通常是指在Linux符号表中的一种符号类型,表示未定义的符号(Undefined Symbol)。在程序编译时,如果某个函数或变量在当前模块中没有定义,但在其他模块中有定义,编译器就会在符号表中为该符号创建一个U类型的符号表项,表示该符号未定义。
例如,假设我们有两个模块A和B,模块A中定义了一个函数foo(),而模块B中调用了函数foo()。在编译模块B时,编译器会在符号表中为函数foo()创建一个U类型的符号表项,表示该符号在当前模块中未定义,但在其他模块中有定义。
在链接时,编译器会将所有模块中的符号进行解析和链接,将所有未定义的符号与其他模块中的定义进行匹配,最终生成可执行文件或共享库。
因此,如果在使用nm命令查看符号表时,发现某个符号的类型为U,就表示该符号未在当前模块中定义。
readelf
readelf 是一个用于查看 ELF 文件信息的命令行工具,-p 参数表示显示特定段的内容,.GCC.command.line 是一个特定的段名,用于存储编译器命令行参数。
因此,readelf -p .GCC.command.line aa.ko 命令的含义是显示 aa.ko 文件中 .GCC.command.line 段的内容,即编译器执行时使用的命令行参数。
在 Linux 内核中,.GCC.command.line 段通常用于存储内核模块的编译参数,例如编译器版本、编译选项等。通过查看该段的内容,可以了解内核模块的编译信息,例如是否开启了调试信息、是否启用了某些特定的编译选项等。
除了查看 .GCC.command.line 段的内容之外,readelf 命令还可以用于查看 ELF 文件的其他信息,包括:
- ELF 文件头信息,包括文件类型、机器类型、入口地址等;
- 段表信息,包括段的起始地址、大小、属性等;
- 符号表信息,包括符号的名称、类型、值等;
- 动态符号表信息,包括动态符号的名称、类型、值等;
- 动态链接器信息,包括动态链接器名称、动态链接器需要的信息等。
通过 readelf 命令,可以深入了解 ELF 文件的结构和内容,以及了解内核模块的编译信息、符号表信息等。例如,以下是一些常用的 readelf 命令示例:
- 查看 ELF 文件头信息:readelf -h <文件名>
- 查看段表信息:readelf -S <文件名>
- 查看符号表信息:readelf -s <文件名>
- 查看动态符号表信息:readelf -d <文件名>
- 查看动态链接器信息:readelf -l <文件名>
需要注意的是,readelf 命令需要安装 binutils 工具包才能使用,可以通过以下命令安装:
sudo apt-get install binutils