diff options
| author | Matthew Wilcox <willy@debian.org> | 2002-08-27 20:29:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-08-27 20:29:53 -0700 |
| commit | ea3bc13f362e71fba7d341e0d2ffed813790be58 (patch) | |
| tree | 4b45e6e86c9c453af19c6d310730016656c9f7fe /fs/exec.c | |
| parent | b4093e0c0ac8c55820b8a58eea032bbf430414f6 (diff) | |
[PATCH] More support for upward growing stacks
- remove elf_caddr_t. It's positively dangerous to #define this since
elf_caddr_t foo, bar; creates variables of different types (foo is
char *, bar is char).
- rewrite large chunks of create_elf_tables(), it needed cleaning anyway.
- add upwards-growing stack support to create_elf_tables.
- redefine the ARCH_DLINFO stuff on powerpc -- it's tested, works.
- add upwards-growing-stack support to exec.c too.
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 63 |
1 files changed, 54 insertions, 9 deletions
diff --git a/fs/exec.c b/fs/exec.c index fd97224fbe53..769380e3899a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -323,9 +323,50 @@ int setup_arg_pages(struct linux_binprm *bprm) { unsigned long stack_base; struct vm_area_struct *mpnt; + struct mm_struct *mm = current->mm; int i; - stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; +#ifdef ARCH_STACK_GROWSUP + /* Move the argument and environment strings to the bottom of the + * stack space. + */ + int offset, j; + char *to, *from; + + /* Start by shifting all the pages down */ + i = 0; + for (j = 0; j < MAX_ARG_PAGES; j++) { + struct page *page = bprm->page[j]; + if (!page) + continue; + bprm->page[i++] = page; + } + + /* Now move them within their pages */ + offset = bprm->p % PAGE_SIZE; + to = kmap(bprm->page[0]); + for (j = 1; j < i; j++) { + memmove(to, to + offset, PAGE_SIZE - offset); + from = kmap(bprm->page[j]); + memcpy(to + PAGE_SIZE - offset, from, offset); + kunmap(bprm[j - 1]); + to = from; + } + memmove(to, to + offset, PAGE_SIZE - offset); + kunmap(bprm[j - 1]); + + /* Adjust bprm->p to point to the end of the strings. */ + bprm->p = PAGE_SIZE * i - offset; + stack_base = STACK_TOP - current->rlim[RLIMIT_STACK].rlim_max; + mm->arg_start = stack_base; + + /* zero pages that were copied above */ + while (i < MAX_ARG_PAGES) + bprm->page[i++] = NULL; +#else + stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; + mm->arg_start = bprm->p + stack_base; +#endif bprm->p += stack_base; if (bprm->loader) @@ -333,7 +374,7 @@ int setup_arg_pages(struct linux_binprm *bprm) bprm->exec += stack_base; mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!mpnt) + if (!mpnt) return -ENOMEM; if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { @@ -341,19 +382,25 @@ int setup_arg_pages(struct linux_binprm *bprm) return -ENOMEM; } - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); { - mpnt->vm_mm = current->mm; + mpnt->vm_mm = mm; +#ifdef ARCH_STACK_GROWSUP + mpnt->vm_start = stack_base; + mpnt->vm_end = PAGE_MASK & + (PAGE_SIZE - 1 + (unsigned long) bprm->p); +#else mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; +#endif mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; - insert_vm_struct(current->mm, mpnt); - current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + insert_vm_struct(mm, mpnt); + mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -364,7 +411,7 @@ int setup_arg_pages(struct linux_binprm *bprm) } stack_base += PAGE_SIZE; } - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return 0; } @@ -732,7 +779,6 @@ void compute_creds(struct linux_binprm *bprm) security_ops->bprm_compute_creds(bprm); } - void remove_arg_zero(struct linux_binprm *bprm) { if (bprm->argc) { @@ -854,7 +900,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) return retval; } - /* * sys_execve() executes a new program. */ |
