静心学习之路系列

静心学习之路(10)——链接(2)

2021-01-08  本文已影响0人  游学者夏纳

续:静心学习之路(8)——链接


0x07 重定位

链接器完成了符号解析以后,把代码里每个符号引用每个符号定义关联了起来。此时链接器就知道了目标模块中代码节和数据节的确切大小,此时就可以执行重定位步骤了,重定位由两步组成:

0x08 可执行目标文件

可执行目标文件的格式类似于可重定位目标文件.o。比较之下,多了程序的入口点(entry point),因为可执行文件是完全链接的,所以他不再需要rel节。

说明
ELF头
段头部表
.init 定义了_init函数,程序初始化会用到
.text 已编译程序的机器码
.rodata read-only data(比如printf的字符串,和swtich的跳转表)
.data init过的 global & static c-vars
.bss 未init过或init(0)的 global & static c-vars(纯占位,省空间用)
.symtab 符号表,存放定义和引用的 funciton 和 global vars 的信息
.rel.text .text节位置的列表,再和其他.o文件组合时修改
.rel.data 被引用或定义的 global vars 的重定位信息
.debug 调试符号表,-g选项才获得
.line C代码行号和.text映射表,-g选项才获得
.strtab 字符串表,包含.symtab和.debug的符号表,以及节头部中的节名字
节头部表 描述不同节的位置和大小

当然上面是课本内容,我们也可以用反汇编工具objdump查看文件:(假设prog文件由此产生:linux > gcc -Og -o prog main.c sum.c

因为内容输出巨多,为了方便浏览(且不污染终端界面)建议输出到文件或者vim类浏览器中(比如less):
linux > objdump -x prog | less

部分结果如下:

prog:     file format elf64-x86-64
prog
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00000000004003a0

Program Header:
    PHDR off    0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3
         filesz 0x00000000000001c0 memsz 0x00000000000001c0 flags r-x
  INTERP off    0x0000000000000200 vaddr 0x0000000000400200 paddr 0x0000000000400200 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
         filesz 0x00000000000006dc memsz 0x00000000000006dc flags r-x
    LOAD off    0x00000000000006e0 vaddr 0x00000000006006e0 paddr 0x00000000006006e0 align 2**21
         filesz 0x00000000000001f8 memsz 0x0000000000000208 flags rw-
 DYNAMIC off    0x0000000000000700 vaddr 0x0000000000600700 paddr 0x0000000000600700 align 2**3
         filesz 0x0000000000000190 memsz 0x0000000000000190 flags rw-
    NOTE off    0x000000000000021c vaddr 0x000000000040021c paddr 0x000000000040021c align 2**2
         filesz 0x0000000000000020 memsz 0x0000000000000020 flags r--
EH_FRAME off    0x00000000000005c8 vaddr 0x00000000004005c8 paddr 0x00000000004005c8 align 2**2
         filesz 0x0000000000000034 memsz 0x0000000000000034 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**3
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-

...

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400200  0000000000400200  00000200  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  000000000040021c  000000000040021c  0000021c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .hash         00000018  0000000000400240  0000000000400240  00000240  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynsym       00000048  0000000000400258  0000000000400258  00000258  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynstr       00000038  00000000004002a0  00000000004002a0  000002a0  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .gnu.version  00000006  00000000004002d8  00000000004002d8  000002d8  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version_r 00000020  00000000004002e0  00000000004002e0  000002e0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .rela.dyn     00000018  0000000000400300  0000000000400300  00000300  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.plt     00000030  0000000000400318  0000000000400318  00000318  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .init         00000024  0000000000400348  0000000000400348  00000348  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .plt          00000030  000000000040036c  000000000040036c  0000036c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .text         00000214  00000000004003a0  00000000004003a0  000003a0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .fini         0000000e  00000000004005b4  00000000004005b4  000005b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .rodata       00000004  00000000004005c4  00000000004005c4  000005c4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 14 .eh_frame_hdr 00000034  00000000004005c8  00000000004005c8  000005c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame     000000dc  0000000000400600  0000000000400600  00000600  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .ctors        00000010  00000000006006e0  00000000006006e0  000006e0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 17 .dtors        00000010  00000000006006f0  00000000006006f0  000006f0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .dynamic      00000190  0000000000600700  0000000000600700  00000700  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .got          00000008  0000000000600890  0000000000600890  00000890  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .got.plt      00000028  0000000000600898  0000000000600898  00000898  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .data         00000018  00000000006008c0  00000000006008c0  000008c0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .bss          00000010  00000000006008d8  00000000006008d8  000008d8  2**3
                  ALLOC
 23 .comment      00000011  0000000000000000  0000000000000000  000008d8  2**0
                  CONTENTS, READONLY
 24 .debug_aranges 00000100  0000000000000000  0000000000000000  000008f0  2**4
                  CONTENTS, READONLY, DEBUGGING
 25 .debug_info   00000361  0000000000000000  0000000000000000  000009f0  2**0
                  CONTENTS, READONLY, DEBUGGING
 26 .debug_abbrev 000001a0  0000000000000000  0000000000000000  00000d51  2**0
                  CONTENTS, READONLY, DEBUGGING
 27 .debug_line   0000022c  0000000000000000  0000000000000000  00000ef1  2**0
                  CONTENTS, READONLY, DEBUGGING
 28 .debug_str    00000216  0000000000000000  0000000000000000  0000111d  2**0
                  CONTENTS, READONLY, DEBUGGING
 29 .debug_loc    00000155  0000000000000000  0000000000000000  00001333  2**0
                  CONTENTS, READONLY, DEBUGGING
 30 .debug_ranges 00000080  0000000000000000  0000000000000000  00001490  2**4
                  CONTqENTS, READONLY, DEBUGGING
SYMBOL TABLE:
...

可以在Sections这部分找到具体的节信息。顺便一提笔者在生产环境中得知,debug相对于release来说会多了 .stab.stabstr这两部分(在.bss.common之间),这样用gdb进行dump文件分析的时候就能追踪的具体代码行数,release版本就不行。

...
 24 .bss          003d7680  0000000000c285c0  0000000000c285c0  006285b0  2**5
                  ALLOC
 25 .stab         00adb068  0000000000000000  0000000000000000  006285b0  2**2
                  CONTENTS, READONLY, DEBUGGING
 26 .stabstr      05379895  0000000000000000  0000000000000000  01103618  2**0
                  CONTENTS, READONLY, DEBUGGING
 27 .comment      0000004f  0000000000000000  0000000000000000  0647cead  2**0
                  CONTENTS, READONLY
...

(↑ 生产环境中线上Debug版本反编译时看到的多出的两节内容)

而在Program Header这部分里展示了prog的头部表, 这里截取上面输出的部分内容:

    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
         filesz 0x00000000000006dc memsz 0x00000000000006dc flags r-x
    LOAD off    0x00000000000006e0 vaddr 0x00000000006006e0 paddr 0x00000000006006e0 align 2**21
         filesz 0x00000000000001f8 memsz 0x0000000000000208 flags rw-

我们可以看到可执行目标文件的内容初始化两个内存段,前两行告诉我们第一个代码段具有读/执行权限r-x并开始于内存地址vaddr0x400000,总内存大小memsz0x6dc个字节,其中包括ELF头 程序头部表 .init .text .rodata

后两行告诉第二个数据段具有读/写权限rw-并开始于内存地址0x6006e0,总大小为0x208个字节,并用从目标文件偏移量off0x6e0处的.data节中的filesz 0x1f8个字节初始化。该段的 0x208 - 0x1f8 = 0x10即16个字节用于运行时初始化为0的.bss数据。

0x09 加载可执行目标文件

linux > ./prog

因为prog不是内置shell命令,所以shell判定prog是一个可执行目标文件,然后linux执行execve函数=>调用加载器(loader)。loader把目标文件的代码和数据从磁盘复制到内存,然后跳转到程序的第一条指令或者入口点来运行程序,这个过程就叫做加载。

Linux x86-64系统中,代码段总是从0x400000开始(vaddr 0x0000000000400000),后面是数据段,再后面是运行是的,由调用malloc往上增长。而用户栈则从最大用户合法地址(2^48-1 即 0x0000ffffffffffff,)开始高位向低位,向下增长。

图来源: https://blog.csdn.net/u013581207/article/details/95199139

具体关于loader的工作方式,要到CSAPP第8章和第9章中了解。

0x0A 动态链接共享库

0x0B 从应用程序中加载和链接共享库

0x0C 位置无关代码

0x0D 库打桩机制

上一篇下一篇

猜你喜欢

热点阅读