GCC編譯鏈接過程


編譯鏈接過程

代碼

#cat main.c
#include <stdio.h>

int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);

int main(void)
{
	printf("add:%d\n", add(1,2));
	printf("sub:%d\n", sub(10,100));
	printf("mul:%d\n", mul(5,10));
	printf("div:%d\n", div(200,100));

	return 0;
}

===


#cat math.c
#include <stdio.h>

int add(int x, int y)
{
	return (x + y);
}

int sub(int x, int y)
{
	return (x - y);
}

int mul(int x, int y)
{
	return (x * y);
}

int div(int x, int y)
{
	return (x/y);
}
預處理:
#gcc -E main.c -o main.i

編譯: 生成.s 文件 
#gcc -c main.c math.c
#ls main.s math.s
main.s  math.s

匯編:生成.o 文件(可重定位目標文件)
#gcc -c main.c math.c
#ls main.o math.o
main.o  math.o


鏈接:生成 (可執行目標文件)
#gcc -o main.out main.o math.o

目標文件

分三種:

  1. 可重定位目標文件 (Relocatable file) (.o 文件,沒有被鏈接的)
  2. 可執行目標文件 (Executable file)(.out文件 最終二進制文件)
  3. 可被共享目標文件 (Shared object file) (.so 結尾的)

看ELF的常見命令:

ELF文件格式需要知道;

#readelf -h main.out  看ELF文件的header部分
#readelf -S main.out  看ELF文件的Section header
#readelf -h main.out
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:               0x400430   // 函數入口地址
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6720 (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:         30
  Section header string table index: 27

  
  
#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 // 所以,這里看函數入口地址為0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1152 (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: 10

靜態庫:

靜態庫: (.a 結尾的) 從 .o 文件而來

//生成靜態庫 : 使用ar命令,將.o 生成.a 文件。這里名字有講究的, lib + math + .a  中間的才是庫名字。
#ar rcs libmath.a math.o

// 使用靜態庫: -L 表示路徑, -l 表示庫的名字
#gcc main.o -L. -l math -o main.out
#./main.out
add:3
sub:-90
mul:50
div:2

其實和.o 文件差距不大,都是 重定向文件,只不過做了歸檔。

#readelf -h  libmath.a
File: libmath.a(math.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:          840 (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:         11
  Section header string table index: 8

共享庫:

共享庫: (.so 結尾的)

#gcc --shared -fPIC -o libmath.so math.c
#ll libmath.so
-rwxr-xr-x 1 root root 7864 Feb  1 16:21 libmath.so

類型: Shared object file

#readelf -h libmath.so
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:               0x5b0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6216 (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:         27
  Section header string table index: 24

gcc 不是一個簡單的命令,里面有很多庫

[root@r10n04359.sqa.zmf /usr/lib/gcc/x86_64-redhat-linux/6.4.0]
#ls
32           crtendS.o      finclude           libcaf_single.a  libgcc_s.so       libgomp.so    libmpx.spec        libstdc++.so
crtbegin.o   crtfastmath.o  include            libcilkrts.so    libgcov.a         libgomp.spec  libmpxwrappers.so  libtsan.so
crtbeginS.o  crtprec32.o    libasan_preinit.o  libcilkrts.spec  libgfortran.so    libitm.spec   libquadmath.so     libubsan.so
crtbeginT.o  crtprec64.o    libasan.so         libgcc.a         libgfortran.spec  liblsan.so    libsanitizer.spec  rpmver
crtend.o     crtprec80.o    libatomic.so       libgcc_eh.a      libgomp.a         libmpx.so     libstdc++fs.a

編譯階段

分析ELF文件

ELF文件的格式,可以通過readelf -a xxx.o 看到。

包含幾個主要部分: 1. ELF header 2. Section header 3. symble table

其中比較重要的是symble table。

那么, 符號表 是什么時候產生的? compile? assemble? 其實是,兩個階段都會產生一份,但是目的是不同的。

匯編階段, 匯編器會掃描 匯編源文件 生成各種表(包含符號表)。

鏈接階段,將各個目標文件合並之后,重新修改符號表中各個符號的地址。

ELF文件中的符號表

幾個簡單命令,不要混淆:

#readelf -S math.o  // 查看Section header
#readelf -s math.o  //  查看symble table
#readelf -h math.o // 查看ELF 的header(主要存放一些,ELF文件的類型,架構之類的)

ELF文件中的Section header

一個ELF 的section 有哪些?

大家都知道的.text, .data, .bss 等section

#readelf -S math.o
There are 11 section headers, starting at offset 0x348:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       000000000000004c  0000000000000000  AX       0     0     1
  [ 2] .data             PROGBITS         0000000000000000  0000008c
       0000000000000000  0000000000000000  WA       0     0     1
  [ 3] .bss              NOBITS           0000000000000000  0000008c
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .comment          PROGBITS         0000000000000000  0000008c
       000000000000002d  0000000000000001  MS       0     0     1
  [ 5] .note.GNU-stack   PROGBITS         0000000000000000  000000b9
       0000000000000000  0000000000000000           0     0     1
  [ 6] .eh_frame         PROGBITS         0000000000000000  000000c0
       0000000000000098  0000000000000000   A       0     0     8
  [ 7] .rela.eh_frame    RELA             0000000000000000  00000290
       0000000000000060  0000000000000018   I       9     6     8
  [ 8] .shstrtab         STRTAB           0000000000000000  000002f0 // 保存 section name,比如:.bss,.text,.data
       0000000000000054  0000000000000000           0     0     1
  [ 9] .symtab           SYMTAB           0000000000000000  00000158 //表
       0000000000000120  0000000000000018          10     8     8
  [10] .strtab           STRTAB           0000000000000000  00000278 // 字符名字, 比如這里的:add, mul, sub, div..
       0000000000000018  0000000000000000           0     0     1
#vim include/uapi/linux/elf.h
typedef struct elf64_sym {
  Elf64_Word st_name;       /* Symbol name, index in string tbl */ 
  unsigned char st_info;    /* Type and binding attributes */
  unsigned char st_other;   /* No defined meaning, 0 */
  Elf64_Half st_shndx;      /* Associated section index */
  Elf64_Addr st_value;      /* Value of the symbol */
  Elf64_Xword st_size;      /* Associated symbol size */
} Elf64_Sym;

strtab:

#readelf -x .strtab math.o

Hex dump of section '.strtab':
  0x00000000 006d6174 682e6300 61646400 73756200 .math.c.add.sub.
  0x00000010 6d756c00 64697600                   mul.div.
#readelf -x .symtab math.o

Hex dump of section '.symtab':
  0x00000000 00000000 00000000 00000000 00000000 ................
  0x00000010 00000000 00000000 01000000 0400f1ff ................
  0x00000020 00000000 00000000 00000000 00000000 ................
  0x00000030 00000000 03000100 00000000 00000000 ................
  0x00000040 00000000 00000000 00000000 03000200 ................
  0x00000050 00000000 00000000 00000000 00000000 ................
  0x00000060 00000000 03000300 00000000 00000000 ................
  0x00000070 00000000 00000000 00000000 03000500 ................
  0x00000080 00000000 00000000 00000000 00000000 ................
  0x00000090 00000000 03000600 00000000 00000000 ................
  0x000000a0 00000000 00000000 00000000 03000400 ................
  0x000000b0 00000000 00000000 00000000 00000000 ................
  0x000000c0 08000000 12000100 00000000 00000000 ................
  0x000000d0 14000000 00000000 0c000000 12000100 ................
  0x000000e0 14000000 00000000 12000000 00000000 ................
  0x000000f0 10000000 12000100 26000000 00000000 ........&.......
  0x00000100 13000000 00000000 14000000 12000100 ................
  0x00000110 39000000 00000000 13000000 00000000 9...............

查看Symbol table

雖然,你可以看到 math.c 中的add, sub, mul, div 這些符號表的名字,但是,這個符號表不存在這里,是通過索引獲取的。 實際上是存在.strtab 這個section中的。

#readelf -s math.o

Symbol table '.symtab' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS math.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     8: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 add
     9: 0000000000000014    18 FUNC    GLOBAL DEFAULT    1 sub
    10: 0000000000000026    19 FUNC    GLOBAL DEFAULT    1 mul
    11: 0000000000000039    19 FUNC    GLOBAL DEFAULT    1 div

鏈接過程

鏈接過程分 3個階段: 1. 組裝新的ELF,創建全局符號表,收集各個符號表地址 2.

通過 鏈接腳本(linker script) 來指定: 代碼段 起始地址, 數據段 起始地址

#ld -verbose

重定位:

在main.c 中調用了外部定義的函數,或者 變量,在沒有鏈接之前,匯編器生成這個main.o 的同時,會記錄下來,哪些 符號表(函數,變量) 是沒有找到的,需要 等待 鏈接過程 去找一下。

#readelf -r main.o

Relocation section '.rela.text' at offset 0x328 contains 14 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000006  000a00000002 R_X86_64_PC32     0000000000000000 i - 8
000000000010  000b00000002 R_X86_64_PC32     0000000000000000 j - 5
000000000020  000c00000002 R_X86_64_PC32     0000000000000000 add - 4
000000000027  00050000000a R_X86_64_32       0000000000000000 .rodata + 0
000000000031  000d00000002 R_X86_64_PC32     0000000000000000 printf - 4
000000000040  000e00000002 R_X86_64_PC32     0000000000000000 sub - 4
000000000047  00050000000a R_X86_64_32       0000000000000000 .rodata + 8
000000000051  000d00000002 R_X86_64_PC32     0000000000000000 printf - 4
000000000060  000f00000002 R_X86_64_PC32     0000000000000000 mul - 4
000000000067  00050000000a R_X86_64_32       0000000000000000 .rodata + 10
000000000071  000d00000002 R_X86_64_PC32     0000000000000000 printf - 4
000000000080  001000000002 R_X86_64_PC32     0000000000000000 div - 4
000000000087  00050000000a R_X86_64_32       0000000000000000 .rodata + 18
000000000091  000d00000002 R_X86_64_PC32     0000000000000000 printf - 4

Relocation section '.rela.eh_frame' at offset 0x478 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0

反匯編到.s

#objdump -D main.o
Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	c7 05 00 00 00 00 0a 	movl   $0xa,0x0(%rip)        # e <main+0xe>
   b:	00 00 00
   e:	c6 05 00 00 00 00 61 	movb   $0x61,0x0(%rip)        # 15 <main+0x15>
  15:	be 02 00 00 00       	mov    $0x2,%esi
  1a:	bf 01 00 00 00       	mov    $0x1,%edi
  1f:	e8 00 00 00 00       	callq  24 <main+0x24>
  24:	89 c6                	mov    %eax,%esi
  26:	bf 00 00 00 00       	mov    $0x0,%edi
  2b:	b8 00 00 00 00       	mov    $0x0,%eax
  30:	e8 00 00 00 00       	callq  35 <main+0x35>
  35:	be 64 00 00 00       	mov    $0x64,%esi
  3a:	bf 0a 00 00 00       	mov    $0xa,%edi
  3f:	e8 00 00 00 00       	callq  44 <main+0x44>
  44:	89 c6                	mov    %eax,%esi
  46:	bf 00 00 00 00       	mov    $0x0,%edi
  4b:	b8 00 00 00 00       	mov    $0x0,%eax
  50:	e8 00 00 00 00       	callq  55 <main+0x55>
  55:	be 0a 00 00 00       	mov    $0xa,%esi
  5a:	bf 05 00 00 00       	mov    $0x5,%edi
  5f:	e8 00 00 00 00       	callq  64 <main+0x64>
  64:	89 c6                	mov    %eax,%esi
  66:	bf 00 00 00 00       	mov    $0x0,%edi
  6b:	b8 00 00 00 00       	mov    $0x0,%eax
  70:	e8 00 00 00 00       	callq  75 <main+0x75>
  75:	be 64 00 00 00       	mov    $0x64,%esi
  7a:	bf c8 00 00 00       	mov    $0xc8,%edi
  7f:	e8 00 00 00 00       	callq  84 <main+0x84>
  84:	89 c6                	mov    %eax,%esi
  86:	bf 00 00 00 00       	mov    $0x0,%edi
  8b:	b8 00 00 00 00       	mov    $0x0,%eax
  90:	e8 00 00 00 00       	callq  95 <main+0x95>
  95:	b8 00 00 00 00       	mov    $0x0,%eax
  9a:	5d                   	pop    %rbp
  9b:	c3                   	retq

程序的運行

可執行文件(ELF文件)

program-headers 表

program-headers 表,只有.out 可執行文件才有,.o 文件是沒有的(因為.o文件還沒有經過鏈接)。

另一個重要的概念是“程序的入口地址”, 如下case中,通過program-headers查看 程序的入口地址: 0x400430

#readelf -l ./main.out

Elf file type is EXEC (Executable file)
Entry point 0x400430   // 可執行文件 的 程序入口地址, 程序入口地址 = 鏈接地址+偏移
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000000086c 0x000000000000086c  R E    200000
  LOAD           0x0000000000000e08 0x0000000000600e08 0x0000000000600e08
                 0x0000000000000228 0x0000000000000230  RW     200000
  DYNAMIC        0x0000000000000e20 0x0000000000600e20 0x0000000000600e20
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000006a4 0x00000000004006a4 0x00000000004006a4
                 0x0000000000000054 0x0000000000000054  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e08 0x0000000000600e08 0x0000000000600e08
                 0x00000000000001f8 0x00000000000001f8  R      1

通過匯編也可以看到,程序的入口地址:

#readelf  -s main.out
...
    59: 0000000000400680     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    60: 0000000000400600   101 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    61: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 _end
    62: 0000000000400430    43 FUNC    GLOBAL DEFAULT   13 _start  // 程序的入口地址
    63: 0000000000601030     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    64: 0000000000400526   139 FUNC    GLOBAL DEFAULT   13 main
    65: 00000000004005d7    19 FUNC    GLOBAL DEFAULT   13 mul
...

為什么沒有地址沖突呢?

因為我們操作的是虛擬地址,MMU會幫我們完成虛擬地址 和 物理地址的 映射關系。

加載器

  1. 如果執行一個可執行文件, 加載器 將ELF文件 映射到內存中, 主要實現是通過 execv 系統調用
  2. 加載器拷貝數據完成后,當執行的時候,就會直接跳轉到程序的入口地址。

BSS段的處理

在可執行文件中,是不占用空間的,只有在ELF文件執行的時候,當映射到內存中才開辟呢。原因和歷史有關系,早期的內存比較珍貴。

BSS段的大小,起始地址,存儲在哪里?

  • Section header tables.

例子1:

這個例子中,全局變量,global_a 在.data section, global_b 在.bss section中。 但是, 另外兩個local_a , local_b 因為都是函數內的,都存在於stack中,所以,不在.data, .bss中。

#cat aa.c
#include <stdio.h>

int global_a = 1;
int global_b;

int main(void)
{
	int local_a = 2;
	int local_b;
	return 0;
}

#gcc -o aa.out aa.c
#readelf  -S aa.out
There are 28 section headers, starting at offset 0x1980:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [22] .data             PROGBITS         0000000000601018  00001018
       0000000000000014  0000000000000000  WA       0     0     8
  [23] .bss              NOBITS           000000000060102c  0000102c
       000000000000000c  0000000000000000  WA       0     0     4
#readelf  -s aa.out  | grep global
   Num:    Value          Size Type    Bind   Vis      Ndx Name
    45: 0000000000601030     4 OBJECT  GLOBAL DEFAULT   23 global_b 
    48: 0000000000601028     4 OBJECT  GLOBAL DEFAULT   22 global_a // 可見,global_a 在 22號(.bss section)

例子2:

如果我們給局部變量 添加上 static ,那么就會存放在 .data, .bss中。

#cat aa.c
#include <stdio.h>

int global_a = 1;
int global_b;

int main(void)
{
	static int local_a = 2;
	static int local_b;
	return 0;
}

#readelf -s aa.out  | grep local_
    35: 0000000000601034     4 OBJECT  LOCAL  DEFAULT   23 local_b.2214
    36: 000000000060102c     4 OBJECT  LOCAL  DEFAULT   22 local_a.2213
#readelf -S aa.out
  [22] .data             PROGBITS         0000000000601018  00001018
       0000000000000018  0000000000000000  WA       0     0     8
  [23] .bss              NOBITS           0000000000601030  00001030
       0000000000000010  0000000000000000  WA       0     0     4

解讀匯編代碼實現 .bss 的操作

#gcc -S aa.c -o aa.s
#gcc -c aa.s -o aa.o
#gcc aa.o -o aa.out
#cat  aa.s
	.file	"aa.c"
	.globl	global_a   // global_a 放在.data中
	.data
	.align 4
	.type	global_a, @object  // global_a 類型是object
	.size	global_a, 4
global_a:
	.long	1
	.comm	global_b,4,4   // .comm 指令,在.bss段 給global_b 分配 4個字節的大小
	.text
	.globl	main              // main放在.text中
	.type	main, @function   // main 類型是 function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.local	local_b.2214
	.comm	local_b.2214,4,4  // .comm 指令,在.bss段 給local_b 分配 4個字節的大小
	.data
	.align 4
	.type	local_a.2213, @object
	.size	local_a.2213, 4
local_a.2213:
	.long	2
	.ident	"GCC: (GNU) 6.4.0 20170704 (Red Hat 6.4.0-1)"
	.section	.note.GNU-stack,"",@progbits

例子3:

#cat aa.c
#include <stdio.h>

int global_a = 1;
int global_b;

int main(void)
{
	static int local_a = 2;
	static int local_b;

	printf("global_a:%lx\n", &global_a);
	printf("global_b:%lx\n", &global_b);
	printf("local_a:%lx\n", &local_a);
	printf("local_b:%lx\n", &local_b);
	return 0;
}

在ELF中的看到的地址,其實就是,運行結果看到的地址。(都是在虛擬地址中)

打印變量地址:

#./aa.out
global_a:601030
global_b:601040
local_a:601034
local_b:60103c

查看ELF中的符號表:

#readelf -s aa.out | grep global_
    49: 0000000000601040     4 OBJECT  GLOBAL DEFAULT   25 global_b
    52: 0000000000601030     4 OBJECT  GLOBAL DEFAULT   24 global_a
#readelf -s aa.out | grep local_
    37: 0000000000601034     4 OBJECT  LOCAL  DEFAULT   24 local_a.2213
    38: 000000000060103c     4 OBJECT  LOCAL  DEFAULT   25 local_b.2214
#readelf -S aa.out | grep -w 24
  [24] .data             PROGBITS         0000000000601020  00001020
#readelf -S aa.out | grep -w 25
  [25] .bss              NOBITS           0000000000601038  00001038

main函數的執行

編譯器 對程序入口的規定:

  1. 編譯器默認的程序入口是_start 符號,而不是main.
  2. 符號main 是被C標准庫調用的符號,它用來告訴編譯器,一個項目里,哪里是程序的入口

在執行main之前的“暗箱操作”:

#objdump -D aa.out | grep start -A 30
0000000000400400 <_start>:
  400400:	31 ed                	xor    %ebp,%ebp
  400402:	49 89 d1             	mov    %rdx,%r9
  400405:	5e                   	pop    %rsi
  400406:	48 89 e2             	mov    %rsp,%rdx
  400409:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  40040d:	50                   	push   %rax
  40040e:	54                   	push   %rsp
  40040f:	49 c7 c0 d0 05 40 00 	mov    $0x4005d0,%r8
  400416:	48 c7 c1 60 05 40 00 	mov    $0x400560,%rcx
  40041d:	48 c7 c7 f6 04 40 00 	mov    $0x4004f6,%rdi
  400424:	ff 15 c6 0b 20 00    	callq  *0x200bc6(%rip)        # 600ff0 <_DYNAMIC+0x1d0>
  40042a:	f4                   	hlt
  40042b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
#rpm -ql glibc-devel-2.24-3.1.alios7.x86_64
/usr/include/gnu/lib-names-64.h
/usr/include/gnu/stubs-64.h
/usr/lib64/Mcrt1.o
/usr/lib64/Scrt1.o
/usr/lib64/crt1.o
/usr/lib64/crti.o
/usr/lib64/crtn.o
/usr/lib64/gcrt1.o
/usr/lib64/libBrokenLocale.so
/usr/lib64/libanl.so
/usr/lib64/libc.so
/usr/lib64/libc_nonshared.a
/usr/lib64/libcidn.so
/usr/lib64/libcrypt.so
/usr/lib64/libdl.so
/usr/lib64/libg.a
/usr/lib64/libieee.a
/usr/lib64/libm.so
/usr/lib64/libmcheck.a
/usr/lib64/libmvec.so

glibc下的 /usr/lib64/ 下面的.o 會被gcc默認鏈接使用。

#objdump -D /usr/lib64/crt1.o

0000000000000000 <_start>:
   0:	31 ed                	xor    %ebp,%ebp
   2:	49 89 d1             	mov    %rdx,%r9
   5:	5e                   	pop    %rsi
   6:	48 89 e2             	mov    %rsp,%rdx
   9:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
   d:	50                   	push   %rax
   e:	54                   	push   %rsp
   f:	49 c7 c0 00 00 00 00 	mov    $0x0,%r8
  16:	48 c7 c1 00 00 00 00 	mov    $0x0,%rcx
  1d:	48 c7 c7 00 00 00 00 	mov    $0x0,%rdi
  24:	ff 15 00 00 00 00    	callq  *0x0(%rip)        # 2a <_start+0x2a>
  2a:	f4                   	hlt
#ldd /usr/bin/ls
	linux-vdso.so.1 (0x00007fff63bfd000)
	libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f514133f000)
	libcap.so.2 => /lib64/libcap.so.2 (0x00007f514113a000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f5140d74000)
	libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f5140b13000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f514090f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5141566000)
	libattr.so.1 => /lib64/libattr.so.1 (0x00007f514070a000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f51404ec000)
	
#objdump -D /lib64/libc.so.6  | grep libc_start_main
0000000000020310 <__libc_start_main>:
   2033a:	0f 84 c8 00 00 00    	je     20408 <__libc_start_main+0xf8>
   20356:	74 0c                	je     20364 <__libc_start_main+0x54>
   20370:	0f 85 d1 00 00 00    	jne    20447 <__libc_start_main+0x137>
   20379:	74 15                	je     20390 <__libc_start_main+0x80>
   203a1:	0f 85 f4 00 00 00    	jne    2049b <__libc_start_main+0x18b>
   203a9:	0f 85 c9 00 00 00    	jne    20478 <__libc_start_main+0x168>
   203bb:	75 52                	jne    2040f <__libc_start_main+0xff>
   2040a:	e9 38 ff ff ff       	jmpq   20347 <__libc_start_main+0x37>
   20441:	74 20                	je     20463 <__libc_start_main+0x153>
   20445:	eb ba                	jmp    20401 <__libc_start_main+0xf1>
   2045e:	e9 13 ff ff ff       	jmpq   20376 <__libc_start_main+0x66>
   20476:	eb f8                	jmp    20470 <__libc_start_main+0x160>
   20496:	e9 14 ff ff ff       	jmpq   203af <__libc_start_main+0x9f>
   204bd:	74 05                	je     204c4 <__libc_start_main+0x1b4>
   204d3:	75 e1                	jne    204b6 <__libc_start_main+0x1a6>
   204d5:	e9 cd fe ff ff       	jmpq   203a7 <__libc_start_main+0x97>

下載glibc的 源代碼, 找找看 __libc_start_main 的實現,其實就會調用到 main.

靜態鏈接

  1. 生成的可執行文件體積比較大,相同公共代碼浪費空間。
  2. 要一次性加載到內存中

靜態庫: (.a 結尾的) 從 .o 文件而來

//生成靜態庫 : 使用ar命令,將.o 生成.a 文件。這里名字有講究的, lib + math + .a  中間的才是庫名字。
#ar rcs libmath.a math.o

// 使用靜態庫: -L 表示路徑, -l 表示庫的名字
#gcc main.o -L. -l math -o main.out
#./main.out
add:3
sub:-90
mul:50
div:2

動態鏈接(1) - 與位置無關的代碼

動態鏈接(2) - 全局符號表

共享庫: (.so 結尾的)

#cat main.c
#include <stdio.h>

int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);

int main(void)
{
	printf("add:%d\n", add(1,2));
	printf("sub:%d\n", sub(10,100));
	printf("mul:%d\n", mul(5,10));
	printf("div:%d\n", div(200,100));

	return 0;
}

#cat math.c
#include <stdio.h>

int add(int x, int y)
{
	return (x + y);
}

int sub(int x, int y)
{
	return (x - y);
}

int mul(int x, int y)
{
	return (x * y);
}

int div(int x, int y)
{
	return (x/y);
}
#gcc --shared -fPIC -o libmath.so math.c
#ll libmath.so
-rwxr-xr-x 1 root root 7864 Feb  1 16:21 libmath.so
#gcc -o main.out main.c -L. -lmath
#ldd main.out
	linux-vdso.so.1 (0x00007ffe12ec8000)
	libmath.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f05295b5000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f052997b000)
#./main.out
./main.out: error while loading shared libraries: libmath.so: cannot open shared object file: No such file or directory
#cp libmath.so  /usr/lib/

動態鏈接-全局符號表

動態鏈接-全局符號表

  1. 靜態鏈接的符號表
    1. .symtab section
  2. 動態鏈接的符號表
    1. .dynsym section
  3. 查看動態鏈接符號表:#readelf -s main.out
#readelf -s main.out

// 動態符號表.dynsym
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 add
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND div
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND mul
     8: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     9: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    10: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sub
    11: 0000000000601050     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    12: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   25 _end
    13: 0000000000601050     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    14: 0000000000400600     0 FUNC    GLOBAL DEFAULT   11 _init
    15: 0000000000400884     0 FUNC    GLOBAL DEFAULT   14 _fini

// 靜態符號表.symtab
Symbol table '.symtab' contains 70 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000400254     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000400274     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000400298     0 SECTION LOCAL  DEFAULT    4
     5: 00000000004002d0     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000400450     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000400518     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000400538     0 SECTION LOCAL  DEFAULT    8
     9: 0000000000400558     0 SECTION LOCAL  DEFAULT    9
    10: 0000000000400588     0 SECTION LOCAL  DEFAULT   10
    11: 0000000000400600     0 SECTION LOCAL  DEFAULT   11
    12: 0000000000400620     0 SECTION LOCAL  DEFAULT   12
    13: 0000000000400680     0 SECTION LOCAL  DEFAULT   13
    14: 0000000000400884     0 SECTION LOCAL  DEFAULT   14
    15: 0000000000400890     0 SECTION LOCAL  DEFAULT   15
    16: 00000000004008b4     0 SECTION LOCAL  DEFAULT   16
    17: 00000000004008e8     0 SECTION LOCAL  DEFAULT   17
    18: 0000000000600df8     0 SECTION LOCAL  DEFAULT   18
    19: 0000000000600e00     0 SECTION LOCAL  DEFAULT   19
    20: 0000000000600e08     0 SECTION LOCAL  DEFAULT   20
    21: 0000000000600e10     0 SECTION LOCAL  DEFAULT   21
    22: 0000000000600ff0     0 SECTION LOCAL  DEFAULT   22
    23: 0000000000601000     0 SECTION LOCAL  DEFAULT   23
    24: 0000000000601040     0 SECTION LOCAL  DEFAULT   24
    25: 0000000000601050     0 SECTION LOCAL  DEFAULT   25
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26
    27: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 0000000000600e08     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    29: 00000000004006b0     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    30: 00000000004006f0     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    31: 0000000000400730     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    32: 0000000000601050     1 OBJECT  LOCAL  DEFAULT   25 completed.6917
    33: 0000000000600e00     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fin
    34: 0000000000400750     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    35: 0000000000600df8     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    38: 00000000004009d8     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    39: 0000000000600e08     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    40: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    41: 0000000000600e00     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    42: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    43: 0000000000600df8     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    44: 00000000004008b4     0 NOTYPE  LOCAL  DEFAULT   16 __GNU_EH_FRAME_HDR
    45: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    46: 0000000000400880     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    47: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
    48: 0000000000601040     0 NOTYPE  WEAK   DEFAULT   24 data_start
    49: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND add
    50: 0000000000601050     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    51: 0000000000400884     0 FUNC    GLOBAL DEFAULT   14 _fini
    52: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND div
    53: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
    54: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    55: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    56: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    57: 0000000000601048     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle
    58: 0000000000400890     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    59: 0000000000400810   101 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    60: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   25 _end
    61: 0000000000400680    43 FUNC    GLOBAL DEFAULT   13 _start
    62: 0000000000601050     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    63: 0000000000400776   139 FUNC    GLOBAL DEFAULT   13 main
    64: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND mul
    65: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    66: 0000000000601050     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    67: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    68: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sub
    69: 0000000000400600     0 FUNC    GLOBAL DEFAULT   11 _init

#readelf -S main.out
There are 30 section headers, starting at offset 0x1a40:

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         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       0000000000000038  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002d0  000002d0  // 動態鏈接符號表
       0000000000000180  0000000000000018   A       6     1     8    
  [ 6] .dynstr           STRTAB           0000000000400450  00000450 // 動態鏈接符號表
       00000000000000c8  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400518  00000518
       0000000000000020  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400538  00000538
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400558  00000558
       0000000000000030  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400588  00000588
       0000000000000078  0000000000000018  AI       5    23     8
  [11] .init             PROGBITS         0000000000400600  00000600
       0000000000000017  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000400620  00000620
       0000000000000060  0000000000000010  AX       0     0     16
  [13] .text             PROGBITS         0000000000400680  00000680
       0000000000000202  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         0000000000400884  00000884
       0000000000000009  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         0000000000400890  00000890
       0000000000000024  0000000000000000   A       0     0     4
  [16] .eh_frame_hdr     PROGBITS         00000000004008b4  000008b4
       0000000000000034  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         00000000004008e8  000008e8
       00000000000000f4  0000000000000000   A       0     0     8
  [18] .init_array       INIT_ARRAY       0000000000600df8  00000df8
       0000000000000008  0000000000000000  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000600e00  00000e00
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .jcr              PROGBITS         0000000000600e08  00000e08
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000600e10  00000e10 
       00000000000001e0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000600ff0  00000ff0
       0000000000000010  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000040  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         0000000000601040  00001040
       0000000000000010  0000000000000000  WA       0     0     8
  [25] .bss              NOBITS           0000000000601050  00001050
       0000000000000008  0000000000000000  WA       0     0     1
  [26] .comment          PROGBITS         0000000000000000  00001050
       000000000000002c  0000000000000001  MS       0     0     1
  [27] .shstrtab         STRTAB           0000000000000000  00001935  // 靜態鏈接符號表
       0000000000000108  0000000000000000           0     0     1
  [28] .symtab           SYMTAB           0000000000000000  00001080  // 靜態鏈接符號表
       0000000000000690  0000000000000018          29    46     8
  [29] .strtab           STRTAB           0000000000000000  00001710  // 靜態鏈接符號表
       0000000000000225  0000000000000000           0     0     1

動態連接器

section .interp 段存放一個字符串,用於指明“動態連接器”的路徑: /lib64/ld-linux-x86-64.so.2, 其實“動態連接器” 也是一個共享庫。 使用 objdump 可以查看。

查看section .interp 段 的內容:

“動態連接器” 牛掰的地方在於,他是一個 共享庫,但是,他可以給自己重定位,然后運行。

#objdump -s main.out

main.out:     file format elf64-x86-64

Contents of section .interp:
 400238 2f6c6962 36342f6c 642d6c69 6e75782d  /lib64/ld-linux-
 400248 7838362d 36342e73 6f2e3200           x86-64.so.2.
Contents of section .note.ABI-tag:
 400254 04000000 10000000 01000000 474e5500  ............GNU.
 400264 00000000 02000000 06000000 20000000  ............ ...
Contents of section .note.gnu.build-id:
 400274 04000000 14000000 03000000 474e5500  ............GNU.
 400284 c9750717 6241288d 5147bdd9 e0795409  .u..bA(.QG...yT.
 400294 36d5e600                             6...
Contents of section .gnu.hash:
 400298 03000000 0b000000 01000000 06000000  ................
 4002a8 88c02001 00044009 0b000000 0d000000  .. ...@.........
 4002b8 0f000000 4245d5ec bbe3927c d871581c  ....BE.....|.qX.
 4002c8 b98df10e ebd3ef0e                    ........
Contents of section .dynsym:
 4002d0 00000000 00000000 00000000 00000000  ................
 4002e0 00000000 00000000 0c000000 20000000  ............ ...
 4002f0 00000000 00000000 00000000 00000000  ................
 400300 69000000 12000000 00000000 00000000  i...............
 400310 00000000 00000000 6d000000 12000000  ........m.......

.dynamic 段

section .dynamic: 保存了“動態鏈接器”所需要的信息,比如:

  • 依賴哪些共享庫
  • 動態鏈接符號表位置
  • 動態鏈接字符串表的位置

查看.dynamic段,用:#readelf -d

#readelf -d main.out

Dynamic section at offset 0xe10 contains 25 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libmath.so] // 動態鏈接器 依賴的共享庫
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6] // 動態鏈接器 依賴的共享庫
 0x000000000000000c (INIT)               0x400600
 0x000000000000000d (FINI)               0x400884
 0x0000000000000019 (INIT_ARRAY)         0x600df8
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x600e00
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x400450   // 字符串表
 0x0000000000000006 (SYMTAB)             0x4002d0  // 符號表
 0x000000000000000a (STRSZ)              200 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x601000
 0x0000000000000002 (PLTRELSZ)           120 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400588
 0x0000000000000007 (RELA)               0x400558
 0x0000000000000008 (RELASZ)             48 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400538
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400518
 0x0000000000000000 (NULL)               0x0

符號哈希表

To complete

動態鏈接重定位表

動態鏈接重定位表 分為 兩個section:

  • .rela.dyn : 數據段重定位信息
  • .rela.plt : 代碼段重定位信息
#readelf -r main.out

Relocation section '.rela.dyn' at offset 0x558 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600ff0  000500000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
000000600ff8  000600000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x588 contains 5 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000601018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 add + 0
000000601020  000300000007 R_X86_64_JUMP_SLO 0000000000000000 div + 0
000000601028  000400000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000601030  000700000007 R_X86_64_JUMP_SLO 0000000000000000 mul + 0
000000601038  000a00000007 R_X86_64_JUMP_SLO 0000000000000000 sub + 0

過程鏈接表

To complete

動態鏈接(3) - 共享庫

配置: /etc/ld.so.conf.d/*.conf

緩存在: /etc/ld.so.cache,當新增或者刪除一個庫的時候,執行一下ldconfig , 更新一下緩存(/etc/ld.so.cache)

#./main.out
./main.out: error while loading shared libraries: libmath.so: cannot open shared object file: No such file or directory

自定義庫,一般放在這個目錄:

#cp libmath.so /usr/local/lib/

增加lib查找路徑, 指定鏈接器 去哪里查找:

#cat /etc/ld.so.conf.d/jianyi.conf
/usr/local/lib

重新生成 cache文件:

#ldconfig

運行:

#./main.out
add:3
sub:-90
mul:50
div:2

使用環境變量 LD_LIBRARY_PATH

#echo $LD_LIBRARY_PATH


#export LD_LIBRARY_PATH=.
#./main.out
add:3
sub:-90
mul:50
div:2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM