Exemple #1
0
static elf_addr_t * 
create_elf_tables(char *p, int argc, int envc,
		  struct elfhdr * exec,
		  unsigned long load_addr,
		  unsigned long load_bias,
		  unsigned long interp_load_addr, int ibcs)
{
	elf_caddr_t *argv;
	elf_caddr_t *envp;
	elf_addr_t *sp, *csp;
	char *k_platform, *u_platform;
	long hwcap;
	size_t platform_len = 0;
	size_t len;

	/*
	 * Get hold of platform and hardware capabilities masks for
	 * the machine we are running on.  In some cases (Sparc), 
	 * this info is impossible to get, in others (i386) it is
	 * merely difficult.
	 */

	hwcap = ELF_HWCAP;
	k_platform = ELF_PLATFORM;

	if (k_platform) {
		platform_len = strlen(k_platform) + 1;
		u_platform = p - platform_len;
		__copy_to_user(u_platform, k_platform, platform_len);
	} else
		u_platform = p;

#if defined(__i386__) && defined(CONFIG_SMP)
	/*
	 * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
	 * by the processes running on the same package. One thing we can do
	 * is to shuffle the initial stack for them.
	 *
	 * The conditionals here are unneeded, but kept in to make the
	 * code behaviour the same as pre change unless we have hyperthreaded
	 * processors. This keeps Mr Marcelo Person happier but should be
	 * removed for 2.5
	 */
	 
	if(smp_num_siblings > 1)
		u_platform = u_platform - ((current->pid % 64) << 7);
#endif	

	/*
	 * Force 16 byte _final_ alignment here for generality.
	 */
	sp = (elf_addr_t *)(~15UL & (unsigned long)(u_platform));
	csp = sp;
	csp -= (1+DLINFO_ITEMS)*2 + (k_platform ? 2 : 0);
#ifdef DLINFO_ARCH_ITEMS
	csp -= DLINFO_ARCH_ITEMS*2;
#endif
	csp -= envc+1;
	csp -= argc+1;
	csp -= (!ibcs ? 3 : 1);	/* argc itself */
	if ((unsigned long)csp & 15UL)
		sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);

	/*
	 * Put the ELF interpreter info on the stack
	 */
#define NEW_AUX_ENT(nr, id, val) \
	  __put_user ((id), sp+(nr*2)); \
	  __put_user ((val), sp+(nr*2+1)); \

	sp -= 2;
	NEW_AUX_ENT(0, AT_NULL, 0);
	if (k_platform) {
		sp -= 2;
		NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
	}
	sp -= DLINFO_ITEMS*2;
	NEW_AUX_ENT( 0, AT_HWCAP, hwcap);
	NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE);
	NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC);
	NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff);
	NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr));
	NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum);
	NEW_AUX_ENT( 6, AT_BASE, interp_load_addr);
	NEW_AUX_ENT( 7, AT_FLAGS, 0);
	NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry);
	NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid);
	NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid);
	NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid);
	NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid);
#ifdef ARCH_DLINFO
	/* 
	 * ARCH_DLINFO must come last so platform specific code can enforce
	 * special alignment requirements on the AUXV if necessary (eg. PPC).
	 */
	ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT

	sp -= envc+1;
	envp = (elf_caddr_t *) sp;
	sp -= argc+1;
	argv = (elf_caddr_t *) sp;
	if (!ibcs) {
		__put_user((elf_addr_t)(unsigned long) envp,--sp);
		__put_user((elf_addr_t)(unsigned long) argv,--sp);
	}

	__put_user((elf_addr_t)argc,--sp);
	current->mm->arg_start = current->mm->arg_end = (unsigned long) p;
	while (argc-->0) {
		__put_user((elf_caddr_t)(unsigned long)p,argv++);
		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
			return NULL;
		p += len;
	}
	__put_user(NULL, argv);
	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
	while (envc-->0) {
		__put_user((elf_caddr_t)(unsigned long)p,envp++);
		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
			return NULL;
		p += len;
	}
	__put_user(NULL, envp);
	current->mm->env_end = (unsigned long) p;
	return sp;
}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                   struct elfhdr * exec,
                                   abi_ulong load_addr,
                                   abi_ulong load_bias,
                                   abi_ulong interp_load_addr, int ibcs,
                                   struct image_info *info)
{
        abi_ulong sp;
        int size;
        abi_ulong u_platform;
        const char *k_platform;
        const int n = sizeof(elf_addr_t);

        sp = p;
        u_platform = 0;
        k_platform = ELF_PLATFORM;
        if (k_platform) {
            size_t len = strlen(k_platform) + 1;
            sp -= (len + n - 1) & ~(n - 1);
            u_platform = sp;
            /* FIXME - check return value of memcpy_to_target() for failure */
            memcpy_to_target(sp, k_platform, len);
        }
	/*
	 * Force 16 byte _final_ alignment here for generality.
	 */
        sp = sp &~ (abi_ulong)15;
        size = (DLINFO_ITEMS + 1) * 2;
        if (k_platform)
          size += 2;
#ifdef DLINFO_ARCH_ITEMS
	size += DLINFO_ARCH_ITEMS * 2;
#endif
        size += envc + argc + 2;
	size += (!ibcs ? 3 : 1);	/* argc itself */
        size *= n;
        if (size & 15)
            sp -= 16 - (size & 15);

        /* This is correct because Linux defines
         * elf_addr_t as Elf32_Off / Elf64_Off
         */
#define NEW_AUX_ENT(id, val) do {		\
            sp -= n; put_user_ual(val, sp);	\
            sp -= n; put_user_ual(id, sp);	\
          } while(0)

        NEW_AUX_ENT (AT_NULL, 0);

        /* There must be exactly DLINFO_ITEMS entries here.  */
        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
        if (k_platform)
            NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
	/*
	 * ARCH_DLINFO must come last so platform specific code can enforce
	 * special alignment requirements on the AUXV if necessary (eg. PPC).
	 */
        ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT

        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
        return sp;
}
Exemple #3
0
static unsigned long * create_irix_tables(char * p, int argc, int envc,
	struct elfhdr * exec, unsigned int load_addr,
	unsigned int interp_load_addr, struct pt_regs *regs,
	struct elf_phdr *ephdr)
{
	elf_addr_t *argv;
	elf_addr_t *envp;
	elf_addr_t *sp, *csp;

	pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] "
	         "load_addr[%08x] interp_load_addr[%08x]\n",
	         p, argc, envc, load_addr, interp_load_addr);

	sp = (elf_addr_t *) (~15UL & (unsigned long) p);
	csp = sp;
	csp -= exec ? DLINFO_ITEMS*2 : 2;
	csp -= envc+1;
	csp -= argc+1;
	csp -= 1;		/* argc itself */
	if ((unsigned long)csp & 15UL) {
		sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
	}

	/*
	 * Put the ELF interpreter info on the stack
	 */
#define NEW_AUX_ENT(nr, id, val) \
	  __put_user((id), sp+(nr*2)); \
	  __put_user((val), sp+(nr*2+1)); \

	sp -= 2;
	NEW_AUX_ENT(0, AT_NULL, 0);

	if (exec) {
		sp -= 11*2;

		NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff);
		NEW_AUX_ENT(1, AT_PHENT, sizeof(struct elf_phdr));
		NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum);
		NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
		NEW_AUX_ENT(4, AT_BASE, interp_load_addr);
		NEW_AUX_ENT(5, AT_FLAGS, 0);
		NEW_AUX_ENT(6, AT_ENTRY, (elf_addr_t) exec->e_entry);
		NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid);
		NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid);
		NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid);
		NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) current->egid);
	}
#undef NEW_AUX_ENT

	sp -= envc+1;
	envp = sp;
	sp -= argc+1;
	argv = sp;

	__put_user((elf_addr_t)argc, --sp);
	current->mm->arg_start = (unsigned long) p;
	while (argc-->0) {
		__put_user((unsigned long)p, argv++);
		p += strlen_user(p);
	}
	__put_user((unsigned long) NULL, argv);
	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
	while (envc-->0) {
		__put_user((unsigned long)p, envp++);
		p += strlen_user(p);
	}
	__put_user((unsigned long) NULL, envp);
	current->mm->env_end = (unsigned long) p;
	return sp;
}
Exemple #4
0
static elf_addr_t *
create_elf_tables(char *p, int argc, int envc,
                  struct elfhdr * exec,
                  unsigned long load_addr,
                  unsigned long load_bias,
                  unsigned long interp_load_addr, int ibcs)
{
  elf_caddr_t *argv;
  elf_caddr_t *envp;
  elf_addr_t *sp, *csp;
  char *k_platform, *u_platform;
  long hwcap;
  size_t platform_len = 0;

  /*
   * Get hold of platform and hardware capabilities masks for
   * the machine we are running on.  In some cases (Sparc), 
   * this info is impossible to get, in others (i386) it is
   * merely difficult.
   */

  hwcap = ELF_HWCAP;
  k_platform = ELF_PLATFORM;

  if (k_platform) {
    platform_len = strlen(k_platform) + 1;
    u_platform = p - platform_len;
    memcpy(u_platform, k_platform, platform_len);
  } else
    u_platform = p;

  /*
   * Force 16 byte _final_ alignment here for generality.
   * Leave an extra 16 bytes free so that on the PowerPC we
   * can move the aux table up to start on a 16-byte boundary.
   */
  sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL);
  csp = sp;
  csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0));
  csp -= envc+1;
  csp -= argc+1;
  csp -= (!ibcs ? 3 : 1);  /* argc itself */
  if ((unsigned long)csp & 15UL)
    sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);


  /*
   * Put the ELF interpreter info on the stack
   */
#define NEW_AUX_ENT(nr, id, val) \
  __put_user ((id), sp+(nr*2)); \
  __put_user ((val), sp+(nr*2+1)); 

  sp -= 2;
  NEW_AUX_ENT(0, AT_NULL, 0);
  if (k_platform) {
    sp -= 2;
    NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
  }
  sp -= 2;
  NEW_AUX_ENT(0, AT_HWCAP, hwcap);

  if (exec) {
    sp -= 11*2;

    NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff);
    NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr));
    NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum);
    NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
    NEW_AUX_ENT(4, AT_BASE, interp_load_addr);
    NEW_AUX_ENT(5, AT_FLAGS, 0);
    NEW_AUX_ENT(6, AT_ENTRY, load_bias + exec->e_entry);
    NEW_AUX_ENT(7, AT_UID, (elf_addr_t) getuid());
    NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) geteuid());
    NEW_AUX_ENT(9, AT_GID, (elf_addr_t) getgid());
    NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) getegid());
  }
#undef NEW_AUX_ENT

  sp -= envc+1;
  envp = (elf_caddr_t *) sp;
  sp -= argc+1;
  argv = (elf_caddr_t *) sp;
  if (!ibcs) {
    __put_user((elf_addr_t)(unsigned long) envp,--sp);
    __put_user((elf_addr_t)(unsigned long) argv,--sp);
  }

  __put_user((elf_addr_t)argc,--sp);
  current->arg_start = (unsigned long) p;
  while (argc-->0) {
    __put_user((elf_caddr_t)(unsigned long)p,argv++);
    p += strlen(p)+1;
  }
  __put_user(NULL, argv);
  current->arg_end = current->env_start = (unsigned long) p;
  while (envc-->0) {
    __put_user((elf_caddr_t)(unsigned long)p,envp++);
    p += strlen(p)+1;
  }
  __put_user(NULL, envp);
  current->env_end = (unsigned long) p;
  return sp;
}
Exemple #5
0
/*
 * create_elf_tables
 */
static int
create_elf_tables_aux(struct linux_binprm *bprm,
                      unsigned long ntdll_load_addr, elf_off_t ntdll_phoff, elf_half_t ntdll_phnum, unsigned long ntdll_start_thunk,
                      unsigned long exeso_load_addr, elf_off_t exeso_phoff, elf_half_t exeso_phnum, unsigned long exeso_start_thunk,
                      unsigned long interp_load_addr, unsigned long interp_entry, unsigned long init_entry)
{
    unsigned long p = bprm->p;
    int argc = bprm->argc;
    int envc = bprm->envc;
    elf_addr_t __user *argv;
    elf_addr_t __user *envp;
    elf_addr_t __user *sp;
    elf_addr_t __user *u_platform;
    const char *k_platform = ELF_PLATFORM;
    int items;
    elf_addr_t *elf_info;
    elf_addr_t *elf_info2;
    int ei_index = 0;
    const struct cred *cred = current_cred();

    /*
     * If this architecture has a platform capability string, copy it
     * to userspace.  In some cases (Sparc), this info is impossible
     * for userspace to get any other way, in others (i386) it is
     * merely difficult.
     */

    u_platform = NULL;
    if (k_platform) {
        size_t len = strlen(k_platform) + 1;

        /*
         * In some cases (e.g. Hyper-Threading), we want to avoid L1
         * evictions by the processes running on the same package. One
         * thing we can do is to shuffle the initial stack for them.
         */

        p = arch_align_stack(p);

        u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
        if (__copy_to_user(u_platform, k_platform, len))
            return -EFAULT;
    }

    /* Create the ELF interpreter info */
    elf_info = (elf_addr_t *) current->mm->saved_auxv;
#define NEW_AUX_ENT(id, val) \
	do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)

#ifdef ARCH_DLINFO11
    /*
     * ARCH_DLINFO must come first so PPC can do its special alignment of
     * AUXV.
     */
    ARCH_DLINFO;
#endif
    NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
    NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
    NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
    NEW_AUX_ENT(AT_PHDR, ntdll_load_addr + ntdll_phoff);
    NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
    NEW_AUX_ENT(AT_PHNUM, ntdll_phnum);
    NEW_AUX_ENT(AT_BASE, interp_load_addr);
    NEW_AUX_ENT(AT_FLAGS, 0);
    NEW_AUX_ENT(AT_ENTRY, ntdll_start_thunk);
    NEW_AUX_ENT(AT_UID, cred->uid);
    NEW_AUX_ENT(AT_EUID, cred->euid);
    NEW_AUX_ENT(AT_GID, cred->gid);
    NEW_AUX_ENT(AT_EGID, cred->egid);
    NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm));
#if 0
    if (k_platform) {
        /* FIXME */
        NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform);
    }
#endif
    if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
        NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data);
    }
#undef NEW_AUX_ENT
    /* AT_NULL is zero; clear the rest too */
    memset(&elf_info[ei_index], 0,
           sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]);

    /* And advance past the AT_NULL entry.  */
    ei_index += 2;

    sp = STACK_ADD(p, ei_index * 2);

    items = (argc + 1) + (envc + 1);
    items += 1; /* ELF interpreters only put argc on the stack */
    items += 3; /* interp entry address & _init address & load_base */
    bprm->p = STACK_ROUND(sp, items);

    /* Point sp at the lowest address on the stack */
#ifdef CONFIG_STACK_GROWSUP
    sp = (elf_addr_t __user *)bprm->p - items - ei_index;
    bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */
#else
    sp = (elf_addr_t __user *)bprm->p;
#endif

    /* Now, let's put argc (and argv, envp if appropriate) on the stack */
    if (__put_user(argc, sp))
        return -EFAULT;
    ++sp;
    argv = sp;
    envp = argv + argc + 1;

    /* Populate argv and envp */
    p = current->mm->arg_end = current->mm->arg_start;
    while (argc-- > 0) {
        size_t len;
        __put_user((elf_addr_t)p, argv);
        ++argv;
        len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
        if (!len || len > MAX_ARG_STRLEN)
            return 0;
        p += len;
    }
    if (__put_user(0, argv))
        return -EFAULT;
    current->mm->arg_end = current->mm->env_start = p;
    while (envc-- > 0) {
        size_t len;
        __put_user((elf_addr_t)p, envp);
        ++envp;
        len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
        if (!len || len > MAX_ARG_STRLEN)
            return 0;
        p += len;
    }
    if (__put_user(0, envp))
        return -EFAULT;
    current->mm->env_end = p;

    /* Put the elf_info on the stack in the right place.  */
    sp = (elf_addr_t __user *)envp + 1;
    if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)))
        return -EFAULT;
    sp += ei_index;


    elf_info2 = (elf_addr_t *)kmalloc(sizeof(current->mm->saved_auxv), GFP_KERNEL);
    if(!elf_info2)
        return -ENOMEM;

    ei_index = 0;
#define NEW_AUX_ENT(id, val) \
	do { elf_info2[ei_index++] = id; elf_info2[ei_index++] = val; } while (0)

#ifdef ARCH_DLINFO11
    /*
     * ARCH_DLINFO must come first so PPC can do its special alignment of
     * AUXV.
     */
    ARCH_DLINFO;
#endif
    NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
    NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
    NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
    NEW_AUX_ENT(AT_PHDR, exeso_load_addr + exeso_phoff);
    NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
    NEW_AUX_ENT(AT_PHNUM, exeso_phnum);
    NEW_AUX_ENT(AT_BASE, interp_load_addr);
    NEW_AUX_ENT(AT_FLAGS, 0);
    NEW_AUX_ENT(AT_ENTRY, exeso_start_thunk);
    NEW_AUX_ENT(AT_UID, cred->uid);
    NEW_AUX_ENT(AT_EUID, cred->euid);
    NEW_AUX_ENT(AT_GID, cred->gid);
    NEW_AUX_ENT(AT_EGID, cred->egid);
    NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm));
#if 0
    if (k_platform) {
        /* FIXME */
        NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform);
    }
#endif
    if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
        NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data);
    }
#undef NEW_AUX_ENT
    /* AT_NULL is zero; clear the rest too */
    memset(&elf_info2[ei_index], 0,
           sizeof(current->mm->saved_auxv) - ei_index * sizeof elf_info2[0]);
    ei_index += 2;
    if (copy_to_user(sp, elf_info2, ei_index * sizeof(elf_addr_t))) {
        kfree(elf_info2);
        return -EFAULT;
    }
    kfree(elf_info2);
    sp += ei_index;

    __put_user(interp_entry, sp);
    ++sp;
    __put_user(init_entry, sp);
    ++sp;
    __put_user(exeso_load_addr, sp);

    memset(current->mm->saved_auxv, 0, sizeof(current->mm->saved_auxv));

    return 0;
} /* end create_elf_tables */
/*
 * present useful information to the program
 */
static int create_elf_fdpic_tables(struct linux_binprm *bprm,
				   struct mm_struct *mm,
				   struct elf_fdpic_params *exec_params,
				   struct elf_fdpic_params *interp_params)
{
	unsigned long sp, csp, nitems;
	elf_caddr_t *argv, *envp;
	size_t platform_len = 0, len;
	char *k_platform, *u_platform, *p;
	long hwcap;
	int loop;

	/* we're going to shovel a whole load of stuff onto the stack */
#ifdef CONFIG_MMU
	sp = bprm->p;
#else
	sp = mm->start_stack;

	/* stack the program arguments and environment */
	if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0)
		return -EFAULT;
#endif

	/* get hold of platform and hardware capabilities masks for the machine
	 * we are running on.  In some cases (Sparc), this info is impossible
	 * to get, in others (i386) it is merely difficult.
	 */
	hwcap = ELF_HWCAP;
	k_platform = ELF_PLATFORM;

	if (k_platform) {
		platform_len = strlen(k_platform) + 1;
		sp -= platform_len;
		if (__copy_to_user(u_platform, k_platform, platform_len) != 0)
			return -EFAULT;
	}

	u_platform = (char *) sp;

#if defined(__i386__) && defined(CONFIG_SMP)
	/* in some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
	 * by the processes running on the same package. One thing we can do
	 * is to shuffle the initial stack for them.
	 *
	 * the conditionals here are unneeded, but kept in to make the
	 * code behaviour the same as pre change unless we have hyperthreaded
	 * processors. This keeps Mr Marcelo Person happier but should be
	 * removed for 2.5
	 */
	if (smp_num_siblings > 1)
		sp = sp - ((current->pid % 64) << 7);
#endif

	sp &= ~7UL;

	/* stack the load map(s) */
	len = sizeof(struct elf32_fdpic_loadmap);
	len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs;
	sp = (sp - len) & ~7UL;
	exec_params->map_addr = sp;

	if (copy_to_user((void *) sp, exec_params->loadmap, len) != 0)
		return -EFAULT;

	current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;

	if (interp_params->loadmap) {
		len = sizeof(struct elf32_fdpic_loadmap);
		len += sizeof(struct elf32_fdpic_loadseg) * interp_params->loadmap->nsegs;
		sp = (sp - len) & ~7UL;
		interp_params->map_addr = sp;

		if (copy_to_user((void *) sp, interp_params->loadmap, len) != 0)
			return -EFAULT;

		current->mm->context.interp_fdpic_loadmap = (unsigned long) sp;
	}

	/* force 16 byte _final_ alignment here for generality */
#define DLINFO_ITEMS 13

	nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0);
#ifdef DLINFO_ARCH_ITEMS
	nitems += DLINFO_ARCH_ITEMS;
#endif

	csp = sp;
	sp -= nitems * 2 * sizeof(unsigned long);
	sp -= (bprm->envc + 1) * sizeof(char *);	/* envv[] */
	sp -= (bprm->argc + 1) * sizeof(char *);	/* argv[] */
	sp -= 1 * sizeof(unsigned long);		/* argc */

	csp -= sp & 15UL;
	sp -= sp & 15UL;

	/* put the ELF interpreter info on the stack */
#define NEW_AUX_ENT(nr, id, val)						\
	do {									\
		struct { unsigned long _id, _val; } *ent = (void *) csp;	\
		__put_user((id), &ent[nr]._id);					\
		__put_user((val), &ent[nr]._val);				\
	} while (0)

	csp -= 2 * sizeof(unsigned long);
	NEW_AUX_ENT(0, AT_NULL, 0);
	if (k_platform) {
		csp -= 2 * sizeof(unsigned long);
		NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
	}

	csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
	NEW_AUX_ENT( 0, AT_HWCAP,		hwcap);
	NEW_AUX_ENT( 1, AT_PAGESZ,		PAGE_SIZE);
	NEW_AUX_ENT( 2, AT_CLKTCK,		CLOCKS_PER_SEC);
	NEW_AUX_ENT( 3, AT_PHDR,		exec_params->ph_addr);
	NEW_AUX_ENT( 4, AT_PHENT,		sizeof(struct elf_phdr));
	NEW_AUX_ENT( 5, AT_PHNUM,		exec_params->hdr.e_phnum);
	NEW_AUX_ENT( 6,	AT_BASE,		interp_params->elfhdr_addr);
	NEW_AUX_ENT( 7, AT_FLAGS,		0);
	NEW_AUX_ENT( 8, AT_ENTRY,		exec_params->entry_addr);
	NEW_AUX_ENT( 9, AT_UID,			(elf_addr_t) current->uid);
	NEW_AUX_ENT(10, AT_EUID,		(elf_addr_t) current->euid);
	NEW_AUX_ENT(11, AT_GID,			(elf_addr_t) current->gid);
	NEW_AUX_ENT(12, AT_EGID,		(elf_addr_t) current->egid);

#ifdef ARCH_DLINFO
	/* ARCH_DLINFO must come last so platform specific code can enforce
	 * special alignment requirements on the AUXV if necessary (eg. PPC).
	 */
	ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT

	/* allocate room for argv[] and envv[] */
	csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
	envp = (elf_caddr_t *) csp;
	csp -= (bprm->argc + 1) * sizeof(elf_caddr_t);
	argv = (elf_caddr_t *) csp;

	/* stack argc */
	csp -= sizeof(unsigned long);
	__put_user(bprm->argc, (unsigned long *) csp);

	if (csp != sp)
		BUG();

	/* fill in the argv[] array */
#ifdef CONFIG_MMU
	current->mm->arg_start = bprm->p;
#else
	current->mm->arg_start = current->mm->start_stack - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p);
#endif

	p = (char *) current->mm->arg_start;
	for (loop = bprm->argc; loop > 0; loop--) {
		__put_user((elf_caddr_t) p, argv++);
		len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
		if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
			return -EINVAL;
		p += len;
	}
	__put_user(NULL, argv);
	current->mm->arg_end = (unsigned long) p;

	/* fill in the envv[] array */
	current->mm->env_start = (unsigned long) p;
	for (loop = bprm->envc; loop > 0; loop--) {
		__put_user((elf_caddr_t)(unsigned long) p, envp++);
		len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
		if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
			return -EINVAL;
		p += len;
	}
	__put_user(NULL, envp);
	current->mm->env_end = (unsigned long) p;

	mm->start_stack = (unsigned long) sp;
	return 0;
} /* end create_elf_fdpic_tables() */