linux elf加载过程

在Linux系统中,调用execve()系统调用启动进程后,会进入do_execve()函数进行可执行文件的加载。本文将探讨这一加载过程,从内存分配到binfmt_elf模块的参与,详细阐述elf加载的各个环节,包括bprm结构体的分配、binfmts模块的注册以及最终由load_elf_binary()函数完成的ELF文件的实际加载。
摘要由CSDN通过智能技术生成

通过前面linux 进程的创建和加载我们知道,调用ececve()系统调用后会加载指定的可执行程序并且运行起来,接下来我们分析这个加载过程,跑到do_execve()函数中。

linux-4.10/fs/exec.c

int do_execve(struct filename *filename,
1806  	const char __user *const __user *__argv,
1807  	const char __user *const __user *__envp)
1808  {
1809  	struct user_arg_ptr argv = { .ptr.native = __argv };
1810  	struct user_arg_ptr envp = { .ptr.native = __envp };
1811  	return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
1812  }
关键的实现就在do_execveat_common()这个函数里面了

/*
1657   * sys_execve() executes a new program.
1658   */
1659  static int do_execveat_common(int fd, struct filename *filename,
1660  			      struct user_arg_ptr argv,
1661  			      struct user_arg_ptr envp,
1662  			      int flags)
1663  {
1664  	char *pathbuf = NULL;
1665  	struct linux_binprm *bprm;
1666  	struct file *file;
1667  	struct files_struct *displaced;
1668  	int retval;
        ...
1693  	retval = -ENOMEM;
1694  	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); //申请一个linux_binprm 结构体
        ...
1705  	file = do_open_execat(fd, filename, flags);  //打开可执行文件
1706  	retval = PTR_ERR(file);
1707  	if (IS_ERR(file))
1708  		goto out_unmark;
1709  
1710  	sched_exec();  //找到loading最低的cpu执行这个加载
1711  
        ...
1736  	retval = bprm_mm_init(bprm); //创建进程的内存地址空间
        ...
1748  	retval = prepare_binprm(bprm);  //读取可执行文件前面的128字节
        ...
1767  	retval = exec_binprm(bprm);  //加载可执行程序并执行
         ...
1771  	/* execve succeeded */
1772  	current->fs->in_exec = 0;
1773  	current->in_execve = 0;
1774  	acct_update_integrals(current);
1775  	task_numa_free(current);
1776  	free_bprm(bprm);
1777  	kfree(pathbuf);
1778  	putname(filename);
1779  	if (displaced)
1780  		put_files_struct(displaced);
1781  	return retval;
        ...
1803  }

bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);

sizeof(*bprm) 的大小是多少,是不是就是这个结构体的大小,有疑问的时候,我们可以通过代码实际的运行结果来验证。

main.c

#include <stdio.h>
struct debug_struct{
	 int a;
	 int b;
	 int c;
};

int main()
{
	struct debug_struct *debug0;
    printf("sizeof(*debug0) is:%d \n",sizeof(*debug0));	
    struct debug_struct debug1;
    printf("sizeof(debug1) is:%d \n",sizeof(debug1));
    
    return 0;
}


通过代码的实际运行情况,我们知道sizeof(*bprm) 就是结构体linux_binprm的大小。

linux-4.10/fs/exec.c

1634  static int exec_binprm(struct linux_binprm *bprm)
1635  {
1636  	pid_t old_pid, old_vpid;
1637  	int ret;
1638  
1639  	/* Need to fetch pid before load_binary changes it */
1640  	old_pid = current->pid;
1641  	rcu_read_lock();
1642  	old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
1643  	rcu_read_unlock();
1644  
1645  	ret = search_binary_handler(bprm);
1646  	if (ret >= 0) {
1647  		audit_bprm(bprm);
1648  		trace_sched_process_exec(current, old_pid, bprm);
1649  		ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
1650  		proc_exec_connector(current);
1651  	}
1652  
1653  	return ret;
1654  }
因为我们是重点分析可执行程序文件的加载流程,所以我们理所当然的认为在调用exec_binprm()时,相关的初始化操作已经完成,并且bprm已经准备好了。

linux-4.10/include/linux/binfmts.h


                
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值