计算机原理系列之五 -------- 编译过程分析

欢迎访问我的个人博客: luomuxiaoxiao.com



如何编译目标文件中我们了解到汇编文件经过编译器之后生成了可重定位文件,并且在 可重定位文件详解中我们以一个最简单的 'hello, wolrd'程序为例,分析了可重定位文件的详细内容。这篇文章中我们主要分析一下 汇编文件和可重定位文件代码段的关系,以及从汇编文件生成可重定位文件的详细过程。

我们还是以如何编译目标文件中的hello.c来研究。

一、 由汇编器生成的汇编代码

首先我们先查看一下经过汇编之后转换成的汇编代码:

        .file   "hello.c"
        .section        .rodata
.LC0:
        .string "hello, world"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        popq    %rbp
        ret
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609"
        .section        .note.GNU-stack,"",@progbits

为了方便阅读代码中我们省略了CFI信息,关于CFI详细信息,请参考参考阅读[1]

二、 查看可重定位文件的内容

2.1 可重定位文件的实际内容

由于可重定位文件属于二进制文件。在linux机器上,可以使用hexdump命令来查看二进制文件的内容。

$ hexdump -C hello.o
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 3e 00 01 00 00 00  00 00 00 00 00 00 00 00  |..>.............|
00000020  00 00 00 00 00 00 00 00  a0 02 00 00 00 00 00 00  |................|
00000030  00 00 00 00 40 00 00 00  00 00 40 00 0d 00 0a 00  |....@.....@.....|
00000040  55 48 89 e5 bf 00 00 00  00 e8 00 00 00 00 b8 00  |UH..............|
00000050  00 00 00 5d c3 68 65 6c  6c 6f 2c 20 77 6f 72 6c  |...].hello, worl|
00000060  64 00 00 47 43 43 3a 20  28 55 62 75 6e 74 75 20  |d..GCC: (Ubuntu |
00000070  35 2e 34 2e 30 2d 36 75  62 75 6e 74 75 31 7e 31  |5.4.0-6ubuntu1~1|
00000080  36 2e 30 34 2e 31 30 29  20 35 2e 34 2e 30 20 32  |6.04.10) 5.4.0 2|
00000090  30 31 36 30 36 30 39 00  14 00 00 00 00 00 00 00  |0160609.........|

... snip ...

2.2 反汇编可重定位的代码段

hello.o是一个二进制文件,显然,代码段也被编译成了一系列的二进制数字,而且这些数字就被包含于上面hexdump输出的数字里,那么如何找到他们呢?

我们知道ELF文件中,Section Header Table指定了各个section的起始地址,长度等信息,那么,我们查看hello.o的信息得到以下内容:

$ readelf -S hello.o
There are 13 section headers, starting at offset 0x2a0:

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
       0000000000000015  0000000000000000  AX       0     0     1

... snip ...

上述信息我们知道.text(代码段)起始于ELF文件首地址偏移00000040处,长度为0x15个字节。也即0x40 ~ 0x54之间都为代码段部分,结合hexdump输出的信息,即以下内容:

00000040  55 48 89 e5 bf 00 00 00  00 e8 00 00 00 00 b8 00  |UH..............|
00000050  00 00 00 5d c3                                    |...]

这些二进制数据显然不那么的友好,我们可以使用objdump命令来反编译一下。objdump工具用来显示二进制文件的信息,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。-d参数表示反汇编ELF文件中可执行的代码(代码段)部分。

$ objdump -d hello.o

hello.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   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 <main+0xe>
   e:   b8 00 00 00 00          mov    $0x0,%eax
  13:   5d                      pop    %rbp
  14:   c3                      retq

输出内容中最左侧依然是字节序列的序号,中间部分表示ELF文件内保存的字节序列,最右侧是反汇编出来的汇编代码。我们注意到,反编译出的字节序列正好就是根据hexdump命令和section header table推算出来的字节序列。

仔细观察发现,objdump反汇编出来的代码中除了省略掉了.cfi_*相关的信息,和原来的汇编文件的代码部分唯一的差异有两条指令。摘录如下:

# 汇编器生成的汇编代码:
        movl    $.LC0, %edi
		call    puts

# 反编译出来的汇编代码:
   4:   bf 00 00 00 00          mov    $0x0,%edi
   9:   e8 00 00 00 00          callq  e <main+0xe>

首先,我们分析第二条语句,结合C代码这行汇编代码对应的是printf("hello, world\n");。这里我们不用在意为什么C代码中调用的是printf函数,而到汇编语言中却变成了puts函数(实际上是编译器做了优化)。我们主要讨论为什么由汇编器生成的call指令和反编译出来的call指令会有区别。

请点击此处继续阅读


想第一时间查看我的文章吗?请关注我的微信公众号号,搜索“落木萧萧技术论坛”或登陆我的个人博客:www.luomuxiaoxiao.com,更多精彩文章等你。

qrcode
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值