linux-2.6.11-exec

在unistd.h中
asmlinkage int sys_execve(struct pt_regs regs);
进入函数实现,在process.c中

asmlinkage int sys_execve(struct pt_regs regs)
{
    int error;
    char * filename;

    filename = getname((char __user *) regs.ebx);
    error = PTR_ERR(filename);
    if (IS_ERR(filename))
        goto out;
    error = do_execve(filename,
            (char __user * __user *) regs.ecx,
            (char __user * __user *) regs.edx,
            &regs);//核心函数
    if (error == 0) {
        task_lock(current);
        current->ptrace &= ~PT_DTRACE;
        task_unlock(current);
        /* Make sure we don't return using sysenter.. */
        set_thread_flag(TIF_IRET);
    }
    putname(filename);
out:
    return error;
}

它调用了do_exec

do_execve(filename,(char __user * __user *) regs.ecx,(char __user * __user *) regs.edx,&regs);

一共是四个参数,看一下我们调用的exec族的函数原型

int execl(const char *path, const char *arg, ...)  
int execv(const char *path, char *const argv[])  
int execle(const char *path, const char *arg, ..., char *const envp[])  
int execve(const char *path, char *const argv[], char *const envp[])  
int execlp(const char *file, const char *arg, ...)  
int execvp(const char *file, char *const argv[]) 

作对比可知,第一个参数都是文件名称,其余参数都是由regs这个结构体代进去的,看一下regs结构体好了

struct pt_regs {
    long ebx;//存放文件名称
    long ecx;//参数1
    long edx;//环境变量
    long esi;
    long edi;
    long ebp;
    long eax;
    int  xds;
    int  xes;
    long orig_eax;
    long eip;
    int  xcs;
    long eflags;
    long esp;
    int  xss;
};

这个结构体里存的是寄存器,在ptrace.h中定义
看一下do_execve的函数原型

int do_execve(char * filename,
    char __user *__user *argv,
    char __user *__user *envp,
    struct pt_regs * regs)

在这个函数中定义了一个struct linux_binprm 类型的结构体指针*bprm,这个结构用来保存装载二进制文件时使用的参数。

struct linux_binprm{
    char buf[BINPRM_BUF_SIZE];
    struct page *page[MAX_ARG_PAGES];
    struct mm_struct *mm;//k
    unsigned long p; /* current top of mem */
    int sh_bang;
    struct file * file;
    int e_uid, e_gid;
    kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
    void *security;
    int argc, envc;
    char * filename;    
    /* Name of binary as seen by procps */
    /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */
    unsigned interp_flags;
    unsigned interp_data;
    unsigned long loader, exec;
};

为它申请空间并置0

bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
    if (!bprm)
        goto out_ret;
    memset(bprm, 0, sizeof(*bprm));

然后调用struct file *open_exec(const char *name)函数,在此函数中调用path_lookup,dentry_open,path_release三个函数以获得与可执行文件相关的目录项对象、文件对象和索引结点对象。

struct file *open_exec(const char *name)
{
    struct nameidata nd;
    int err;
    struct file *file;

    nd.intent.open.flags = FMODE_READ;
    /**
     * 调用path_lookup,dentry_open,path_release以获得与可执行文件
     * 相关的目录项对象、文件对象和索引结点对象。
     */
    err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);
    file = ERR_PTR(err);

    if (!err) {
        struct inode *inode = nd.dentry->d_inode;
        file = ERR_PTR(-EACCES);
        if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
            S_ISREG(inode->i_mode)) {
            /**
             * 检查执行权限
             */
            int err = permission(inode, MAY_EXEC, &nd);
            if (!err && !(inode->i_mode & 0111))
                err = -EACCES;
            file = ERR_PTR(err);
            if (!err) {
                file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);//打开一个目录项
                if (!IS_ERR(file)) {
                    /**
                     * deny_write_access通过检查索引结点的i_writecount字段,
                     * 确定可执行文件没有被写入。并把-1存放在这个字段以禁止进一步的写访问
                     */
                    err = deny_write_access(file);
                    if (err) {
                        fput(file);
                        file = ERR_PTR(err);
                    }
                }
out:
                return file;
            }
        }
        path_release(&nd);
    }
    goto out;
}

出来之后经过多项检查,调用sched_exec()确定最小负载CPU以执行新程序,并把当前进程转移过去。
这步完成之后进行对部分参数进行赋值

    bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
    bprm->file = file;
    bprm->filename = filename;
    bprm->interp = filename;
    bprm->mm = mm_alloc();
    retval = -ENOMEM;
    if (!bprm->mm)
        goto out_file;

注:bprm是struct linux_binprm 类型的结构体指针

    /**
     * 把路径名,命令行参数,环境串复制到一个或者多个新分配的页框中,
     * 最终,它们会被分配给用户态地址空间
     */
    retval = copy_strings_kernel(1, &bprm->filename, bprm);
    if (retval < 0)
        goto out;

    bprm->exec = bprm->p;
    retval = copy_strings(bprm->envc, envp, bprm);
    if (retval < 0)
        goto out;

    retval = copy_strings(bprm->argc, argv, bprm);
    if (retval < 0)
        goto out;

下面调用了search_binary_handler(bprm,regs);

int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)

在search_binary_handler中定义了一个结构体struct exec * eh,在A.out.h中定义

struct exec
{
  unsigned long a_info;     /使用宏的N_MAGIC */
  unsigned a_text;      /* length of text, in bytes */
  unsigned a_data;      /* length of data, in bytes */
  unsigned a_bss;       /* 用字节表示文件的未初始化数据区域的长度*/
  unsigned a_syms;      /* 文件中符号表数据的长度,以字节为单位*/
  unsigned a_entry;     /* start address */
  unsigned a_trsize;    /* 文本的重新定位信息的长度,以字节为单位*/
  unsigned a_drsize;    /* 数据的重新定位信息的长度,以字节为单位*/
};

看一下内核对cpu的操作代码

/**
 * 所有CPU的运行队列。
 */
static DEFINE_PER_CPU(struct runqueue, runqueues);

#define for_each_domain(cpu, domain) \
    for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent)

/**
 * 该宏产生索引为n的CPU的运行队列的地址。
 */
#define cpu_rq(cpu)     (&per_cpu(runqueues, (cpu)))
/**
 * 该宏产生本地CPU的运行队列的地址。
 */
#define this_rq()       (&__get_cpu_var(runqueues))
/**
 * 该宏产生任务所在的运行队列的地址。
 */
#define task_rq(p)      cpu_rq(task_cpu(p))
/**
 * 该宏产生索引为n的CPU的运行队列的当前任务。
 */
#define cpu_curr(cpu)       (cpu_rq(cpu)->curr)

/*

这里写图片描述
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值