在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,
®s);//核心函数
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,®s);
一共是四个参数,看一下我们调用的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)
/*