Browsed by
月份:2016年3月

函数调用 foobar 实验

函数调用 foobar 实验

本文记录对 C 与汇编的联系, C的函数调用在汇编下的实现, 下面是实验用的C语言源码

 

ELF 文件格式初步探索

ELF 文件格式初步探索

在Linux下编译一个汇编程序需要的工具为 as(汇编器) ld(链接器)

e.g: 一个非常简单的AT&T汇编程序

.section .globl 这种叫做 伪操作, .section将代码分为若干段

_start 是 symbol(符号)  符号在汇编程序中代表一个地址 .globl 表示一个符号会被链接器使用 as –32 将 汇编代码编译为 relocatable object file elf32_i386

 

解读ELF 文件格式

对于汇编 , 链接器来看 , elf文件是由 Section Header Table 描述的一系列Section 集合, 而执行一个ELF文件的时候, 在loader看来 它是由 Programer Header Table 描述的一系列Segment的集合

对于程序运行的时候 Program Header Table 是必须

程序链接的时候 Section Header Table 是必须的

对于一个在运行的时候动态链接的程序, Program Header Table 和 Section Header Table 都是需要的, 因为程序既要加载 也要动态链接

ELF文件可以简单分为以下部分:(通过readelf 打印出来的 一个汇编程序的 结构)

汇编代码如下:

 

ELF 文件由ELF Header 和各个Section组成 上面给出的文件是一个 *.o 文件的 ELF Header , 通过ELF Header 可以计算出Section Header 在文件中的位置

上面的内容是Section Header Table中含有的各个段的信息, 因为这是一个 Relocatable Object File(*.o) 还没有被链接,  因此所有的加载到内存中的地址都是 0 , 这里的Offset表示每个Section在 ELF文件中的位置, Size 为每个Section的大小, 通过这些信息,可以将ELF文件的结构做出来 如图所示:

 

通过hexdump -C 可以查看整个二进制文件的每一位内容, 有了上面的结构图, 可以很容易的和二进制内容对应起来

 

注意, .bss段中没有任何信息, 在Section 中只占一个Section Header , 没有对应的Section, .shstrtab 用来保存各个Section的名字 .strtab 保存程序中的符号的名字  .rel.text 提供重定位需要的信息, 告诉linker 哪些地方要重定位 .symtab是符号表  Ndx表示这个符号在哪个Section内 Section的编号从 Section Header Table里查到 

.text 段保存的就是程序的汇编代码了

Executable ELF Format

上面我们说的都是Relocatable Object File 而不是 Executable File  我们下面来看一下 Object File 在链接之后成为Executable 有什么区别

我们将刚刚的 max.o 编译为 a.out 看ELF Header

这个Header 和 之前的Header没有太大区别 , Type 变为了EXEC, 并且多了Program Header, 下面我们看一下Section Header

对比前面的可以发现, section header少了一些 , .rel.text .bss 没有了, .rel.text只是用于链接的信息, 链接之后就没有用了 (如果使用 strip 会将符号表symtab 以及 保存符号的Section .strtab也删除, 只保留 .data 和 .shstrtab)

下面看一下多出来的Program Header

两个Program Header 一个是从 0x00 -> 0x97 (通过查看该Program 的Section Header Table 能够看出来 这部分内容就是ELF Header 加上 .text的内容 (根据Size和 Offset来看), 这个被加载到了0x08048000 这个虚拟地址处 (物理地址无意义) 而虽然0x08048000-0x08049097 的空间比 0x00 — 0x97占的空间要大, 但是第二个Segment却没有加载到紧接着它0x08048097之后, 原因是  MMU 的权限保护机制 权限保护是以页面为单位的,也就是说,每一个页面只能设置一种保护权限, 而 .text 以及 ELF Header 的权限是 Read Execute 而 .data段的权限是Read Write 二者权限不同, 应该放在不同的页面内, 内存每一个页面的大小是由Align列表示的, 在x86平台一页为 4K 大小(0x1000) 另外要注意的就是, 每个Segment在文件内的Offset多少,加载到页面内的时候, 要有相同的Offset, 所以第二个Segment加载到了 0x08049097 而不是 0x08049000

以上就是对ELF文件格式的一个简单的解读