Why doesn't nm display the debugging symbols like it does for object files ?
Is that also normal that all the symbol addresses in my objects files are all 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
output:$ 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
output (addendum):$ 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)
Those debugging symbols output by nm -a foo.o
are the names of linkage sections
containing debugging info. The compiler puts all section names into the symbol
table of an object file because the linker will need them to merge input sections
into output sections in the output file. By default nm
does not report symbols that are
section names: with -a
it does. The linker does not put the names of
the merged output sections into the symbol table of the output file because
they can no longer be needed for any further merging - unless the linkage
is a partial linkage (-Wl,-r
) - in which case they are put into the symbol table.
Illustration:
$ 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
The symbol table of foobar.o
is:
$ 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
All sections, including debug sections, are represented.
By default nm
does not report section names:
$ nm foobar.o
0000000000000000 T bar
0000000000000000 r bint
0000000000000000 T foo
But nm -a
does:
$ 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
Now link a program and generate the mapfile:
$ gcc -g -o prog main.o foobar.o -Wl,-Map=mapfile
The (abbreviated) mapfile shows the input-to-output section merges:
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)
Note e.g. how the input function sections text.foo
and text.bar
are merged into the output .text
section; the input debug_info
sections from main.o
and foobar.o
are merged into the output debug_info
section, etc.
All the section names are gone from the symbol table of the output file:
$ 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
But the output section names remain section names:
$ 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
The .text
section of course survives, but .text.foo
and .text.bar
don't,
having been merged into .text
.
On the other hand, if we perform a partial linkage:
$ gcc -r -g -o prog.o main.o foobar.o
then the section names go into the symbol table:
$ readelf --syms prog.o
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
and they are reported by:
$ nm -a prog.o
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