1*d83602c1Schristos /* $NetBSD: linux_exec_elf32.c,v 1.15 1996/06/13 19:27:01 christos Exp $ */ 23bf459f3Sfvdl 33bf459f3Sfvdl /* 43bf459f3Sfvdl * Copyright (c) 1995 Frank van der Linden 5fb777788Sfvdl * Copyright (c) 1994 Christos Zoulas 63bf459f3Sfvdl * All rights reserved. 73bf459f3Sfvdl * 83bf459f3Sfvdl * Redistribution and use in source and binary forms, with or without 93bf459f3Sfvdl * modification, are permitted provided that the following conditions 103bf459f3Sfvdl * are met: 113bf459f3Sfvdl * 1. Redistributions of source code must retain the above copyright 123bf459f3Sfvdl * notice, this list of conditions and the following disclaimer. 133bf459f3Sfvdl * 2. Redistributions in binary form must reproduce the above copyright 143bf459f3Sfvdl * notice, this list of conditions and the following disclaimer in the 153bf459f3Sfvdl * documentation and/or other materials provided with the distribution. 16fb777788Sfvdl * 3. The name of the author may not be used to endorse or promote products 173bf459f3Sfvdl * derived from this software without specific prior written permission 183bf459f3Sfvdl * 193bf459f3Sfvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 203bf459f3Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 213bf459f3Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 223bf459f3Sfvdl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 233bf459f3Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 243bf459f3Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 253bf459f3Sfvdl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 263bf459f3Sfvdl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 273bf459f3Sfvdl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 283bf459f3Sfvdl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 293bf459f3Sfvdl * 30fb777788Sfvdl * based on exec_aout.c, sunos_exec.c and svr4_exec.c 313bf459f3Sfvdl */ 323bf459f3Sfvdl 333bf459f3Sfvdl #include <sys/param.h> 343bf459f3Sfvdl #include <sys/systm.h> 353bf459f3Sfvdl #include <sys/kernel.h> 363bf459f3Sfvdl #include <sys/proc.h> 373bf459f3Sfvdl #include <sys/malloc.h> 383bf459f3Sfvdl #include <sys/namei.h> 393bf459f3Sfvdl #include <sys/vnode.h> 40151fa70fSchristos #include <sys/mount.h> 41c4aaa600Sfvdl #include <sys/exec_elf.h> 423bf459f3Sfvdl 433bf459f3Sfvdl #include <sys/mman.h> 44151fa70fSchristos #include <sys/syscallargs.h> 45151fa70fSchristos 463bf459f3Sfvdl #include <vm/vm.h> 473bf459f3Sfvdl #include <vm/vm_param.h> 483bf459f3Sfvdl #include <vm/vm_map.h> 493bf459f3Sfvdl 503bf459f3Sfvdl #include <machine/cpu.h> 513bf459f3Sfvdl #include <machine/reg.h> 523bf459f3Sfvdl #include <machine/exec.h> 5344eef7c2Schristos #include <machine/linux_machdep.h> 543bf459f3Sfvdl 553bf459f3Sfvdl #include <compat/linux/linux_types.h> 5644eef7c2Schristos #include <compat/linux/linux_syscall.h> 5788b8e43aSmycroft #include <compat/linux/linux_signal.h> 583bf459f3Sfvdl #include <compat/linux/linux_syscallargs.h> 593bf459f3Sfvdl #include <compat/linux/linux_util.h> 603bf459f3Sfvdl #include <compat/linux/linux_exec.h> 613bf459f3Sfvdl 62fc7cfb5fSfvdl static void *linux_aout_copyargs __P((struct exec_package *, 63fc7cfb5fSfvdl struct ps_strings *, void *, void *)); 644d9a6e09Schristos static int linux_elf_signature __P((struct proc *p, struct exec_package *, 654d9a6e09Schristos Elf32_Ehdr *)); 66fc7cfb5fSfvdl 67fc7cfb5fSfvdl #define LINUX_AOUT_AUX_ARGSIZ 2 68c4aaa600Sfvdl #define LINUX_ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) 69c4aaa600Sfvdl 7044eef7c2Schristos 716b95b513Schristos const char linux_emul_path[] = "/emul/linux"; 7244eef7c2Schristos extern int linux_error[]; 73245f292fSmycroft extern char linux_sigcode[], linux_esigcode[]; 7444eef7c2Schristos extern struct sysent linux_sysent[]; 7544eef7c2Schristos extern char *linux_syscallnames[]; 7644eef7c2Schristos 77151fa70fSchristos int exec_linux_aout_prep_zmagic __P((struct proc *, struct exec_package *)); 78151fa70fSchristos int exec_linux_aout_prep_nmagic __P((struct proc *, struct exec_package *)); 79151fa70fSchristos int exec_linux_aout_prep_omagic __P((struct proc *, struct exec_package *)); 80151fa70fSchristos int exec_linux_aout_prep_qmagic __P((struct proc *, struct exec_package *)); 81151fa70fSchristos 82fc7cfb5fSfvdl struct emul emul_linux_aout = { 8344eef7c2Schristos "linux", 8444eef7c2Schristos linux_error, 8544eef7c2Schristos linux_sendsig, 8644eef7c2Schristos LINUX_SYS_syscall, 8744eef7c2Schristos LINUX_SYS_MAXSYSCALL, 8844eef7c2Schristos linux_sysent, 8944eef7c2Schristos linux_syscallnames, 90fc7cfb5fSfvdl LINUX_AOUT_AUX_ARGSIZ, 91fc7cfb5fSfvdl linux_aout_copyargs, 92fc7cfb5fSfvdl setregs, 93fc7cfb5fSfvdl linux_sigcode, 94fc7cfb5fSfvdl linux_esigcode, 95fc7cfb5fSfvdl }; 96fc7cfb5fSfvdl 97fc7cfb5fSfvdl struct emul emul_linux_elf = { 98fc7cfb5fSfvdl "linux", 99fc7cfb5fSfvdl linux_error, 100fc7cfb5fSfvdl linux_sendsig, 101fc7cfb5fSfvdl LINUX_SYS_syscall, 102fc7cfb5fSfvdl LINUX_SYS_MAXSYSCALL, 103fc7cfb5fSfvdl linux_sysent, 104fc7cfb5fSfvdl linux_syscallnames, 105fc7cfb5fSfvdl LINUX_ELF_AUX_ARGSIZ, 106c4aaa600Sfvdl elf_copyargs, 10744eef7c2Schristos setregs, 10844eef7c2Schristos linux_sigcode, 10944eef7c2Schristos linux_esigcode, 11044eef7c2Schristos }; 11144eef7c2Schristos 11244eef7c2Schristos 11344eef7c2Schristos static void * 114fc7cfb5fSfvdl linux_aout_copyargs(pack, arginfo, stack, argp) 11544eef7c2Schristos struct exec_package *pack; 11644eef7c2Schristos struct ps_strings *arginfo; 11744eef7c2Schristos void *stack; 11844eef7c2Schristos void *argp; 11944eef7c2Schristos { 12044eef7c2Schristos char **cpp = stack; 12144eef7c2Schristos char **stk = stack; 12244eef7c2Schristos char *dp, *sp; 12344eef7c2Schristos size_t len; 12444eef7c2Schristos void *nullp = NULL; 12544eef7c2Schristos int argc = arginfo->ps_nargvstr; 12644eef7c2Schristos int envc = arginfo->ps_nenvstr; 12744eef7c2Schristos 12844eef7c2Schristos if (copyout(&argc, cpp++, sizeof(argc))) 12944eef7c2Schristos return NULL; 13044eef7c2Schristos 13144eef7c2Schristos /* leave room for envp and argv */ 13244eef7c2Schristos cpp += 2; 13344eef7c2Schristos if (copyout(&cpp, &stk[1], sizeof (cpp))) 13444eef7c2Schristos return NULL; 13544eef7c2Schristos 13644eef7c2Schristos dp = (char *) (cpp + argc + envc + 2); 13744eef7c2Schristos sp = argp; 13844eef7c2Schristos 13944eef7c2Schristos /* XXX don't copy them out, remap them! */ 140bfd22ffdSmycroft arginfo->ps_argvstr = cpp; /* remember location of argv for later */ 14144eef7c2Schristos 14244eef7c2Schristos for (; --argc >= 0; sp += len, dp += len) 14344eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 14444eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 14544eef7c2Schristos return NULL; 14644eef7c2Schristos 14744eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 14844eef7c2Schristos return NULL; 14944eef7c2Schristos 15044eef7c2Schristos if (copyout(&cpp, &stk[2], sizeof (cpp))) 15144eef7c2Schristos return NULL; 15244eef7c2Schristos 153bfd22ffdSmycroft arginfo->ps_envstr = cpp; /* remember location of envp for later */ 15444eef7c2Schristos 15544eef7c2Schristos for (; --envc >= 0; sp += len, dp += len) 15644eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 15744eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 15844eef7c2Schristos return NULL; 15944eef7c2Schristos 16044eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 16144eef7c2Schristos return NULL; 16244eef7c2Schristos 16344eef7c2Schristos return cpp; 16444eef7c2Schristos } 16544eef7c2Schristos 1663bf459f3Sfvdl int 1673bf459f3Sfvdl exec_linux_aout_makecmds(p, epp) 1683bf459f3Sfvdl struct proc *p; 1693bf459f3Sfvdl struct exec_package *epp; 1703bf459f3Sfvdl { 1713bf459f3Sfvdl struct exec *linux_ep = epp->ep_hdr; 1723bf459f3Sfvdl int machtype, magic; 1733bf459f3Sfvdl int error = ENOEXEC; 1743bf459f3Sfvdl 1753bf459f3Sfvdl magic = LINUX_N_MAGIC(linux_ep); 1763bf459f3Sfvdl machtype = LINUX_N_MACHTYPE(linux_ep); 1773bf459f3Sfvdl 1783bf459f3Sfvdl 1793bf459f3Sfvdl if (machtype != LINUX_MID_MACHINE) 1803bf459f3Sfvdl return (ENOEXEC); 1813bf459f3Sfvdl 1823bf459f3Sfvdl switch (magic) { 1833bf459f3Sfvdl case QMAGIC: 1843bf459f3Sfvdl error = exec_linux_aout_prep_qmagic(p, epp); 1853bf459f3Sfvdl break; 1863bf459f3Sfvdl case ZMAGIC: 1873bf459f3Sfvdl error = exec_linux_aout_prep_zmagic(p, epp); 1883bf459f3Sfvdl break; 1893bf459f3Sfvdl case NMAGIC: 1903bf459f3Sfvdl error = exec_linux_aout_prep_nmagic(p, epp); 1913bf459f3Sfvdl break; 1923bf459f3Sfvdl case OMAGIC: 1933bf459f3Sfvdl error = exec_linux_aout_prep_omagic(p, epp); 1943bf459f3Sfvdl break; 1953bf459f3Sfvdl } 19644eef7c2Schristos if (error == 0) 197fc7cfb5fSfvdl epp->ep_emul = &emul_linux_aout; 1983bf459f3Sfvdl return error; 1993bf459f3Sfvdl } 2003bf459f3Sfvdl 2013bf459f3Sfvdl /* 2023bf459f3Sfvdl * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 2033bf459f3Sfvdl * is very likely not page aligned on most architectures, it is treated 2043bf459f3Sfvdl * as an NMAGIC here. XXX 2053bf459f3Sfvdl */ 2063bf459f3Sfvdl 2073bf459f3Sfvdl int 2083bf459f3Sfvdl exec_linux_aout_prep_zmagic(p, epp) 2093bf459f3Sfvdl struct proc *p; 2103bf459f3Sfvdl struct exec_package *epp; 2113bf459f3Sfvdl { 2123bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2133bf459f3Sfvdl 2143bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 2153bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2163bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 2173bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2183bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2193bf459f3Sfvdl 2203bf459f3Sfvdl /* set up command for text segment */ 2213bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2223bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 2233bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2243bf459f3Sfvdl 2253bf459f3Sfvdl /* set up command for data segment */ 2263bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2273bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 2283bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2293bf459f3Sfvdl 2303bf459f3Sfvdl /* set up command for bss segment */ 2313bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 2323bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 2333bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2343bf459f3Sfvdl 2353bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2363bf459f3Sfvdl } 2373bf459f3Sfvdl 2383bf459f3Sfvdl /* 2393bf459f3Sfvdl * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 2403bf459f3Sfvdl * Not different from the normal stuff. 2413bf459f3Sfvdl */ 2423bf459f3Sfvdl 2433bf459f3Sfvdl int 2443bf459f3Sfvdl exec_linux_aout_prep_nmagic(p, epp) 2453bf459f3Sfvdl struct proc *p; 2463bf459f3Sfvdl struct exec_package *epp; 2473bf459f3Sfvdl { 2483bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2493bf459f3Sfvdl long bsize, baddr; 2503bf459f3Sfvdl 2513bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 2523bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2533bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 2543bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2553bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2563bf459f3Sfvdl 2573bf459f3Sfvdl /* set up command for text segment */ 2583bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2593bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 2603bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2613bf459f3Sfvdl 2623bf459f3Sfvdl /* set up command for data segment */ 2633bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2643bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 2653bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2663bf459f3Sfvdl 2673bf459f3Sfvdl /* set up command for bss segment */ 2683bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 2693bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 2703bf459f3Sfvdl if (bsize > 0) 2713bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 2723bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2733bf459f3Sfvdl 2743bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2753bf459f3Sfvdl } 2763bf459f3Sfvdl 2773bf459f3Sfvdl /* 2783bf459f3Sfvdl * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 2793bf459f3Sfvdl * Business as usual. 2803bf459f3Sfvdl */ 2813bf459f3Sfvdl 2823bf459f3Sfvdl int 2833bf459f3Sfvdl exec_linux_aout_prep_omagic(p, epp) 2843bf459f3Sfvdl struct proc *p; 2853bf459f3Sfvdl struct exec_package *epp; 2863bf459f3Sfvdl { 2873bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2883bf459f3Sfvdl long dsize, bsize, baddr; 2893bf459f3Sfvdl 2903bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 2913bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2923bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 2933bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2943bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2953bf459f3Sfvdl 2963bf459f3Sfvdl /* set up command for text and data segments */ 2973bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 2983bf459f3Sfvdl execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 2993bf459f3Sfvdl LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3003bf459f3Sfvdl 3013bf459f3Sfvdl /* set up command for bss segment */ 3023bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 3033bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 3043bf459f3Sfvdl if (bsize > 0) 3053bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 3063bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3073bf459f3Sfvdl 3083bf459f3Sfvdl /* 3093bf459f3Sfvdl * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 3103bf459f3Sfvdl * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 3113bf459f3Sfvdl * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 3123bf459f3Sfvdl * respectively to page boundaries. 3133bf459f3Sfvdl * Compensate `ep_dsize' for the amount of data covered by the last 3143bf459f3Sfvdl * text page. 3153bf459f3Sfvdl */ 3163bf459f3Sfvdl dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG); 3173bf459f3Sfvdl epp->ep_dsize = (dsize > 0) ? dsize : 0; 3183bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3193bf459f3Sfvdl } 3203bf459f3Sfvdl 3213bf459f3Sfvdl int 3223bf459f3Sfvdl exec_linux_aout_prep_qmagic(p, epp) 3233bf459f3Sfvdl struct proc *p; 3243bf459f3Sfvdl struct exec_package *epp; 3253bf459f3Sfvdl { 3263bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 3273bf459f3Sfvdl 3283bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 3293bf459f3Sfvdl epp->ep_tsize = execp->a_text; 3303bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 3313bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 3323bf459f3Sfvdl epp->ep_entry = execp->a_entry; 3333bf459f3Sfvdl 3343bf459f3Sfvdl /* 3353bf459f3Sfvdl * check if vnode is in open for writing, because we want to 3363bf459f3Sfvdl * demand-page out of it. if it is, don't do it, for various 3373bf459f3Sfvdl * reasons 3383bf459f3Sfvdl */ 3393bf459f3Sfvdl if ((execp->a_text != 0 || execp->a_data != 0) && 3403bf459f3Sfvdl epp->ep_vp->v_writecount != 0) { 3413bf459f3Sfvdl #ifdef DIAGNOSTIC 3423bf459f3Sfvdl if (epp->ep_vp->v_flag & VTEXT) 3433bf459f3Sfvdl panic("exec: a VTEXT vnode has writecount != 0\n"); 3443bf459f3Sfvdl #endif 3453bf459f3Sfvdl return ETXTBSY; 3463bf459f3Sfvdl } 3473bf459f3Sfvdl epp->ep_vp->v_flag |= VTEXT; 3483bf459f3Sfvdl 3493bf459f3Sfvdl /* set up command for text segment */ 3503bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 3513bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 3523bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 3533bf459f3Sfvdl 3543bf459f3Sfvdl /* set up command for data segment */ 3553bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 3563bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 3573bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3583bf459f3Sfvdl 3593bf459f3Sfvdl /* set up command for bss segment */ 3603bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 3613bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 3623bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3633bf459f3Sfvdl 3643bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3653bf459f3Sfvdl } 3663bf459f3Sfvdl 3674d9a6e09Schristos /* 3684d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 3694d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 3704d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 3714d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 3724d9a6e09Schristos * but we check all the progbits headers. 3734d9a6e09Schristos */ 3744d9a6e09Schristos static int 3754d9a6e09Schristos linux_elf_signature(p, epp, eh) 376fc7cfb5fSfvdl struct proc *p; 377fc7cfb5fSfvdl struct exec_package *epp; 3784d9a6e09Schristos Elf32_Ehdr *eh; 3794d9a6e09Schristos { 3804d9a6e09Schristos size_t shsize = sizeof(Elf32_Shdr) * eh->e_shnum; 3814d9a6e09Schristos size_t i; 3824d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 3834d9a6e09Schristos char buf[sizeof(signature) - 1]; 3844d9a6e09Schristos Elf32_Shdr *sh; 3854d9a6e09Schristos int error; 3864d9a6e09Schristos 3874d9a6e09Schristos sh = (Elf32_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 3884d9a6e09Schristos 3894d9a6e09Schristos if ((error = elf_read_from(p, epp->ep_vp, eh->e_shoff, 3904d9a6e09Schristos (caddr_t) sh, shsize)) != 0) 3914d9a6e09Schristos goto out; 3924d9a6e09Schristos 3934d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 3944d9a6e09Schristos Elf32_Shdr *s = &sh[i]; 3954d9a6e09Schristos 3964d9a6e09Schristos /* 3974d9a6e09Schristos * Identify candidates for the comment header; 398*d83602c1Schristos * Header cannot have a load address, or flags and 3994d9a6e09Schristos * it must be large enough. 4004d9a6e09Schristos */ 4014d9a6e09Schristos if (s->sh_type != Elf32_sht_progbits || 4024d9a6e09Schristos s->sh_addr != 0 || 4034d9a6e09Schristos s->sh_flags != 0 || 4044d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 4054d9a6e09Schristos continue; 4064d9a6e09Schristos 4074d9a6e09Schristos if ((error = elf_read_from(p, epp->ep_vp, s->sh_offset, 408*d83602c1Schristos (caddr_t) buf, sizeof(signature) - 1)) != 0) 4094d9a6e09Schristos goto out; 4104d9a6e09Schristos 411*d83602c1Schristos /* 412*d83602c1Schristos * error is 0, if the signatures match we are done. 413*d83602c1Schristos */ 414*d83602c1Schristos if (bcmp(buf, signature, sizeof(signature) - 1) == 0) 4154d9a6e09Schristos goto out; 4164d9a6e09Schristos } 4174d9a6e09Schristos error = EFTYPE; 4184d9a6e09Schristos 4194d9a6e09Schristos out: 4204d9a6e09Schristos free(sh, M_TEMP); 4214d9a6e09Schristos return error; 4224d9a6e09Schristos } 4234d9a6e09Schristos 4244d9a6e09Schristos int 4254d9a6e09Schristos linux_elf_probe(p, epp, eh, itp, pos) 4264d9a6e09Schristos struct proc *p; 4274d9a6e09Schristos struct exec_package *epp; 4284d9a6e09Schristos Elf32_Ehdr *eh; 429c4aaa600Sfvdl char *itp; 430c4aaa600Sfvdl u_long *pos; 431fc7cfb5fSfvdl { 432c4aaa600Sfvdl char *bp; 433fc7cfb5fSfvdl int error; 434c4aaa600Sfvdl size_t len; 435fc7cfb5fSfvdl 4364d9a6e09Schristos if ((error = linux_elf_signature(p, epp, eh)) != 0) 4374d9a6e09Schristos return error; 4384d9a6e09Schristos 439c4aaa600Sfvdl if (itp[0]) { 4406b95b513Schristos if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) 441c4aaa600Sfvdl return error; 442c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 443c4aaa600Sfvdl return error; 444c4aaa600Sfvdl free(bp, M_TEMP); 445fc7cfb5fSfvdl } 446fc7cfb5fSfvdl epp->ep_emul = &emul_linux_elf; 447c4aaa600Sfvdl *pos = ELF32_NO_ADDR; 448c4aaa600Sfvdl return 0; 449fc7cfb5fSfvdl } 450c4aaa600Sfvdl 451fc7cfb5fSfvdl /* 452fc7cfb5fSfvdl * The Linux system call to load shared libraries, a.out version. The 453fc7cfb5fSfvdl * a.out shared libs are just files that are mapped onto a fixed 454fc7cfb5fSfvdl * address in the process' address space. The address is given in 4553bf459f3Sfvdl * a_entry. Read in the header, set up some VM commands and run them. 4563bf459f3Sfvdl * 4573bf459f3Sfvdl * Yes, both text and data are mapped at once, so we're left with 4583bf459f3Sfvdl * writeable text for the shared libs. The Linux crt0 seemed to break 4593bf459f3Sfvdl * sometimes when data was mapped seperately. It munmapped a uselib() 4603bf459f3Sfvdl * of ld.so by hand, which failed with shared text and data for ld.so 4613bf459f3Sfvdl * Yuck. 4623bf459f3Sfvdl * 4633bf459f3Sfvdl * Because of the problem with ZMAGIC executables (text starts 464fc7cfb5fSfvdl * at 0x400 in the file, but needs to be mapped at 0), ZMAGIC 4653bf459f3Sfvdl * shared libs are not handled very efficiently :-( 4663bf459f3Sfvdl */ 4673bf459f3Sfvdl 4683bf459f3Sfvdl int 469245f292fSmycroft linux_sys_uselib(p, v, retval) 4703bf459f3Sfvdl struct proc *p; 471e1da0d53Sthorpej void *v; 4723bf459f3Sfvdl register_t *retval; 4733bf459f3Sfvdl { 474245f292fSmycroft struct linux_sys_uselib_args /* { 475e1da0d53Sthorpej syscallarg(char *) path; 476e1da0d53Sthorpej } */ *uap = v; 4773bf459f3Sfvdl caddr_t sg; 4783bf459f3Sfvdl long bsize, dsize, tsize, taddr, baddr, daddr; 4793bf459f3Sfvdl struct nameidata ni; 4803bf459f3Sfvdl struct vnode *vp; 4813bf459f3Sfvdl struct exec hdr; 4823bf459f3Sfvdl struct exec_vmcmd_set vcset; 4833bf459f3Sfvdl int rem, i, magic, error; 4843bf459f3Sfvdl 4856b95b513Schristos sg = stackgap_init(p->p_emul); 4866b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 4873bf459f3Sfvdl 4883bf459f3Sfvdl NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 4893bf459f3Sfvdl 4903bf459f3Sfvdl if ((error = namei(&ni))) 4913bf459f3Sfvdl return error; 4923bf459f3Sfvdl 4933bf459f3Sfvdl vp = ni.ni_vp; 4943bf459f3Sfvdl 4953bf459f3Sfvdl if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE, 4963bf459f3Sfvdl 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, 4973bf459f3Sfvdl &rem, p))) { 4983bf459f3Sfvdl vrele(vp); 4993bf459f3Sfvdl return error; 5003bf459f3Sfvdl } 5013bf459f3Sfvdl 5023bf459f3Sfvdl if (rem != 0) { 5033bf459f3Sfvdl vrele(vp); 5043bf459f3Sfvdl return ENOEXEC; 5053bf459f3Sfvdl } 5063bf459f3Sfvdl 507fc7cfb5fSfvdl if (LINUX_N_MACHTYPE(&hdr) != LINUX_MID_MACHINE) 508fc7cfb5fSfvdl return ENOEXEC; 509fc7cfb5fSfvdl 5103bf459f3Sfvdl magic = LINUX_N_MAGIC(&hdr); 5113bf459f3Sfvdl taddr = hdr.a_entry & (~(NBPG - 1)); 5123bf459f3Sfvdl tsize = hdr.a_text; 5133bf459f3Sfvdl daddr = taddr + tsize; 5143bf459f3Sfvdl dsize = hdr.a_data + hdr.a_bss; 5153bf459f3Sfvdl 5163bf459f3Sfvdl if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) { 5173bf459f3Sfvdl vrele(vp); 5183bf459f3Sfvdl return ETXTBSY; 5193bf459f3Sfvdl } 5203bf459f3Sfvdl vp->v_flag |= VTEXT; 5213bf459f3Sfvdl 5223bf459f3Sfvdl vcset.evs_cnt = 0; 5233bf459f3Sfvdl vcset.evs_used = 0; 5243bf459f3Sfvdl 5253bf459f3Sfvdl NEW_VMCMD(&vcset, 5263bf459f3Sfvdl magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn, 5273bf459f3Sfvdl hdr.a_text + hdr.a_data, taddr, 5283bf459f3Sfvdl vp, LINUX_N_TXTOFF(hdr, magic), 5293bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE); 5303bf459f3Sfvdl 5313bf459f3Sfvdl baddr = roundup(daddr + hdr.a_data, NBPG); 5323bf459f3Sfvdl bsize = daddr + dsize - baddr; 5333bf459f3Sfvdl if (bsize > 0) { 5343bf459f3Sfvdl NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr, 5353bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 5363bf459f3Sfvdl } 5373bf459f3Sfvdl 5383bf459f3Sfvdl for (i = 0; i < vcset.evs_used && !error; i++) { 5393bf459f3Sfvdl struct exec_vmcmd *vcp; 5403bf459f3Sfvdl 5413bf459f3Sfvdl vcp = &vcset.evs_cmds[i]; 5423bf459f3Sfvdl error = (*vcp->ev_proc)(p, vcp); 5433bf459f3Sfvdl } 5443bf459f3Sfvdl 5453bf459f3Sfvdl kill_vmcmds(&vcset); 5463bf459f3Sfvdl 5473bf459f3Sfvdl vrele(vp); 5483bf459f3Sfvdl 5493bf459f3Sfvdl return error; 5503bf459f3Sfvdl } 5513bf459f3Sfvdl 5523bf459f3Sfvdl /* 5533bf459f3Sfvdl * Execve(2). Just check the alternate emulation path, and pass it on 5543bf459f3Sfvdl * to the NetBSD execve(). 5553bf459f3Sfvdl */ 5563bf459f3Sfvdl int 557245f292fSmycroft linux_sys_execve(p, v, retval) 5583bf459f3Sfvdl struct proc *p; 559e1da0d53Sthorpej void *v; 560e1da0d53Sthorpej register_t *retval; 561e1da0d53Sthorpej { 562245f292fSmycroft struct linux_sys_execve_args /* { 5633bf459f3Sfvdl syscallarg(char *) path; 5643bf459f3Sfvdl syscallarg(char **) argv; 5653bf459f3Sfvdl syscallarg(char **) envp; 566e1da0d53Sthorpej } */ *uap = v; 5673bf459f3Sfvdl caddr_t sg; 5683bf459f3Sfvdl 5696b95b513Schristos sg = stackgap_init(p->p_emul); 5706b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 5713bf459f3Sfvdl 572245f292fSmycroft return sys_execve(p, uap, retval); 5733bf459f3Sfvdl } 574