为什么 nm 不像目标文件那样显示调试符号?
我的目标文件中所有符号地址都是0,这也正常吗?
main.c
:#include "foo.h"
int main()
{
foo();
return 0;
}
foo.c
:void foo()
{
}
foo.h
:#ifndef FOO_H
# define FOO_H
void foo();
#endif
libfoo.a
的制作和符号:$ gcc -c -g -o foo.o foo.c
$ nm -a foo.o
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_line_str
0000000000000000 N .debug_str
0000000000000000 T foo
0000000000000000 a foo.c
0000000000000000 t .text
$ ar rc libfoo.a foo.o
$ nm -a libfoo.a
foo.o:
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_line_str
0000000000000000 N .debug_str
0000000000000000 T foo
0000000000000000 a foo.c
0000000000000000 t .text
$
$ gcc -g main.c -L . -lfoo
$ nm -a a.out
0000000000000000 a
0000000000004010 B __bss_start
w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003e20 d _DYNAMIC
0000000000004010 D _edata
0000000000004018 B _end
0000000000001138 T _fini
000000000000112e T foo
0000000000000000 a foo.c
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main@GLIBC_2.34
0000000000001119 T main
0000000000000000 a main.c
0000000000001020 T _start
0000000000004010 D __TMC_END__
$
file
输出:$ file a.out
a.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=48cebaa6f43e93bb1805faa5b71d41f1d1e71501, for GNU/Linux 4.4.0, with debug_info, not stripped
$
readelf -S
输出(附录):$ readelf -S a.out
There are 34 section headers, starting at offset 0x37c0:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000040 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000378 00000378
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000039c 0000039c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003c0 000003c0
000000000000001c 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003e0 000003e0
0000000000000090 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000470 00000470
0000000000000088 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f8 000004f8
000000000000000c 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000508 00000508
0000000000000030 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000538 00000538
00000000000000c0 0000000000000018 A 6 0 8
[11] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[12] .text PROGBITS 0000000000001020 00001020
0000000000000115 0000000000000000 AX 0 0 16
[13] .fini PROGBITS 0000000000001138 00001138
000000000000000d 0000000000000000 AX 0 0 4
[14] .rodata PROGBITS 0000000000002000 00002000
0000000000000004 0000000000000004 AM 0 0 4
[15] .eh_frame_hdr PROGBITS 0000000000002004 00002004
0000000000000024 0000000000000000 A 0 0 4
[16] .eh_frame PROGBITS 0000000000002028 00002028
0000000000000074 0000000000000000 A 0 0 8
[17] .init_array INIT_ARRAY 0000000000003e10 00002e10
0000000000000008 0000000000000008 WA 0 0 8
[18] .fini_array FINI_ARRAY 0000000000003e18 00002e18
0000000000000008 0000000000000008 WA 0 0 8
[19] .dynamic DYNAMIC 0000000000003e20 00002e20
00000000000001a0 0000000000000010 WA 7 0 8
[20] .got PROGBITS 0000000000003fc0 00002fc0
0000000000000028 0000000000000008 WA 0 0 8
[21] .got.plt PROGBITS 0000000000003fe8 00002fe8
0000000000000018 0000000000000008 WA 0 0 8
[22] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[23] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[24] .comment PROGBITS 0000000000000000 00003010
0000000000000036 0000000000000001 MS 0 0 1
[25] .debug_aranges PROGBITS 0000000000000000 00003046
0000000000000060 0000000000000000 0 0 1
[26] .debug_info PROGBITS 0000000000000000 000030a6
00000000000000ab 0000000000000000 0 0 1
[27] .debug_abbrev PROGBITS 0000000000000000 00003151
000000000000007b 0000000000000000 0 0 1
[28] .debug_line PROGBITS 0000000000000000 000031cc
00000000000000a1 0000000000000000 0 0 1
[29] .debug_str PROGBITS 0000000000000000 0000326d
000000000000003d 0000000000000001 MS 0 0 1
[30] .debug_line_str PROGBITS 0000000000000000 000032aa
000000000000003e 0000000000000001 MS 0 0 1
[31] .symtab SYMTAB 0000000000000000 000032e8
0000000000000258 0000000000000018 32 7 8
[32] .strtab STRTAB 0000000000000000 00003540
000000000000011f 0000000000000000 0 0 1
[33] .shstrtab STRTAB 0000000000000000 0000365f
000000000000015c 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
nm -a foo.o
输出的那些调试符号是链接节的名称
包含调试信息。编译器将 all 节名称放入符号中
目标文件的表,因为链接器需要它们来合并输入部分
到输出文件中的输出部分。默认情况下 nm
不报告以下符号
部分名称:使用 -a
即可。链接器不放置名称
将输出部分合并到输出文件的符号表中,因为
任何进一步的合并不再需要它们 - 除非链接
是部分链接 (-Wl,-r
) - 在这种情况下,它们被放入符号表中。
图示:
$ cat foobar.c
static const int bint = 47;
void foo() __attribute__((section(".text.foo")));
void foo()
{
}
int bar() __attribute__((section(".text.bar")));
int bar()
{
return bint;
}
$ cat foobar.h
#ifndef FOOBAR_H
# define FOOBAR_H
void foo();
int bar();
#endif
$ cat main.c
#include "foobar.h"
int main()
{
foo();
return bar();
}
$ gcc -g -c main.c foobar.c
符号表操作系统
foobar.o
是:
$ readelf --syms foobar.o
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 4 .rodata
3: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 bint
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 .text.foo
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 .text.bar
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 .debug_info
7: 0000000000000000 0 SECTION LOCAL DEFAULT 9 .debug_abbrev
8: 0000000000000000 0 SECTION LOCAL DEFAULT 12 .debug_rnglists
9: 0000000000000000 0 SECTION LOCAL DEFAULT 14 .debug_line
10: 0000000000000000 0 SECTION LOCAL DEFAULT 16 .debug_str
11: 0000000000000000 0 SECTION LOCAL DEFAULT 17 .debug_line_str
12: 0000000000000000 11 FUNC GLOBAL DEFAULT 5 foo
13: 0000000000000000 15 FUNC GLOBAL DEFAULT 6 bar
代表了所有部分,包括调试部分。
默认情况下
nm
不报告部分名称:
$ nm foobar.o
0000000000000000 T bar
0000000000000000 r bint
0000000000000000 T foo
但是
nm -a
确实:
$ nm -a foobar.o
0000000000000000 T bar
0000000000000000 r bint
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_line_str
0000000000000000 N .debug_rnglists
0000000000000000 N .debug_str
0000000000000000 T foo
0000000000000000 a foobar.c
0000000000000000 r .rodata
0000000000000000 t .text.bar
0000000000000000 t .text.foo
现在链接程序并生成地图文件:
$ gcc -g -o prog main.o foobar.o -Wl,-Map=mapfile
(缩写)映射文件显示输入到输出部分合并:
Merging program properties
...[cut]...
Memory Configuration
...[cut]...
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
...[cut]...
.text 0x0000000000001040 0x121
...[cut]...
.text 0x0000000000001147 0x0 foobar.o
.text.foo 0x0000000000001147 0xb foobar.o
0x0000000000001147 foo
.text.bar 0x0000000000001152 0xf foobar.o
0x0000000000001152 bar
...[cut]...
.rodata 0x0000000000002000 0x8
...[cut]...
.rodata 0x0000000000002004 0x4 foobar.o
...[cut]...
.debug_info 0x0000000000000000 0xf9
*(.debug_info .gnu.linkonce.wi.*)
.debug_info 0x0000000000000000 0x74 main.o
.debug_info 0x0000000000000074 0x85 foobar.o
.debug_abbrev 0x0000000000000000 0xcc
*(.debug_abbrev)
.debug_abbrev 0x0000000000000000 0x65 main.o
.debug_abbrev 0x0000000000000065 0x67 foobar.o
.debug_line 0x0000000000000000 0xba
*(.debug_line .debug_line.* .debug_line_end)
.debug_line 0x0000000000000000 0x57 main.o
.debug_line 0x0000000000000057 0x63 foobar.o
...[cut]...
.debug_str 0x0000000000000000 0x98
*(.debug_str)
.debug_str 0x0000000000000000 0x98 main.o
0x93 (size before relaxing)
.debug_str 0x0000000000000098 0x93 foobar.o
...[cut]...
.debug_line_str
0x0000000000000000 0x34
*(.debug_line_str)
.debug_line_str
0x0000000000000000 0x34 main.o
0x54 (size before relaxing)
.debug_line_str
0x0000000000000034 0x51 foobar.o
...[cut] ...
OUTPUT(prog elf64-x86-64)
注意例如输入函数部分
text.foo
和 text.bar
如何合并到
输出.text
部分。
所有节名称都从输出文件的符号表中消失了:
$ readelf -W --syms prog
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.34 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
5: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (3)
Symbol table '.symtab' contains 39 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS Scrt1.o
2: 000000000000038c 32 OBJECT LOCAL DEFAULT 4 __abi_tag
3: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
4: 0000000000001070 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
5: 00000000000010a0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
6: 00000000000010e0 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
7: 0000000000004010 1 OBJECT LOCAL DEFAULT 24 completed.0
8: 0000000000003df8 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fini_array_entry
9: 0000000000001120 0 FUNC LOCAL DEFAULT 14 frame_dummy
10: 0000000000003df0 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_entry
11: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c
12: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
13: 0000000000002004 4 OBJECT LOCAL DEFAULT 16 bint
14: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
15: 0000000000002118 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
16: 0000000000000000 0 FILE LOCAL DEFAULT ABS
17: 0000000000003e00 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
18: 0000000000002008 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
19: 0000000000003fc0 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_
20: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.34
21: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
22: 0000000000004000 0 NOTYPE WEAK DEFAULT 23 data_start
23: 0000000000004010 0 NOTYPE GLOBAL DEFAULT 23 _edata
24: 0000000000001152 15 FUNC GLOBAL DEFAULT 14 bar
25: 0000000000001164 0 FUNC GLOBAL HIDDEN 15 _fini
26: 0000000000004000 0 NOTYPE GLOBAL DEFAULT 23 __data_start
27: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
28: 0000000000004008 0 OBJECT GLOBAL HIDDEN 23 __dso_handle
29: 0000000000002000 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
30: 0000000000001147 11 FUNC GLOBAL DEFAULT 14 foo
31: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 24 _end
32: 0000000000001040 38 FUNC GLOBAL DEFAULT 14 _start
33: 0000000000004010 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
34: 0000000000001129 30 FUNC GLOBAL DEFAULT 14 main
35: 0000000000004010 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__
36: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
37: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5
38: 0000000000001000 0 FUNC GLOBAL HIDDEN 11 _init
但是输出节名称仍然是节名称:
$ readelf -S prog
There are 36 section headers, starting at offset 0x3b10:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
0000000000000090 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000468 00000468
0000000000000088 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f0 000004f0
000000000000000c 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000500 00000500
0000000000000030 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000530 00000530
00000000000000c0 0000000000000018 A 6 0 8
[11] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000001020 00001020
0000000000000010 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 0000000000001030 00001030
0000000000000010 0000000000000010 AX 0 0 16
[14] .text PROGBITS 0000000000001040 00001040
0000000000000121 0000000000000000 AX 0 0 16
[15] .fini PROGBITS 0000000000001164 00001164
000000000000000d 0000000000000000 AX 0 0 4
[16] .rodata PROGBITS 0000000000002000 00002000
0000000000000008 0000000000000000 A 0 0 4
[17] .eh_frame_hdr PROGBITS 0000000000002008 00002008
000000000000003c 0000000000000000 A 0 0 4
[18] .eh_frame PROGBITS 0000000000002048 00002048
00000000000000d4 0000000000000000 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000003df0 00002df0
0000000000000008 0000000000000008 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000003df8 00002df8
0000000000000008 0000000000000008 WA 0 0 8
[21] .dynamic DYNAMIC 0000000000003e00 00002e00
00000000000001c0 0000000000000010 WA 7 0 8
[22] .got PROGBITS 0000000000003fc0 00002fc0
0000000000000040 0000000000000008 WA 0 0 8
[23] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[24] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[25] .comment PROGBITS 0000000000000000 00003010
0000000000000026 0000000000000001 MS 0 0 1
[26] .debug_aranges PROGBITS 0000000000000000 00003036
0000000000000070 0000000000000000 0 0 1
[27] .debug_info PROGBITS 0000000000000000 000030a6
00000000000000f9 0000000000000000 0 0 1
[28] .debug_abbrev PROGBITS 0000000000000000 0000319f
00000000000000cc 0000000000000000 0 0 1
[29] .debug_line PROGBITS 0000000000000000 0000326b
00000000000000ba 0000000000000000 0 0 1
[30] .debug_str PROGBITS 0000000000000000 00003325
0000000000000098 0000000000000001 MS 0 0 1
[31] .debug_line_str PROGBITS 0000000000000000 000033bd
0000000000000034 0000000000000001 MS 0 0 1
[32] .debug_rnglists PROGBITS 0000000000000000 000033f1
0000000000000021 0000000000000000 0 0 1
[33] .symtab SYMTAB 0000000000000000 00003418
00000000000003a8 0000000000000018 34 20 8
[34] .strtab STRTAB 0000000000000000 000037c0
00000000000001df 0000000000000000 0 0 1
[35] .shstrtab STRTAB 0000000000000000 0000399f
000000000000016c 0000000000000000 0 0 1
.text
部分当然会保留下来,但.text.foo
和.text.bar
不会,
已合并为 .text
.
另一方面,如果我们执行部分链接:
$ gcc -r -g -o prog main.o foobar.o
然后节名称进入符号表:
$ readelf --syms prog
Symbol table '.symtab' contains 24 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 SECTION LOCAL DEFAULT 1 .note.gnu.property
2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 .text
3: 0000000000000000 0 SECTION LOCAL DEFAULT 4 .text.foo
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 .text.bar
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 .rodata
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 .eh_frame
7: 0000000000000000 0 SECTION LOCAL DEFAULT 9 .data
8: 0000000000000000 0 SECTION LOCAL DEFAULT 10 .bss
9: 0000000000000000 0 SECTION LOCAL DEFAULT 11 .comment
10: 0000000000000000 0 SECTION LOCAL DEFAULT 12 .note.GNU-stack
11: 0000000000000000 0 SECTION LOCAL DEFAULT 13 .debug_aranges
12: 0000000000000000 0 SECTION LOCAL DEFAULT 15 .debug_info
13: 0000000000000000 0 SECTION LOCAL DEFAULT 17 .debug_abbrev
14: 0000000000000000 0 SECTION LOCAL DEFAULT 18 .debug_line
15: 0000000000000000 0 SECTION LOCAL DEFAULT 20 .debug_str
16: 0000000000000000 0 SECTION LOCAL DEFAULT 21 .debug_line_str
17: 0000000000000000 0 SECTION LOCAL DEFAULT 22 .debug_rnglists
18: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c
19: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
20: 0000000000000000 4 OBJECT LOCAL DEFAULT 6 bint
21: 0000000000000000 30 FUNC GLOBAL DEFAULT 2 main
22: 0000000000000000 11 FUNC GLOBAL DEFAULT 4 foo
23: 0000000000000000 15 FUNC GLOBAL DEFAULT 5 bar
他们的报道者:
$ nm -a prog
0000000000000000 T bar
0000000000000000 r bint
0000000000000000 b .bss
0000000000000000 n .comment
0000000000000000 d .data
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_aranges
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_line_str
0000000000000000 N .debug_rnglists
0000000000000000 N .debug_str
0000000000000000 r .eh_frame
0000000000000000 T foo
0000000000000000 a foobar.c
0000000000000000 T main
0000000000000000 a main.c
0000000000000000 r .note.gnu.property
0000000000000000 n .note.GNU-stack
0000000000000000 r .rodata
0000000000000000 t .text
0000000000000000 t .text.bar
0000000000000000 t .text.foo