execve系统调用_通过do_execve源码分析程序的执行(上)(基于linux0.11)

本文通过分析Linux 0.11内核中的do_execve函数,揭示了execve系统调用如何将程序转换为进程的过程。内容包括:检查文件可执行性和权限,加载头文件,申请物理内存,设置环境变量和参数,释放原有进程映射,调整段寄存器,创建页表,设置堆栈,并最终准备执行第一条指令。
摘要由CSDN通过智能技术生成

execve函数是操作系统非常重要的一个函数,他使得程序变成进程成为可能。下面我们通过do_execve的实现,了解一下程序变成进程的过程。首先do_execve是一个系统调用。之前分析过系统调用的过程。这里就不详细说了。直接从sys_execve函数开始。

_sys_execve:
    lea EIP(%esp),%eax
    pushl %eax
    call _do_execve
    addl $4,%esp
    ret

执行_do_execve函数前,先看看这时候的内核栈。

52124ce881522ab80b3e6119d368949e.png

下面开始分析do_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];
    int i,argc,envc;
    int e_uid, e_gid;
    int retval;
    int sh_bang = 0;
    unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
    // eip指向系统调用前的eip,eip[1]则指向cs,判断一下这时候的cs是不是用户的cs
    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)))       /* get executables inode */
        return -ENOENT;
    // 计算环境变量和参数个数
    argc = count(argv);
    envc = count(envp);

restart_interp:
    if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
        retval = -EACCES;
        goto exec_error2;
    }
    i = inode->i_mode;
    // 设置了uid则执行的时候uid是设置的uid,否则是用户的有效id
    e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
    e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
    // 相等说明该文件是该用户创建的,则判断user位的权限
    if (current->euid == inode->i_uid)
        i >>= 6;
    // 同上,判断组权限
    else if (current->egid == inode->i_gid)
        i >>= 3;
    /*
        else 判断 other的权限
    */

    if (!(i & 1) &&
        !((inode->i_mode & 0111) && suser())) {
        retval = -ENOEXEC;
        goto exec_error2;
    }
    // 读第一块数据进来
    if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
        retval = -EACCES;
        goto exec_error2;
    }
    // 前面是执行文件的头,包括一些元数据
    ex = *((struct exec *) bh->b_data); /* read exec-header */
    // 是脚脚本文件,不是编译后的文件,sh_bang控制只会进入一次
    if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
        /*
         * This section does the #! interpretation.
         * Sorta complicated, but hopefully it will work.  -TYT
         */

        char buf[1023], *cp, *interp, *i_name, *i_arg;
        unsigned long old_fs;
        // 把#!之外的字符复制到buf
        strncpy(buf, bh->b_data+2, 1022);
        brelse(bh);
        iput(inode);
        buf[1022] = '0';
        // 找出buf里第一次出现换行字符的地址,没有则返回NULL
        if (cp = strchr(buf, 'n')) {
            // 更新换行字符为0,表示字符串结束
            *cp = '0';
            // cp指向文件的第一个字符
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值