qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] qemu Makefile.target configure linux-user/elflo...


From: Paul Brook
Subject: [Qemu-devel] qemu Makefile.target configure linux-user/elflo...
Date: Sun, 11 Jun 2006 13:32:59 +0000

CVSROOT:        /sources/qemu
Module name:    qemu
Changes by:     Paul Brook <pbrook>     06/06/11 13:32:59

Modified files:
        .              : Makefile.target configure 
        linux-user     : elfload.c main.c qemu.h 
Added files:
        linux-user     : flat.h flatload.c linuxload.c 

Log message:
        bFLT loader (for uClinux binaries).

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemu/Makefile.target?cvsroot=qemu&r1=1.113&r2=1.114
http://cvs.savannah.gnu.org/viewcvs/qemu/configure?cvsroot=qemu&r1=1.102&r2=1.103
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/elfload.c?cvsroot=qemu&r1=1.34&r2=1.35
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/main.c?cvsroot=qemu&r1=1.83&r2=1.84
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/qemu.h?cvsroot=qemu&r1=1.26&r2=1.27
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/flat.h?cvsroot=qemu&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/flatload.c?cvsroot=qemu&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemu/linux-user/linuxload.c?cvsroot=qemu&rev=1.1

Patches:
Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.113
retrieving revision 1.114
diff -u -b -r1.113 -r1.114
--- Makefile.target     30 May 2006 01:48:12 -0000      1.113
+++ Makefile.target     11 Jun 2006 13:32:58 -0000      1.114
@@ -171,7 +171,12 @@
 main.o: CFLAGS+=-p
 endif
 
-OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o 
+OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
+      elfload.o linuxload.o
+ifdef TARGET_HAS_BFLT
+OBJS+= flatload.o
+endif
+
 ifeq ($(TARGET_ARCH), i386)
 OBJS+= vm86.o
 endif

Index: configure
===================================================================
RCS file: /sources/qemu/qemu/configure,v
retrieving revision 1.102
retrieving revision 1.103
diff -u -b -r1.102 -r1.103
--- configure   14 May 2006 11:30:38 -0000      1.102
+++ configure   11 Jun 2006 13:32:58 -0000      1.103
@@ -773,6 +773,7 @@
 echo "include ../config-host.mak" >> $config_mak
 echo "#include \"../config-host.h\"" >> $config_h
 
+bflt="no"
 interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
 echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
 
@@ -787,6 +788,7 @@
   echo "TARGET_ARCH=arm" >> $config_mak
   echo "#define TARGET_ARCH \"arm\"" >> $config_h
   echo "#define TARGET_ARM 1" >> $config_h
+  bflt="yes"
 elif test "$target_cpu" = "sparc" ; then
   echo "TARGET_ARCH=sparc" >> $config_mak
   echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -842,6 +844,10 @@
   echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
   echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
 fi
+if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
+  echo "TARGET_HAS_BFLT=yes" >> $config_mak
+  echo "#define TARGET_HAS_BFLT 1" >> $config_h
+fi
 # sdl defines
 
 if test "$target_user_only" = "no"; then

Index: linux-user/elfload.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/elfload.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -b -r1.34 -r1.35
--- linux-user/elfload.c        27 Apr 2006 21:07:12 -0000      1.34
+++ linux-user/elfload.c        11 Jun 2006 13:32:58 -0000      1.35
@@ -3,7 +3,6 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <fcntl.h>
-#include <sys/stat.h>
 #include <errno.h>
 #include <unistd.h>
 #include <sys/mman.h>
@@ -59,6 +58,11 @@
 #define ELF_DATA       ELFDATA2LSB
 #define ELF_ARCH       EM_386
 
+static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
        /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
           starts %edx contains a pointer to a function which might be
           registered using `atexit'.  This provides a mean for the
@@ -66,12 +70,7 @@
           that have been loaded before the code runs.
 
           A value of 0 tells we have no such handler.  */
-#define ELF_PLAT_INIT(_r)      _r->edx = 0
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
-{
-    regs->esp = infop->start_stack;
-    regs->eip = infop->entry;
+    regs->edx = 0;
 }
 
 #define USE_ELF_CORE_DUMP
@@ -93,8 +92,6 @@
 #endif
 #define ELF_ARCH       EM_ARM
 
-#define ELF_PLAT_INIT(_r)      _r->ARM_r0 = 0
-
 static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
 {
     target_long stack = infop->start_stack;
@@ -107,7 +104,9 @@
     regs->ARM_r2 = tgetl(stack + 8); /* envp */
     regs->ARM_r1 = tgetl(stack + 4); /* envp */
     /* XXX: it seems that r0 is zeroed after ! */
-    //    regs->ARM_r0 = tgetl(stack); /* argc */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    regs->ARM_r10 = infop->start_data;
 }
 
 #define USE_ELF_CORE_DUMP
@@ -142,9 +141,6 @@
 #define ELF_DATA    ELFDATA2MSB
 #define ELF_ARCH    EM_SPARC
 
-/*XXX*/
-#define ELF_PLAT_INIT(_r)
-
 static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
 {
     regs->tstate = 0;
@@ -163,9 +159,6 @@
 #define ELF_DATA    ELFDATA2MSB
 #define ELF_ARCH    EM_SPARC
 
-/*XXX*/
-#define ELF_PLAT_INIT(_r)
-
 static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
 {
     regs->psr = 0;
@@ -192,20 +185,6 @@
 #endif
 #define ELF_ARCH       EM_PPC
 
-/* Note that isn't exactly what regular kernel does
- * but this is what the ABI wants and is needed to allow
- * execution of PPC BSD programs.
- */
-#define ELF_PLAT_INIT(_r)                                  \
-do {                                                       \
-    target_ulong *pos = (target_ulong *)bprm->p, tmp = 1;  \
-    _r->gpr[3] = bprm->argc;                               \
-    _r->gpr[4] = (unsigned long)++pos;                     \
-    for (; tmp != 0; pos++)                                \
-        tmp = ldl(pos);                                    \
-    _r->gpr[5] = (unsigned long)pos;                       \
-} while (0)
-
 /*
  * We need to put in some extra aux table entries to tell glibc what
  * the cache block size is, so it can use the dcbz instruction safely.
@@ -239,9 +218,22 @@
 
 static inline void init_thread(struct target_pt_regs *_regs, struct image_info 
*infop)
 {
+    target_ulong pos = infop->start_stack;
+    target_ulong tmp;
+
     _regs->msr = 1 << MSR_PR; /* Set user mode */
     _regs->gpr[1] = infop->start_stack;
     _regs->nip = infop->entry;
+    /* Note that isn't exactly what regular kernel does
+     * but this is what the ABI wants and is needed to allow
+     * execution of PPC BSD programs.
+     */
+    _regs->gpr[3] = tgetl(pos);
+    pos += sizeof(target_ulong);
+    _regs->gpr[4] = pos;
+    for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
+        tmp = ldl(pos);
+    _regs->gpr[5] = pos;
 }
 
 #define USE_ELF_CORE_DUMP
@@ -263,8 +255,6 @@
 #endif
 #define ELF_ARCH    EM_MIPS
 
-#define ELF_PLAT_INIT(_r) 
-
 static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
 {
     regs->cp0_status = CP0St_UM;
@@ -284,8 +274,6 @@
 #define ELF_DATA  ELFDATA2LSB
 #define ELF_ARCH  EM_SH
 
-#define ELF_PLAT_INIT(_r) /* XXXXX */
-
 static inline void init_thread(struct target_pt_regs *regs, struct image_info 
*infop)
 {
   /* Check other registers XXXXX */
@@ -308,30 +296,6 @@
 
 #include "elf.h"
 
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
- */
-#define MAX_ARG_PAGES 32
-
-/*
- * This structure is used to hold the arguments that are 
- * used when loading binaries.
- */
-struct linux_binprm {
-        char buf[128];
-        void *page[MAX_ARG_PAGES];
-        unsigned long p;
-        int sh_bang;
-       int fd;
-        int e_uid, e_gid;
-        int argc, envc;
-        char * filename;        /* Name of binary */
-        unsigned long loader, exec;
-        int dont_iput;          /* binfmt handler has put inode */
-};
-
 struct exec
 {
   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
@@ -377,8 +341,6 @@
 #define PER_XENIX              (0x0007 | STICKY_TIMEOUTS)
 
 /* Necessary parameters */
-#define NGROUPS 32
-
 #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
 #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned 
long)(TARGET_ELF_EXEC_PAGESIZE-1))
 #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
@@ -452,12 +414,12 @@
 #endif
 
 /*
- * 'copy_string()' copies argument/envelope strings from user
+ * 'copy_elf_strings()' copies argument/envelope strings from user
  * memory to free pages in kernel mem. These are in a format ready
  * to be put directly into the top of new user memory.
  *
  */
-static unsigned long copy_strings(int argc,char ** argv, void **page,
+static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
                 unsigned long p)
 {
     char *tmp, *tmp1, *pag = NULL;
@@ -506,101 +468,6 @@
     return p;
 }
 
-static int in_group_p(gid_t g)
-{
-    /* return TRUE if we're in the specified group, FALSE otherwise */
-    int                ngroup;
-    int                i;
-    gid_t      grouplist[NGROUPS];
-
-    ngroup = getgroups(NGROUPS, grouplist);
-    for(i = 0; i < ngroup; i++) {
-       if(grouplist[i] == g) {
-           return 1;
-       }
-    }
-    return 0;
-}
-
-static int count(char ** vec)
-{
-    int                i;
-
-    for(i = 0; *vec; i++) {
-        vec++;
-    }
-
-    return(i);
-}
-
-static int prepare_binprm(struct linux_binprm *bprm)
-{
-    struct stat                st;
-    int mode;
-    int retval, id_change;
-
-    if(fstat(bprm->fd, &st) < 0) {
-       return(-errno);
-    }
-
-    mode = st.st_mode;
-    if(!S_ISREG(mode)) {       /* Must be regular file */
-       return(-EACCES);
-    }
-    if(!(mode & 0111)) {       /* Must have at least one execute bit set */
-       return(-EACCES);
-    }
-
-    bprm->e_uid = geteuid();
-    bprm->e_gid = getegid();
-    id_change = 0;
-
-    /* Set-uid? */
-    if(mode & S_ISUID) {
-       bprm->e_uid = st.st_uid;
-       if(bprm->e_uid != geteuid()) {
-           id_change = 1;
-       }
-    }
-
-    /* Set-gid? */
-    /*
-     * If setgid is set but no group execute bit then this
-     * is a candidate for mandatory locking, not a setgid
-     * executable.
-     */
-    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-       bprm->e_gid = st.st_gid;
-       if (!in_group_p(bprm->e_gid)) {
-               id_change = 1;
-       }
-    }
-
-    memset(bprm->buf, 0, sizeof(bprm->buf));
-    retval = lseek(bprm->fd, 0L, SEEK_SET);
-    if(retval >= 0) {
-        retval = read(bprm->fd, bprm->buf, 128);
-    }
-    if(retval < 0) {
-       perror("prepare_binprm");
-       exit(-1);
-       /* return(-errno); */
-    }
-    else {
-       return(retval);
-    }
-}
-
-static inline void memcpy_to_target(target_ulong dest, const void *src,
-                                    unsigned long len)
-{
-    void *host_ptr;
-
-    host_ptr = lock_user(dest, len, 0);
-    memcpy(host_ptr, src, len);
-    unlock_user(host_ptr, dest, 1);
-}
-
 unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
                                              struct image_info * info)
 {
@@ -628,11 +495,6 @@
     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
     p += stack_base;
 
-    if (bprm->loader) {
-       bprm->loader += stack_base;
-    }
-    bprm->exec += stack_base;
-
     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
        if (bprm->page[i]) {
            info->rss++;
@@ -703,7 +565,6 @@
                                        unsigned long interp_load_addr, int 
ibcs,
                                        struct image_info *info)
 {
-        target_ulong argv, envp;
         target_ulong sp;
         int size;
         target_ulong u_platform;
@@ -765,28 +626,7 @@
 #endif
 #undef NEW_AUX_ENT
 
-        sp -= (envc + 1) * n;
-        envp = sp;
-        sp -= (argc + 1) * n;
-        argv = sp;
-        if (!ibcs) {
-            sp -= n; tputl(sp, envp);
-            sp -= n; tputl(sp, argv);
-        }
-        sp -= n; tputl(sp, argc);
-        info->arg_start = p;
-        while (argc-->0) {
-            tputl(argv, p); argv += n;
-            p += target_strlen(p) + 1;
-        }
-        tputl(argv, 0);
-        info->arg_end = info->env_start = p;
-        while (envc-->0) {
-            tputl(envp, p); envp += n;
-            p += target_strlen(p) + 1;
-        }
-        tputl(envp, 0);
-        info->env_end = p;
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
         return sp;
 }
 
@@ -1001,7 +841,7 @@
     syminfos = s;
 }
 
-static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * 
regs,
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                            struct image_info * info)
 {
     struct elfhdr elf_ex;
@@ -1034,17 +874,19 @@
     bswap_ehdr(&elf_ex);
 #endif
 
-    if (elf_ex.e_ident[0] != 0x7f ||
-       strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-           return  -ENOEXEC;
-    }
-
     /* First of all, some simple consistency checks */
     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
                                        (! elf_check_arch(elf_ex.e_machine))) {
            return -ENOEXEC;
     }
 
+    bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
+    bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
+    bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+    if (!bprm->p) {
+        retval = -E2BIG;
+    }
+
     /* Now read in all of the header information */
     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
     if (elf_phdata == NULL) {
@@ -1188,7 +1030,7 @@
     /* OK, we are done with that, now set up the arg stuff,
        and then start this sucker up */
 
-    if (!bprm->sh_bang) {
+    {
        char * passed_p;
 
        if (interpreter_type == INTERPRETER_AOUT) {
@@ -1196,7 +1038,7 @@
            passed_p = passed_fileno;
 
            if (elf_interpreter) {
-               bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
+               bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
                bprm->argc++;
            }
        }
@@ -1347,11 +1189,10 @@
                    interp_load_addr,
                    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
                    info);
-    if (interpreter_type == INTERPRETER_AOUT)
-      info->arg_start += strlen(passed_fileno) + 1;
     info->start_brk = info->brk = elf_brk;
     info->end_code = end_code;
     info->start_code = start_code;
+    info->start_data = end_code;
     info->end_data = end_data;
     info->start_stack = bprm->p;
 
@@ -1380,79 +1221,18 @@
                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
     }
 
-#ifdef ELF_PLAT_INIT
-    /*
-     * The ABI may specify that certain registers be set up in special
-     * ways (on i386 %edx is the address of a DT_FINI function, for
-     * example.  This macro performs whatever initialization to
-     * the regs structure is required.
-     */
-    ELF_PLAT_INIT(regs);
-#endif
-
-
     info->entry = elf_entry;
 
     return 0;
 }
 
-
-
-int elf_exec(const char * filename, char ** argv, char ** envp, 
-             struct target_pt_regs * regs, struct image_info *infop)
-{
-        struct linux_binprm bprm;
-        int retval;
-        int i;
-
-        bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
-        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-                bprm.page[i] = 0;
-        retval = open(filename, O_RDONLY);
-        if (retval < 0)
-            return retval;
-        bprm.fd = retval;
-        bprm.filename = (char *)filename;
-        bprm.sh_bang = 0;
-        bprm.loader = 0;
-        bprm.exec = 0;
-        bprm.dont_iput = 0;
-       bprm.argc = count(argv);
-       bprm.envc = count(envp);
-
-        retval = prepare_binprm(&bprm);
-
-        if(retval>=0) {
-           bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
-           bprm.exec = bprm.p;
-           bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
-           bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
-           if (!bprm.p) {
-               retval = -E2BIG;
-           }
-        }
-
-        if(retval>=0) {
-           retval = load_elf_binary(&bprm,regs,infop);
-       }
-        
-        if(retval>=0) {
-           /* success.  Initialize important registers */
-            init_thread(regs, infop);
-           return retval;
-       }
-
-        /* Something went wrong, return the inode and free the argument pages*/
-        for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-           free(bprm.page[i]);
-       }
-        return(retval);
-}
-
-
 static int load_aout_interp(void * exptr, int interp_fd)
 {
     printf("a.out interpreter not yet supported\n");
     return(0);
 }
 
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    init_thread(regs, infop);
+}

Index: linux-user/main.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/main.c,v
retrieving revision 1.83
retrieving revision 1.84
diff -u -b -r1.83 -r1.84
--- linux-user/main.c   14 May 2006 11:30:38 -0000      1.83
+++ linux-user/main.c   11 Jun 2006 13:32:59 -0000      1.84
@@ -1545,7 +1545,7 @@
     env = cpu_init();
     global_env = env;
     
-    if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
+    if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
        printf("Error loading %s\n", filename);
        _exit(1);
     }
@@ -1556,6 +1556,7 @@
         fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
         fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
         fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
+        fprintf(logfile, "start_data  0x%08lx\n" , info->start_data);
         fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
         fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
         fprintf(logfile, "brk         0x%08lx\n" , info->brk);

Index: linux-user/qemu.h
===================================================================
RCS file: /sources/qemu/qemu/linux-user/qemu.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -b -r1.26 -r1.27
--- linux-user/qemu.h   14 May 2006 11:30:38 -0000      1.26
+++ linux-user/qemu.h   11 Jun 2006 13:32:59 -0000      1.27
@@ -18,6 +18,7 @@
 struct image_info {
        unsigned long   start_code;
        unsigned long   end_code;
+        unsigned long   start_data;
        unsigned long   end_data;
        unsigned long   start_brk;
        unsigned long   brk;
@@ -25,10 +26,6 @@
        unsigned long   mmap;
        unsigned long   rss;
        unsigned long   start_stack;
-       unsigned long   arg_start;
-       unsigned long   arg_end;
-       unsigned long   env_start;
-       unsigned long   env_end;
        unsigned long   entry;
        int             personality;
 };
@@ -82,9 +79,43 @@
 extern TaskState *first_task_state;
 extern const char *qemu_uname_release;
 
-int elf_exec(const char * filename, char ** argv, char ** envp, 
+/* ??? See if we can avoid exposing so much of the loader internals.  */
+/*
+ * MAX_ARG_PAGES defines the number of pages allocated for arguments
+ * and envelope for the new program. 32 should suffice, this gives
+ * a maximum env+arg of 128kB w/4KB pages!
+ */
+#define MAX_ARG_PAGES 32
+
+/*
+ * This structure is used to hold the arguments that are 
+ * used when loading binaries.
+ */
+struct linux_binprm {
+        char buf[128];
+        void *page[MAX_ARG_PAGES];
+        unsigned long p;
+       int fd;
+        int e_uid, e_gid;
+        int argc, envc;
+        char **argv;
+        char **envp;
+        char * filename;        /* Name of binary */
+};
+
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
+target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
+                                 target_ulong stringp, int push_ptr);
+int loader_exec(const char * filename, char ** argv, char ** envp, 
              struct target_pt_regs * regs, struct image_info *infop);
 
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+
+void memcpy_to_target(target_ulong dest, const void *src,
+                      unsigned long len);
 void target_set_brk(target_ulong new_brk);
 long do_brk(target_ulong new_brk);
 void syscall_init(void);

Index: linux-user/flat.h
===================================================================
RCS file: linux-user/flat.h
diff -N linux-user/flat.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ linux-user/flat.h   11 Jun 2006 13:32:59 -0000      1.1
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2002-2003  David McCullough <address@hidden>
+ * Copyright (C) 1998       Kenneth Albanowski <address@hidden>
+ *                          The Silver Hammer Group, Ltd.
+ *
+ * This file provides the definitions and structures needed to
+ * support uClinux flat-format executables.
+ */
+
+#define        FLAT_VERSION                    0x00000004L
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#define        MAX_SHARED_LIBS                 (4)
+#else
+#define        MAX_SHARED_LIBS                 (1)
+#endif
+
+/*
+ * To make everything easier to port and manage cross platform
+ * development,  all fields are in network byte order.
+ */
+
+struct flat_hdr {
+       char magic[4];
+       unsigned long rev;          /* version (as above) */
+       unsigned long entry;        /* Offset of first executable instruction
+                                      with text segment from beginning of file 
*/
+       unsigned long data_start;   /* Offset of data segment from beginning of
+                                      file */
+       unsigned long data_end;     /* Offset of end of data segment
+                                      from beginning of file */
+       unsigned long bss_end;      /* Offset of end of bss segment from 
beginning
+                                      of file */
+
+       /* (It is assumed that data_end through bss_end forms the bss segment.) 
*/
+
+       unsigned long stack_size;   /* Size of stack, in bytes */
+       unsigned long reloc_start;  /* Offset of relocation records from
+                                      beginning of file */
+       unsigned long reloc_count;  /* Number of relocation records */
+       unsigned long flags;       
+       unsigned long build_date;   /* When the program/library was built */
+       unsigned long filler[5];    /* Reservered, set to zero */
+};
+
+#define FLAT_FLAG_RAM    0x0001 /* load program entirely into RAM */
+#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
+#define FLAT_FLAG_GZIP   0x0004 /* all but the header is compressed */
+#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
+#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
+
+
+/*
+ * While it would be nice to keep this header clean,  users of older
+ * tools still need this support in the kernel.  So this section is
+ * purely for compatibility with old tool chains.
+ *
+ * DO NOT make changes or enhancements to the old format please,  just work
+ *        with the format above,  except to fix bugs with old format support.
+ */
+
+#define        OLD_FLAT_VERSION                        0x00000002L
+#define OLD_FLAT_RELOC_TYPE_TEXT       0
+#define OLD_FLAT_RELOC_TYPE_DATA       1
+#define OLD_FLAT_RELOC_TYPE_BSS                2
+
+#      define OLD_FLAT_FLAG_RAM    0x1 /* load program entirely into RAM */

Index: linux-user/flatload.c
===================================================================
RCS file: linux-user/flatload.c
diff -N linux-user/flatload.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ linux-user/flatload.c       11 Jun 2006 13:32:59 -0000      1.1
@@ -0,0 +1,790 @@
+/****************************************************************************/
+/*
+ *  QEMU bFLT binary loader.  Based on linux/fs/binfmt_flat.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *      Copyright (C) 2006 CodeSourcery.
+ *     Copyright (C) 2000-2003 David McCullough <address@hidden>
+ *     Copyright (C) 2002 Greg Ungerer <address@hidden>
+ *     Copyright (C) 2002 SnapGear, by Paul Dale <address@hidden>
+ *     Copyright (C) 2000, 2001 Lineo, by David McCullough <address@hidden>
+ *  based heavily on:
+ *
+ *  linux/fs/binfmt_aout.c:
+ *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
+ *  linux/fs/binfmt_flat.c for 2.0 kernel
+ *         Copyright (C) 1998  Kenneth Albanowski <address@hidden>
+ *     JAN/99 -- coded full program relocation (address@hidden)
+ */
+
+/* ??? ZFLAT and shared library support is currently disabled.  */
+
+/****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "qemu.h"
+#include "flat.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define        DBG_FLT(a...)   printf(a)
+#else
+#define        DBG_FLT(a...)
+#endif
+
+#define flat_reloc_valid(reloc, size)             ((reloc) <= (size))
+#define flat_old_ram_flag(flag)                   (flag)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define flat_get_relocate_addr(relval)            (relval)
+#else
+#define flat_get_relocate_addr(relval)            bswap32(relval)
+#endif
+
+#define RELOC_FAILED 0xff00ff01                /* Relocation incorrect 
somewhere */
+#define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused 
library */
+
+struct lib_info {
+    target_ulong start_code;   /* Start of text segment */
+    target_ulong start_data;   /* Start of data segment */
+    target_ulong end_data;      /* Start of bss section */
+    target_ulong start_brk;    /* End of data segment */
+    target_ulong text_len;     /* Length of text segment */
+    target_ulong entry;                /* Start address for this module */
+    target_ulong build_date;   /* When this one was compiled */
+    short loaded;              /* Has this library been loaded? */
+};
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+static int load_flat_shared_library(int id, struct lib_info *p);
+#endif
+
+struct linux_binprm;
+
+#define ntohl(x) be32_to_cpu(x)
+
+/****************************************************************************/
+/*
+ * create_flat_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+
+/* Push a block of strings onto the guest stack.  */
+static target_ulong copy_strings(target_ulong p, int n, char **s)
+{
+    int len;
+
+    while (n-- > 0) {
+        len = strlen(s[n]) + 1;
+        p -= len;
+        memcpy_to_target(p, s[n], len);
+    }
+
+    return p;
+}
+
+int target_pread(int fd, target_ulong ptr, target_ulong len,
+                 target_ulong offset)
+{
+    void *buf;
+    int ret;
+
+    buf = lock_user(ptr, len, 0);
+    ret = pread(fd, buf, len, offset);
+    unlock_user(buf, ptr, len);
+    return ret;
+}
+/****************************************************************************/
+
+#ifdef CONFIG_BINFMT_ZFLAT
+
+#include <linux/zlib.h>
+
+#define LBUFSIZE       4000
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+static int decompress_exec(
+       struct linux_binprm *bprm,
+       unsigned long offset,
+       char *dst,
+       long len,
+       int fd)
+{
+       unsigned char *buf;
+       z_stream strm;
+       loff_t fpos;
+       int ret, retval;
+
+       DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, 
(int)dst, (int)len);
+
+       memset(&strm, 0, sizeof(strm));
+       strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+       if (strm.workspace == NULL) {
+               DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
+               return -ENOMEM;
+       }
+       buf = kmalloc(LBUFSIZE, GFP_KERNEL);
+       if (buf == NULL) {
+               DBG_FLT("binfmt_flat: no memory for read buffer\n");
+               retval = -ENOMEM;
+               goto out_free;
+       }
+
+       /* Read in first chunk of data and parse gzip header. */
+       fpos = offset;
+       ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
+
+       strm.next_in = buf;
+       strm.avail_in = ret;
+       strm.total_in = 0;
+
+       retval = -ENOEXEC;
+
+       /* Check minimum size -- gzip header */
+       if (ret < 10) {
+               DBG_FLT("binfmt_flat: file too small?\n");
+               goto out_free_buf;
+       }
+
+       /* Check gzip magic number */
+       if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
+               DBG_FLT("binfmt_flat: unknown compression magic?\n");
+               goto out_free_buf;
+       }
+
+       /* Check gzip method */
+       if (buf[2] != 8) {
+               DBG_FLT("binfmt_flat: unknown compression method?\n");
+               goto out_free_buf;
+       }
+       /* Check gzip flags */
+       if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
+           (buf[3] & RESERVED)) {
+               DBG_FLT("binfmt_flat: unknown flags?\n");
+               goto out_free_buf;
+       }
+
+       ret = 10;
+       if (buf[3] & EXTRA_FIELD) {
+               ret += 2 + buf[10] + (buf[11] << 8);
+               if (unlikely(LBUFSIZE == ret)) {
+                       DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
+                       goto out_free_buf;
+               }
+       }
+       if (buf[3] & ORIG_NAME) {
+               for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
+                       ;
+               if (unlikely(LBUFSIZE == ret)) {
+                       DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
+                       goto out_free_buf;
+               }
+       }
+       if (buf[3] & COMMENT) {
+               for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
+                       ;
+               if (unlikely(LBUFSIZE == ret)) {
+                       DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
+                       goto out_free_buf;
+               }
+       }
+
+       strm.next_in += ret;
+       strm.avail_in -= ret;
+
+       strm.next_out = dst;
+       strm.avail_out = len;
+       strm.total_out = 0;
+
+       if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
+               DBG_FLT("binfmt_flat: zlib init failed?\n");
+               goto out_free_buf;
+       }
+
+       while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
+               ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
+               if (ret <= 0)
+                       break;
+               if (ret >= (unsigned long) -4096)
+                       break;
+               len -= ret;
+
+               strm.next_in = buf;
+               strm.avail_in = ret;
+               strm.total_in = 0;
+       }
+
+       if (ret < 0) {
+               DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
+                       ret, strm.msg);
+               goto out_zlib;
+       }
+
+       retval = 0;
+out_zlib:
+       zlib_inflateEnd(&strm);
+out_free_buf:
+       kfree(buf);
+out_free:
+       kfree(strm.workspace);
+out:
+       return retval;
+}
+
+#endif /* CONFIG_BINFMT_ZFLAT */
+
+/****************************************************************************/
+
+static target_ulong
+calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
+{
+    target_ulong addr;
+    int id;
+    target_ulong start_brk;
+    target_ulong start_data;
+    target_ulong text_len;
+    target_ulong start_code;
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#error needs checking
+    if (r == 0)
+        id = curid;    /* Relocs of 0 are always self referring */
+    else {
+        id = (r >> 24) & 0xff; /* Find ID for this reloc */
+        r &= 0x00ffffff;       /* Trim ID off here */
+    }
+    if (id >= MAX_SHARED_LIBS) {
+        fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
+                (unsigned) r, id);
+        goto failed;
+    }
+    if (curid != id) {
+        if (internalp) {
+            fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
+                    "in same module (%d != %d)\n",
+                    (unsigned) r, curid, id);
+            goto failed;
+        } else if ( ! p[id].loaded &&
+                    load_flat_shared_library(id, p) > (unsigned long) -4096) {
+            fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
+            goto failed;
+        }
+        /* Check versioning information (i.e. time stamps) */
+        if (p[id].build_date && p[curid].build_date
+            && p[curid].build_date < p[id].build_date) {
+            fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
+                    id, curid);
+            goto failed;
+        }
+    }
+#else
+    id = 0;
+#endif
+
+    start_brk = p[id].start_brk;
+    start_data = p[id].start_data;
+    start_code = p[id].start_code;
+    text_len = p[id].text_len;
+
+    if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
+        fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
+                "(0 - 0x%x/0x%x)\n",
+               (int) r,(int)(start_brk-start_code),(int)text_len);
+        goto failed;
+    }
+
+    if (r < text_len)                  /* In text segment */
+        addr = r + start_code;
+    else                                       /* In data segment */
+        addr = r - text_len + start_data;
+
+    /* Range checked already above so doing the range tests is redundant...*/
+    return(addr);
+
+failed:
+    abort();
+    return RELOC_FAILED;
+}
+
+/****************************************************************************/
+
+/* ??? This does not handle endianness correctly.  */
+void old_reloc(struct lib_info *libinfo, uint32_t rl)
+{
+#ifdef DEBUG
+       char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
+#endif
+       uint32_t *ptr;
+        uint32_t offset;
+        int reloc_type;
+
+        offset = rl & 0x3fffffff;
+        reloc_type = rl >> 30;
+        /* ??? How to handle this?  */
+#if defined(CONFIG_COLDFIRE)
+       ptr = (uint32_t *) (libinfo->start_code + offset);
+#else
+       ptr = (uint32_t *) (libinfo->start_data + offset);
+#endif
+
+#ifdef DEBUG
+       fprintf(stderr, "Relocation of variable at DATASEG+%x "
+               "(address %p, currently %x) into segment %s\n",
+               offset, ptr, (int)*ptr, segment[reloc_type]);
+#endif
+       
+       switch (reloc_type) {
+       case OLD_FLAT_RELOC_TYPE_TEXT:
+               *ptr += libinfo->start_code;
+               break;
+       case OLD_FLAT_RELOC_TYPE_DATA:
+               *ptr += libinfo->start_data;
+               break;
+       case OLD_FLAT_RELOC_TYPE_BSS:
+               *ptr += libinfo->end_data;
+               break;
+       default:
+               fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
+                        reloc_type);
+               break;
+       }
+       DBG_FLT("Relocation became %x\n", (int)*ptr);
+}              
+
+/****************************************************************************/
+
+static int load_flat_file(struct linux_binprm * bprm,
+               struct lib_info *libinfo, int id, target_ulong *extra_stack)
+{
+    struct flat_hdr * hdr;
+    target_ulong textpos = 0, datapos = 0, result;
+    target_ulong realdatastart = 0;
+    target_ulong text_len, data_len, bss_len, stack_len, flags;
+    target_ulong memp = 0; /* for finding the brk area */
+    target_ulong extra;
+    target_ulong reloc = 0, rp;
+    int i, rev, relocs = 0;
+    target_ulong fpos;
+    target_ulong start_code, end_code;
+
+    hdr = ((struct flat_hdr *) bprm->buf);             /* exec-header */
+
+    text_len  = ntohl(hdr->data_start);
+    data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
+    bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
+    stack_len = ntohl(hdr->stack_size);
+    if (extra_stack) {
+        stack_len += *extra_stack;
+        *extra_stack = stack_len;
+    }
+    relocs    = ntohl(hdr->reloc_count);
+    flags     = ntohl(hdr->flags);
+    rev       = ntohl(hdr->rev);
+
+    DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
+
+    if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
+        fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
+                rev, (int) FLAT_VERSION);
+        return -ENOEXEC;
+    }
+    
+    /* Don't allow old format executables to use shared libraries */
+    if (rev == OLD_FLAT_VERSION && id != 0) {
+        fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
+        return -ENOEXEC;
+    }
+
+    /*
+     * fix up the flags for the older format,  there were all kinds
+     * of endian hacks,  this only works for the simple cases
+     */
+    if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
+        flags = FLAT_FLAG_RAM;
+
+#ifndef CONFIG_BINFMT_ZFLAT
+    if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
+        fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
+        return -ENOEXEC;
+    }
+#endif
+
+    /*
+     * calculate the extra space we need to map in
+     */
+    extra = relocs * sizeof(target_ulong);
+    if (extra < bss_len + stack_len)
+        extra = bss_len + stack_len;
+
+    /*
+     * there are a couple of cases here,  the separate code/data
+     * case,  and then the fully copied to RAM case which lumps
+     * it all together.
+     */
+    if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
+        /*
+         * this should give us a ROM ptr,  but if it doesn't we don't
+         * really care
+         */
+        DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
+
+        textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
+                              MAP_PRIVATE, bprm->fd, 0);
+        if (textpos == -1) { 
+            fprintf(stderr, "Unable to mmap process text\n");
+            return -1;
+        }
+
+        realdatastart = target_mmap(0, data_len + extra +
+                                    MAX_SHARED_LIBS * sizeof(target_ulong),
+                                    PROT_READ|PROT_WRITE|PROT_EXEC,
+                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+        if (realdatastart == -1) {
+            fprintf(stderr, "Unable to allocate RAM for process data\n");
+            return realdatastart;
+        }
+        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+
+        DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
+                        (int)(data_len + bss_len + stack_len), (int)datapos);
+
+        fpos = ntohl(hdr->data_start);
+#ifdef CONFIG_BINFMT_ZFLAT
+        if (flags & FLAT_FLAG_GZDATA) {
+            result = decompress_exec(bprm, fpos, (char *) datapos, 
+                                     data_len + (relocs * 
sizeof(target_ulong)))
+        } else
+#endif
+        {
+            result = target_pread(bprm->fd, datapos,
+                                  data_len + (relocs * sizeof(target_ulong)),
+                                  fpos);
+        }
+        if (result < 0) {
+            fprintf(stderr, "Unable to read data+bss\n");
+            return result;
+        }
+
+        reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
+        memp = realdatastart;
+
+    } else {
+
+        textpos = target_mmap(0, text_len + data_len + extra +
+                              MAX_SHARED_LIBS * sizeof(target_ulong),
+                              PROT_READ | PROT_EXEC | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+        if (textpos == -1 ) {
+            fprintf(stderr, "Unable to allocate RAM for process text/data\n");
+            return -1;
+        }
+
+        realdatastart = textpos + ntohl(hdr->data_start);
+        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+        reloc = (textpos + ntohl(hdr->reloc_start) +
+                 MAX_SHARED_LIBS * sizeof(target_ulong));
+        memp = textpos;
+
+#ifdef CONFIG_BINFMT_ZFLAT
+#error code needs checking
+        /*
+         * load it all in and treat it like a RAM load from now on
+         */
+        if (flags & FLAT_FLAG_GZIP) {
+                result = decompress_exec(bprm, sizeof (struct flat_hdr),
+                                 (((char *) textpos) + sizeof (struct 
flat_hdr)),
+                                 (text_len + data_len + (relocs * 
sizeof(unsigned long))
+                                          - sizeof (struct flat_hdr)),
+                                 0);
+                memmove((void *) datapos, (void *) realdatastart,
+                                data_len + (relocs * sizeof(unsigned long)));
+        } else if (flags & FLAT_FLAG_GZDATA) {
+                fpos = 0;
+                result = bprm->file->f_op->read(bprm->file,
+                                (char *) textpos, text_len, &fpos);
+                if (result < (unsigned long) -4096)
+                        result = decompress_exec(bprm, text_len, (char *) 
datapos,
+                                         data_len + (relocs * sizeof(unsigned 
long)), 0);
+        }
+        else
+#endif
+        {
+            result = target_pread(bprm->fd, textpos,
+                                  text_len, 0);
+            if (result >= 0) {
+                result = target_pread(bprm->fd, datapos,
+                    data_len + (relocs * sizeof(target_ulong)),
+                    ntohl(hdr->data_start));
+            }
+        }
+        if (result < 0) {
+            fprintf(stderr, "Unable to read code+data+bss\n");
+            return result;
+        }
+    }
+
+    DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n",
+            (int)textpos, 0x00ffffff&ntohl(hdr->entry),
+            ntohl(hdr->data_start));
+
+    /* The main program needs a little extra setup in the task structure */
+    start_code = textpos + sizeof (struct flat_hdr);
+    end_code = textpos + text_len;
+
+    DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
+            id ? "Lib" : "Load", bprm->filename,
+            (int) start_code, (int) end_code,
+            (int) datapos,
+            (int) (datapos + data_len),
+            (int) (datapos + data_len),
+            (int) (((datapos + data_len + bss_len) + 3) & ~3));
+
+    text_len -= sizeof(struct flat_hdr); /* the real code len */
+
+    /* Store the current module values into the global library structure */
+    libinfo[id].start_code = start_code;
+    libinfo[id].start_data = datapos;
+    libinfo[id].end_data = datapos + data_len;
+    libinfo[id].start_brk = datapos + data_len + bss_len;
+    libinfo[id].text_len = text_len;
+    libinfo[id].loaded = 1;
+    libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
+    libinfo[id].build_date = ntohl(hdr->build_date);
+    
+    /*
+     * We just load the allocations into some temporary memory to
+     * help simplify all this mumbo jumbo
+     *
+     * We've got two different sections of relocation entries.
+     * The first is the GOT which resides at the begining of the data segment
+     * and is terminated with a -1.  This one can be relocated in place.
+     * The second is the extra relocation entries tacked after the image's
+     * data segment. These require a little more processing as the entry is
+     * really an offset into the image which contains an offset into the
+     * image.
+     */
+    if (flags & FLAT_FLAG_GOTPIC) {
+        rp = datapos;
+        while (1) {
+            target_ulong addr;
+            addr = tgetl(rp);
+            if (addr == -1)
+                break;
+            if (addr) {
+                addr = calc_reloc(addr, libinfo, id, 0);
+                if (addr == RELOC_FAILED)
+                    return -ENOEXEC;
+                tputl(rp, addr);
+            }
+            rp += sizeof(target_ulong);
+        }
+    }
+
+    /*
+     * Now run through the relocation entries.
+     * We've got to be careful here as C++ produces relocatable zero
+     * entries in the constructor and destructor tables which are then
+     * tested for being not zero (which will always occur unless we're
+     * based from address zero).  This causes an endless loop as __start
+     * is at zero.  The solution used is to not relocate zero addresses.
+     * This has the negative side effect of not allowing a global data
+     * reference to be statically initialised to _stext (I've moved
+     * __start to address 4 so that is okay).
+     */
+    if (rev > OLD_FLAT_VERSION) {
+        for (i = 0; i < relocs; i++) {
+            target_ulong addr, relval;
+
+            /* Get the address of the pointer to be
+               relocated (of course, the address has to be
+               relocated first).  */
+            relval = tgetl(reloc + i * sizeof (target_ulong));
+            addr = flat_get_relocate_addr(relval);
+            rp = calc_reloc(addr, libinfo, id, 1);
+            if (rp == RELOC_FAILED)
+                return -ENOEXEC;
+
+            /* Get the pointer's value.  */
+            addr = tgetl(rp);
+            if (addr != 0) {
+                /*
+                 * Do the relocation.  PIC relocs in the data section are
+                 * already in target order
+                 */
+
+#ifndef TARGET_WORDS_BIGENDIAN
+                if ((flags & FLAT_FLAG_GOTPIC) == 0)
+                    addr = bswap32(addr);
+#endif
+                addr = calc_reloc(addr, libinfo, id, 0);
+                if (addr == RELOC_FAILED)
+                    return -ENOEXEC;
+
+                /* Write back the relocated pointer.  */
+                tputl(rp, addr);
+            }
+        }
+    } else {
+        for (i = 0; i < relocs; i++) {
+            target_ulong relval;
+            relval = tgetl(reloc + i * sizeof (target_ulong));
+            old_reloc(&libinfo[0], relval);
+        }
+    }
+    
+    /* zero the BSS.  */
+    memset((void*)(datapos + data_len), 0, bss_len);
+
+    return 0;
+}
+
+
+/****************************************************************************/
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+
+/*
+ * Load a shared library into memory.  The library gets its own data
+ * segment (including bss) but not argv/argc/environ.
+ */
+
+static int load_flat_shared_library(int id, struct lib_info *libs)
+{
+       struct linux_binprm bprm;
+       int res;
+       char buf[16];
+
+       /* Create the file name */
+       sprintf(buf, "/lib/lib%d.so", id);
+
+       /* Open the file up */
+       bprm.filename = buf;
+       bprm.file = open_exec(bprm.filename);
+       res = PTR_ERR(bprm.file);
+       if (IS_ERR(bprm.file))
+               return res;
+
+       res = prepare_binprm(&bprm);
+
+       if (res <= (unsigned long)-4096)
+               res = load_flat_file(&bprm, libs, id, NULL);
+       if (bprm.file) {
+               allow_write_access(bprm.file);
+               fput(bprm.file);
+               bprm.file = NULL;
+       }
+       return(res);
+}
+
+#endif /* CONFIG_BINFMT_SHARED_FLAT */
+
+int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info)
+{
+    struct lib_info libinfo[MAX_SHARED_LIBS];
+    target_ulong p = bprm->p;
+    target_ulong stack_len;
+    target_ulong start_addr;
+    target_ulong sp;
+    int res;
+    int i, j;
+
+    memset(libinfo, 0, sizeof(libinfo));
+    /*
+     * We have to add the size of our arguments to our stack size
+     * otherwise it's too easy for users to create stack overflows
+     * by passing in a huge argument list.  And yes,  we have to be
+     * pedantic and include space for the argv/envp array as it may have
+     * a lot of entries.
+     */
+#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
+    stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
+    stack_len += (bprm->argc + 1) * 4; /* the argv array */
+    stack_len += (bprm->envc + 1) * 4; /* the envp array */
+
+    
+    res = load_flat_file(bprm, libinfo, 0, &stack_len);
+    if (res > (unsigned long)-4096)
+            return res;
+    
+    /* Update data segment pointers for all libraries */
+    for (i=0; i<MAX_SHARED_LIBS; i++) {
+        if (libinfo[i].loaded) {
+            target_ulong p;
+            p = libinfo[i].start_data;
+            for (j=0; j<MAX_SHARED_LIBS; j++) {
+                p -= 4;
+                tput32(p, libinfo[j].loaded
+                          ? libinfo[j].start_data
+                          : UNLOADED_LIB);
+            }
+        }
+    }
+
+    p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4;
+    DBG_FLT("p=%x\n", (int)p);
+
+    /* Copy argv/envp.  */
+    p = copy_strings(p, bprm->argc, bprm->argv);
+    p = copy_strings(p, bprm->envc, bprm->envp);
+    /* Align stack.  */
+    sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
+    
+    /* Fake some return addresses to ensure the call chain will
+     * initialise library in order for us.  We are required to call
+     * lib 1 first, then 2, ... and finally the main program (id 0).
+     */
+    start_addr = libinfo[0].entry;
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#error here
+    for (i = MAX_SHARED_LIBS-1; i>0; i--) {
+            if (libinfo[i].loaded) {
+                    /* Push previos first to call address */
+                    --sp;      put_user(start_addr, sp);
+                    start_addr = libinfo[i].entry;
+            }
+    }
+#endif
+    
+    /* Stash our initial stack pointer into the mm structure */
+    info->start_code = libinfo[0].start_code;
+    info->end_code = libinfo[0].start_code = libinfo[0].text_len;
+    info->start_data = libinfo[0].start_data;
+    info->end_data = libinfo[0].end_data;
+    info->start_brk = libinfo[0].start_brk;
+    info->start_stack = sp;
+    info->entry = start_addr;
+    DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
+            (int)info->entry, (int)info->start_stack);
+    
+    return 0;
+}

Index: linux-user/linuxload.c
===================================================================
RCS file: linux-user/linuxload.c
diff -N linux-user/linuxload.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ linux-user/linuxload.c      11 Jun 2006 13:32:59 -0000      1.1
@@ -0,0 +1,195 @@
+/* Code for loading Linux executables.  Mostly linux kenrel code.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "qemu.h"
+
+#define NGROUPS 32
+
+/* ??? This should really be somewhere else.  */
+void memcpy_to_target(target_ulong dest, const void *src,
+                      unsigned long len)
+{
+    void *host_ptr;
+
+    host_ptr = lock_user(dest, len, 0);
+    memcpy(host_ptr, src, len);
+    unlock_user(host_ptr, dest, 1);
+}
+
+static int in_group_p(gid_t g)
+{
+    /* return TRUE if we're in the specified group, FALSE otherwise */
+    int                ngroup;
+    int                i;
+    gid_t      grouplist[NGROUPS];
+
+    ngroup = getgroups(NGROUPS, grouplist);
+    for(i = 0; i < ngroup; i++) {
+       if(grouplist[i] == g) {
+           return 1;
+       }
+    }
+    return 0;
+}
+
+static int count(char ** vec)
+{
+    int                i;
+
+    for(i = 0; *vec; i++) {
+        vec++;
+    }
+
+    return(i);
+}
+
+static int prepare_binprm(struct linux_binprm *bprm)
+{
+    struct stat                st;
+    int mode;
+    int retval, id_change;
+
+    if(fstat(bprm->fd, &st) < 0) {
+       return(-errno);
+    }
+
+    mode = st.st_mode;
+    if(!S_ISREG(mode)) {       /* Must be regular file */
+       return(-EACCES);
+    }
+    if(!(mode & 0111)) {       /* Must have at least one execute bit set */
+       return(-EACCES);
+    }
+
+    bprm->e_uid = geteuid();
+    bprm->e_gid = getegid();
+    id_change = 0;
+
+    /* Set-uid? */
+    if(mode & S_ISUID) {
+       bprm->e_uid = st.st_uid;
+       if(bprm->e_uid != geteuid()) {
+           id_change = 1;
+       }
+    }
+
+    /* Set-gid? */
+    /*
+     * If setgid is set but no group execute bit then this
+     * is a candidate for mandatory locking, not a setgid
+     * executable.
+     */
+    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+       bprm->e_gid = st.st_gid;
+       if (!in_group_p(bprm->e_gid)) {
+               id_change = 1;
+       }
+    }
+
+    memset(bprm->buf, 0, sizeof(bprm->buf));
+    retval = lseek(bprm->fd, 0L, SEEK_SET);
+    if(retval >= 0) {
+        retval = read(bprm->fd, bprm->buf, 128);
+    }
+    if(retval < 0) {
+       perror("prepare_binprm");
+       exit(-1);
+       /* return(-errno); */
+    }
+    else {
+       return(retval);
+    }
+}
+
+/* Construct the envp and argv tables on the target stack.  */
+target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
+                                 target_ulong stringp, int push_ptr)
+{
+    int n = sizeof(target_ulong);
+    target_ulong envp;
+    target_ulong argv;
+
+    sp -= (envc + 1) * n;
+    envp = sp;
+    sp -= (argc + 1) * n;
+    argv = sp;
+    if (push_ptr) {
+        sp -= n; tputl(sp, envp);
+        sp -= n; tputl(sp, argv);
+    }
+    sp -= n; tputl(sp, argc);
+
+    while (argc-- > 0) {
+        tputl(argv, stringp); argv += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    tputl(argv, 0);
+    while (envc-- > 0) {
+        tputl(envp, stringp); envp += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    tputl(envp, 0);
+
+    return sp;
+}
+
+int loader_exec(const char * filename, char ** argv, char ** envp, 
+             struct target_pt_regs * regs, struct image_info *infop)
+{
+    struct linux_binprm bprm;
+    int retval;
+    int i;
+
+    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
+            bprm.page[i] = 0;
+    retval = open(filename, O_RDONLY);
+    if (retval < 0)
+        return retval;
+    bprm.fd = retval;
+    bprm.filename = (char *)filename;
+    bprm.argc = count(argv);
+    bprm.argv = argv;
+    bprm.envc = count(envp);
+    bprm.envp = envp;
+
+    retval = prepare_binprm(&bprm);
+
+    if(retval>=0) {
+        if (bprm.buf[0] == 0x7f
+                && bprm.buf[1] == 'E'
+                && bprm.buf[2] == 'L'
+                && bprm.buf[3] == 'F') {
+            retval = load_elf_binary(&bprm,regs,infop);
+#if defined(TARGET_HAS_BFLT)
+        } else if (bprm.buf[0] == 'b'
+                && bprm.buf[1] == 'F'
+                && bprm.buf[2] == 'L'
+                && bprm.buf[3] == 'T') {
+            retval = load_flt_binary(&bprm,regs,infop);
+#endif
+        } else {
+            fprintf(stderr, "Unknown binary format\n");
+            return -1;
+        }
+    }
+    
+    if(retval>=0) {
+        /* success.  Initialize important registers */
+        do_init_thread(regs, infop);
+        return retval;
+    }
+
+    /* Something went wrong, return the inode and free the argument pages*/
+    for (i=0 ; i<MAX_ARG_PAGES ; i++) {
+        free(bprm.page[i]);
+    }
+    return(retval);
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]