通过进程2加载shell进程,详解execve

    一直以来都对execve到底做了什么,总是犯迷糊,原来看Linux内核设计的艺术,这部分讲解的非常不细致,这次结合赵博士的书,重新理解了这部分代码。

    首先列出代码,如下:

	if (!(pid=fork())) {//进程1创建进程2
		close(0);
		if (open("/etc/rc",O_RDONLY,0))
			_exit(1);
		execve("/bin/sh",argv_rc,envp_rc);
		_exit(2);
	}
    进程1创建进程2,进程2的页目录表及页表如图1,页目录表项是第32位,由于页目录表从内核0x0的位置,所以进程2的页目录项的位置为32,由于每个页目录项所占的字节数为4,所以内存地址为128。



                                          图 1

    此时用命令行,查看内核地址为128的数据。0xffa027,就是进程2页表的首地址 。

    

                             图 2

    0xffa000开始存放的进程2的页表项,如下图:

    

                            图 3


    下面看真正的execve,代码如下:

int do_execve(unsigned long * eip,long tmp,char * filename,
	char ** argv, char ** envp)
{
	struct m_inode * inode;
	struct buffer_head * bh;
	struct exec ex;
	unsigned long page[MAX_ARG_PAGES];//MAX_ARG_PAGES为32
	int i,argc,envc;
	int e_uid, e_gid;
	int retval;
	int sh_bang = 0;
	unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;//4096*32-4=131068=1FFFC

	if ((0xffff & eip[1]) != 0x000f)
		panic("execve called from supervisor mode");
	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
		page[i]=0;
	if (!(inode=namei(filename)))		//找到/bin/sh的i节点
		return -ENOENT;
	argc = count(argv);//参数的数量
	envc = count(envp);//环境变量的数量
	
restart_interp:
	.....
	if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {//读取第一块的数据
		retval = -EACCES;
		goto exec_error2;
	}
	ex = *((struct exec *) bh->b_data);	//赋值给文件头
	.....
	if (!sh_bang) {
		p = copy_strings(envc,envp,page,p,0);
		p = copy_strings(argc,argv,page,p,0);//最后返回的p是131068减去参数和环境变量的字节数,堆栈的指针。目前page数组中,page[31]已经是一个新申请页面的地址了。
		if (!p) {
			retval = -ENOMEM;
			g
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值