-rwxr-xr-x1 yuan yuan205814月292004 tshref
查阅资料后,原因是系统位数与该可执行文件需要的lib库位数不匹配。
用uname命令打印系统信息,发现系统是64位系统
uname-a Linux yuan-vm3.13.0-32-generic#57-Ubuntu SMP Tue Jul1503:51:08 UTC2014 x86_64 x86_64 x86_64 GNU/Linux
用file命令查看文件信息,发现是一个32位可执行文件。
file ./tshref ./tshref: ELF32-bit LSB executable, Intel80386, version1 (SYSV), dynamically linked (usesshared libs),for GNU/Linux2.2.5,not stripped
要想在64位系统上与运行32位程序,则需要安装32位lib库。
对于Ubuntu用户可以使用下面的命令安装。
sudo apt-get install ia32-libs Reading package lists... Done Building dependency tree Reading state information... Done Package ia32-libsisnot available,butis referredtoby another package. This may meanthatthe packageis missing, has been obsoleted,oris only availablefrom another source Howeverthe following packages replaceit: lib32z1 lib32ncurses5 lib32bz2-1.0
过程中有可能找不到需要的库,但是会有几个替代包,选择安装其中一个。
sudo apt-get install lib32bz2-1.0 lib32bz2-1.0
然后就可以正常运行之前的可执行文件了。
遇到这种问题其实还有可能是其他原因,例如文本的编码格式问题等,本文仅提出了一种解决方法,读者遇到相同问题要具体问题具体分析。
一、Linux下装载ELF可执行文件的过程 1、创建子进程 内核创建task_struct数据结构,继承父进程的虚拟地址空间(Virtual Memory Space,VMS)。 2、调用execve()系统调用执行指定的ELF文件 (1)调用内核态函数sys_...

一、Linux下装载ELF可执行文件的过程

1、创建子进程
内核创建task_struct数据结构,继承父进程的虚拟地址空间(Virtual Memory Space,VMS)。
2、调用execve()系统调用执行指定的ELF文件
(1)调用内核态函数sys_execve(),动态申请一个linux_binprm数据结构,并用ELF可执行文件的数据填充这个结构;
(2)调用prepare_binprm()函数用位于inode中的数据填充linux_binprm数据结构;
(3)调用search_binary_handler()函数遍历formats链表依次应用其load_binary的方法。对于ELF文件会找到elf_format节点,调用load_elf_binary()函数进行如下工作:
1)检查存放在文件前128字节中的魔数以确认可执行格式及其有效性;
2) 读取可执行文件的首部;
3)从可执行文件的.interp段获得动态链接器(Dynamic Linker,DL)的路径名;
4)将DL的前128字节copy到缓冲区;
5)对DL类型进行一致性检查;
6)调用flush_old_exec()函数释放前一次计算占用的几乎所有资源(应该是从父进程继承过来的);
7)调用setup_new_exec()函数,进行为新的进程建立进程线性区布局等工作;
8)调用setup_arg_pages()函数为进程的用户态栈分配一个新的线性区描述符,并把那个线性区插入到进程的地址空间。
setup_arg_pages()函数还把命令行参数和环境变量串所在的页框分配给新的线性区。
9)创建新的线性区映射ELF中的各个LOAD段,包括代码段和数据段;
线性区中的虚拟地址(Virtual Memory Address, VMA)与ELF中的加载地址(Load Memory Address, LMA)正常情况下是一样的,但在有些嵌入式系统中是不一样的。VMA与ELF中的大多数段(这些段在映射到VMA时都需要建立VMA到文件的映射关系)都是完全对应的,但有一些特殊的段(如.bss)不需要映射到文件,它们与VMA中的地址并不是完全对应的。在对应的段中,其地址与VMS中的地址完全一致。链接器会负责将各个权限相同的段合并到一起,以减少装载并进行页映射时产生的内存浪费。
10)调用load_elf_interp()函数装载DL;
11)调用start_thread()函数修改保存在内核态堆栈但属于用户态寄存器的EIP和ESP的值,以使它们分别指向DL的入口(如果没有获得DL则指向ELF的入口)和新的用户态栈的栈顶;
12)返回0值(成功)。
3、execve()系统调用返回后,新的程序会从EIP寄存器指向的地址开始执行。如果ELF没有链接动态库,则开始执行ELF文件的代码;如果ELF链接了动态库,则执行动态链接;
(1)启动动态链接器本身;
(2)装载所有需要的共享对象;
依次找到所有共享对象的名字、位置,打开相应的文件,将其代码段和数据段映射到进程的地址空间中。