ELF的段(segment)
ELF程序头表里的每个条目其实是一个个的段(segment)描述信息,真正的段数据不在里头。这一点务必要清楚。真正的段数据是靠这些描述信息去定位。
我们继续使用Hello,world!示例文件来拆分。前面已知示例文件的前64个字节是文件头,接着11个条目(段描述信息)*56(每个段的描述信息的大小)=616个字节是整个程序头(或程序头表)的大小,那么64+616=680个字节,说明示例文件的前680个字节分别是文件头和程序头(或程序头表),那么680个字节后面开始的数据是什么?
上一篇文章里提到了PT_INTERP段的文件偏移量是680
大小是28个字节
那说明680个字节后面的28个字节是PT_INTERP段的段数据,里面的内容如下:
内容是动态链接器的路径。
680+28=708,那708个字节后面的内容是什么呢?
上一篇文章里提到了PT_NOTE段的文件偏移量是708,大小是68个字节
说明708个字节后面的68个字节是PT_NOTE段的数据内容,该段保存的是操作系统的规范信息。
708+68=776,继续,776个字节后面的内容是什么呢?
没有直接的偏移量表明,但是我们通过上一篇文章知道示例文件的前4096个字节是第1个PT_LOAD段的段数据,而4096个字节里的776个字节是文件头、程序头表、PT_INTERP段和PT_NOTE段,那么剩下的3320个字节也还是属于PT_LOAD段,这就说明776个字节后面的3320个字节是第一个PT_LOAD段的数据内容。程序运行时PT_LOAD段的数据是要载入内存的。
776+3320=4096,那么4096个字节后面的数据是什么呢?
这是上一篇文章里的分析,可以看到4096个字节后面的445个字节是第2个PT_LOAD段,程序运行时且该段的数据也会被载入内存,权限是可读可写。
4096+445=4541,那么4541个字节后面的数据是什么呢?
答案是3651个0x00,因为第二个PT_LOAD段的对齐数是4096个字节
因为445+3651=4096,所以4541个字节后面是3651个0x00。
4541+3651=8192,那么8192个字节后面的数据是什么呢?
可以看到8192个字节后面的344个字节是第3个PT_LOAD段,权限是可读,对齐字节数也是4096个字节。插一句,上一篇文章通过拆分发现PT_GNU_EH_FRAME段的文件偏移量是8212,大小是60个字节,直接被包含在了这第3个PT_LOAD段中了。
8192+344=8536,8536个字节后面是什么呢?
8536个字节后面开始是0x00,一值到3216个字节之后开始是第4个PT_LOAD段,因为上一篇文章已经分析过第4个PTLOAD段的偏移量是0x2de8,8536+3216=11752,即十六进制0x2de8。
满屏的0,而0x2de8开始就有数据了
也就是说11752个字节开始是第4个PT_LOAD段,占584个字节
值得注意的是,我这里示例文件可以发现PT_DYNAMIC段的段数据竟然被包含在这第4个PT_LOAD段中,我是怎么发现的呢?
PT_DYNAMIC段的文件偏移量是0x2df8,即十进制11768,占480个字节,而第4个PT_LOAD段的文件偏移量是0x2de8,即十进制11752,占584个字节,直接把PT_DYNAMIC段的数据包含进来了。
不知道是不是所有文件都是如此,我这边随便挑一个文件验证一下看看,我挑的是/bin/ls可执行文件进行了拆分,发现同样是PT_DYNAMIC段的数据被包含在第4个PT_LOAD段数据中。
上面的是PT_LOAD段,下面的是PT_DYNAMIC段,PT_LOAD段的偏移量是0x20390,大小是0x1258,PT_DYNAMIC段的偏移量是0x20dd8,大小是01f0,直接被包含在PT_LOAD段中了。
再插一句,通过上一篇文章拆分发现PT_GNU_RELRO段的偏移量是0x2de8,即与第4个PT_LOAD段的偏移量相等,但大小不等,PT_GNU_RELRO段的大小是536个字节,第4个PT_LOAD段大小是584个字节,也就是说PT_GNU_RELRO被包含在第4个PT_LOAD段中,但同时它又把这第4个PT_LOAD段中的PT_DYNAMIC段包含了,即第4个PT_LOAD段包含了PT_GUN_RELRO段,PT_GUN_RELO段包含了PT_DYNAMIC段。所以第4个PT_LOAD段里头有2个子段。
回到刚才11752个字节开始是第4个PT_LOAD段,占584个字节,其中包含了PT_GUN_RELRO段,PT_GUN_RELO段包含了PT_DYNAMIC段。
至此程序头表里的所有段(segment)都已经在文件中找到位置了,结构也清晰了,来一张图记录一下
11752+584=12336,上图是示例文件的前12336个字节,那么12336个字节后面是什么呢?这个问题我们暂时先放着,等拆解完ELF的节头和ELF的节(section),我们再继续补充。