进击的荆棘头像
Linux系统——库的原理与制作之ELF文件的形成与加载的过程(上)封面图

Linux系统——库的原理与制作之ELF文件的形成与加载的过程(上)

 💁‍♂️个人主页:进击的荆棘

👇作者其它专栏:

《数据结构与算法》《算法》《C++起始之路》《Linux》


目录

1.什么是库

2.静态库

3.动态库

4.使用外部库

5.目标文件

6.ELF文件

7.ELF从形成到加载轮廓

8.理解链接与加载

附录:操作大全


6.ELF文件

要理解编译链链接的细节,就必须了解ELF文件。以下四种文件都是ELF文件:

●可重定位文件(Relocatable File):即xxx.o文件。包含适合于与其它目标文件链接来创建可执行文件或共享目标文件的代码和数据

●可执行文件(Executable File):即可执行程序

●共享目标文件(Shared Object File):即xxx.so文件

●内核转储(core dumps):存放当前进程的执行上下文,用于dump信号触发

一个ELF文件由以下四部分组成:

●ELF头(ELT header):描述文件的主要特性。其位于文件的开始位置,它的主要目的是定位文件的其它部分

●程序头表(Program header table):列举了所有有效的段(segments)和它们的属性。表里记着每个段的开始的位置和位移(offset)、长度,这些段,都是紧密的放在二进制文件中,需要段表的描述信息,才能把它们每个段分割开

●节头表(Section header table):包含对节(sections)的描述

●节(Section):ELF文件中的基本组成单位,包含了特定类型的数据。ELF文件的各种信息和数据都存储在不同的节中,如代码节存储了可执行代码,数据节存储了全局变量和静态数据等

最常见的节:

●代码节(.text):用于保存机器指令,是程序的主要执行部分

●数据节(.data):保存已初始化的全局变量和局部静态变量

[sjx@VM-0-6-centos ~]$ size /usr/bin/ls
   text	   data	    bss	    dec	    hex	filename
 103207	   4792	   3360	 111359	  1b2ff	/usr/bin/ls

7.ELF从形成到加载轮廓

7.1ELF形成可执行

●step1:将多份C/C++源代码,翻译成目标.o文件+动静态库(ELF)

●step2:将多份.o文件section进行合并

注:

●实际合并是在链接是进行的,但是并不是简单的合并,也会涉及对库合并

7.2ELF可执行文件加载

●一个ELF会由多种不同的Section,在加载到内存时,也会进行Section合并,形成segment

●合并原则:相同属性,如:可读,可写,可执行,需要加载时申请空间等

●这样,即使是不同的Section,在加载到内存中,可能会以segment的形式,加载到一起

●很显然,合并工作在形成ELF的时候,合并方式就已经确定了,具体合并原则被记录在了ELF的程序头表(Program header table)中

#查看可执行程序的section
[sjx@VM-0-6-centos ~]$ readelf -S main.exe
There are 30 section headers, starting at offset 0x1960:

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
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000060  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400318  00000318
       000000000000003d  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400356  00000356
       0000000000000008  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400380  00000380
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400398  00000398
       0000000000000048  0000000000000018  AI       5    23     8
  [11] .init             PROGBITS         00000000004003e0  000003e0
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000400400  00000400
       0000000000000040  0000000000000010  AX       0     0     16
  [13] .text             PROGBITS         0000000000400440  00000440
       0000000000000192  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         00000000004005d4  000005d4
       0000000000000009  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         00000000004005e0  000005e0
       000000000000002b  0000000000000000   A       0     0     8
  [16] .eh_frame_hdr     PROGBITS         000000000040060c  0000060c
       000000000000003c  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         0000000000400648  00000648
       0000000000000114  0000000000000000   A       0     0     8
  [18] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000008  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000030  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         0000000000601030  00001030
       0000000000000004  0000000000000000  WA       0     0     1
  [25] .bss              NOBITS           0000000000601034  00001034
       0000000000000004  0000000000000000  WA       0     0     1
  [26] .comment          PROGBITS         0000000000000000  00001034
       000000000000002d  0000000000000001  MS       0     0     1
  [27] .symtab           SYMTAB           0000000000000000  00001068
       0000000000000618  0000000000000018          28    47     8
  [28] .strtab           STRTAB           0000000000000000  00001680
       00000000000001d5  0000000000000000           0     0     1
  [29] .shstrtab         STRTAB           0000000000000000  00001855
       0000000000000108  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

#查看可执行程序合并后的segment
[sjx@VM-0-6-centos ~]$ readelf -l main.exe

Elf file type is EXEC (Executable file)
Entry point 0x400440
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
                 0x000000000000075c 0x000000000000075c  R E    200000
  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x0000000000000224 0x0000000000000228  RW     200000
  DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x000000000000060c 0x000000000040060c 0x000000000040060c
                 0x000000000000003c 0x000000000000003c  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x00000000000001f0 0x00000000000001f0  R      1

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

为什么要将section合并成为segment

●Section合并的主要原因是为了减少页面碎片,提高内存使用效率。若不进行合并,假设页面大小为4096字节(内存块基本大小,加载,管理的基本单位),若.text部分为4097字节,.init部分为512字节,那么它们将占用3个页面,而合并后,只需2个页面

●此外,操作系统在加载程序时,会将具有相同属性的section合并成一个大的segment,这样就可以实现不同的访问权限,从而优化内存管理和权限访问控制

对于程序头表和节头表,ELF文件提供了2个不同的视角/视图来理解这两个部分:

●链接视图(Linking view)-对应节头表 Section header table

        ▢文件结构的粒度更细,将文件按功能模块的差异进行划分,静态链接分析的时候一般关注的是链接视图,能够理解ELF文件中包含的各个部分的信息

        ▢为了空间布局上的效率,将来在链接目标文件是,链接器会把很多节(section)合并,规整成可执行的段(segment)、可读写的段、只读段。合并了后,空间利用率就高了,否则,很小的一段,未来物理内存页浪费太大(物理内存页分配一般都是整数倍一块给你,如4k),所以,链接器趁着链接就把小块们都合并了

●执行视图(execution view)-对应程序头表Program header table

        ▢告诉操作系统,如何加载可执行文件,完成进程内存的初始化。一个可执行程序的格式中,一定有 program header table

●即一个在链接时作用,一个在运性加载时作用

从链接视图来看:

●命令readelf -S main.exe可以帮助查看ELF文件的节头表

●.text节:是保存了程序代码指令的代码节

●.data节:保存了初始化的全局变量和局部静态变量等数据

●.rodata节:保存了只读的数据,如一行C代码中的字符串。由于.rodata节是只读的,所以只能存在一个可执行的只读段中。因此,只能是在text段(不是data段)中找到.rodata节

●.BSS节:为未初始化的全局变量和局部静态变量预留位置

●.symtab:symbol Table 符号表,就是源码中的那些函数名、变量名和代码的对应关系

●.got.plt节(全局偏移表-过程链接表):.got节保存了全局偏移表。.got节和.plt节一起提供了对导入的共享库函数的访问入口,有动态链接器在运行时进行修改。

        ▢使用readelf命令查看.so文件可以看到该节

从执行视图来看:

●告诉操作系统哪些模块可以被加载进内存

●加载进内存之后哪些分段是可读可写,哪些分段是只读,哪些分段是可执行的

可以在ELF头中找到文件的基本信息,以及可以看到ELF头是如何定位程序头表和节头表的。例:可以查看main.exe这个可重定位文件的主要信息:

#查看目标文件
[sjx@VM-0-6-centos ~]$ readelf -h code.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00     #ELF文件标识符(魔数)
  Class:                             ELF64    #文件类:64位架构
  Data:                              2's complement, little endian    #数据编码:小端序二进制补码
  Version:                           1 (current)    #ELF版本:当前版本(1)
  OS/ABI:                            UNIX - System V    #操作系统ABI:System V UNIX
  ABI Version:                       0    #ABI扩展版本:未扩展(0)
  Type:                              REL (Relocatable file)    #文件类型:可重定位文件(目标文件)
  Machine:                           Advanced Micro Devices X86-64    #目标平台:x86-64架构
  Version:                           0x1    #对象文件版本:1
  Entry point address:               0x0    #入口点地址:无(目标文件为0)
  Start of program headers:          0 (bytes into file)    #程序头表起始偏移:无(目标文件为0)
  Start of section headers:          664 (bytes into file)    #节头表起始偏移664字节处
  Flags:                             0x0    #处理器特定标志:五标志(0)
  Size of this header:               64 (bytes)    #ELF头大小:64字节
  Size of program headers:           0 (bytes)    #程序头表条目大小:无(目标文件为0)
  Number of program headers:         0    #程序头表条目数:无(目标文件为0)
  Size of section headers:           64 (bytes)    #节头表条目大小:64字节
  Number of section headers:         13    #节头表条目数:13个字节
  Section header string table index: 12    #节名称字符串表索引:第12节(.shstrtab)


#查看可执行程序
[sjx@VM-0-6-centos ~]$ readelf -h main.exe
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00     #ELF文件标识符(魔数)
  Class:                             ELF64    #文件类:64为架构
  Data:                              2's complement, little endian    #数据编码:小端序二进制补码
  Version:                           1 (current)    #ELF版本:当前版本(1)
  OS/ABI:                            UNIX - System V    #操作系统ABI:System V UNIX
  ABI Version:                       0    #ABI扩展版本:未扩展(0)
  Type:                              EXEC (Executable file)    #文件类型:可重定位文件(目标文件
  Machine:                           Advanced Micro Devices X86-64    #目标平台:x86-64架构
  Version:                           0x1    #对象文件版本:1
  Entry point address:               0x400440    :入口点地址:0x400440
  Start of program headers:          64 (bytes into file)    #程序头表起始偏移:64字节处
  Start of section headers:          6496 (bytes into file)    #节头表起始偏移:6496字节处
  Flags:                             0x0    #处理器特定标志:无标志(0)
  Size of this header:               64 (bytes)    #ELF头大小:64字节
  Size of program headers:           56 (bytes)    #程序头表条目大小:56个字节
  Number of program headers:         9    #程序头表条目数:9个节
  Size of section headers:           64 (bytes)    #节头表条目数:64个字节
  Number of section headers:         30    #节头表条目数:30个节
  Section header string table index: 29    #节名称字符串表索引:第29节(.shstrtab)

对于ELF HEADER来说,它的主要目的是定位文件的其它部分

8.理解链接与加载

8.1静态链接

●无论是自己的.o,还是静态库中的.o,本质都是把.o文件进行链接的过程

●所以:研究静态链接,本质就是研究.o是如何链接的

[sjx@VM-0-6-centos test]$ ll
total 16
-rw-rw-r-- 1 sjx sjx   65 Oct  9 17:41 code.c
-rw-rw-r-- 1 sjx sjx 1496 Oct  9 17:42 code.o
-rw-rw-r-- 1 sjx sjx   85 Oct  9 17:41 main.c
-rw-rw-r-- 1 sjx sjx 1552 Oct  9 17:42 main.o
[sjx@VM-0-6-centos test]$ gcc -o main.exe *.o
[sjx@VM-0-6-centos test]$ ll
total 28
-rw-rw-r-- 1 sjx sjx   65 Oct  9 17:41 code.c
-rw-rw-r-- 1 sjx sjx 1496 Oct  9 17:42 code.o
-rw-rw-r-- 1 sjx sjx   85 Oct  9 17:41 main.c
-rwxrwxr-x 1 sjx sjx 8416 Oct  9 20:15 main.exe
-rw-rw-r-- 1 sjx sjx 1552 Oct  9 17:42 main.o

查看编译后的.o目标文件

[sjx@VM-0-6-centos test]$ objdump -d code.o

code.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <test>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	bf 00 00 00 00       	mov    $0x0,%edi
   9:	e8 00 00 00 00       	callq  e <test+0xe>
   e:	5d                   	pop    %rbp
   f:	c3                   	retq   
[sjx@VM-0-6-centos test]$ objdump -d main.o

main.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	b8 00 00 00 00       	mov    $0x0,%eax
   9:	e8 00 00 00 00       	callq  e <main+0xe>
   e:	bf 00 00 00 00       	mov    $0x0,%edi
  13:	e8 00 00 00 00       	callq  18 <main+0x18>
  18:	5d                   	pop    %rbp
  19:	c3                   	retq 

●objdump -d命令:将代码段(.text)进行反汇编查看

●main.o中的main函数不认识printf和test函数

[sjx@VM-0-6-centos test]$ cat main.c
#include <stdio.h>

void test();

int main(){
  test();
  printf("hello world\n");
}

●code.o不认识printf函数

[sjx@VM-0-6-centos test]$ cat code.c
#include <stdio.h>

void test(){
  printf("this is a test\n");
}

可以看到这里的call指令,分别对应之前调用的printf和run函数,但是它们的跳转地址都被设成了0。为什么?

因为在编译main.c的时候,编译器不知道printf和test函数的存在,如它们位于内存的哪个区块,代码长什么样都是不知道的。因此,编译器只能将这两个函数的跳转地址先暂时设为0

这个地址什么时候被修正?链接的时候。为了让链接器将来在链接时能正确定位到这些被修正的地址,在代码块(.data)中还存在一个重定位表,这张表将来在链接的时候,就会根据表里记录的地址将其修正

#读取code.o符号表
[sjx@VM-0-6-centos test]$ readelf -s code.o

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS code.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     9: 0000000000000000    16 FUNC    GLOBAL DEFAULT    1 test
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
puts:就是printf的实现
UND:就是undefine,表示未定义,即本.o文件找不到

#读取main.o符号表
[sjx@VM-0-6-centos test]$ readelf -s main.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 main.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     9: 0000000000000000    26 FUNC    GLOBAL DEFAULT    1 main
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND test
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
puts:就是printf的实现
test:我们自己定义的方法在main.o中未定义(因为在code.o中)
UND:就是undefine,表示未定义,即本.o文件找不到

[sjx@VM-0-6-centos test]$ readelf -s main.exe

Symbol table '.dynsym' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

Symbol table '.symtab' contains 65 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: 00000000004002b8     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000400318     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000400356     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000400360     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000400380     0 SECTION LOCAL  DEFAULT    9 
    10: 0000000000400398     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000004003e0     0 SECTION LOCAL  DEFAULT   11 
    12: 0000000000400400     0 SECTION LOCAL  DEFAULT   12 
    13: 0000000000400440     0 SECTION LOCAL  DEFAULT   13 
    14: 00000000004005d4     0 SECTION LOCAL  DEFAULT   14 
    15: 00000000004005e0     0 SECTION LOCAL  DEFAULT   15 
    16: 000000000040060c     0 SECTION LOCAL  DEFAULT   16 
    17: 0000000000400648     0 SECTION LOCAL  DEFAULT   17 
    18: 0000000000600e10     0 SECTION LOCAL  DEFAULT   18 
    19: 0000000000600e18     0 SECTION LOCAL  DEFAULT   19 
    20: 0000000000600e20     0 SECTION LOCAL  DEFAULT   20 
    21: 0000000000600e28     0 SECTION LOCAL  DEFAULT   21 
    22: 0000000000600ff8     0 SECTION LOCAL  DEFAULT   22 
    23: 0000000000601000     0 SECTION LOCAL  DEFAULT   23 
    24: 0000000000601030     0 SECTION LOCAL  DEFAULT   24 
    25: 0000000000601034     0 SECTION LOCAL  DEFAULT   25 
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26 
    27: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    29: 0000000000400470     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    30: 00000000004004a0     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    31: 00000000004004e0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    32: 0000000000601034     1 OBJECT  LOCAL  DEFAULT   25 completed.6355
    33: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fin
    34: 0000000000400500     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    35: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS code.c
    37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    38: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    39: 0000000000400758     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    40: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
    42: 0000000000600e18     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    43: 0000000000600e28     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    44: 0000000000600e10     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    45: 000000000040060c     0 NOTYPE  LOCAL  DEFAULT   16 __GNU_EH_FRAME_HDR
    46: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    47: 00000000004005d0     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    48: 0000000000601030     0 NOTYPE  WEAK   DEFAULT   24 data_start
    49: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.2.5
    50: 0000000000601034     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    51: 00000000004005d4     0 FUNC    GLOBAL DEFAULT   14 _fini
    52: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    53: 0000000000601030     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    54: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    55: 00000000004005e8     0 OBJECT  GLOBAL HIDDEN    15 __dso_handle
    56: 00000000004005e0     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    57: 0000000000400560   101 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    58: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 _end
    59: 0000000000400440     0 FUNC    GLOBAL DEFAULT   13 _start
    60: 0000000000601034     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    61: 000000000040053d    26 FUNC    GLOBAL DEFAULT   13 main
    62: 0000000000601038     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    63: 00000000004003e0     0 FUNC    GLOBAL DEFAULT   11 _init
    64: 000000000040052d    16 FUNC    GLOBAL DEFAULT   13 test
两个.o进行合并之后,在最终的可执行程序中,找到了test
000000000040052d:地址
FUNC:表示test符号类型是个函数
13:test函数所在的section被合并最终的那一个section中,13就是下标

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2501_93697341/article/details/167391832

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--