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. 静态链接的符号表
    3. .symtab section
  2. 动态链接的符号表
    4. .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
posted @ 2019-02-01 18:57  苏小北1024  阅读(3042)  评论(0编辑  收藏  举报