Argument list too long从何而来

转载时请注明出处和作者联系方式
文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli at hotmail dot com>

这两天在Android eclair版本上增加WML浏览功能,以前在cupcake版本(broncho a1)上实现过,技术上倒是没有什么难题,但编译时总是出现Argument list too long的错误。WebKit里源文件太多,没有WML时还可以编译过去,但加上了WML之后,命令行参数确实很长了,ar后面跟的参数大概都有几百K。奇怪的是,在终端单独运行ar没有问题,但是在Makefile里就是不行。

先尝试去改Android.mk,把它分成几个静态库来编译,但老是编译不过去,试一次要很长时间,真的很烦。后来只好尝试去找出这个长度限制在哪里:

1.这个错误是glibc打出来,所以先到glibc里去找Argument list too long对应错误码。在sysdeps/gnu/errlist.c找到这样一行代码:

[ERR_REMAP (E2BIG)] = N_("Argument list too long"),

很明显,错误码就是E2BIG。

2.错误码应该是exec系统调用返回的,于是到内核里去查找返回E2BIG的代码,在exec.c里找到几处:

static int count(char __user * __user * argv, int max) { int i = 0; if (argv != NULL) { for (;;) { char __user * p; if (get_user(p, argv)) return -EFAULT; if (!p) break; argv++; if (i++ >= max) return -E2BIG; cond_resched(); } } return i; } bprm->argc = count(argv, MAX_ARG_STRINGS); if ((retval = bprm->argc) < 0) goto out; bprm->envc = count(envp, MAX_ARG_STRINGS); if ((retval = bprm->envc) < 0) goto out;
这是对参数个数的限制,MAX_ARG_STRINGS的定义为:

#define MAX_ARG_STRINGS 0x7FFFFFFF

这个值已经大得吓人了,不可能是参数个数超出了。

另外一处是:
static int copy_strings(int argc, char __user * __user * argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; char *kaddr = NULL; unsigned long kpos = 0; int ret; while (argc-- > 0) { char __user *str; int len; unsigned long pos; if (get_user(str, argv+argc) || !(len = strnlen_user(str, MAX_ARG_STRLEN))) { ret = -EFAULT; goto out; } if (!valid_arg_len(bprm, len)) { ret = -E2BIG; goto out; } ... } #ifdef CONFIG_MMU static bool valid_arg_len(struct linux_binprm *bprm, long len) { return len <= MAX_ARG_STRLEN; } static bool valid_arg_len(struct linux_binprm *bprm, long len) { return len <= bprm->p; } #endif /* CONFIG_MMU */

valid_arg_len是用来限制单个参数长度的,PC上肯定是定义了CONFIG_MMU的,所以单个参数的长度应该是MAX_ARG_STRLEN,即:

#define MAX_ARG_STRLEN (PAGE_SIZE * 32)

对于4K的page大小来说,单个参数长度限制是128K, 这也够大了。不过如果前面所说的整个ar命令,在Makefile里被当作一个参数的话,那肯定是超长了。这可以解释在终端单独运行ar没有问题,在 Makefile调用不行的疑问。回头再研究一下Makefile里是怎么调用的吧。

你可能感兴趣的:(linux,list,struct,user,null,makefile)