1.理解编译链接的过程和ELF可执行文件格式
1)程序编译链接过程
编译->汇编->链接
1)预处理
gcc -E -o hello.cpp hello.c -m32
2)编译为汇编代码
gcc -x cpp-output -S -o hello.s hello.cpp -m32
3)汇编代码编译为目标代码
gcc -x assembler -c hello.s -o hello.o -m32
4)链接
gcc -o hello hello.o -m32
使用共享库的编译,libc, printf
5)
静态编译(所依赖的都放在hello.static内部)
gcc -o hello.static hello.o -m32 -static
2)ELF文件格式
a.out
COFF
PE
ELF(EXECUTABLE AND LINKABLE FORMAT)
三种目标文件:
可重定位文件 .o文件
可执行文件
共享目标文件 .so文件
用来被两个链接器链接:链接编辑器,可以和其他可重定位和共享文件object来创建其他object(静态链接); 动态链接器,联合一个可执行文件和其他共享object文件来创建一个进程映像 .
ELF文件加载内存(静态链接,所有代码放在一个段),形成进程,默认是加载到以0x8048000开始处.
gcc -shared shlibexample.c -o libshlibexample.so -m32
gcc -shared dllibexample.c -o libdllibexample.so -m32
gcc main.c -o main -L$PWD -lshlibexample -ldl -m32 //-ldl动态加载库
export LD_LIBRARY_PATH=$PWD //当前目录加入到库搜索路径
2.编程使用exec*库函数加载一个可执行文件
可执行文件的装载
执行一个程序的shell环境,直接使用execve系统调用
shell不限制命令行个数,取决于命令本身
shell调用execve将命令行参数和环境参数传递给可执行程序的main函数
int execve(const char *filename, char * const argv[], char * const envp[])
库函数exec*是系统调用execve的封装例程
sys_execve会解析可执行文件格式
do_execve -> do_execve_common -> exec_binprm
search_binary_handler符合寻找文件格式对应的解析模块(根据文件头部信息寻找对应的文件格式处理模块)
list_for_each_entry(fmt, &formats, lh) {
if (!try_module_get(fmt->module))
continue;
read_unlock(&binfmt_lock);
bprm->recursion_depth++;
retval = fmt->load_binary(bprm);//解析elf文件格式的执行位置
read_lock(&binfmt_lock);
对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读
Linux内核是如何支持多种不同的可执行文件格式的?
static struct linux_binfmt elf_format = {
.module = THIS_MODULE,
.load_binary = load