有多种工具可用来分析 ELF 文件的内容。要显示文件的大小,请使用 size(1) 命令。
$ size -x libfoo.so.1 59c + 10c + 20 = 0x6c8 $ size -xf libfoo.so.1 ..... + 1c(.init) + ac(.text) + c(.fini) + 4(.rodata) + \ ..... + 18(.data) + 20(.bss) ..... |
第一个示例指明共享库文本、数据以及 bss(SunOS 操作系统早期发行版中使用的一种分类)的大小。
ELF 格式通过将数据组织到多个节中,为表示文件中的数据提供了更佳的粒度。第二个示例显示了文件的每个可装入节的大小。
分配给单元的各节称为段,某些段描述如何将文件的各部分映射到内存。请参见 mmap(2)。可以使用 dump(1) 命令并检查 LOAD 项来显示这些可装入段。
$ dump -ov libfoo.so.1 libfoo.so.1: ***** PROGRAM EXECUTION HEADER ***** Type Offset Vaddr Paddr Filesz Memsz Flags Align LOAD 0x94 0x94 0x0 0x59c 0x59c r-x 0x10000 LOAD 0x630 0x10630 0x0 0x10c 0x12c rwx 0x10000 |
在共享库 libfoo.so.1 中存在两种可装入段,通常称为文本段和数据段。将映射文本段以允许读取和执行其内容 (r-x),同时将映射数据段以允许修改其内容 (rwx)。数据段的内存大小 (Memsz) 不同于文件大小 (Filesz)。该差异说明存在 .bss 节,此节属于数据段并在装入数据段时动态创建。
程序员通常根据定义其代码中的函数和数据元素的符号来考虑文件。可以使用 nm(1) 显示这些符号。 例如:
$ nm -x libfoo.so.1 [Index] Value Size Type Bind Other Shndx Name ......... [39] |0x00000538|0x00000000|FUNC |GLOB |0x0 |7 |_init [40] |0x00000588|0x00000034|FUNC |GLOB |0x0 |8 |foo [41] |0x00000600|0x00000000|FUNC |GLOB |0x0 |9 |_fini [42] |0x00010688|0x00000010|OBJT |GLOB |0x0 |13 |data [43] |0x0001073c|0x00000020|OBJT |GLOB |0x0 |16 |bss ......... |
可以通过引用符号表中的节索引 (Shndx) 字段并使用 dump(1) 显示文件各节来确定包含符号的节。 例如:
$ dump -hv libfoo.so.1 libfoo.so.1: **** SECTION HEADER TABLE **** [No] Type Flags Addr Offset Size Name ......... [7] PBIT -AI 0x538 0x538 0x1c .init [8] PBIT -AI 0x554 0x554 0xac .text [9] PBIT -AI 0x600 0x600 0xc .fini ......... [13] PBIT WA- 0x10688 0x688 0x18 .data [16] NOBI WA- 0x1073c 0x73c 0x20 .bss ......... |
上述 nm(1) 和 dump(1) 示例的输出显示函数 _init、foo 和 _fini 与节 .init、.text 和 .fini 关联。这些节由于具有只读性质,因此属于文本段。
同样,数据数组 data 和 bss 分别与节 .data 和 .bss 关联。这些节由于具有可写性质,因此属于数据段。
先前的 dump(1) 显示已针对本示例进行了简化。