elf文件解析原理 (elf文件怎么验证正确性)

前言

在Linux中,可执行文件的格式是ELF格式,而有一些命令可以帮助我们了解它们更多的“秘密”,以此来帮助我们解决问题。

elf文件是怎么被加载的,elf文件解析原理

示例程序

我们的示例程序如下:

#include<stdio.h>
intmain(intargc,char*argv[])
{
     ntf("helloshouwangxiansheng\n");return0;}

编译:

nbsp;gcc-ohellohello.c

得到hello可执行文件。

查看文件类型

file命令可以用来查看文件类型:

nbsp;filehello
hello:ELF64-bitLSBexecutable,x86-64,version1(SYSV),dynamicallylinked,interpreter/lib64/l,forGNU/Linux2.6.32,BuildID[sha1]=8f1de0f59bdfe9aaff85ade6898173aa436b296a,notstripped

从结果中,我们可以知道,它是ELF可执行文件,且是64位程序,有动态链接,最后的not stripped也表明了它保留了符号表信息或者调试信息。

如果不是可执行文件,它的信息是怎样的呢?举个例子:

nbsp;filehello.c
hello.c:Csource,UTF-8Unicodetext

看到了吧。

查看ELF头

readelf用于查看ELF文件,而:

nbsp;readelf-hhello
ELFHeader:
Magic:7f454c46020101000000000000000000
Class:ELF64
Data:2'scomplement,littleendian
Version:1(current)
OS/ABI:UNIX-SystemV
ABIVersion:0
Type:EXEC(Executablefile)
Machine:AdvancedMicroDevicesX86-64
(略)

可以看到它是EXEC,即可执行文件,且小端程序,运行于X86-64。在交叉编译的时候,这个文件头的信息也非常有用。例如你在x86的机器上交叉编译出powerpc的可执行文件,在powerpc上却不被识别,不能运行,不如用readelf看看它的Machine字段,是不是没有编译好。

查找ELF文件中的字符串

例如,你在文件中写入了版本号或者特殊字符串,可以通过strings命令搜索到:

nbsp;stringshello|grepshouwang
helloshouwangxiansheng

查看ELF文件各段大小

nbsp;sizehello
textdatabssdechexfilename
1210552817706eahello

这里可以看到代码段,数据段各自占多少,必要时候还可以根据需要优化代码,减少磁盘空间占用。

查看链接的动态库

运行时出现找不到动态库?不如看看它链接了哪些库吧:

nbsp;lddhellolinux-vdso.so.1=>(0x00007ffd16386000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f507e083000)
/lib64/ld-linux-x86-64.so.2(0x00007f507e44d000)

可以看到它链接的动态库是/lib/x86_64-linux-gnu/libc.so.6,而如果该文件不存在,则运行时将会出错。这里也可以参考《动态库的制作和使用》。

查看符号表

新加的函数或者全局变量不知道有没有编译进去?如何看看符号表里有没有吧(前提是符号表没有被去掉):

nbsp;nmhello|grepmain#符号表中查找main函数
U__libc_start_main@@GLIBC_2.2.5
0000000000400526Tmain

如果没有找到或者前面是U,没有地址,表明在这个elf文件中没有定义这个函数。

链接出问题的时候很有用。

为ELF文件瘦身

前面通过file查看文件时,看到有not stripped的字样,由于它里面包含了一些符号表信息,因为文件会稍大,如果去掉,二进制文件将会变小,但是里面的符号表信息也就没有了,将会影响问题定位。

nbsp;ls-lhhello#瘦身前
  -rwxrwxr-x1rootroot8.4K
  nbsp;striphello
  nbsp;ls-lhhello#瘦身后
   -rwxrwxr-x1rootroot6.2K

可以看到,瘦身后二进制文件变得更小。当可执行文件越大时,瘦身效果就会更明显了。当然放心,这不会影响程序的正常运行,只是对调试和问题定位有影响。

这个时候再看符号表:

nbsp;nmhello
nm:hello:nosymbols

打印文件校验和

二进制文件传输过程中有没有被损坏或者是否是同一个版本,看看校验和以及程序块计数吧:

nbsp;sumhello
335137

当然你也可以使用:

nbsp;md5sumhello
521efed706c3b485dd3b5e96e48b138ahello

来比对md5值。

总结

ELF文件中隐藏了丰富的信息,只要使用得当,将会帮助我们更好地进行开发或者问题的定位。