相信大家在学习C语言的时候都是从经典的示例程序 Hello World!开始的,相信大家都能随手写出一个这样的程序来。这样的程序都滚瓜烂熟了。下面给出代码:
/*************hello.c***************/
#include <stdio.h>
int mian(int argc ,char ** argv)
{
printf("Hello World!\r\n");
return 0;
}
代码写好后,很自然的大家就开始对代码进行编译了:
在Linux 是这样的:
gcc hello.c
./a.out
屏幕输出一行 Hello World!
windows 下是这样的:
建立一个VC项目工程,然后直接编译,直接点运行,弹出一个DOS运行界面,输出一行Hello World!
一切都是那么的自然,我们也重来没有怀疑过这些操作步骤,按照这个步骤做下去一般程序都能运行成功,就这样我们就可以进行程序开发了。
忽然有一天,我们开始思考:
1、程序为什么要通过编译才能运行呢?
2、编译器对我们的代码做了什么呢?
3、编译我们的代码后生成的文件内容又是什么呢?
4、程序是怎么运行起来的呢?
5、Hello world 为什么能输出呢?
6、如果没有操作系统,我们的程序还能运行吗?
这些谜团伴随着我....让我一步步进入了C/C++语言的深入学习。
●目标文件里有什么
目标文件的格式与操作系统有着直接的联系,但是大都是基于COFF标准的变种。目标文件中除了有可供计算机CPU直接识别运行的机器码之外,还包括了连接时所需要的一些其它信息。一般以节(Section)或段(Segmation)的形式存储,在一般情况下,目标文件都存在以下结构:
1 文件头
2 段表
3 符号表
4 调试信息
在不同操作系统中有不同的目标文件格式标准,在windows下为PE文件格式,在Linux下为Elf文件格式,在Unix下为a.out文件格式。
在Linux系统中分析Elf文件格式有很多命令,主要有objdump,binutils,readelf,size等。
下面以Linux Elf标准进行分析
一Elf文件头
Elf文件头在文件中主要存储了一个结构体,其结构体成员主要有以下几个变量:
e_ident[16] 魔数;
e_type Elf文件类型
e_machine Elf文件CPU平台
e_version Elf文件版本
e_entry 入口地址
e_phoff
e_shoff 段表文件中的偏移
e_word Elf标志位,用来标志一些平台相关的东西
e_ehsize Elf文件大小
e_phentsize
e_phnum
e_shentsize 段描述符大小
e_shnum 段描述符数量
e_shstrndx 段表字符串在段表中的下标