写在前面
想要从最简单开始了解ELF文件,即使只有一个main函数,c语言编译出的源文件也还是太复杂了,我们从一个非常简短的汇编程序入手分析
不了解AT&T汇编的请参考AT&T汇编入门[0] hello world
非常简短
汇编和C代码对比
这个C代码已经轻量到极致了吧,,,啥都不做就return,编译生成的ELF文件1万多个字节
而这份汇编代码生成的ELF文件只有1008,相比起来要容易分析十倍(哈哈)
汇编源码
.data
strr: .string "hello world~"
len = .-strr
.text
.global _start
_start:
# write
movq $1, %rax
movq $1, %rdi
movq $strr, %rsi
movq $len, %rdx
syscall
# exit
movq $60, %rax
syscall
readelf工具使用
readelf -a filename 显示全部内容
readelf -h filename 显示ELF文件头↓
readelf -S filename 显示节头表↓
readelf -s filename 显示符号表↓
readelf输出分析
本篇仅做介绍说明:
详细分析请阅:ELF文件内容详解——各节内容分析
节头表
以text节为例:
可以看到text节的Address是0x4000b0,Offset是0xb0,Size是0x27,Align是1
这些就表示 text节在运行时会被装载到0x4000b0的地址处,在此ELF文件中的起始地址是第0xb0个字节,长度是0x27(就是在0xb0,0xb7+0x28这个范围内),以1字节对齐
符号表
看一下在汇编程序中我们定义的3个符号:字符串strr、字符串长度len、标签_start
第4行strr:Value意为在运行时会装载到0x6000d7这个地址,LOCAL意为它是一个本地符号 对外部不可见
第5行len的值则是d,因为他就是个固定的数值
第8行_start的则是GLOBAL,因为我们用伪指令.global修饰了他,这个符号是全局可见的。
上述内容中的0x6000d7、0x4000b0之类的地址,是由链接脚本控制的