完整分析一个hello程序

关键词:hello,world 程序的完整执行过程 Linux工具使用

写作目的:熟悉Linux各种工具的使用,并在实际场景中理解打印一条"hello, world"在Linux操作系统中完整执行的过程。
读者需要掌握Linux基础命令、vim编辑器的使用、x86-64的寄存器传参方式、......等准备知识才能阅读本文。文中出现的所有Linux指令及参数在manual中都有说明,如有疑问请RTFM(Reading The Friendly Manual)。

目录:
1.从源码到机器码的各种中间形态
2.指令和数据在可执行文件中的摆放格式


3.可执行文件如何被加载
4.指令逐条执行过程详解

======================写于2019_11_15=====================

1.从源代码到机器码

理论过程:gcc预编译展开include和宏,编译成可重定位目标文件,静态链接,生成可执行目标文件(,动态链接)。

实际过程:
(1)用C语言写一个hello程序


C语言源程序

(2)展开include的内容
gcc -E hello-test.c -o hello-test.pre(由于Linux不关心扩展名,所以我随便写了一个表示预处理preprocess)


预编译后的C语言源程序

看到行数了吗?这个main函数前面794行都是#include的展开。
(3)生成汇编语言(文本)文件
gcc -S hello-test.c -o hello-test.asm
汇编程序(文本形态)

(4)生成可重定位(二进制)目标文件
gcc -c hello-test.c -o hello-test.obj
打开hello-test.obj会显示乱码,这时候需要在vim中执行shell中的命令xxd,并将结果输出到当前文件中,因此在vim命令控制台里输入:%!xxd(:%!表示执行后面的shell命令然后将结果输出到当前文件中,如果是:!就只是执行后面的shell命令)就可以得到下面的格式化输出了。你可以在里面搜索"hello, world"字符串。


可重定位(二进制)目标文件

(5)生成可执行(二进制)文件
gcc hello-test.c -o hello-test.bin


可执行(二进制)文件

(6)可执行文件的反汇编
objdump -D hello-test.bin > hello-test.objdump
有意思的是,反汇编器将只读数据"hello, world"翻译成指令,而非数据。


可执行文件的反汇编结果(.rodate节部分)

这不是说明反汇编器的愚蠢,而恰恰说明了指令和数据在机器看来别无二致,都只是字节值而已。

2.指令和数据

我们已经通过gcc和objdump得到了最初的C语言源文件转化为二进制可执行文件的各种中间形态,现在我们将着眼于它的最终形态:二进制可执行文件。我们在上面的第(6)步大概了解了这个文件里有指令,有数据,但是这些指令和数据如何被组织,而且操作系统在加载时又如何去读取,我们还不清楚。

理论:Linux下的可执行文件(以及可重定位目标文件,这个我们不讨论,读者有兴趣自己尝试)遵循ELF格式。
(1)什么是ELF格式?
readelf -h hello-test.bin

ELF头信息

-h表示只解析ELF头的相关信息,上述信息是一个大纲层次的,更多的细节需要阅读段头表信息和节头表信息:
段头表(也称程序头表,Program Header)
readelf -l hello-test.bin
段头表信息

节头表(Section Header)
readelf -S hello-test.bin
节头表信息

可以发现程序入口地址就是.text节的起始地址,也是汇编代码中_start的位置,这就是整个程序执行的第一条指令。
(2)指令在哪?数据在哪?
hello-test.bin整个文件的组织格式就是ELF格式,ELF格式将文件按自然意义分成节(section),按工程意义分成段(segment)。接下来我们在这个二进制文件中去寻找数据"hello, world"和main函数的指令(其实就是阅读ELF格式信息的过程)。
要找指令,就要找.text节的内容,我们看到.txet节的偏移量为0x530,因此我们在两个文件(objdump文件和bin文件)中分别寻找,objdump可以很轻松地找到,而在bin文件中,寻找0x530处的各个字节:
在bin文件中寻找.text节

与在objdump文件中找到的各个字节是完全相同的:
在objdump文件中寻找.text节

要找数据"hello, world",就去.rodata节。与上述过程类似,先确定.rodata节的偏移,然后找到各个字节即可。(发现"hello, world"的位置在偏移量0x6e4处)
在objdump中寻找数据

在bin中寻找数据

3.文件被加载的过程
//TODO()

4.指令逐条执行
//TODO()

你可能感兴趣的:(完整分析一个hello程序)