码迷,mamicode.com
首页 > 系统相关 > 详细

Linux加载一个可执行程序并启动的过程

时间:2016-04-10 14:13:57      阅读:274      评论:0      收藏:0      [点我收藏+]

标签:

原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

作者:严哲璟

以shell下执行ls命令为例介绍Linux通过fork()和execve()类函数的执行程序启动过程:

父进程为shell,命令为ls,目录为/bin/ls  

当输入ls时,shell进程通过fork()创建一个新的子进程,fork()进程复制代码,以及新建堆栈等之前已经说明,子进程有机会执行的时候,在ret_from_fork()开始,返回到子进程的用户堆栈中,执行其余的子进程的代码.

在这些子进程需要执行的代码中,有execve(/bin/ls,ls,NULL),ls是列出当前路径的目录的一个可执行文件,同理如./a.out等

为加载此可执行文件到内存中执行,关键的地方在于,execve返回之后,执行的代码变成了需要加载的可执行文件的代码,下面详细说明它是如何做到的.

首先 execve()函数是系统调用,陷入内核,调用do_execve_common()函数,此函数的作用是加载需要执行的可执行文件的ELF头,因为后面需要将可执行文件的信息压入代码段以及将PC指向可执行文件的起点

 

1430static int do_execve_common(struct filename *filename,
1431				struct user_arg_ptr argv,
1432				struct user_arg_ptr envp)
1433{
1434	struct linux_binprm *bprm;
1435	struct file *file;
1436	struct files_struct *displaced;
1437	int retval;
1438
1439	if (IS_ERR(filename))
1440		return PTR_ERR(filename);
1441
1442	/*
1443	 * We move the actual failure in case of RLIMIT_NPROC excess from
1444	 * set*uid() to execve() because too many poorly written programs
1445	 * don‘t check setuid() return code.  Here we additionally recheck
1446	 * whether NPROC limit is still exceeded.
1447	 */
1448	if ((current->flags & PF_NPROC_EXCEEDED) &&
1449	    atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
1450		retval = -EAGAIN;
1451		goto out_ret;
1452	}
1453
1454	/* We‘re below the limit (still or again), so we don‘t want to make
1455	 * further execve() calls fail. */
1456	current->flags &= ~PF_NPROC_EXCEEDED;
1457
1458	retval = unshare_files(&displaced);
1459	if (retval)
1460		goto out_ret;
1461
1462	retval = -ENOMEM;
1463	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1464	if (!bprm)
1465		goto out_files;
1466
1467	retval = prepare_bprm_creds(bprm);
1468	if (retval)
1469		goto out_free;
1470
1471	check_unsafe_exec(bprm);
1472	current->in_execve = 1;
1473
1474	file = do_open_exec(filename);
1475	retval = PTR_ERR(file);
1476	if (IS_ERR(file))
1477		goto out_unmark;
1478
1479	sched_exec();
1480
1481	bprm->file = file;
1482	bprm->filename = bprm->interp = filename->name;
1483
1484	retval = bprm_mm_init(bprm);
1485	if (retval)
1486		goto out_unmark;
1487
1488	bprm->argc = count(argv, MAX_ARG_STRINGS);
1489	if ((retval = bprm->argc) < 0)
1490		goto out;
1491
1492	bprm->envc = count(envp, MAX_ARG_STRINGS);
1493	if ((retval = bprm->envc) < 0)
1494		goto out;
1495
1496	retval = prepare_binprm(bprm);
1497	if (retval < 0)
1498		goto out;
1499
1500	retval = copy_strings_kernel(1, &bprm->filename, bprm);
1501	if (retval < 0)
1502		goto out;
1503
1504	bprm->exec = bprm->p;
1505	retval = copy_strings(bprm->envc, envp, bprm);
1506	if (retval < 0)
1507		goto out;
1508
1509	retval = copy_strings(bprm->argc, argv, bprm);
1510	if (retval < 0)
1511		goto out;
1512
1513	retval = exec_binprm(bprm)

 

Linux加载一个可执行程序并启动的过程

标签:

原文地址:http://www.cnblogs.com/yzjustc/p/yzj.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!