菜鸟科技网

nlist命令如何使用?

nlist 是一个在 Unix 和类 Unix 系统(如 Linux)中,用于从目标文件(如可执行文件、目标文件、共享库等)中提取符号名的命令行工具,这些符号名通常包括变量名和函数名。

nlist命令如何使用?-图1
(图片来源网络,侵删)

基本概念

什么是符号? 在程序编译和链接的过程中,源代码中的变量名和函数名会被转换成符号,这些符号存储在目标文件或最终的可执行文件中,符号分为几种类型:

  • 定义符号: 在当前文件中定义的全局变量或函数,你在一个 .c 文件中实现了一个 void my_function()my_function 就是一个定义符号。
  • 未定义符号: 在当前文件中引用,但定义在其他文件中的变量或函数,链接器的工作之一就是找到这些未定义符号的定义。
  • 静态符号: 使用 static 关键字声明的函数或变量,它们的作用域仅限于当前文件,不会暴露给链接器。

nlist 的作用 nlist 命令读取一个目标文件,并根据你提供的符号名列表,从该文件中查找这些符号的信息,如果符号存在,它会输出该符号的地址、类型等信息。

语法

nlist 命令的基本语法如下:

nlist [option] filename symbol...

参数说明:

nlist命令如何使用?-图2
(图片来源网络,侵删)
  • option: 可选的命令行选项。
  • filename: 必须参数,要检查的目标文件路径(a.out, mylib.so)。
  • symbol...: 可选参数,一个或多个你想要查找的符号名,如果你不提供任何符号名,nlist 默认会输出一个预定义的符号列表(这通常是特定于操作系统的,_edata, _end 等)。

常用选项

nlist 的选项可能因 Unix 发行版(如 BSD, Solaris)而略有不同,但以下是一些常见的选项:

  • -g: 只列出全局符号(定义和未定义的)。
  • -u: 只列出未定义的符号。
  • -n: 按地址(数值)排序输出结果。
  • -p: 不对符号名进行排序,保持文件中的原始顺序(这是默认行为)。
  • -s: 显示符号的类型(T 表示文本/代码段,D 表示数据段,U 表示未定义等)。
  • -x: 以十六进制格式显示符号的地址。

输出格式

nlist 找到符号时,其默认输出格式通常是:

address type symbol_name

输出字段解释:

  • address: 符号在内存中的地址(通常是十六进制格式)。
  • type: 符号的类型,用一个字母表示,常见的类型有:
    • T: 文本符号,通常是一个函数。
    • D: 数据符号,通常是一个已初始化的全局变量。
    • B: BSS 符号,通常是一个未初始化的全局变量。
    • U: 未定义符号,在当前文件中被引用但未定义。
    • A: 绝对符号,地址是固定的。
    • W: 弱符号,类似于 TD,但链接时如果没有找到强定义,也不会报错。
  • symbol_name: 符号的名称。

使用示例

假设我们有一个 C 程序 test.c

nlist命令如何使用?-图3
(图片来源网络,侵删)
// test.c
#include <stdio.h>
int global_var = 10; // 全局变量,已初始化 (D)
static int static_var = 20; // 静态变量,不对外暴露
void my_function() { // 全局函数 (T)
    printf("Hello from my_function!\n");
}
int main() {
    my_function();
    return 0;
}

编译它:

gcc -o test test.c

我们使用 nlist 来检查 test 这个可执行文件。

示例 1:查找特定符号

查找 global_varmy_function

nlist test global_var my_function

可能的输出:

0000000000404014 D global_var
0000000000401126 T my_function

解释:

  • global_var 的地址是 0x404014,类型是 D(数据段)。
  • my_function 的地址是 0x401126,类型是 T(文本段/代码段)。

示例 2:查找不存在的符号

查找一个不存在的符号 non_existent_func

nlist test non_existent_func

输出: 如果没有找到,nlist 可能会静默退出,或者输出一个空行,具体取决于实现。

示例 3:使用 -s-x 选项

以更详细和易读的格式查看符号。

nlist -s -x test global_var my_function

可能的输出:

0x404014 D global_var
0x401126 T my_function

在这个例子中,-x 选项确保地址以十六进制显示(虽然默认通常也是),而 -s 选项明确要求显示类型。

示例 4:查找未定义符号

如果我们的程序调用了另一个库中的函数,printf,它就是一个未定义符号。

nlist -u test printf

可能的输出:

U printf

解释:

  • printftest 文件中被引用(在 my_function 内部),但它的定义在 libc.so 库中,因此类型是 U(未定义)。

现代替代工具

虽然 nlist 是一个经典工具,但在现代 Linux 系统中,开发者更倾向于使用更强大、更通用的工具,

  1. nm

    • 这是最常用、最推荐的替代品。nm 列出目标文件中的符号表,功能比 nlist 更丰富,输出格式更灵活,并且是 GNU Binutils 的一部分,在所有 Linux 系统上都可用。
    • 示例:nm test 会列出 test 文件中的所有符号。
  2. objdump

    • 这是一个极其强大的工具,用于显示一个或多个目标文件的信息,它可以显示反汇编代码、头部信息、符号表、重定位条目等。
    • 要查看符号表,可以使用:objdump -t test
  3. readelf

    • 专门用于分析 ELF (Executable and Linkable Format) 格式文件的工具,这是 Linux 下最常用的可执行文件格式。
    • 要查看符号表,可以使用:readelf -s test
特性 nlist nm objdump / readelf
主要用途 从文件中提取特定符号的信息。 列出目标文件的符号表。 显示目标文件的详细信息(包括但不限于符号)。
优点 简单直接,专注于符号查找。 功能强大,选项丰富,是行业标准。 功能最全面,是二进制分析的“瑞士军刀”。
缺点 功能相对有限,选项较少,在现代系统上可能不被默认安装或行为略有差异。 - 输出信息可能过于冗杂,对于简单任务显得笨重。
推荐场景 遇到旧系统或脚本,需要快速查找几个已知符号。 日常开发和调试的首选工具 深入分析二进制文件,如反汇编、检查段信息等。

nlist 是一个历史悠久的工具,理解它有助于了解 Unix 系统的底层工作原理,但在今天,如果你在 Linux 上工作,nm 是处理符号表更现代、更可靠的选择。

分享:
扫描分享到社交APP
上一篇
下一篇