From 7d151a09c3f9613590f35dad81c77959e4f34381 Mon Sep 17 00:00:00 2001 From: sos Date: Sun, 10 Mar 1996 08:42:54 +0000 Subject: First attempt at FreeBSD & Linux ELF support. Compile and link a new kernel, that will give native ELF support, and provide the hooks for other ELF interpreters as well. To make native ELF binaries use John Polstras elf-kit-1.0.1.. For the time being also use his ld-elf.so.1 and put it in /usr/libexec. The Linux emulator has been enhanced to also run ELF binaries, it is however in its very first incarnation. Just get some Linux ELF libs (Slackware-3.0) and put them in the prober place (/compat/linux/...). I've ben able to run all the Slackware-3.0 binaries I've tried so far. (No it won't run quake yet :) --- lkm/linux/Makefile | 4 +- lkm/linux/linux.c | 14 +- sys/alpha/linux/linux.h | 14 +- sys/alpha/linux/linux_sysvec.c | 166 ++++++---- sys/compat/linux/linux_util.h | 4 +- sys/conf/files | 1 + sys/i386/linux/imgact_linux.c | 6 +- sys/i386/linux/linux.h | 14 +- sys/i386/linux/linux_sysvec.c | 166 ++++++---- sys/i386/linux/linux_util.h | 4 +- sys/kern/imgact_elf.c | 705 +++++++++++++++++++++++++++++++++++++++++ sys/kern/kern_exec.c | 23 +- sys/modules/linux/Makefile | 4 +- sys/modules/linux/linux.c | 14 +- sys/sys/imgact.h | 3 +- sys/sys/imgact_elf.h | 213 +++++++++++++ 16 files changed, 1205 insertions(+), 150 deletions(-) create mode 100644 sys/kern/imgact_elf.c create mode 100644 sys/sys/imgact_elf.h diff --git a/lkm/linux/Makefile b/lkm/linux/Makefile index 7c7074c..e544b7f 100644 --- a/lkm/linux/Makefile +++ b/lkm/linux/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 1996/01/27 23:57:06 rgrimes Exp $ +# $Id: Makefile,v 1.6 1996/03/02 20:00:35 peter Exp $ .PATH: ${.CURDIR}/../../sys/i386/linux KMOD= linux_mod @@ -11,7 +11,7 @@ NOMAN= CFLAGS+= -DLKM -I. -DCOMPAT_43 -DCOMPAT_LINUX #-DDEBUG CPPFLAGS= -I. -I${.CURDIR}/../../sys - +EXPORT_SYMS=_linux_mod CLEANFILES+= vnode_if.h vnode_if.c linux_genassym.o linux_genassym machine \ linux_assym.h diff --git a/lkm/linux/linux.c b/lkm/linux/linux.c index 67faa18..dbd319f 100644 --- a/lkm/linux/linux.c +++ b/lkm/linux/linux.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux.c,v 1.3 1995/11/13 07:18:38 bde Exp $ + * $Id: linux.c,v 1.4 1995/11/14 07:34:18 bde Exp $ */ #include @@ -34,14 +34,24 @@ #include #include #include +#include +#include "i386/linux/linux.h" extern const struct execsw linux_execsw; MOD_EXEC(linux, -1, (struct execsw*)&linux_execsw); +static Elf32_Interp_info linux_interp = { + &elf_linux_sysvec, + "/lib/ld-linux.so.1", + "/compat/linux" + }; + static int linux_load(struct lkm_table *lkmtp, int cmd) { + if (elf_insert_interp(&linux_interp)) + uprintf("Could not install ELF interpreter entry\n"); uprintf("Linux emulator installed\n"); return 0; } @@ -49,6 +59,8 @@ linux_load(struct lkm_table *lkmtp, int cmd) static int linux_unload(struct lkm_table *lkmtp, int cmd) { + if (elf_remove_interp(&linux_interp)) + uprintf("Could not deinstall ELF interpreter entry\n"); uprintf("Linux emulator removed\n"); return 0; } diff --git a/sys/alpha/linux/linux.h b/sys/alpha/linux/linux.h index af0eb04..cf97265 100644 --- a/sys/alpha/linux/linux.h +++ b/sys/alpha/linux/linux.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994-1995 Søren Schmidt + * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,11 +25,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux.h,v 1.5 1996/03/02 19:37:47 peter Exp $ + * $Id: linux.h,v 1.6 1996/03/03 19:07:49 peter Exp $ */ #ifndef _I386_LINUX_LINUX_H_ #define _I386_LINUX_LINUX_H_ +#include "i386/linux/linux_syscall.h" typedef unsigned short linux_uid_t; typedef unsigned short linux_gid_t; @@ -97,13 +98,20 @@ struct linux_sigframe { sig_t sf_handler; }; +extern int bsd_to_linux_errno[]; extern int bsd_to_linux_signal[]; extern int linux_to_bsd_signal[]; +extern char linux_sigcode[]; +extern int linux_szsigcode; +extern const char linux_emul_path[]; +extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; extern struct sysentvec linux_sysvec; +extern struct sysentvec elf_linux_sysvec; +/* dummy struct definitions */ struct image_params; -int linux_fixup __P((int **stack_base, struct image_params *iparams)); +struct trapframe; /* misc defines */ #define LINUX_NAME_MAX 255 diff --git a/sys/alpha/linux/linux_sysvec.c b/sys/alpha/linux/linux_sysvec.c index 9278102..e7a72ae 100644 --- a/sys/alpha/linux/linux_sysvec.c +++ b/sys/alpha/linux/linux_sysvec.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994-1995 Søren Schmidt + * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux_sysent.c,v 1.4 1996/01/14 10:59:57 sos Exp $ + * $Id: linux_sysvec.c,v 1.1 1996/03/02 19:38:01 peter Exp $ */ /* XXX we use functions that might not exist. */ @@ -36,7 +36,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -59,62 +61,93 @@ #include #include -#include + +int linux_fixup __P((int **stack_base, struct image_params *iparams)); +int elf_linux_fixup __P((int **stack_base, struct image_params *iparams)); +void linux_prepsyscall __P((struct trapframe *tf, int *args, u_int *code, caddr_t *params)); +void linux_sendsig __P((sig_t catcher, int sig, int mask, unsigned code)); /* * Linux syscalls return negative errno's, we do positive and map them */ int bsd_to_linux_errno[ELAST] = { - -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, - -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, - -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, - -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, - -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, - -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, - -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, - -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, - -6, + -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, + -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, + -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, + -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, + -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, + -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, + -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, + -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, + -6, }; int bsd_to_linux_signal[NSIG] = { - 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, - LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, - LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, - 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, - LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, - LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, - LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, - LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 + 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, + LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, + LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, + 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, + LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, + LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, + LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, + LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 }; int linux_to_bsd_signal[LINUX_NSIG] = { - 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, - SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, - SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO, - SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0 + 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, + SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, + SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO, + SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0 }; int linux_fixup(int **stack_base, struct image_params *imgp) { - int *argv, *envp; - - argv = *stack_base; - envp = *stack_base + (imgp->argc + 1); - (*stack_base)--; - **stack_base = (int)envp; - (*stack_base)--; - **stack_base = (int)argv; - (*stack_base)--; - **stack_base = (int)imgp->argc; - return 0; /* XXX */ + int *argv, *envp; + + argv = *stack_base; + envp = *stack_base + (imgp->argc + 1); + (*stack_base)--; + **stack_base = (int)envp; + (*stack_base)--; + **stack_base = (int)argv; + (*stack_base)--; + **stack_base = (int)imgp->argc; + return 0; } -extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; +int elf_linux_fixup(int **stack_base, struct image_params *imgp) +{ + Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; + int *pos; + + pos = *stack_base + (imgp->argc + imgp->envc + 2); + + if (args->trace) { + AUXARGS_ENTRY(pos, AT_DEBUG, 1); + } + if (args->execfd != -1) { + AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); + } + AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); + AUXARGS_ENTRY(pos, AT_PHENT, args->phent); + AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); + AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); + AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); + AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); + AUXARGS_ENTRY(pos, AT_BASE, args->base); + AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid); + AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid); + AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid); + AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid); + AUXARGS_ENTRY(pos, AT_NULL, 0); + + free(imgp->auxargs, M_TEMP); + imgp->auxargs = NULL; -static void linux_sendsig(sig_t action, - int sig, - int returnmask, - unsigned code); + (*stack_base)--; + **stack_base = (int)imgp->argc; + return 0; +} extern int _ucodesel, _udatasel; @@ -129,12 +162,8 @@ extern int _ucodesel, _udatasel; * specified pc, psl. */ -static void -linux_sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig; - int mask; - unsigned code; +void +linux_sendsig(sig_t catcher, int sig, int mask, unsigned code) { register struct proc *p = curproc; register int *regs; @@ -327,7 +356,7 @@ linux_sigreturn(p, args, retval) return (EJUSTRETURN); } -static void +void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) { int i; @@ -339,20 +368,33 @@ linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) *params = NULL; /* no copyin */ } -extern char linux_sigcode[]; -extern int linux_szsigcode; - struct sysentvec linux_sysvec = { - sizeof (linux_sysent) / sizeof(linux_sysent[0]), - linux_sysent, - 0xff, - NSIG, - bsd_to_linux_signal, - ELAST, - bsd_to_linux_errno, - linux_fixup, - linux_sendsig, - linux_sigcode, - &linux_szsigcode, - linux_prepsyscall, + LINUX_SYS_MAXSYSCALL, + linux_sysent, + 0xff, + NSIG, + bsd_to_linux_signal, + ELAST, + bsd_to_linux_errno, + linux_fixup, + linux_sendsig, + linux_sigcode, + &linux_szsigcode, + linux_prepsyscall, +}; + +struct sysentvec elf_linux_sysvec = { + LINUX_SYS_MAXSYSCALL, + linux_sysent, + 0xff, + NSIG, + bsd_to_linux_signal, + ELAST, + bsd_to_linux_errno, + elf_linux_fixup, + linux_sendsig, + linux_sigcode, + &linux_szsigcode, + linux_prepsyscall, }; + diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h index 46edfc5..6a09cf3 100644 --- a/sys/compat/linux/linux_util.h +++ b/sys/compat/linux/linux_util.h @@ -28,7 +28,7 @@ * * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp - * $Id$ + * $Id: linux_util.h,v 1.1 1996/03/02 19:38:02 peter Exp $ */ /* @@ -78,8 +78,6 @@ stackgap_alloc(sgp, sz) #define DPRINTF(a) #endif -extern const char linux_emul_path[]; - int linux_emul_find __P((struct proc *, caddr_t *, const char *, char *, char **, int)); diff --git a/sys/conf/files b/sys/conf/files index 4f383ab..35858a2 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -42,6 +42,7 @@ kdb/kdb_runpcs.c optional kadb kdb/kdb_sym.c optional kadb kdb/kdb_trap.c optional kadb kern/imgact_aout.c standard +kern/imgact_elf.c standard kern/imgact_gzip.c optional gzip kern/imgact_shell.c standard kern/inflate.c optional gzip diff --git a/sys/i386/linux/imgact_linux.c b/sys/i386/linux/imgact_linux.c index 9d6906d..e070aa2 100644 --- a/sys/i386/linux/imgact_linux.c +++ b/sys/i386/linux/imgact_linux.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994-1995 Søren Schmidt + * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Based heavily on /sys/kern/imgact_aout.c which is: @@ -28,7 +28,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: imgact_linux.c,v 1.8 1996/02/16 18:40:48 peter Exp $ + * $Id: imgact_linux.c,v 1.9 1996/03/02 19:37:47 peter Exp $ */ #include @@ -227,6 +227,6 @@ exec_linux_imgact(imgp) * Since `const' objects end up in the text segment, TEXT_SET is the * correct directive to use. */ -const struct execsw linux_execsw = { exec_linux_imgact, "linux" }; +const struct execsw linux_execsw = { exec_linux_imgact, "linux a.out" }; TEXT_SET(execsw_set, linux_execsw); diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h index af0eb04..cf97265 100644 --- a/sys/i386/linux/linux.h +++ b/sys/i386/linux/linux.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994-1995 Søren Schmidt + * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,11 +25,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux.h,v 1.5 1996/03/02 19:37:47 peter Exp $ + * $Id: linux.h,v 1.6 1996/03/03 19:07:49 peter Exp $ */ #ifndef _I386_LINUX_LINUX_H_ #define _I386_LINUX_LINUX_H_ +#include "i386/linux/linux_syscall.h" typedef unsigned short linux_uid_t; typedef unsigned short linux_gid_t; @@ -97,13 +98,20 @@ struct linux_sigframe { sig_t sf_handler; }; +extern int bsd_to_linux_errno[]; extern int bsd_to_linux_signal[]; extern int linux_to_bsd_signal[]; +extern char linux_sigcode[]; +extern int linux_szsigcode; +extern const char linux_emul_path[]; +extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; extern struct sysentvec linux_sysvec; +extern struct sysentvec elf_linux_sysvec; +/* dummy struct definitions */ struct image_params; -int linux_fixup __P((int **stack_base, struct image_params *iparams)); +struct trapframe; /* misc defines */ #define LINUX_NAME_MAX 255 diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 9278102..e7a72ae 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994-1995 Søren Schmidt + * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux_sysent.c,v 1.4 1996/01/14 10:59:57 sos Exp $ + * $Id: linux_sysvec.c,v 1.1 1996/03/02 19:38:01 peter Exp $ */ /* XXX we use functions that might not exist. */ @@ -36,7 +36,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -59,62 +61,93 @@ #include #include -#include + +int linux_fixup __P((int **stack_base, struct image_params *iparams)); +int elf_linux_fixup __P((int **stack_base, struct image_params *iparams)); +void linux_prepsyscall __P((struct trapframe *tf, int *args, u_int *code, caddr_t *params)); +void linux_sendsig __P((sig_t catcher, int sig, int mask, unsigned code)); /* * Linux syscalls return negative errno's, we do positive and map them */ int bsd_to_linux_errno[ELAST] = { - -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, - -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, - -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, - -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, - -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, - -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, - -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, - -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, - -6, + -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, + -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, + -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, + -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, + -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, + -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, + -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, + -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, + -6, }; int bsd_to_linux_signal[NSIG] = { - 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, - LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, - LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, - 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, - LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, - LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, - LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, - LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 + 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, + LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, + LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, + 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, + LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, + LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, + LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, + LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 }; int linux_to_bsd_signal[LINUX_NSIG] = { - 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, - SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, - SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO, - SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0 + 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, + SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, + SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO, + SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0 }; int linux_fixup(int **stack_base, struct image_params *imgp) { - int *argv, *envp; - - argv = *stack_base; - envp = *stack_base + (imgp->argc + 1); - (*stack_base)--; - **stack_base = (int)envp; - (*stack_base)--; - **stack_base = (int)argv; - (*stack_base)--; - **stack_base = (int)imgp->argc; - return 0; /* XXX */ + int *argv, *envp; + + argv = *stack_base; + envp = *stack_base + (imgp->argc + 1); + (*stack_base)--; + **stack_base = (int)envp; + (*stack_base)--; + **stack_base = (int)argv; + (*stack_base)--; + **stack_base = (int)imgp->argc; + return 0; } -extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; +int elf_linux_fixup(int **stack_base, struct image_params *imgp) +{ + Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; + int *pos; + + pos = *stack_base + (imgp->argc + imgp->envc + 2); + + if (args->trace) { + AUXARGS_ENTRY(pos, AT_DEBUG, 1); + } + if (args->execfd != -1) { + AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); + } + AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); + AUXARGS_ENTRY(pos, AT_PHENT, args->phent); + AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); + AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); + AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); + AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); + AUXARGS_ENTRY(pos, AT_BASE, args->base); + AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid); + AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid); + AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid); + AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid); + AUXARGS_ENTRY(pos, AT_NULL, 0); + + free(imgp->auxargs, M_TEMP); + imgp->auxargs = NULL; -static void linux_sendsig(sig_t action, - int sig, - int returnmask, - unsigned code); + (*stack_base)--; + **stack_base = (int)imgp->argc; + return 0; +} extern int _ucodesel, _udatasel; @@ -129,12 +162,8 @@ extern int _ucodesel, _udatasel; * specified pc, psl. */ -static void -linux_sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig; - int mask; - unsigned code; +void +linux_sendsig(sig_t catcher, int sig, int mask, unsigned code) { register struct proc *p = curproc; register int *regs; @@ -327,7 +356,7 @@ linux_sigreturn(p, args, retval) return (EJUSTRETURN); } -static void +void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) { int i; @@ -339,20 +368,33 @@ linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) *params = NULL; /* no copyin */ } -extern char linux_sigcode[]; -extern int linux_szsigcode; - struct sysentvec linux_sysvec = { - sizeof (linux_sysent) / sizeof(linux_sysent[0]), - linux_sysent, - 0xff, - NSIG, - bsd_to_linux_signal, - ELAST, - bsd_to_linux_errno, - linux_fixup, - linux_sendsig, - linux_sigcode, - &linux_szsigcode, - linux_prepsyscall, + LINUX_SYS_MAXSYSCALL, + linux_sysent, + 0xff, + NSIG, + bsd_to_linux_signal, + ELAST, + bsd_to_linux_errno, + linux_fixup, + linux_sendsig, + linux_sigcode, + &linux_szsigcode, + linux_prepsyscall, +}; + +struct sysentvec elf_linux_sysvec = { + LINUX_SYS_MAXSYSCALL, + linux_sysent, + 0xff, + NSIG, + bsd_to_linux_signal, + ELAST, + bsd_to_linux_errno, + elf_linux_fixup, + linux_sendsig, + linux_sigcode, + &linux_szsigcode, + linux_prepsyscall, }; + diff --git a/sys/i386/linux/linux_util.h b/sys/i386/linux/linux_util.h index 46edfc5..6a09cf3 100644 --- a/sys/i386/linux/linux_util.h +++ b/sys/i386/linux/linux_util.h @@ -28,7 +28,7 @@ * * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp - * $Id$ + * $Id: linux_util.h,v 1.1 1996/03/02 19:38:02 peter Exp $ */ /* @@ -78,8 +78,6 @@ stackgap_alloc(sgp, sz) #define DPRINTF(a) #endif -extern const char linux_emul_path[]; - int linux_emul_find __P((struct proc *, caddr_t *, const char *, char *, char **, int)); diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c new file mode 100644 index 0000000..c8bb57f --- /dev/null +++ b/sys/kern/imgact_elf.c @@ -0,0 +1,705 @@ +/*- + * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1996 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_PHDR 32 /* XXX enough ? */ + +static int read_from_vp __P((struct vnode *vp, vm_offset_t offset, caddr_t buf, vm_size_t size)); +static int map_pages __P((struct vnode *vp, vm_offset_t offset, vm_offset_t *buf, vm_size_t size)); +static void unmap_pages __P((struct vnode *vp, vm_offset_t buf, vm_size_t size)); +static int elf_check_header __P((Elf32_Ehdr *hdr, int type)); +static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)); +static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry)); +static int elf_freebsd_fixup __P((int **stack_base, struct image_params *imgp)); +int exec_elf_imgact __P((struct image_params *imgp)); + +int elf_trace = 0; +SYSCTL_INT(_debug, 1, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); +#define UPRINTF if (elf_trace) uprintf + +static struct sysentvec elf_freebsd_sysvec = { + SYS_MAXSYSCALL, + sysent, + 0, + 0, + 0, + 0, + 0, + elf_freebsd_fixup, + sendsig, + sigcode, + &szsigcode, + 0, +}; + +static Elf32_Interp_info freebsd_interp = { + &elf_freebsd_sysvec, + "/usr/libexec/ld-elf.so.1", + "" + }; +static Elf32_Interp_info *interp_list[MAX_INTERP] = { + &freebsd_interp, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL + }; + +int +elf_insert_interp(Elf32_Interp_info *entry) +{ + int i; + + for (i=1; iv_writecount) { + return (ETXTBSY); + } + + /* Get file attributes */ + error = VOP_GETATTR(vp, &attr, p->p_ucred, p); + if (error) + return (error); + + /* + * 1) Check if file execution is disabled for the filesystem that this + * file resides on. + * 2) Insure that at least one execute bit is on - otherwise root + * will always succeed, and we don't want to happen unless the + * file really is executable. + * 3) Insure that the file is a regular file. + */ + if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || + ((attr.va_mode & 0111) == 0) || + (attr.va_type != VREG)) { + return (EACCES); + } + + /* + * Zero length files can't be exec'd + */ + if (attr.va_size == 0) + return (ENOEXEC); + + /* + * Check for execute permission to file based on current credentials. + * Then call filesystem specific open routine (which does nothing + * in the general case). + */ + error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); + if (error) + return (error); + + error = VOP_OPEN(vp, FREAD, p->p_ucred, p); + if (error) + return (error); + + return (0); +} + +static int +elf_check_header(Elf32_Ehdr *hdr, int type) +{ + if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && + hdr->e_ident[EI_MAG1] == ELFMAG1 && + hdr->e_ident[EI_MAG2] == ELFMAG2 && + hdr->e_ident[EI_MAG3] == ELFMAG3)) + return ENOEXEC; + + if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) + return ENOEXEC; + + if (hdr->e_type != type) + return ENOEXEC; + + return 0; +} + +static int +elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) +{ + size_t map_len; + vm_offset_t map_addr; + int error; + unsigned char *data_buf = 0; + size_t copy_len; + + map_addr = trunc_page(vmaddr); + + if (memsz > filsz) + map_len = trunc_page(offset+filsz) - trunc_page(offset); + else + map_len = round_page(offset+filsz) - trunc_page(offset); + + if (error = vm_mmap (&vmspace->vm_map, + &map_addr, + map_len, + prot, + VM_PROT_ALL, + MAP_FILE | MAP_PRIVATE | MAP_FIXED, + (caddr_t)vp, + trunc_page(offset))) + return error; + + if (memsz == filsz) + return 0; + + /* + * We have to map the remaining bit of the file into the kernel's + * memory map, allocate some anonymous memory, and copy that last + * bit into it. The remaining space should be .bss... + */ + copy_len = (offset + filsz) - trunc_page(offset + filsz); + map_addr = trunc_page(vmaddr + filsz); + map_len = round_page(memsz) - trunc_page(filsz); + + if (map_len != 0) + if (error = vm_map_find(&vmspace->vm_map, NULL, 0, + &map_addr, map_len, FALSE, + VM_PROT_ALL, VM_PROT_ALL,0)) + return error; + + if (error = vm_mmap(kernel_map, + (vm_offset_t *)&data_buf, + PAGE_SIZE, + VM_PROT_READ, + VM_PROT_READ, + MAP_FILE, + (caddr_t)vp, + trunc_page(offset + filsz))) + return error; + + error = copyout(data_buf, (caddr_t)map_addr, copy_len); + + vm_map_remove(kernel_map, (vm_offset_t)data_buf, + (vm_offset_t)data_buf + PAGE_SIZE); + + /* + * Clear the remaining page, we dont need the potential + * garbage from the file in there. + */ + bzero((caddr_t)(map_addr+copy_len), map_len-copy_len); + UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); + return error; +} + +static int +elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) +{ + Elf32_Ehdr *hdr = NULL; + Elf32_Phdr *phdr = NULL; + struct nameidata nd; + struct vmspace *vmspace = p->p_vmspace; + vm_prot_t prot = 0; + unsigned long text_size = 0, data_size = 0; + unsigned long text_addr = 0, data_addr = 0; + int header_size = 0; + int error, i; + + NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); + + if (error = namei(&nd)) + goto fail; + + if (nd.ni_vp == NULL) { + error = ENOEXEC; + goto fail; + } + + /* + * Check permissions, modes, uid, etc on the file, and "open" it. + */ + error = elf_check_permissions(p, nd.ni_vp); + + /* + * No longer need this, and it prevents demand paging. + */ + VOP_UNLOCK(nd.ni_vp); + + if (error) + goto fail; + + /* + * Map in the header + */ + if (error = map_pages(nd.ni_vp, 0, (vm_offset_t *)&hdr, sizeof(hdr))) + goto fail; + + /* + * Do we have a valid ELF header ? + */ + if (error = elf_check_header(hdr, ET_DYN)) + goto fail; + + /* + * ouch, need to bounds check in case user gives us a corrupted + * file with an insane header size + */ + if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ + error = ENOEXEC; + goto fail; + } + + header_size = hdr->e_phentsize * hdr->e_phnum; + + if (error = map_pages(nd.ni_vp, hdr->e_phoff, (vm_offset_t *)&phdr, + header_size)) + goto fail; + + for (i = 0; i < hdr->e_phnum; i++) { + switch(phdr[i].p_type) { + + case PT_NULL: /* NULL section */ + UPRINTF ("ELF(file) PT_NULL section\n"); + break; + case PT_LOAD: /* Loadable segment */ + { + UPRINTF ("ELF(file) PT_LOAD section "); + if (phdr[i].p_flags & PF_X) + prot |= VM_PROT_EXECUTE; + if (phdr[i].p_flags & PF_W) + prot |= VM_PROT_WRITE; + if (phdr[i].p_flags & PF_R) + prot |= VM_PROT_READ; + + if (error = elf_load_section(vmspace, nd.ni_vp, + phdr[i].p_offset, + (caddr_t)phdr[i].p_vaddr + + (*addr), + phdr[i].p_memsz, + phdr[i].p_filesz, prot)) + goto fail; + + /* + * Is this .text or .data ?? + * + * We only handle one each of those yet XXX + */ + if (hdr->e_entry >= phdr[i].p_vaddr && + hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { + text_size = round_page(phdr[i].p_memsz); + text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); + *entry=(unsigned long)hdr->e_entry+(*addr); + UPRINTF(".text <%08x,%08x> entry=%08x\n", + text_addr, text_size, *entry); + } else { + data_size = round_page(phdr[i].p_memsz); + data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); + UPRINTF(".data <%08x,%08x>\n", + data_addr, data_size); + } + } + break; + + case PT_DYNAMIC:/* Dynamic link information */ + UPRINTF ("ELF(file) PT_DYNAMIC section\n"); + break; + case PT_INTERP: /* Path to interpreter */ + UPRINTF ("ELF(file) PT_INTERP section\n"); + break; + case PT_NOTE: /* Note section */ + UPRINTF ("ELF(file) PT_NOTE section\n"); + break; + case PT_SHLIB: /* Shared lib section */ + UPRINTF ("ELF(file) PT_SHLIB section\n"); + break; + case PT_PHDR: /* Program header table info */ + UPRINTF ("ELF(file) PT_PHDR section\n"); + break; + default: + UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); + } + } + +fail: + if (phdr) + unmap_pages(nd.ni_vp, (vm_offset_t)phdr, header_size); + if (hdr) + unmap_pages(nd.ni_vp, (vm_offset_t)hdr, sizeof(hdr)); + + return error; +} + +int +exec_elf_imgact(struct image_params *imgp) +{ + Elf32_Ehdr *hdr = (Elf32_Ehdr *) imgp->image_header; + Elf32_Phdr *phdr, *mapped_phdr = NULL; + Elf32_Auxargs *elf_auxargs = NULL; + struct vmspace *vmspace = imgp->proc->p_vmspace; + vm_prot_t prot = 0; + u_long text_size = 0, data_size = 0; + u_long text_addr = 0, data_addr = 0; + u_long addr, entry = 0, proghdr = 0; + int error, i, header_size = 0, interp_len = 0; + char *interp = NULL; + + /* + * Do we have a valid ELF header ? + */ + if (elf_check_header(hdr, ET_EXEC)) + return -1; + + /* + * From here on down, we return an errno, not -1, as we've + * detected an ELF file. + */ + + /* + * ouch, need to bounds check in case user gives us a corrupted + * file with an insane header size + */ + if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ + return ENOEXEC; + } + + header_size = hdr->e_phentsize * hdr->e_phnum; + + if ((hdr->e_phoff > PAGE_SIZE) || + (hdr->e_phoff + header_size) > PAGE_SIZE) { + /* + * Ouch ! we only get one page full of header... + * Try to map it in ourselves, and see how we go. + */ + if (error = map_pages(imgp->vp, hdr->e_phoff, + (vm_offset_t *)&mapped_phdr, header_size)) + return (error); + /* + * Save manual mapping for cleanup + */ + phdr = mapped_phdr; + } else { + phdr = (Elf32_Phdr*) + ((char*)(imgp->image_header)+hdr->e_phoff); + } + + /* + * From this point on, we may have resources that need to be freed. + */ + if (error = exec_extract_strings(imgp)) + goto fail; + + exec_new_vmspace(imgp); + + for (i = 0; i < hdr->e_phnum; i++) { + switch(phdr[i].p_type) { + + case PT_NULL: /* NULL section */ + UPRINTF ("ELF PT_NULL section\n"); + break; + case PT_LOAD: /* Loadable segment */ + { + UPRINTF ("ELF PT_LOAD section "); + if (phdr[i].p_flags & PF_X) + prot |= VM_PROT_EXECUTE; + if (phdr[i].p_flags & PF_W) + prot |= VM_PROT_WRITE; + if (phdr[i].p_flags & PF_R) + prot |= VM_PROT_READ; + + if (error = elf_load_section(vmspace, imgp->vp, + phdr[i].p_offset, + (caddr_t)phdr[i].p_vaddr, + phdr[i].p_memsz, + phdr[i].p_filesz, prot)) + goto fail; + + /* + * Is this .text or .data ?? + * + * We only handle one each of those yet XXX + */ + if (hdr->e_entry >= phdr[i].p_vaddr && + hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { + text_size = round_page(phdr[i].p_memsz); + text_addr = trunc_page(phdr[i].p_vaddr); + entry = (u_long)hdr->e_entry; + UPRINTF(".text <%08x,%08x> entry=%08x\n", + text_addr, text_size, entry); + } else { + data_size = round_page(phdr[i].p_memsz); + data_addr = trunc_page(phdr[i].p_vaddr); + UPRINTF(".data <%08x,%08x>\n", + data_addr, data_size); + } + } + break; + + case PT_DYNAMIC:/* Dynamic link information */ + UPRINTF ("ELF PT_DYNAMIC section ??\n"); + break; + case PT_INTERP: /* Path to interpreter */ + UPRINTF ("ELF PT_INTERP section "); + if (phdr[i].p_filesz > MAXPATHLEN) { + error = ENOEXEC; + goto fail; + } + interp_len = MAXPATHLEN; + if (error = map_pages(imgp->vp, phdr[i].p_offset, + (vm_offset_t *)&interp, interp_len)) + goto fail; + UPRINTF("<%s>\n", interp); + break; + case PT_NOTE: /* Note section */ + UPRINTF ("ELF PT_NOTE section\n"); + break; + case PT_SHLIB: /* Shared lib section */ + UPRINTF ("ELF PT_SHLIB section\n"); + break; + case PT_PHDR: /* Program header table info */ + UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); + proghdr = phdr[i].p_vaddr; + break; + default: + UPRINTF ("ELF %d section ??\n", phdr[i].p_type); + } + } + + vmspace->vm_tsize = text_size >> PAGE_SHIFT; + vmspace->vm_taddr = (caddr_t)text_addr; + vmspace->vm_dsize = data_size >> PAGE_SHIFT; + vmspace->vm_daddr = (caddr_t)data_addr; + + addr = 2*MAXDSIZ; /* May depend on OS type XXX */ + + if (interp) { + char path[MAXPATHLEN]; + /* + * So which kind of ELF binary do we have at hand + * FreeBSD, SVR4 or Linux ?? + */ + for (i=0; ipath)) { + imgp->proc->p_sysent = + interp_list[i]->sysvec; + strcpy(path, interp_list[i]->emul_path); + strcat(path, interp_list[i]->path); + UPRINTF("interpreter=<%s> %s\n", + interp_list[i]->path, + interp_list[i]->emul_path); + break; + } + } + } + if (i == MAX_INTERP) { + uprintf("ELF interpreter %s not known\n", interp); + error = ENOEXEC; + goto fail; + } + if (error = elf_load_file(imgp->proc, + path, + &addr, /* XXX */ + &imgp->entry_addr)) { + uprintf("ELF interpreter %s not found\n", path); + goto fail; + } + } + else + imgp->entry_addr = entry; + + /* + * Construct auxargs table (used by the fixup routine) + */ + elf_auxargs = malloc(sizeof(Elf32_Auxargs), M_TEMP, M_WAITOK); + elf_auxargs->execfd = -1; + elf_auxargs->phdr = proghdr; + elf_auxargs->phent = hdr->e_phentsize; + elf_auxargs->phnum = hdr->e_phnum; + elf_auxargs->pagesz = PAGE_SIZE; + elf_auxargs->base = addr; + elf_auxargs->flags = 0; + elf_auxargs->entry = entry; + elf_auxargs->trace = elf_trace; + + imgp->auxargs = elf_auxargs; + imgp->interpreted = 0; + + /* don't allow modifying the file while we run it */ + imgp->vp->v_flag |= VTEXT; + +fail: + if (mapped_phdr) + unmap_pages(imgp->vp, (vm_offset_t)mapped_phdr, header_size); + if (interp) + unmap_pages(imgp->vp, (vm_offset_t)interp, interp_len); + + return error; +} + +static int +elf_freebsd_fixup(int **stack_base, struct image_params *imgp) +{ + Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; + int *pos; + + pos = *stack_base + (imgp->argc + imgp->envc + 2); + + if (args->trace) { + AUXARGS_ENTRY(pos, AT_DEBUG, 1); + } + if (args->execfd != -1) { + AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); + } + AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); + AUXARGS_ENTRY(pos, AT_PHENT, args->phent); + AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); + AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); + AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); + AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); + AUXARGS_ENTRY(pos, AT_BASE, args->base); + AUXARGS_ENTRY(pos, AT_NULL, 0); + + free(imgp->auxargs, M_TEMP); + imgp->auxargs = NULL; + + (*stack_base)--; + **stack_base = (int)imgp->argc; + return 0; +} + +/* + * Tell kern_execve.c about it, with a little help from the linker. + * Since `const' objects end up in the text segment, TEXT_SET is the + * correct directive to use. + */ +const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; +TEXT_SET(execsw_set, elf_execsw); + diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 65fdaff..954cce1 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: kern_exec.c,v 1.35 1996/02/24 14:32:52 peter Exp $ + * $Id: kern_exec.c,v 1.36 1996/03/02 19:38:08 peter Exp $ */ #include @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ execve(p, uap, retval) imgp->vmspace_destroyed = 0; imgp->interpreted = 0; imgp->interpreter_name[0] = '\0'; + imgp->auxargs = NULL; /* * Allocate temporary demand zeroed space for argument and @@ -475,11 +477,24 @@ exec_copyout_strings(imgp) ((caddr_t)arginfo - szsigcode), szsigcode); /* + * If we have a valid auxargs ptr, prepare some room + * on the stack. + */ + if (imgp->auxargs) + /* + * The '+ 2' is for the null pointers at the end of each of the + * arg and env vector sets, and 'AT_COUNT*2' is room for the + * ELF Auxargs data. + */ + vectp = (char **)(destp - (imgp->argc + imgp->envc + 2 + + AT_COUNT*2) * sizeof(char*)); + else + /* * The '+ 2' is for the null pointers at the end of each of the - * arg and env vector sets + * arg and env vector sets */ - vectp = (char **) (destp - - (imgp->argc + imgp->envc + 2) * sizeof(char *)); + vectp = (char **) + (destp - (imgp->argc + imgp->envc + 2) * sizeof(char*)); /* * vectp also becomes our initial stack base diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile index 7c7074c..e544b7f 100644 --- a/sys/modules/linux/Makefile +++ b/sys/modules/linux/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 1996/01/27 23:57:06 rgrimes Exp $ +# $Id: Makefile,v 1.6 1996/03/02 20:00:35 peter Exp $ .PATH: ${.CURDIR}/../../sys/i386/linux KMOD= linux_mod @@ -11,7 +11,7 @@ NOMAN= CFLAGS+= -DLKM -I. -DCOMPAT_43 -DCOMPAT_LINUX #-DDEBUG CPPFLAGS= -I. -I${.CURDIR}/../../sys - +EXPORT_SYMS=_linux_mod CLEANFILES+= vnode_if.h vnode_if.c linux_genassym.o linux_genassym machine \ linux_assym.h diff --git a/sys/modules/linux/linux.c b/sys/modules/linux/linux.c index 67faa18..dbd319f 100644 --- a/sys/modules/linux/linux.c +++ b/sys/modules/linux/linux.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux.c,v 1.3 1995/11/13 07:18:38 bde Exp $ + * $Id: linux.c,v 1.4 1995/11/14 07:34:18 bde Exp $ */ #include @@ -34,14 +34,24 @@ #include #include #include +#include +#include "i386/linux/linux.h" extern const struct execsw linux_execsw; MOD_EXEC(linux, -1, (struct execsw*)&linux_execsw); +static Elf32_Interp_info linux_interp = { + &elf_linux_sysvec, + "/lib/ld-linux.so.1", + "/compat/linux" + }; + static int linux_load(struct lkm_table *lkmtp, int cmd) { + if (elf_insert_interp(&linux_interp)) + uprintf("Could not install ELF interpreter entry\n"); uprintf("Linux emulator installed\n"); return 0; } @@ -49,6 +59,8 @@ linux_load(struct lkm_table *lkmtp, int cmd) static int linux_unload(struct lkm_table *lkmtp, int cmd) { + if (elf_remove_interp(&linux_interp)) + uprintf("Could not deinstall ELF interpreter entry\n"); uprintf("Linux emulator removed\n"); return 0; } diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h index 11f911b..a0b8793 100644 --- a/sys/sys/imgact.h +++ b/sys/sys/imgact.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: imgact.h,v 1.9 1995/05/30 08:14:24 rgrimes Exp $ + * $Id: imgact.h,v 1.10 1995/11/06 12:52:37 davidg Exp $ */ #ifndef _SYS_IMGACT_H_ @@ -54,6 +54,7 @@ struct image_params { char vmspace_destroyed; /* flag - we've blown away original vm space */ char interpreted; /* flag - this executable is interpreted */ char interpreter_name[64]; /* name of the interpreter */ + void *auxargs; /* ELF Auxinfo structure pointer */ }; #ifdef KERNEL diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h new file mode 100644 index 0000000..d24a725 --- /dev/null +++ b/sys/sys/imgact_elf.h @@ -0,0 +1,213 @@ +/*- + * Copyright (c) 1995-1996 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +#ifndef _IMGACT_ELF_H_ +#define _IMGACT_ELF_H_ + +typedef u_int32_t Elf32_Addr; +typedef u_int32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef u_int32_t Elf32_Word; +typedef u_int16_t Elf32_Half; + +extern int elf_trace; + +#define EI_NINDENT 16 +typedef struct { + unsigned char e_ident[EI_NINDENT]; /* file id */ + Elf32_Half e_type; /* type */ + Elf32_Half e_machine; /* machine type */ + Elf32_Word e_version; /* version number */ + Elf32_Addr e_entry; /* entry point */ + Elf32_Off e_phoff; /* program hdr offset */ + Elf32_Off e_shoff; /* section hdr offset */ + Elf32_Word e_flags; /* flags */ + Elf32_Half e_ehsize; /* sizeof ehdr */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program headers */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section headers */ + Elf32_Half e_shstrndx; /* string table index */ +} Elf32_Ehdr; + +/* + * Values for e_indent entry in struct Elf32_Ehdr. + */ +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 + + +#define ELFMAG0 '\177' +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFCLASSNONE 0 /* invalid class */ +#define ELFCLASS32 1 /* 32bit object class */ +#define ELFCLASS64 2 /* 64bit object class */ +#define ELFDATANONE 0 /* invalid data encoding */ +#define ELFDATA2LSB 1 /* little endian */ +#define ELFDATA2MSB 2 /* big endian */ + +/* + * Values for e_version entry in struct Elf32_Ehdr. + */ +#define EV_NONE 0 /* invalid version */ +#define EV_CURRENT 1 /* current version */ + +/* + * Values for e_type entry in struct Elf32_Ehdr. + */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 5 +#define ET_HIPROC 6 + +/* + * Values for e_machine entry in struct Elf32_Ehdr. + */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 +#define EM_860 7 + + +typedef struct { + Elf32_Word p_type; /* entry type */ + Elf32_Off p_offset; /* offset */ + Elf32_Addr p_vaddr; /* virtual address */ + Elf32_Addr p_paddr; /* physical address */ + Elf32_Word p_filesz; /* file size */ + Elf32_Word p_memsz; /* memory size */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory & file alignment */ +} Elf32_Phdr; + +/* + * Values for p_type entry in struct Elf32_Phdr. + */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* + * Values for p_flags entry in struct Elf32_Phdr. + */ +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + +/* + * Auxiliary vector entry on initial stack. + */ +typedef struct { + Elf32_Sword a_type; + Elf32_Word a_val; +} Elf32_Auxinfo; + +#define AUXARGS_ENTRY(pos, id, val) {suword(pos++, id); suword(pos++, val);} + +/* + * Values for a_type in struct Elf32_Auxinfo. + */ +#define AT_NULL 0 /* Terminates the vector */ +#define AT_IGNORE 1 /* Ignored */ +#define AT_EXECFD 2 /* File descriptor of program to load */ +#define AT_PHDR 3 /* Program header of program already loaded */ +#define AT_PHENT 4 /* Size of each program header entry */ +#define AT_PHNUM 5 /* Number of program header entries */ +#define AT_PAGESZ 6 /* Page size in bytes */ +#define AT_BASE 7 /* Interpreter's base address */ +#define AT_FLAGS 8 /* Flags (unused for i386) */ +#define AT_ENTRY 9 /* Where interpreter should transfer control */ + +/* + * The following non-standard values are used for passing information + * to the (FreeBSD ELF) dynamic linker. Will probably go away soon.... + */ +#define AT_BRK 10 /* Starting point for sbrk and brk */ +#define AT_DEBUG 11 /* Debugging level */ +#define AT_COUNT 15 + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ + +/* + * Structure used to pass infomation from the loader to the + * stack fixup routine. + */ +typedef struct { + Elf32_Sword execfd; + Elf32_Word phdr; + Elf32_Word phent; + Elf32_Word phnum; + Elf32_Word pagesz; + Elf32_Word base; + Elf32_Word flags; + Elf32_Word entry; + Elf32_Word trace; +} Elf32_Auxargs; + +typedef struct { + struct sysentvec *sysvec; + char *path; + char *emul_path; +} Elf32_Interp_info; + +#define MAX_INTERP 8 + +int elf_insert_interp __P((Elf32_Interp_info *entry)); +int elf_remove_interp __P((Elf32_Interp_info *entry)); + +#endif /* _IMGACT_ELF_H_ */ -- cgit v1.1