zoukankan      html  css  js  c++  java
  • 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
    ", add(1,2));
    	printf("sub:%d
    ", sub(10,100));
    	printf("mul:%d
    ", mul(5,10));
    	printf("div:%d
    ", 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
    ", &global_a);
    	printf("global_b:%lx
    ", &global_b);
    	printf("local_a:%lx
    ", &local_a);
    	printf("local_b:%lx
    ", &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
    ", add(1,2));
    	printf("sub:%d
    ", sub(10,100));
    	printf("mul:%d
    ", mul(5,10));
    	printf("div:%d
    ", 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
    
  • 相关阅读:
    SpringMVC(二)
    SpringMVC(一)
    Mybatis之mapper.xml配置文件中的#{}和${}
    Mybatis(二)
    Mybatis(一)
    Linux部署项目
    BOS物流项目第十三天
    Failed to read schema document 'http://www.springframework.org/schema/beans/spring-beans.xsd'
    景点API支持查询携程旅游门票景点详情
    Html引入百度富文本编辑器ueditor及自定义工具栏
  • 原文地址:https://www.cnblogs.com/muahao/p/10346724.html
Copyright © 2011-2022 走看看