runsisi's

technical notes

ELF headers

2019-09-08 runsisi#elf

elf

binutils

分析 ELF 文件的工具主要有如下几个:

$ dpkg -L binutils
/usr/bin/nm
/usr/bin/objdump
/usr/bin/readelf

实际上是它们都是指向 binutils-x86-64-linux-gnu 中文件的符号链接:

$ dpkg -L binutils-x86-64-linux-gnu
/usr/bin/x86_64-linux-gnu-nm
/usr/bin/x86_64-linux-gnu-objdump
/usr/bin/x86_64-linux-gnu-readelf
$ sudo apt install pax-utils
$ dpkg -L pax-utils
/usr/bin/dumpelf
/usr/bin/lddtree
/usr/bin/pspax
/usr/bin/scanelf
/usr/bin/scanmacho
/usr/bin/symtree

ELF file header

ELF 主要结构体定义:

$ man 5 elf

读取 ELF file header:

$ readelf -h main.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1560 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 12

$ readelf -h main
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x700
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6680 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

$ readelf -h libso.so.1.0.0
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x620
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6248 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         28
  Section header string table index: 27

$ cat > gomain.go <<EOF
> package main
> 
> import "fmt"
> 
> func main() {
>     fmt.Println("Hello world")
> }
> EOF
$ go build gomain.go
$ readelf -h gomain
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x452270
  Start of program headers:          64 (bytes into file)
  Start of section headers:          456 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         24
  Section header string table index: 3
e_type    This member of the structure identifies the object file type:

                 ET_NONE         An unknown type.
                 ET_REL          A relocatable file.
                 ET_EXEC         An executable file.
                 ET_DYN          A shared object.
                 ET_CORE         A core file.

ET_REL 表示编译过程中的对象文件(gcc -c),ET_EXEC 表示静态链接的可执行文件,ET_DYN 表示动态链接的可执行文件或动态库,ET_CORE 表示 coredump 文件。

dumpelf 比 readelf 更接近底层实现(以数据结构的形式进行呈现):

$ dumpelf -v main
#include <elf.h>

/*
 * ELF dump of 'main'
 *     8536 (0x2158) bytes
 */

Elf64_Dyn dumpedelf_dyn_0[];
struct {
	Elf64_Ehdr ehdr;
	Elf64_Phdr phdrs[9];
	Elf64_Shdr shdrs[29];
	Elf64_Dyn *dyns;
} dumpedelf_0 = {

.ehdr = {
	.e_ident = { /* (EI_NIDENT bytes) */
		/* [0] EI_MAG:        */ 0x7F,'E','L','F',
		/* [4] EI_CLASS:      */ 2 , /* (ELFCLASS64) */
		/* [5] EI_DATA:       */ 1 , /* (ELFDATA2LSB) */
		/* [6] EI_VERSION:    */ 1 , /* (EV_CURRENT) */
		/* [7] EI_OSABI:      */ 0 , /* (ELFOSABI_NONE) */
		/* [8] EI_ABIVERSION: */ 0 ,
		/* [9-15] EI_PAD:     */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	},
	.e_type      = 3          , /* (ET_DYN) */
	.e_machine   = 62         , /* (EM_X86_64) */
	.e_version   = 1          , /* (EV_CURRENT) */
	.e_entry     = 0x700      , /* (start address at runtime) */
	.e_phoff     = 64         , /* (bytes into file) */
	.e_shoff     = 6680       , /* (bytes into file) */
	.e_flags     = 0x0        ,
	.e_ehsize    = 64         , /* (bytes) */
	.e_phentsize = 56         , /* (bytes) */
	.e_phnum     = 9          , /* (program headers) */
	.e_shentsize = 64         , /* (bytes) */
	.e_shnum     = 29         , /* (section headers) */
	.e_shstrndx  = 28        
},

.phdrs = {
/* Program Header #0 0x40 */
{
	.p_type   = 6          , /* [PT_PHDR] */
	.p_offset = 64         , /* (bytes into file) */
	.p_vaddr  = 0x40       , /* (virtual addr at runtime) */
...
// DT_RPATH    String table offset to library search path
$ scanelf -r main
 TYPE   RPATH FILE 
ET_DYN . main

// DT_NEEDED   String table offset to name of a needed library
$ scanelf -n main
 TYPE   NEEDED FILE 
ET_DYN libso.so.1,libc.so.6 main

Whenever a library defines a soname, it is that soname that is stored in the DT_NEEDED field of ELF objects linked against that library.

program headers (describing segments in execution view)

读取 ELF program headers:

$ readelf -l main

Elf file type is DYN (Shared object file)
Entry point 0x700
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000001f8 0x00000000000001f8  R      0x8
  INTERP         0x0000000000000238 0x0000000000000238 0x0000000000000238
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000bd8 0x0000000000000bd8  R E    0x200000
  LOAD           0x0000000000000d88 0x0000000000200d88 0x0000000000200d88
                 0x0000000000000289 0x00000000000002a0  RW     0x200000
  DYNAMIC        0x0000000000000d98 0x0000000000200d98 0x0000000000200d98
                 0x0000000000000210 0x0000000000000210  RW     0x8
  NOTE           0x0000000000000254 0x0000000000000254 0x0000000000000254
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_EH_FRAME   0x0000000000000a40 0x0000000000000a40 0x0000000000000a40
                 0x000000000000004c 0x000000000000004c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000000d88 0x0000000000200d88 0x0000000000200d88
                 0x0000000000000278 0x0000000000000278  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .init_array .fini_array .dynamic .got .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .init_array .fini_array .dynamic .got

查看进程地址空间(内存视图):

$ man pmap
$ cat /proc/15929/maps
555555554000-555555555000 r-xp 00000000 08:05 412321                     /home/runsisi/working/test/elf-symbol-experiment/main
555555754000-555555755000 r--p 00000000 08:05 412321                     /home/runsisi/working/test/elf-symbol-experiment/main
555555755000-555555756000 rw-p 00001000 08:05 412321                     /home/runsisi/working/test/elf-symbol-experiment/main
555555756000-555555777000 rw-p 00000000 00:00 0                          [heap]
7ffff77e2000-7ffff79c9000 r-xp 00000000 08:05 7357802                    /lib/x86_64-linux-gnu/libc-2.27.so
7ffff79c9000-7ffff7bc9000 ---p 001e7000 08:05 7357802                    /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7bc9000-7ffff7bcd000 r--p 001e7000 08:05 7357802                    /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7bcd000-7ffff7bcf000 rw-p 001eb000 08:05 7357802                    /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7bcf000-7ffff7bd3000 rw-p 00000000 00:00 0 
7ffff7bd3000-7ffff7bd4000 r-xp 00000000 08:05 418522                     /home/runsisi/working/test/elf-symbol-experiment/libso.so.1.0.0
7ffff7bd4000-7ffff7dd3000 ---p 00001000 08:05 418522                     /home/runsisi/working/test/elf-symbol-experiment/libso.so.1.0.0
7ffff7dd3000-7ffff7dd4000 r--p 00000000 08:05 418522                     /home/runsisi/working/test/elf-symbol-experiment/libso.so.1.0.0
7ffff7dd4000-7ffff7dd5000 rw-p 00001000 08:05 418522                     /home/runsisi/working/test/elf-symbol-experiment/libso.so.1.0.0
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:05 7352967                    /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7fc0000-7ffff7fc3000 rw-p 00000000 00:00 0 
7ffff7ff5000-7ffff7ff7000 rw-p 00000000 00:00 0 
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00027000 08:05 7352967                    /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffd000-7ffff7ffe000 rw-p 00028000 08:05 7352967                    /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

更详细的进程地址空间信息(pmap -X):

$ cat /proc/15929/smaps
555555554000-555555555000 r-xp 00000000 08:05 412321                     /home/runsisi/working/test/elf-symbol-experiment/main
Size:                  4 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                   4 kB
Pss:                   4 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         4 kB
Referenced:            4 kB
Anonymous:             4 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB
...

section headers (describing sections in linking view)

读取 ELF section headers:

$ readelf -S main
There are 29 section headers, starting at offset 0x1a18:

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         0000000000000238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000000254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000000274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298
       0000000000000040  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000000002d8  000002d8
       0000000000000180  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000000458  00000458
       00000000000000d9  0000000000000000   A       0     0     1
...

反汇编指定的 section:

$ objdump -d -j .text main | grep -A 20 \<main\>:
000000000000080a <main>:
 80a:	55                   	push   %rbp
 80b:	48 89 e5             	mov    %rsp,%rbp
 80e:	48 8d 3d 7f 01 00 00 	lea    0x17f(%rip),%rdi        # 994 <_IO_stdin_used+0x4>
 815:	e8 a6 fe ff ff       	callq  6c0 <puts@plt>
 81a:	b8 00 00 00 00       	mov    $0x0,%eax
 81f:	e8 a8 00 00 00       	callq  8cc <x_hello>
 824:	b8 00 00 00 00       	mov    $0x0,%eax
 829:	e8 b2 fe ff ff       	callq  6e0 <so_hello@plt>
 82e:	c6 05 db 07 20 00 62 	movb   $0x62,0x2007db(%rip)        # 201010 <g_x_char>
 835:	48 c7 05 d8 07 20 00 	movq   $0x2,0x2007d8(%rip)        # 201018 <g_so_long>
 83c:	02 00 00 00 
 840:	48 8d 3d 64 01 00 00 	lea    0x164(%rip),%rdi        # 9ab <_IO_stdin_used+0x1b>
 847:	e8 74 fe ff ff       	callq  6c0 <puts@plt>
 84c:	0f b6 05 bd 07 20 00 	movzbl 0x2007bd(%rip),%eax        # 201010 <g_x_char>
 853:	0f be c0             	movsbl %al,%eax
 856:	89 c2                	mov    %eax,%edx
 858:	48 8d 35 b1 07 20 00 	lea    0x2007b1(%rip),%rsi        # 201010 <g_x_char>
 85f:	48 8d 3d 5d 01 00 00 	lea    0x15d(%rip),%rdi        # 9c3 <_IO_stdin_used+0x33>
 866:	b8 00 00 00 00       	mov    $0x0,%eax
 86b:	e8 60 fe ff ff       	callq  6d0 <printf@plt>
...

relocation section

$ readelf -r main

Relocation section '.rela.dyn' at offset 0x578 contains 9 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000200d88  000000000008 R_X86_64_RELATIVE                    800
000000200d90  000000000008 R_X86_64_RELATIVE                    7c0
000000201008  000000000008 R_X86_64_RELATIVE                    201008
000000200fd8  000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000200fe0  000400000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
000000200fe8  000500000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000200ff0  000700000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000200ff8  000800000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0
000000201018  000b00000005 R_X86_64_COPY     0000000000201018 g_so_long + 0

Relocation section '.rela.plt' at offset 0x650 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000200fc0  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
000000200fc8  000300000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000200fd0  000600000007 R_X86_64_JUMP_SLO 0000000000000000 so_hello + 0

dynamic section

.dynamic: Holds all needed information for dynamic linking.

d_tag     This member may have any of the following values:

                 DT_NULL     Marks end of dynamic section

                 DT_NEEDED   String table offset to name of a needed library

                 DT_PLTRELSZ Size in bytes of PLT relocation entries

                 DT_PLTGOT   Address of PLT and/or GOT    // exe .got / so .got.plt

                 DT_HASH     Address of symbol hash table   // .gnu.hash

                 DT_STRTAB   Address of string table    // .dynstr

                 DT_SYMTAB   Address of symbol table    // .dynsym

                 DT_RELA     Address of Rela relocation table   // .rela.dyn

                 DT_RELASZ   Size in bytes of the Rela relocation table

                 DT_RELAENT  Size in bytes of a Rela relocation table entry

                 DT_STRSZ    Size in bytes of string table

                 DT_SYMENT   Size in bytes of a symbol table entry

                 DT_INIT     Address of the initialization function   // .init

                 DT_FINI     Address of the termination function      // .fini

                 DT_SONAME   String table offset to name of shared object

                 DT_RPATH    String table offset to library search path (deprecated)

                 DT_SYMBOLIC Alert  linker to search this shared object before the exe‐
                             cutable for symbols

                 DT_REL      Address of Rel relocation table

                 DT_RELSZ    Size in bytes of Rel relocation table

                 DT_RELENT   Size in bytes of a Rel table entry

                 DT_PLTREL   Type of relocation entry to which the PLT refers (Rela  or
                             Rel)

                 DT_DEBUG    Undefined use for debugging

                 DT_TEXTREL  Absence of this entry indicates that no relocation entries
                             should apply to a nonwritable segment

                 DT_JMPREL   Address of relocation entries associated solely  with  the
                             PLT    // .rela.plt

                 DT_BIND_NOW Instruct  dynamic linker to process all relocations before
                             transferring control to the executable

                 DT_RUNPATH  String table offset to library search path

                 DT_LOPROC, DT_HIPROC
                             Values in the inclusive range [DT_LOPROC,  DT_HIPROC]  are
                             reserved for processor-specific semantics
$ readelf -d main

Dynamic section at offset 0xd98 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libso.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [.]
 0x000000000000000c (INIT)               0x698
 0x000000000000000d (FINI)               0x984
 0x0000000000000019 (INIT_ARRAY)         0x200d88
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x200d90
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x298
 0x0000000000000005 (STRTAB)             0x458
 0x0000000000000006 (SYMTAB)             0x2d8
 0x000000000000000a (STRSZ)              217 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x200fa8
 0x0000000000000002 (PLTRELSZ)           72 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x650
 0x0000000000000007 (RELA)               0x578
 0x0000000000000008 (RELASZ)             216 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000000000001e (FLAGS)              BIND_NOW
 0x000000006ffffffb (FLAGS_1)            Flags: NOW PIE
 0x000000006ffffffe (VERNEED)            0x558
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x532
 0x000000006ffffff9 (RELACOUNT)          3
 0x0000000000000000 (NULL)               0x0

symbols

.dynsym + .symtab

$ readelf -s main

Symbol table '.dynsym' contains 16 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND so_hello
     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     8: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)
     9: 0000000000201011     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    10: 0000000000201028     0 NOTYPE  GLOBAL DEFAULT   24 _end
    11: 0000000000201018     8 OBJECT  GLOBAL DEFAULT   24 g_so_long
    12: 0000000000201011     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
    13: 0000000000000698     0 FUNC    GLOBAL DEFAULT   11 _init
    14: 0000000000000984     0 FUNC    GLOBAL DEFAULT   15 _fini
    15: 00000000000008b9    19 FUNC    GLOBAL DEFAULT   14 common_func

Symbol table '.symtab' contains 70 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000238     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000254     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000274     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000298     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000000002d8     0 SECTION LOCAL  DEFAULT    5
...

.dynsym: symbol tables dedicated to dynamically linked symbols.

$ readelf --dyn-syms main

Symbol table '.dynsym' contains 16 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND so_hello
     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     8: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)
     9: 0000000000201011     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    10: 0000000000201028     0 NOTYPE  GLOBAL DEFAULT   24 _end
    11: 0000000000201018     8 OBJECT  GLOBAL DEFAULT   24 g_so_long
    12: 0000000000201011     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
    13: 0000000000000698     0 FUNC    GLOBAL DEFAULT   11 _init
    14: 0000000000000984     0 FUNC    GLOBAL DEFAULT   15 _fini
    15: 00000000000008b9    19 FUNC    GLOBAL DEFAULT   14 common_func

objdump 在显示符号时支持 demangle (-C 选项) 且信息更为直观(readelf 中的 Ndx 字段在 objdump 中直接翻译成了 section 名字):

.dynsym + .symtab

$ objdump -t -C main

main:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000238 l    d  .interp	0000000000000000              .interp
0000000000000254 l    d  .note.ABI-tag	0000000000000000              .note.ABI-tag
0000000000000274 l    d  .note.gnu.build-id	0000000000000000              .note.gnu.build-id
0000000000000298 l    d  .gnu.hash	0000000000000000              .gnu.hash
00000000000002d8 l    d  .dynsym	0000000000000000              .dynsym
0000000000000458 l    d  .dynstr	0000000000000000              .dynstr
0000000000000532 l    d  .gnu.version	0000000000000000              .gnu.version
0000000000000558 l    d  .gnu.version_r	0000000000000000              .gnu.version_r
0000000000000578 l    d  .rela.dyn	0000000000000000              .rela.dyn
0000000000000650 l    d  .rela.plt	0000000000000000              .rela.plt
0000000000000698 l    d  .init	0000000000000000              .init
00000000000006b0 l    d  .plt	0000000000000000              .plt
00000000000006f0 l    d  .plt.got	0000000000000000              .plt.got
0000000000000700 l    d  .text	0000000000000000              .text
0000000000000984 l    d  .fini	0000000000000000              .fini
0000000000000990 l    d  .rodata	0000000000000000              .rodata
...

.dynsym

$ objdump -T -C main

main:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  *UND*	0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF *UND*	0000000000000000  GLIBC_2.2.5 puts
0000000000000000      DF *UND*	0000000000000000  GLIBC_2.2.5 printf
0000000000000000      DF *UND*	0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  *UND*	0000000000000000              __gmon_start__
0000000000000000      DF *UND*	0000000000000000              so_hello
0000000000000000  w   D  *UND*	0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF *UND*	0000000000000000  GLIBC_2.2.5 __cxa_finalize
0000000000201011 g    D  .data	0000000000000000  Base        _edata
0000000000201028 g    D  .bss	0000000000000000  Base        _end
0000000000201018 g    DO .bss	0000000000000008              g_so_long
0000000000201011 g    D  .bss	0000000000000000  Base        __bss_start
0000000000000698 g    DF .init	0000000000000000  Base        _init
0000000000000984 g    DF .fini	0000000000000000  Base        _fini
00000000000008b9 g    DF .text	0000000000000013  Base        common_func

参考资料

ELF-symbol-resolution

https://gist.github.com/DhavalKapil/2243db1b732b211d0c16fd5d9140ab0b

PLT and GOT - the key to code sharing and dynamic libraries

https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html

Executable and Linkable Format 101 - Part 1 Sections and Segments

https://www.intezer.com/executable-linkable-format-101-part1-sections-segments/

Executable and Linkable Format 101. Part 2: Symbols

https://www.intezer.com/executable-linkable-format-101-part-2-symbols/

Executable and Linkable Format 101 Part 3: Relocations

https://www.intezer.com/executable-and-linkable-format-101-part-3-relocations/

Executable and Linkable Format 101 Part 4: Dynamic Linking

https://www.intezer.com/executable-linkable-format-101-part-4-dynamic-linking/

ELF Object File Format

http://www.360doc.com/content/15/0722/19/7377734_486702882.shtml

ELF Sections & Segments and Linux VMA Mappings

http://www.360doc.com/content/17/1204/11/7377734_709762695.shtml