《程序员的自我修养——链接、装在与库》第三章《目标文件里有什么》读书笔记

一. 目标文件的概念

  1. 编译器编译源代码后生成的文件叫做目标文件。
  2. 从结构上讲,它是编译后的可执行文件格式,只是还没有经过链接过程。

二. 目标文件的格式

  1. PC平台上主流的可执行文件格式(Executable)主要有

    • Windows下的PE(Portable Executable)
    • Linux的ELF(Executable)

    它们都是COFF(Common file format)格式的变种。

  2. ELF分类

    ELF文件类型 说明 实例
    可重定位文件(Relocateable File) 包含代码和数据,可以链接成可执行文件或共享目标文件 Linux的 .o .a,Windows的.obj .lib
    可执行文件(Executeable File) 包含可直接执行的程序,它的代表就是ELF可执行文件 Linux的/bin/bash文件,Windows的.exe
    共享目标文件(Shared Object File) 包含代码和数据。链接器可以使用它跟其他可重定位文件或共享目标文件链接,产生新的目标文件。 动态链接器可以将几个共享目标文件与可执行文件结合,作为进程映像的一部分来运行 Linux的.so,Windows的.dll
    核心转存储文件(Core Dump File) 当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转存储到核心转存储文件 Linux下的core dump

三. 目标文件是什么样的

内容
File Header 描述整个文件的属性,包括文件是否可执行,是静态链接还是动态链接以及入口地址(如果是位置相关的可执行文件),目标硬件,目标操作系统等信息,文件头还包括一个段表(Section Table)
.text(or .code) section 代码段
.data section 已初始化的全局变量和静态变量
.bss section 未初始化的全局变量和静态变量

目标文件可分为程序指令和程序数据,这样做的好处有以下几个方面:

  1. 程序被装载后,数据和指令分别被映射到两个虚拟区域,数据区可读写,指令区只读,这样可以防止程序指令被改写。
  2. 现代CPU的缓存一般都被设计成数据缓存和指令缓存分离,所以程序的指令和数据分离对提高CPU的缓存命中率有好处。
  3. 副本进程之间可以共享程序指令。

四. 通过一个.o来了解目标文件的段

实验环境为:
GNU ld version 2.23.52.0.1-55.el7 20130226  
gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)  
CentOS Linux release 7.2.1511 (Core)

源代码如下:

int g_init_var = 84;
int g_unint_var;

void func1(int i) {
    printf("%d\n", i);
}

int main(void) {
    static int static_var = 85;
    static int static_var2;
    int a = 1;
    int b;
    func1(static_var2 + static_var + a + b);
    return a;
}

执行

$ gcc -c SimpleSection.c 

编译结果为 SimpleSection.o。执行

$ objdump -h SimpleSection.o

查看段基本信息。

SimpleSection.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000054  0000000000000000  0000000000000000  00000040  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  00000094  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  0000000000000000  0000000000000000  0000009c  2**2
                  ALLOC
  3 .rodata       00000004  0000000000000000  0000000000000000  0000009c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000002d  0000000000000000  0000000000000000  000000a0  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000cd  2**0
                  CONTENTS, READONLY
  6 .eh_frame     00000058  0000000000000000  0000000000000000  000000d0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

每个段信息的第二行中的CONTENTS、ALLOC等表示了该段的属性,CONTENTS表示该段在ELF文件中存在。

4.1. 代码段

执行

$ objdump -s -d SimpleSection.o

看所有段信息,以及反汇编结果。

SimpleSection.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000054  0000000000000000  0000000000000000  00000040  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  00000094  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  0000000000000000  0000000000000000  0000009c  2**2
                  ALLOC
  3 .rodata       00000004  0000000000000000  0000000000000000  0000009c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000002d  0000000000000000  0000000000000000  000000a0  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000cd  2**0
                  CONTENTS, READONLY
  6 .eh_frame     00000058  0000000000000000  0000000000000000  000000d0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
[tiger@app-20-39 ~]$ objdump -s -d SimpleSection.o

SimpleSection.o:     file format elf64-x86-64

Contents of section .text:
 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
 0010 bf000000 00b80000 0000e800 000000c9  ................
 0020 c3554889 e54883ec 10c745fc 01000000  .UH..H....E.....
 0030 8b150000 00008b05 00000000 01c28b45  ...............E
 0040 fc01c28b 45f801d0 89c7e800 0000008b  ....E...........
 0050 45fcc9c3                             E...            
Contents of section .data:
 0000 54000000 55000000                    T...U...        
Contents of section .rodata:
 0000 25640a00                             %d..            
Contents of section .comment:
 0000 00474343 3a202847 4e552920 342e382e  .GCC: (GNU) 4.8.
 0010 35203230 31353036 32332028 52656420  5 20150623 (Red 
 0020 48617420 342e382e 352d3429 00        Hat 4.8.5-4).   
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 21000000 00410e10 8602430d  ....!....A....C.
 0030 065c0c07 08000000 1c000000 3c000000  .\..........<...
 0040 00000000 33000000 00410e10 8602430d  ....3....A....C.
 0050 066e0c07 08000000                    .n......        

Disassembly of section .text:

0000000000000000 <func1>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   89 7d fc                mov    %edi,-0x4(%rbp)
   b:   8b 45 fc                mov    -0x4(%rbp),%eax
   e:   89 c6       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值