1*e1601dc2Sperry /* $NetBSD: linux_exec_elf32.c,v 1.28 1998/08/09 20:37:54 perry 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 337c325577Scgd #define ELFSIZE 32 /* XXX should die */ 349c3e274cScgd 353bf459f3Sfvdl #include <sys/param.h> 363bf459f3Sfvdl #include <sys/systm.h> 373bf459f3Sfvdl #include <sys/kernel.h> 383bf459f3Sfvdl #include <sys/proc.h> 393bf459f3Sfvdl #include <sys/malloc.h> 403bf459f3Sfvdl #include <sys/namei.h> 413bf459f3Sfvdl #include <sys/vnode.h> 42151fa70fSchristos #include <sys/mount.h> 43d551a4edSchristos #include <sys/exec.h> 44c4aaa600Sfvdl #include <sys/exec_elf.h> 453bf459f3Sfvdl 463bf459f3Sfvdl #include <sys/mman.h> 47151fa70fSchristos #include <sys/syscallargs.h> 48151fa70fSchristos 493bf459f3Sfvdl #include <vm/vm.h> 503bf459f3Sfvdl #include <vm/vm_param.h> 513bf459f3Sfvdl #include <vm/vm_map.h> 523bf459f3Sfvdl 533bf459f3Sfvdl #include <machine/cpu.h> 543bf459f3Sfvdl #include <machine/reg.h> 5544eef7c2Schristos #include <machine/linux_machdep.h> 563bf459f3Sfvdl 573bf459f3Sfvdl #include <compat/linux/linux_types.h> 5844eef7c2Schristos #include <compat/linux/linux_syscall.h> 5988b8e43aSmycroft #include <compat/linux/linux_signal.h> 603bf459f3Sfvdl #include <compat/linux/linux_syscallargs.h> 613bf459f3Sfvdl #include <compat/linux/linux_util.h> 623bf459f3Sfvdl #include <compat/linux/linux_exec.h> 633bf459f3Sfvdl 64fc7cfb5fSfvdl static void *linux_aout_copyargs __P((struct exec_package *, 65fc7cfb5fSfvdl struct ps_strings *, void *, void *)); 669c3e274cScgd static int linux_elf32_signature __P((struct proc *p, struct exec_package *, 674d9a6e09Schristos Elf32_Ehdr *)); 68fc7cfb5fSfvdl 69fc7cfb5fSfvdl #define LINUX_AOUT_AUX_ARGSIZ 2 70c4aaa600Sfvdl #define LINUX_ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) 71c4aaa600Sfvdl 7244eef7c2Schristos 736b95b513Schristos const char linux_emul_path[] = "/emul/linux"; 7444eef7c2Schristos extern int linux_error[]; 75245f292fSmycroft extern char linux_sigcode[], linux_esigcode[]; 7644eef7c2Schristos extern struct sysent linux_sysent[]; 7744eef7c2Schristos extern char *linux_syscallnames[]; 7844eef7c2Schristos 79151fa70fSchristos int exec_linux_aout_prep_zmagic __P((struct proc *, struct exec_package *)); 80151fa70fSchristos int exec_linux_aout_prep_nmagic __P((struct proc *, struct exec_package *)); 81151fa70fSchristos int exec_linux_aout_prep_omagic __P((struct proc *, struct exec_package *)); 82151fa70fSchristos int exec_linux_aout_prep_qmagic __P((struct proc *, struct exec_package *)); 83151fa70fSchristos 84fc7cfb5fSfvdl struct emul emul_linux_aout = { 8544eef7c2Schristos "linux", 8644eef7c2Schristos linux_error, 8744eef7c2Schristos linux_sendsig, 8844eef7c2Schristos LINUX_SYS_syscall, 8944eef7c2Schristos LINUX_SYS_MAXSYSCALL, 9044eef7c2Schristos linux_sysent, 9144eef7c2Schristos linux_syscallnames, 92fc7cfb5fSfvdl LINUX_AOUT_AUX_ARGSIZ, 93fc7cfb5fSfvdl linux_aout_copyargs, 9472623d84Smycroft linux_setregs, 95fc7cfb5fSfvdl linux_sigcode, 96fc7cfb5fSfvdl linux_esigcode, 97fc7cfb5fSfvdl }; 98fc7cfb5fSfvdl 99fc7cfb5fSfvdl struct emul emul_linux_elf = { 100fc7cfb5fSfvdl "linux", 101fc7cfb5fSfvdl linux_error, 102fc7cfb5fSfvdl linux_sendsig, 103fc7cfb5fSfvdl LINUX_SYS_syscall, 104fc7cfb5fSfvdl LINUX_SYS_MAXSYSCALL, 105fc7cfb5fSfvdl linux_sysent, 106fc7cfb5fSfvdl linux_syscallnames, 107fc7cfb5fSfvdl LINUX_ELF_AUX_ARGSIZ, 1089c3e274cScgd elf32_copyargs, 10972623d84Smycroft linux_setregs, 11044eef7c2Schristos linux_sigcode, 11144eef7c2Schristos linux_esigcode, 11244eef7c2Schristos }; 11344eef7c2Schristos 11444eef7c2Schristos 11544eef7c2Schristos static void * 116fc7cfb5fSfvdl linux_aout_copyargs(pack, arginfo, stack, argp) 11744eef7c2Schristos struct exec_package *pack; 11844eef7c2Schristos struct ps_strings *arginfo; 11944eef7c2Schristos void *stack; 12044eef7c2Schristos void *argp; 12144eef7c2Schristos { 12244eef7c2Schristos char **cpp = stack; 12344eef7c2Schristos char **stk = stack; 12444eef7c2Schristos char *dp, *sp; 12544eef7c2Schristos size_t len; 12644eef7c2Schristos void *nullp = NULL; 12744eef7c2Schristos int argc = arginfo->ps_nargvstr; 12844eef7c2Schristos int envc = arginfo->ps_nenvstr; 12944eef7c2Schristos 13044eef7c2Schristos if (copyout(&argc, cpp++, sizeof(argc))) 13144eef7c2Schristos return NULL; 13244eef7c2Schristos 13344eef7c2Schristos /* leave room for envp and argv */ 13444eef7c2Schristos cpp += 2; 13544eef7c2Schristos if (copyout(&cpp, &stk[1], sizeof (cpp))) 13644eef7c2Schristos return NULL; 13744eef7c2Schristos 13844eef7c2Schristos dp = (char *) (cpp + argc + envc + 2); 13944eef7c2Schristos sp = argp; 14044eef7c2Schristos 14144eef7c2Schristos /* XXX don't copy them out, remap them! */ 142bfd22ffdSmycroft arginfo->ps_argvstr = cpp; /* remember location of argv for later */ 14344eef7c2Schristos 14444eef7c2Schristos for (; --argc >= 0; sp += len, dp += len) 14544eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 14644eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 14744eef7c2Schristos return NULL; 14844eef7c2Schristos 14944eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 15044eef7c2Schristos return NULL; 15144eef7c2Schristos 15244eef7c2Schristos if (copyout(&cpp, &stk[2], sizeof (cpp))) 15344eef7c2Schristos return NULL; 15444eef7c2Schristos 155bfd22ffdSmycroft arginfo->ps_envstr = cpp; /* remember location of envp for later */ 15644eef7c2Schristos 15744eef7c2Schristos for (; --envc >= 0; sp += len, dp += len) 15844eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 15944eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 16044eef7c2Schristos return NULL; 16144eef7c2Schristos 16244eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 16344eef7c2Schristos return NULL; 16444eef7c2Schristos 16544eef7c2Schristos return cpp; 16644eef7c2Schristos } 16744eef7c2Schristos 1683bf459f3Sfvdl int 1693bf459f3Sfvdl exec_linux_aout_makecmds(p, epp) 1703bf459f3Sfvdl struct proc *p; 1713bf459f3Sfvdl struct exec_package *epp; 1723bf459f3Sfvdl { 1733bf459f3Sfvdl struct exec *linux_ep = epp->ep_hdr; 1743bf459f3Sfvdl int machtype, magic; 1753bf459f3Sfvdl int error = ENOEXEC; 1763bf459f3Sfvdl 1773bf459f3Sfvdl magic = LINUX_N_MAGIC(linux_ep); 1783bf459f3Sfvdl machtype = LINUX_N_MACHTYPE(linux_ep); 1793bf459f3Sfvdl 1803bf459f3Sfvdl 1813bf459f3Sfvdl if (machtype != LINUX_MID_MACHINE) 1823bf459f3Sfvdl return (ENOEXEC); 1833bf459f3Sfvdl 1843bf459f3Sfvdl switch (magic) { 1853bf459f3Sfvdl case QMAGIC: 1863bf459f3Sfvdl error = exec_linux_aout_prep_qmagic(p, epp); 1873bf459f3Sfvdl break; 1883bf459f3Sfvdl case ZMAGIC: 1893bf459f3Sfvdl error = exec_linux_aout_prep_zmagic(p, epp); 1903bf459f3Sfvdl break; 1913bf459f3Sfvdl case NMAGIC: 1923bf459f3Sfvdl error = exec_linux_aout_prep_nmagic(p, epp); 1933bf459f3Sfvdl break; 1943bf459f3Sfvdl case OMAGIC: 1953bf459f3Sfvdl error = exec_linux_aout_prep_omagic(p, epp); 1963bf459f3Sfvdl break; 1973bf459f3Sfvdl } 19844eef7c2Schristos if (error == 0) 199fc7cfb5fSfvdl epp->ep_emul = &emul_linux_aout; 2003bf459f3Sfvdl return error; 2013bf459f3Sfvdl } 2023bf459f3Sfvdl 2033bf459f3Sfvdl /* 2043bf459f3Sfvdl * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 2053bf459f3Sfvdl * is very likely not page aligned on most architectures, it is treated 2063bf459f3Sfvdl * as an NMAGIC here. XXX 2073bf459f3Sfvdl */ 2083bf459f3Sfvdl 2093bf459f3Sfvdl int 2103bf459f3Sfvdl exec_linux_aout_prep_zmagic(p, epp) 2113bf459f3Sfvdl struct proc *p; 2123bf459f3Sfvdl struct exec_package *epp; 2133bf459f3Sfvdl { 2143bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2153bf459f3Sfvdl 2163bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 2173bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2183bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 2193bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2203bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2213bf459f3Sfvdl 2223bf459f3Sfvdl /* set up command for text segment */ 2233bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2243bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 2253bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2263bf459f3Sfvdl 2273bf459f3Sfvdl /* set up command for data segment */ 2283bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2293bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 2303bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2313bf459f3Sfvdl 2323bf459f3Sfvdl /* set up command for bss segment */ 2333bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 2343bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 2353bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2363bf459f3Sfvdl 2373bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2383bf459f3Sfvdl } 2393bf459f3Sfvdl 2403bf459f3Sfvdl /* 2413bf459f3Sfvdl * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 2423bf459f3Sfvdl * Not different from the normal stuff. 2433bf459f3Sfvdl */ 2443bf459f3Sfvdl 2453bf459f3Sfvdl int 2463bf459f3Sfvdl exec_linux_aout_prep_nmagic(p, epp) 2473bf459f3Sfvdl struct proc *p; 2483bf459f3Sfvdl struct exec_package *epp; 2493bf459f3Sfvdl { 2503bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2513bf459f3Sfvdl long bsize, baddr; 2523bf459f3Sfvdl 2533bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 2543bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2553bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 2563bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2573bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2583bf459f3Sfvdl 2593bf459f3Sfvdl /* set up command for text segment */ 2603bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2613bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 2623bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2633bf459f3Sfvdl 2643bf459f3Sfvdl /* set up command for data segment */ 2653bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2663bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 2673bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2683bf459f3Sfvdl 2693bf459f3Sfvdl /* set up command for bss segment */ 2703bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 2713bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 2723bf459f3Sfvdl if (bsize > 0) 2733bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 2743bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2753bf459f3Sfvdl 2763bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2773bf459f3Sfvdl } 2783bf459f3Sfvdl 2793bf459f3Sfvdl /* 2803bf459f3Sfvdl * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 2813bf459f3Sfvdl * Business as usual. 2823bf459f3Sfvdl */ 2833bf459f3Sfvdl 2843bf459f3Sfvdl int 2853bf459f3Sfvdl exec_linux_aout_prep_omagic(p, epp) 2863bf459f3Sfvdl struct proc *p; 2873bf459f3Sfvdl struct exec_package *epp; 2883bf459f3Sfvdl { 2893bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2903bf459f3Sfvdl long dsize, bsize, baddr; 2913bf459f3Sfvdl 2923bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 2933bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2943bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 2953bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2963bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2973bf459f3Sfvdl 2983bf459f3Sfvdl /* set up command for text and data segments */ 2993bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 3003bf459f3Sfvdl execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 3013bf459f3Sfvdl LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3023bf459f3Sfvdl 3033bf459f3Sfvdl /* set up command for bss segment */ 3043bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 3053bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 3063bf459f3Sfvdl if (bsize > 0) 3073bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 3083bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3093bf459f3Sfvdl 3103bf459f3Sfvdl /* 3113bf459f3Sfvdl * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 3123bf459f3Sfvdl * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 3133bf459f3Sfvdl * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 3143bf459f3Sfvdl * respectively to page boundaries. 3153bf459f3Sfvdl * Compensate `ep_dsize' for the amount of data covered by the last 3163bf459f3Sfvdl * text page. 3173bf459f3Sfvdl */ 3183bf459f3Sfvdl dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG); 3193bf459f3Sfvdl epp->ep_dsize = (dsize > 0) ? dsize : 0; 3203bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3213bf459f3Sfvdl } 3223bf459f3Sfvdl 3233bf459f3Sfvdl int 3243bf459f3Sfvdl exec_linux_aout_prep_qmagic(p, epp) 3253bf459f3Sfvdl struct proc *p; 3263bf459f3Sfvdl struct exec_package *epp; 3273bf459f3Sfvdl { 3283bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 3293bf459f3Sfvdl 3303bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 3313bf459f3Sfvdl epp->ep_tsize = execp->a_text; 3323bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 3333bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 3343bf459f3Sfvdl epp->ep_entry = execp->a_entry; 3353bf459f3Sfvdl 3363bf459f3Sfvdl /* 3373bf459f3Sfvdl * check if vnode is in open for writing, because we want to 3383bf459f3Sfvdl * demand-page out of it. if it is, don't do it, for various 3393bf459f3Sfvdl * reasons 3403bf459f3Sfvdl */ 3413bf459f3Sfvdl if ((execp->a_text != 0 || execp->a_data != 0) && 3423bf459f3Sfvdl epp->ep_vp->v_writecount != 0) { 3433bf459f3Sfvdl #ifdef DIAGNOSTIC 3443bf459f3Sfvdl if (epp->ep_vp->v_flag & VTEXT) 3453bf459f3Sfvdl panic("exec: a VTEXT vnode has writecount != 0\n"); 3463bf459f3Sfvdl #endif 3473bf459f3Sfvdl return ETXTBSY; 3483bf459f3Sfvdl } 3493bf459f3Sfvdl epp->ep_vp->v_flag |= VTEXT; 3503bf459f3Sfvdl 3513bf459f3Sfvdl /* set up command for text segment */ 3523bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 3533bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 3543bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 3553bf459f3Sfvdl 3563bf459f3Sfvdl /* set up command for data segment */ 3573bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 3583bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 3593bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3603bf459f3Sfvdl 3613bf459f3Sfvdl /* set up command for bss segment */ 3623bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 3633bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 3643bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3653bf459f3Sfvdl 3663bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3673bf459f3Sfvdl } 3683bf459f3Sfvdl 3694d9a6e09Schristos /* 3704d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 3714d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 3724d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 3734d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 3744d9a6e09Schristos * but we check all the progbits headers. 3754d9a6e09Schristos */ 3764d9a6e09Schristos static int 3779c3e274cScgd linux_elf32_signature(p, epp, eh) 378fc7cfb5fSfvdl struct proc *p; 379fc7cfb5fSfvdl struct exec_package *epp; 3804d9a6e09Schristos Elf32_Ehdr *eh; 3814d9a6e09Schristos { 3824d9a6e09Schristos size_t shsize = sizeof(Elf32_Shdr) * eh->e_shnum; 3834d9a6e09Schristos size_t i; 3844d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 3854d9a6e09Schristos char buf[sizeof(signature) - 1]; 3864d9a6e09Schristos Elf32_Shdr *sh; 3874d9a6e09Schristos int error; 3884d9a6e09Schristos 3894d9a6e09Schristos sh = (Elf32_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 3904d9a6e09Schristos 3919c3e274cScgd if ((error = elf32_read_from(p, epp->ep_vp, eh->e_shoff, 3924d9a6e09Schristos (caddr_t) sh, shsize)) != 0) 3934d9a6e09Schristos goto out; 3944d9a6e09Schristos 3954d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 3964d9a6e09Schristos Elf32_Shdr *s = &sh[i]; 3974d9a6e09Schristos 3984d9a6e09Schristos /* 3994d9a6e09Schristos * Identify candidates for the comment header; 400d83602c1Schristos * Header cannot have a load address, or flags and 4014d9a6e09Schristos * it must be large enough. 4024d9a6e09Schristos */ 403fb2727b7Sjtk if (s->sh_type != Elf_sht_progbits || 4044d9a6e09Schristos s->sh_addr != 0 || 4054d9a6e09Schristos s->sh_flags != 0 || 4064d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 4074d9a6e09Schristos continue; 4084d9a6e09Schristos 4099c3e274cScgd if ((error = elf32_read_from(p, epp->ep_vp, s->sh_offset, 410d83602c1Schristos (caddr_t) buf, sizeof(signature) - 1)) != 0) 4114d9a6e09Schristos goto out; 4124d9a6e09Schristos 413d83602c1Schristos /* 414d83602c1Schristos * error is 0, if the signatures match we are done. 415d83602c1Schristos */ 416*e1601dc2Sperry if (memcmp(buf, signature, sizeof(signature) - 1) == 0) 4174d9a6e09Schristos goto out; 4184d9a6e09Schristos } 4194d9a6e09Schristos error = EFTYPE; 4204d9a6e09Schristos 4214d9a6e09Schristos out: 4224d9a6e09Schristos free(sh, M_TEMP); 4234d9a6e09Schristos return error; 4244d9a6e09Schristos } 4254d9a6e09Schristos 4264d9a6e09Schristos int 4279c3e274cScgd linux_elf32_probe(p, epp, eh, itp, pos) 4284d9a6e09Schristos struct proc *p; 4294d9a6e09Schristos struct exec_package *epp; 4304d9a6e09Schristos Elf32_Ehdr *eh; 431c4aaa600Sfvdl char *itp; 4329c3e274cScgd Elf32_Addr *pos; 433fc7cfb5fSfvdl { 434c4aaa600Sfvdl char *bp; 435fc7cfb5fSfvdl int error; 436c4aaa600Sfvdl size_t len; 437fc7cfb5fSfvdl 4389c3e274cScgd if ((error = linux_elf32_signature(p, epp, eh)) != 0) 4394d9a6e09Schristos return error; 4404d9a6e09Schristos 441c4aaa600Sfvdl if (itp[0]) { 4426b95b513Schristos if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) 443c4aaa600Sfvdl return error; 444c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 445c4aaa600Sfvdl return error; 446c4aaa600Sfvdl free(bp, M_TEMP); 447fc7cfb5fSfvdl } 448fc7cfb5fSfvdl epp->ep_emul = &emul_linux_elf; 449c4aaa600Sfvdl *pos = ELF32_NO_ADDR; 450c4aaa600Sfvdl return 0; 451fc7cfb5fSfvdl } 452c4aaa600Sfvdl 453fc7cfb5fSfvdl /* 454fc7cfb5fSfvdl * The Linux system call to load shared libraries, a.out version. The 455fc7cfb5fSfvdl * a.out shared libs are just files that are mapped onto a fixed 456fc7cfb5fSfvdl * address in the process' address space. The address is given in 4573bf459f3Sfvdl * a_entry. Read in the header, set up some VM commands and run them. 4583bf459f3Sfvdl * 4593bf459f3Sfvdl * Yes, both text and data are mapped at once, so we're left with 4603bf459f3Sfvdl * writeable text for the shared libs. The Linux crt0 seemed to break 4613bf459f3Sfvdl * sometimes when data was mapped seperately. It munmapped a uselib() 4623bf459f3Sfvdl * of ld.so by hand, which failed with shared text and data for ld.so 4633bf459f3Sfvdl * Yuck. 4643bf459f3Sfvdl * 4653bf459f3Sfvdl * Because of the problem with ZMAGIC executables (text starts 466fc7cfb5fSfvdl * at 0x400 in the file, but needs to be mapped at 0), ZMAGIC 4673bf459f3Sfvdl * shared libs are not handled very efficiently :-( 4683bf459f3Sfvdl */ 4693bf459f3Sfvdl 4703bf459f3Sfvdl int 471245f292fSmycroft linux_sys_uselib(p, v, retval) 4723bf459f3Sfvdl struct proc *p; 473e1da0d53Sthorpej void *v; 4743bf459f3Sfvdl register_t *retval; 4753bf459f3Sfvdl { 476245f292fSmycroft struct linux_sys_uselib_args /* { 477e1da0d53Sthorpej syscallarg(char *) path; 478e1da0d53Sthorpej } */ *uap = v; 4793bf459f3Sfvdl caddr_t sg; 4803bf459f3Sfvdl long bsize, dsize, tsize, taddr, baddr, daddr; 4813bf459f3Sfvdl struct nameidata ni; 4823bf459f3Sfvdl struct vnode *vp; 4833bf459f3Sfvdl struct exec hdr; 4843bf459f3Sfvdl struct exec_vmcmd_set vcset; 48537b70b30Sthorpej int i, magic, error; 48637b70b30Sthorpej size_t rem; 4873bf459f3Sfvdl 4886b95b513Schristos sg = stackgap_init(p->p_emul); 4896b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 4903bf459f3Sfvdl 4913bf459f3Sfvdl NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 4923bf459f3Sfvdl 4933bf459f3Sfvdl if ((error = namei(&ni))) 4943bf459f3Sfvdl return error; 4953bf459f3Sfvdl 4963bf459f3Sfvdl vp = ni.ni_vp; 4973bf459f3Sfvdl 4983bf459f3Sfvdl if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE, 4993bf459f3Sfvdl 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, 5003bf459f3Sfvdl &rem, p))) { 5013bf459f3Sfvdl vrele(vp); 5023bf459f3Sfvdl return error; 5033bf459f3Sfvdl } 5043bf459f3Sfvdl 5053bf459f3Sfvdl if (rem != 0) { 5063bf459f3Sfvdl vrele(vp); 5073bf459f3Sfvdl return ENOEXEC; 5083bf459f3Sfvdl } 5093bf459f3Sfvdl 510fc7cfb5fSfvdl if (LINUX_N_MACHTYPE(&hdr) != LINUX_MID_MACHINE) 511fc7cfb5fSfvdl return ENOEXEC; 512fc7cfb5fSfvdl 5133bf459f3Sfvdl magic = LINUX_N_MAGIC(&hdr); 5143bf459f3Sfvdl taddr = hdr.a_entry & (~(NBPG - 1)); 5153bf459f3Sfvdl tsize = hdr.a_text; 5163bf459f3Sfvdl daddr = taddr + tsize; 5173bf459f3Sfvdl dsize = hdr.a_data + hdr.a_bss; 5183bf459f3Sfvdl 5193bf459f3Sfvdl if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) { 5203bf459f3Sfvdl vrele(vp); 5213bf459f3Sfvdl return ETXTBSY; 5223bf459f3Sfvdl } 5233bf459f3Sfvdl vp->v_flag |= VTEXT; 5243bf459f3Sfvdl 5253bf459f3Sfvdl vcset.evs_cnt = 0; 5263bf459f3Sfvdl vcset.evs_used = 0; 5273bf459f3Sfvdl 5283bf459f3Sfvdl NEW_VMCMD(&vcset, 5293bf459f3Sfvdl magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn, 5303bf459f3Sfvdl hdr.a_text + hdr.a_data, taddr, 5313bf459f3Sfvdl vp, LINUX_N_TXTOFF(hdr, magic), 5323bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE); 5333bf459f3Sfvdl 5343bf459f3Sfvdl baddr = roundup(daddr + hdr.a_data, NBPG); 5353bf459f3Sfvdl bsize = daddr + dsize - baddr; 5363bf459f3Sfvdl if (bsize > 0) { 5373bf459f3Sfvdl NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr, 5383bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 5393bf459f3Sfvdl } 5403bf459f3Sfvdl 5413bf459f3Sfvdl for (i = 0; i < vcset.evs_used && !error; i++) { 5423bf459f3Sfvdl struct exec_vmcmd *vcp; 5433bf459f3Sfvdl 5443bf459f3Sfvdl vcp = &vcset.evs_cmds[i]; 5453bf459f3Sfvdl error = (*vcp->ev_proc)(p, vcp); 5463bf459f3Sfvdl } 5473bf459f3Sfvdl 5483bf459f3Sfvdl kill_vmcmds(&vcset); 5493bf459f3Sfvdl 5503bf459f3Sfvdl vrele(vp); 5513bf459f3Sfvdl 5523bf459f3Sfvdl return error; 5533bf459f3Sfvdl } 5543bf459f3Sfvdl 5553bf459f3Sfvdl /* 5563bf459f3Sfvdl * Execve(2). Just check the alternate emulation path, and pass it on 5573bf459f3Sfvdl * to the NetBSD execve(). 5583bf459f3Sfvdl */ 5593bf459f3Sfvdl int 560245f292fSmycroft linux_sys_execve(p, v, retval) 5613bf459f3Sfvdl struct proc *p; 562e1da0d53Sthorpej void *v; 563e1da0d53Sthorpej register_t *retval; 564e1da0d53Sthorpej { 565245f292fSmycroft struct linux_sys_execve_args /* { 5663bf459f3Sfvdl syscallarg(char *) path; 5673bf459f3Sfvdl syscallarg(char **) argv; 5683bf459f3Sfvdl syscallarg(char **) envp; 569e1da0d53Sthorpej } */ *uap = v; 570a8fd2576Smycroft struct sys_execve_args ap; 5713bf459f3Sfvdl caddr_t sg; 5723bf459f3Sfvdl 5736b95b513Schristos sg = stackgap_init(p->p_emul); 5746b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 5753bf459f3Sfvdl 576a8fd2576Smycroft SCARG(&ap, path) = SCARG(uap, path); 577a8fd2576Smycroft SCARG(&ap, argp) = SCARG(uap, argp); 578a8fd2576Smycroft SCARG(&ap, envp) = SCARG(uap, envp); 579a8fd2576Smycroft 580a8fd2576Smycroft return sys_execve(p, &ap, retval); 5813bf459f3Sfvdl } 582