|

楼主 |
发表于 2004-1-4 21:21:42
|
显示全部楼层
看了http://chinaunix.net/jh/23/227365.html不太明白。
请问这些话都对吗?
我看到的源代码OS版本是
!uname -a
Linux db4.localdomain 2.4.20-8smp #1 SMP È& 7ÔÂ 23 8:58:25 CST 2003 i686 i686 i386 GNU/Linux
和exec相关的有两大块,一是arch下面,主要是控制不同体系结构上的差异。另外一个是fs目录,主要是exec.c。
函数do_execve是执行exec系列函数的入口,这个函数代码比较少,可以看看。
[code:1:c10dec9753]
int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
struct file *file;
int retval;
int i;
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
return retval;
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
bprm.file = file;
bprm.filename = filename;
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
allow_write_access(file);
fput(file);
return bprm.envc;
}
retval = prepare_binprm(&bprm);
if (retval < 0)
goto out;
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;
retval = search_binary_handler(&bprm,regs);
if (retval >= 0)
/* execve success */
return retval;
out:
/* Something went wrong, return the inode and free the argument pages*/
allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
struct page * page = bprm.page;
if (page)
__free_page(page);
}
return retval;
}
[/code:1:c10dec9753]
这个函数相关两个重要的数据结构,一个是第一局定义
struct linux_binprm bprm;
结构linux_binprm可以参看头文件,主要保存运行程序的参数和框架。
还有一个是pt_regs ,主要存储调用时候的寄存器信息。
这个函数大体上完成了如下功能:
1、open_exec初始化文件。
2、检查和设置参数,并且清除页表
3、调用prepare_binprm检查文件类型。文件全县还有文件状态(例如是否处于修改状态),设置uid和gid等
4、调用copy_strings(),这个是我们分析的重点。
5、调用search_binary_handler,这函数负责查找可执行文件的格式
同一个文件中copy_strings()
while(1)中
[code:1:c10dec9753]
int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
{
struct page *kmapped_page = NULL;
char *kaddr = NULL;
int ret;
while (argc-- > 0) {
char *str;
int len;
unsigned long pos;
if (get_user(str, argv+argc) ||
!(len = strnlen_user(str, bprm->p))) {
ret = -EFAULT;
goto out;
}
[/code:1:c10dec9753]
从如上的代码get_user处可以看出来,的确copy了argv的最后一个符号到str,后面的代码北配好空间后
err = ll_copy_from_user(kaddr+offset, str, bytes_to_copy
这时候执行的用户空间串便是str。
看看楼主的问题,最后copy到核心的是多了一个'/'. (/bin/more//more)
如有错误,请各位指正。
的确如此,execl ("/bin/maor", "/more" ...); 中,第二个 "/more" 被原封不动地传给了内核。
execl (path_name, argv[0], argv[1], .....);
其中 path_name 是一个绝对路径, argv[?] 是传给新进程的参数, 很有意思的是 argv[0] 不必是正确的文件名, 实际上可以是任何字符串。(见前面约翰牛的贴子)
在/test 目录下
1.c : --> 生成 b.out
int
main (int argc, char **argv)
{
printf ("%s\n", argv[0]);
exit (0);
}
2.c: --> 生成 a.out
int
main (int argc, char **argv)
{
execl ("/test/b.out", "fake file name", NULL);
exit (0);
}
执行 /test/a.out 得到
"fake file name"
argv[0] 的值是给新进程使用的,内核应该只起到了传递的作用,是否真实,内核并不关心。
:help |
|