新闻  |   论坛  |   博客  |   在线研讨会
linux怎样load elf可执行文件 ---- static vs dynamic
电子禅石 | 2020-08-09 23:14:39    阅读:828   发布文章

linux怎样load elf可执行文件<一> ---- static vs dynamic            

       

在linux下面运行程序:

strace ./test_dynamic
execve("./test_dynamic", ["./test_dynamic"], [/* 20 vars */]) = 0
[ Process PID=3820 runs in 32 bit mode. ]

可以看到其实是调一个系统调用execve,具体这个系统调用是怎么来让程序运行起来的?

本系列会做一个很基础的介绍


static vs dynamic

我们知道gcc在build一个程序的时候,可以指定程序是static link的还是dynamic link的。

static link会让目标文件包含所有需要的libs。生成的目标elf不依赖于任何其他的dso。

dynamic link不会包含所依赖的libs到目标文件。需要其他的dso才能正确加载目标文件。

 

例子:test.c

#include <stdio.h>
#include <stdlib.h>

main()
{
        printf("Hello World!\n");
}

static link command: gcc -m32 -static test.c -o test_static (生成32bit的静态执行程序)

dynamic link command: gcc -m32 test.c -lpthread -o test_dynamic (生成32bit的动态执行程序,并且指定依赖libpthread)


几个有用的工具:

file, readelf.

file 可以输出文件的大概的信息

$file test_static输出:

test_static: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0x471a71e89449ba50d36c892687ad560e501bf5f4, not stripped

$file test_dynamic输出:

test_dynamic: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xcb6a9acbb6b64dd47436874eb8e7b2bb22e6266c, not stripped

 

readelf 可以输出elf相关的信息。比如 readelf -e 输出elf header 信息:

$readelf -e test_static

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x80481c0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          549012 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         5
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 26

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480d4 0000d4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            080480f4 0000f4 000024 00   A  0   0  4
  [ 3] .rel.plt          REL             08048118 000118 000028 08   A  0   5  4
  [ 4] .init             PROGBITS        08048140 000140 000026 00  AX  0   0  4
  [ 5] .plt              PROGBITS        08048170 000170 000050 00  AX  0   0 16
  [ 6] .text             PROGBITS        080481c0 0001c0 06654c 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ae710 066710 000ac1 00  AX  0   0 16
  [ 8] .fini             PROGBITS        080af1d4 0671d4 000017 00  AX  0   0  4
  [ 9] .rodata           PROGBITS        080af200 067200 018a58 00   A  0   0 32
  [10] __libc_atexit     PROGBITS        080c7c58 07fc58 000004 00   A  0   0  4
  [11] __libc_subfreeres PROGBITS        080c7c5c 07fc5c 00002c 00   A  0   0  4
  [12] .eh_frame         PROGBITS        080c7c88 07fc88 0059b0 00   A  0   0  4
  [13] .gcc_except_table PROGBITS        080cd638 085638 000120 00   A  0   0  1
  [14] .tdata            PROGBITS        080ce758 085758 000010 00 WAT  0   0  4
  [15] .tbss             NOBITS          080ce768 085768 000018 00 WAT  0   0  4
  [16] .init_array       INIT_ARRAY      080ce768 085768 000008 00  WA  0   0  4
  [17] .fini_array       FINI_ARRAY      080ce770 085770 000008 00  WA  0   0  4
  [18] .jcr              PROGBITS        080ce778 085778 000004 00  WA  0   0  4
  [19] .data.rel.ro      PROGBITS        080ce77c 08577c 000030 00  WA  0   0  4
  [20] .got              PROGBITS        080ce7ac 0857ac 000008 04  WA  0   0  4
  [21] .got.plt          PROGBITS        080ce7b4 0857b4 000020 04  WA  0   0  4
  [22] .data             PROGBITS        080ce7e0 0857e0 000760 00  WA  0   0 32
  [23] .bss              NOBITS          080cef40 085f40 001b94 00  WA  0   0 32
  [24] __libc_freeres_pt NOBITS          080d0ad4 085f40 000018 00  WA  0   0  4
  [25] .comment          PROGBITS        00000000 085f40 000038 01  MS  0   0  1
  [26] .shstrtab         STRTAB          00000000 085f78 00011a 00      0   0  1
  [27] .symtab           SYMTAB          00000000 08651c 007b60 10     28 830  4
  [28] .strtab           STRTAB          00000000 08e07c 007395 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x85758 0x85758 R E 0x1000
  LOAD           0x085758 0x080ce758 0x080ce758 0x007e8 0x02394 RW  0x1000
  NOTE           0x0000d4 0x080480d4 0x080480d4 0x00044 0x00044 R   0x4
  TLS            0x085758 0x080ce758 0x080ce758 0x00010 0x00028 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     .note.ABI-tag .note.gnu.build-id .rel.plt .init .plt .text __libc_freeres_fn .fini .rodata __libc_atexit __libc_subfreeres .eh_frame .gcc_except_table
   01     .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs
   02     .note.ABI-tag .note.gnu.build-id
   03     .tdata .tbss
   04

$readelf -e test_dynamic

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048360
  Start of program headers:          52 (bytes into file)
  Start of section headers:          2036 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         8
  Size of section headers:           40 (bytes)
  Number of section headers:         31
  Section header string table index: 28

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .hash             HASH            0804818c 00018c 00002c 04   A  6   0  4
  [ 5] .gnu.hash         GNU_HASH        080481b8 0001b8 000020 04   A  6   0  4
  [ 6] .dynsym           DYNSYM          080481d8 0001d8 000060 10   A  7   1  4
  [ 7] .dynstr           STRTAB          08048238 000238 00006e 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          080482a6 0002a6 00000c 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         080482b4 0002b4 000020 00   A  7   1  4
  [10] .rel.dyn          REL             080482d4 0002d4 000008 08   A  6   0  4
  [11] .rel.plt          REL             080482dc 0002dc 000018 08   A  6  13  4
  [12] .init             PROGBITS        080482f4 0002f4 000026 00  AX  0   0  4
  [13] .plt              PROGBITS        08048320 000320 000040 04  AX  0   0 16
  [14] .text             PROGBITS        08048360 000360 000180 00  AX  0   0 16
  [15] .fini             PROGBITS        080484e0 0004e0 000017 00  AX  0   0  4
  [16] .rodata           PROGBITS        080484f8 0004f8 000015 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        08048510 000510 00001c 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0804852c 00052c 000060 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      0804958c 00058c 000004 00  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049590 000590 000004 00  WA  0   0  4
  [21] .jcr              PROGBITS        08049594 000594 000004 00  WA  0   0  4
  [22] .dynamic          DYNAMIC         08049598 000598 0000f8 08  WA  7   0  4
  [23] .got              PROGBITS        08049690 000690 000004 04  WA  0   0  4
  [24] .got.plt          PROGBITS        08049694 000694 000018 04  WA  0   0  4
  [25] .data             PROGBITS        080496ac 0006ac 000008 00  WA  0   0  4
  [26] .bss              NOBITS          080496b4 0006b4 000004 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 0006b4 000038 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 0006ec 000106 00      0   0  1
  [29] .symtab           SYMTAB          00000000 000ccc 000430 10     30  45  4
  [30] .strtab           STRTAB          00000000 0010fc 000250 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
  INTERP         0x000134 0x08048134 0x08048134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x0058c 0x0058c R E 0x1000
  LOAD           0x00058c 0x0804958c 0x0804958c 0x00128 0x0012c RW  0x1000
  DYNAMIC        0x000598 0x08049598 0x08049598 0x000f8 0x000f8 RW  0x4
  NOTE           0x000148 0x08048148 0x08048148 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000510 0x08048510 0x08048510 0x0001c 0x0001c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

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

这里面有一点要注意, dynamic link的有一个program header的item:

INTERP         0x000134 0x08048134 0x08048134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]

在static link里面是没有的。这个INTERP的意思就是说这个可执行elf是动态链接的,它需要一个loader (/lib/ld-linux.so.2)

来协助加载。

static link没有这个item,意味着static link不需要loader协助,可以被linux kernel直接加载。

 

Linux kernel在加载一个可执行elf时,会判断有没有这个INTERP,如果没有,那就是static linked,kernel会直接加载

执行,如果有,那就是dynamic linked,kernel会加载INTERP,然后有INTERP来协助加载。

INTERP 一般都是有libc实现。比如glibc就实现了ld-linux.so.2。 如果看android的话,android的bionic自己也实现了

一个loader: linker。

 

下次我们会介绍execve的具体实现。


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客