您的位置:首页 > 其它

第七课 可执行程序的装载(1)

2016-04-09 18:36 246 查看

可执行文件格式

在linux下的可执行文件的格式是ELF文件格式,与windows下常见的PE格式是不同的文件类型。

ELF文件是指可执行的可链接的文件。常见的.o文件或者可执行文件都可以是这种文件格式,但是他们又有不同,下面将查看分析他们的不同之处。

可重定位的文件

可重定位的文件就是我们常见的*.o目标文件,他包含一段代码和一段数据。用来生成可执行文件或者库文件。这比较好理解。

可执行的文件

可执行文件保存着一个用来执行的程序。该文件将会指出函数exec函数如何创建程序进程映像。这里也说出了我们可以调用exec来执行一个可执行文件的原因。

共享文件

共享文件是指一些库文件,包括了静态链接库和动态链接库两种。保存有代码和数据。用来被不同的连接器处理。

静态库将会被链接编辑器处理,最终和其他的目标文件处理形成新的目标文件。(编译时刻)

动态库将会被动态连接器处理,和可执行文件获取目标文件一起处理形成新的进程映像。(运行时刻)

ELF文件的格式都包含哪些部分呢?

在课件中老师以两种视角来看待一个object文件,其实是和文件的应用场景有关的。比如如果目标文件是库文件将会是可连接的视角来看,如果是可执行文件将会是可执行的视角来看待这个文件,但是文件的基本框架是相同的。

文件内部结构图:

Linking 视角                      Execution 视角
============                      ==============
ELF header                        ELF header
Program header table (optional)   Program header table
Section 1                         Segment 1
...                               Segment 2
Section n                         ...
Section header table              Section header table (optional)


基本框架包括:头部信息,可编程的头部表和分段信息,以及每一个段头部信息。

头部信息的基本格式为:

#define EI_NIDENT       16

typedef struct {
unsigned char       e_ident[EI_NIDENT];
Elf32_Half          e_type;
Elf32_Half          e_machine;
Elf32_Word          e_version;
Elf32_Addr          e_entry;
Elf32_Off           e_phoff;
Elf32_Off           e_shoff;
Elf32_Word          e_flags;
Elf32_Half          e_ehsize;
Elf32_Half          e_phentsize;
Elf32_Half          e_phnum;
Elf32_Half          e_shentsize;
Elf32_Half          e_shnum;
Elf32_Half          e_shstrndx;
} Elf32_Ehdr;


第二个字段是type信息,主要三种类型,列举如下,和我们前文的讲解是能够核对上的。

Name        Value  Meaning
====        =====  =======
ET_NONE         0  No file type
ET_REL          1  Relocatable file
ET_EXEC         2  Executable file
ET_DYN          3  Shared object file


还有一个字段比较重要是:

Elf32_Addr e_entry;

这个值指出了程序的入口地址。

文件与进程

在目标文件中的段的地址和进程中的地址是有对应关系的。

我们知道一个可执行文件要在系统中运行, 必须拷贝程序的程序段和数据段到内存中来。

那么程序段要拷贝哪里呢?

在课件中,老师讲解是固定的虚拟地址位置:0x0804 8000.在这个地址基础之上拷贝可执行文件的头部信息。而0x0804 8300这个地址是在可执行文件中指定的,是加载到程序中执行的第一条可执行指令。

而0x804 8300这个地址就是我们在上文中 elf header中字段Elf32_Addr e_entry的值。

从这个入口地址开始后面都是可执行的连续的代码。在静态库链接状态下,所有的可执行代码都是连续存储的。

通过孟宁老师的讲解,我们知道了,代码段的内存开始位置是0x0804 8000,但是程序的开始执行位置是0x0804 8300.这两个位置是不同的。为什么不同呢?

这里,我这样理解,入口地址是main函数的入口,但是在main函数之前是不是应当在做一些准备工作啊,比如入参啥的。所以和代码段的第一条指令是不同的。这里存疑问。下面做了实验后,我将回来更正。

如果在动态链接库的情况,将会出现多个代码段,并且代码段是在运行时加载的。将会比静态链接库更加复杂一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: