Following the patches done for elfload32, it appeared to me that there
were still problems that would prevent 32 bits executables to run on 64
bits target in linux user mode emulation.
First of all, the personality was never set to PER_LINUX32
The second problem was that pointers used to set the values on the stack
were still of target_ulong size, which lead 32 bits executable crash
dereferencing NULL pointers as soon as they wanted to parse their
arguments.

The attached patch makes 32 bits PowerPC executables run in
ppc64_linux_user target. More fixes may be needed in the start_thread
function and elf_check_arch to make other targets run as well.

Please comment.

-- 
J. Mayer <[EMAIL PROTECTED]>
Never organized
Index: configure
===================================================================
RCS file: /sources/qemu/qemu/configure,v
retrieving revision 1.161
diff -u -d -d -p -r1.161 configure
--- configure	9 Oct 2007 16:34:28 -0000	1.161
+++ configure	10 Oct 2007 07:38:59 -0000
@@ -1029,11 +1030,12 @@ elif test "$target_cpu" = "ppc" ; then
   echo "TARGET_ARCH=ppc" >> $config_mak
   echo "#define TARGET_ARCH \"ppc\"" >> $config_h
   echo "#define TARGET_PPC 1" >> $config_h
 elif test "$target_cpu" = "ppc64" ; then
   echo "TARGET_ARCH=ppc64" >> $config_mak
   echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
   echo "#define TARGET_PPC 1" >> $config_h
   echo "#define TARGET_PPC64 1" >> $config_h
+  elfload32="yes"
 elif test "$target_cpu" = "ppcemb" ; then
   echo "TARGET_ARCH=ppcemb" >> $config_mak
   echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h
Index: linux-user/elfload.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/elfload.c,v
retrieving revision 1.51
diff -u -d -d -p -r1.51 elfload.c
--- linux-user/elfload.c	9 Oct 2007 16:34:29 -0000	1.51
+++ linux-user/elfload.c	10 Oct 2007 07:38:59 -0000
@@ -12,65 +12,10 @@
 #include "qemu.h"
 #include "disas.h"
 
-/* from personality.h */
-
-/*
- * Flags for bug emulation.
- *
- * These occupy the top three bytes.
- */
-enum {
-	ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization of VA space */
-	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
-						 * (signal handling)
-						 */
-	MMAP_PAGE_ZERO =	0x0100000,
-	ADDR_COMPAT_LAYOUT =	0x0200000,
-	READ_IMPLIES_EXEC =	0x0400000,
-	ADDR_LIMIT_32BIT =	0x0800000,
-	SHORT_INODE =		0x1000000,
-	WHOLE_SECONDS =		0x2000000,
-	STICKY_TIMEOUTS	=	0x4000000,
-	ADDR_LIMIT_3GB = 	0x8000000,
-};
-
-/*
- * Personality types.
- *
- * These go in the low byte.  Avoid using the top bit, it will
- * conflict with error returns.
- */
-enum {
-	PER_LINUX =		0x0000,
-	PER_LINUX_32BIT =	0x0000 | ADDR_LIMIT_32BIT,
-	PER_LINUX_FDPIC =	0x0000 | FDPIC_FUNCPTRS,
-	PER_SVR4 =		0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-	PER_SVR3 =		0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
-	PER_SCOSVR3 =		0x0003 | STICKY_TIMEOUTS |
-					 WHOLE_SECONDS | SHORT_INODE,
-	PER_OSR5 =		0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
-	PER_WYSEV386 =		0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
-	PER_ISCR4 =		0x0005 | STICKY_TIMEOUTS,
-	PER_BSD =		0x0006,
-	PER_SUNOS =		0x0006 | STICKY_TIMEOUTS,
-	PER_XENIX =		0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
-	PER_LINUX32 =		0x0008,
-	PER_LINUX32_3GB =	0x0008 | ADDR_LIMIT_3GB,
-	PER_IRIX32 =		0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
-	PER_IRIXN32 =		0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
-	PER_IRIX64 =		0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
-	PER_RISCOS =		0x000c,
-	PER_SOLARIS =		0x000d | STICKY_TIMEOUTS,
-	PER_UW7 =		0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-	PER_OSF4 =		0x000f,			 /* OSF/1 v4 */
-	PER_HPUX =		0x0010,
-	PER_MASK =		0x00ff,
-};
-
 /*
  * Return the base personality without flags.
  */
-#define personality(pers)	(pers & PER_MASK)
+#define personality(pers)	((pers) & PER_MASK)
 
 /* this flag is uneffective under linux too, should be deleted */
 #ifndef MAP_DENYWRITE
@@ -215,6 +160,7 @@ enum
 #define ELF_START_MMAP 0x80000000
 
 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#define elf_check_arch32(x) ( (x) == EM_SPARC32PLUS )
 
 #define ELF_CLASS   ELFCLASS64
 #define ELF_DATA    ELFDATA2MSB
@@ -261,7 +207,8 @@ static inline void init_thread(struct ta
 
 #ifdef TARGET_PPC64
 
-#define elf_check_arch(x) ( (x) == EM_PPC64 )
+#define elf_check_arch(x) ( (x) == EM_PPC64 || (x) == EM_PPC )
+#define elf_check_arch32(x) ( (x) == EM_PPC )
 
 #define ELF_CLASS	ELFCLASS64
 
@@ -311,32 +258,51 @@ do {                                    
 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
  } while (0)
 
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *_regs,
+                               struct image_info *infop)
 {
     target_ulong pos = infop->start_stack;
-    target_ulong tmp;
+    target_ulong tmp, elen;
 #ifdef TARGET_PPC64
     target_ulong entry, toc;
 #endif
 
-    _regs->msr = 1 << MSR_PR; /* Set user mode */
+    _regs->msr = 1ULL << MSR_PR; /* Set user mode */
     _regs->gpr[1] = infop->start_stack;
 #ifdef TARGET_PPC64
-    entry = ldq_raw(infop->entry) + infop->load_addr;
-    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
-    _regs->gpr[2] = toc;
-    infop->entry = entry;
+    if (personality(infop->personality) != PER_LINUX32) {
+        entry = ldq_raw(infop->entry) + infop->load_addr;
+        toc = ldq_raw(infop->entry + 8) + infop->load_addr;
+        _regs->gpr[2] = toc;
+        infop->entry = entry;
+    }
 #endif
     _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);
+#ifdef TARGET_PPC64
+    if (personality(infop->personality) != PER_LINUX32) {
+        _regs->msr = 1ULL << MSR_SF; /* Set 64 bits mode */
+        _regs->gpr[3] = ldq(pos);
+        elen = sizeof(uint64_t);
+    } else
+#endif
+    {
+        _regs->gpr[3] = ldl(pos);
+        elen = sizeof(uint32_t);
+    }
+    pos += elen;
     _regs->gpr[4] = pos;
-    for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
-        tmp = ldl(pos);
+    for (tmp = 1; tmp != 0; pos += elen) {
+#ifdef TARGET_PPC64
+        if (personality(infop->personality) != PER_LINUX32)
+            tmp = ldq(pos);
+        else
+#endif
+            tmp = ldl(pos);
+    }
     _regs->gpr[5] = pos;
 }
 
@@ -742,8 +708,14 @@ static target_ulong create_elf_tables(ta
         int size;
         target_ulong u_platform;
         const char *k_platform;
-        const int n = sizeof(elf_addr_t);
+        int n;
 
+#ifdef OVERRIDE_ELF_CLASS
+        if (personality(info->personality) == PER_LINUX32)
+            n = sizeof(uint32_t);
+        else
+#endif
+            n = sizeof(elf_addr_t);
         sp = p;
         u_platform = 0;
         k_platform = ELF_PLATFORM;
@@ -809,7 +781,7 @@ static target_ulong create_elf_tables(ta
 #endif
 #undef NEW_AUX_ENT
 
-        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs, n);
         return sp;
 }
 
@@ -1388,7 +1359,12 @@ int load_elf_binary(struct linux_binprm 
 	load_symbols(&elf_ex, bprm->fd);
 
     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
-    info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
+#ifdef OVERRIDE_ELF_CLASS
+    if (elf_check_arch32(elf_ex.e_machine))
+        info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX32);
+    else
+#endif
+        info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
 #ifdef LOW_ELF_STACK
     info->start_stack = bprm->p = elf_stack - 4;
Index: linux-user/flatload.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/flatload.c,v
retrieving revision 1.7
diff -u -d -d -p -r1.7 flatload.c
--- linux-user/flatload.c	17 Sep 2007 08:09:49 -0000	1.7
+++ linux-user/flatload.c	10 Oct 2007 07:38:59 -0000
@@ -766,7 +766,8 @@ int load_flt_binary(struct linux_binprm 
     stack_len *= sizeof(target_ulong);
     if ((sp + stack_len) & 15)
         sp -= 16 - ((sp + stack_len) & 15);
-    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1,
+                             sizeof(target_ulong));
 
     /* Fake some return addresses to ensure the call chain will
      * initialise library in order for us.  We are required to call
Index: linux-user/linuxload.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/linuxload.c,v
retrieving revision 1.6
diff -u -d -d -p -r1.6 linuxload.c
--- linux-user/linuxload.c	9 Oct 2007 16:34:29 -0000	1.6
+++ linux-user/linuxload.c	10 Oct 2007 07:38:59 -0000
@@ -109,10 +109,21 @@ static int prepare_binprm(struct linux_b
 }
 
 /* Construct the envp and argv tables on the target stack.  */
+static inline void putl (target_ulong addr, target_ulong data, int n)
+{
+    if (n == sizeof(target_ulong)) {
+        tputl(addr, data);
+    } else {
+        /* Force 32 bits store for 32 program executed on a 64 bits target */
+        stl(addr, data);
+    }
+}
+
 target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
-                                 target_ulong stringp, int push_ptr)
+                                 target_ulong stringp, int push_ptr,
+                                 int plen)
 {
-    int n = sizeof(target_ulong);
+    int n = plen;
     target_ulong envp;
     target_ulong argv;
 
@@ -121,21 +132,21 @@ target_ulong loader_build_argptr(int env
     sp -= (argc + 1) * n;
     argv = sp;
     if (push_ptr) {
-        sp -= n; tputl(sp, envp);
-        sp -= n; tputl(sp, argv);
+        sp -= n; putl(sp, envp, n);
+        sp -= n; putl(sp, argv, n);
     }
-    sp -= n; tputl(sp, argc);
+    sp -= n; putl(sp, argc, n);
 
     while (argc-- > 0) {
-        tputl(argv, stringp); argv += n;
+        putl(argv, stringp, n); argv += n;
         stringp += target_strlen(stringp) + 1;
     }
-    tputl(argv, 0);
+    putl(argv, 0, n);
     while (envc-- > 0) {
-        tputl(envp, stringp); envp += n;
+        putl(envp, stringp, n); envp += n;
         stringp += target_strlen(stringp) + 1;
     }
-    tputl(envp, 0);
+    putl(envp, 0, n);
 
     return sp;
 }
Index: linux-user/main.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/main.c,v
retrieving revision 1.131
diff -u -d -d -p -r1.131 main.c
--- linux-user/main.c	9 Oct 2007 16:34:29 -0000	1.131
+++ linux-user/main.c	10 Oct 2007 07:38:59 -0000
@@ -2159,8 +2159,17 @@ int main(int argc, char **argv)
         int i;
 
         /* Choose and initialise CPU */
+#if defined(TARGET_PPC64)
+        if (cpu_model == NULL) {
+            if (get_personality(info) == PER_LINUX32)
+                cpu_model = "750";
+            else
+                cpu_model = "970";
+        }
+#else
         if (cpu_model == NULL)
             cpu_model = "750";
+#endif
         ppc_find_by_name(cpu_model, &def);
         if (def == NULL) {
             cpu_abort(env,
@@ -2172,9 +2181,6 @@ int main(int argc, char **argv)
             if (i != 12 && i != 6 && i != 13)
                 env->msr[i] = (regs->msr >> i) & 1;
         }
-#if defined(TARGET_PPC64)
-        msr_sf = 1;
-#endif
         env->nip = regs->nip;
         for(i = 0; i < 32; i++) {
             env->gpr[i] = regs->gpr[i];
Index: linux-user/qemu.h
===================================================================
RCS file: /sources/qemu/qemu/linux-user/qemu.h,v
retrieving revision 1.40
diff -u -d -d -p -r1.40 qemu.h
--- linux-user/qemu.h	9 Oct 2007 16:34:29 -0000	1.40
+++ linux-user/qemu.h	10 Oct 2007 07:38:59 -0000
@@ -16,6 +16,66 @@
  * Basically, it replicates in user space what would be certain
  * task_struct fields in the kernel
  */
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+	ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization of VA space */
+	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
+						 * (signal handling)
+						 */
+	MMAP_PAGE_ZERO =	0x0100000,
+	ADDR_COMPAT_LAYOUT =	0x0200000,
+	READ_IMPLIES_EXEC =	0x0400000,
+	ADDR_LIMIT_32BIT =	0x0800000,
+	SHORT_INODE =		0x1000000,
+	WHOLE_SECONDS =		0x2000000,
+	STICKY_TIMEOUTS	=	0x4000000,
+	ADDR_LIMIT_3GB = 	0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+	PER_LINUX =		0x0000,
+	PER_LINUX_32BIT =	0x0000 | ADDR_LIMIT_32BIT,
+	PER_LINUX_FDPIC =	0x0000 | FDPIC_FUNCPTRS,
+	PER_SVR4 =		0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+	PER_SVR3 =		0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+	PER_SCOSVR3 =		0x0003 | STICKY_TIMEOUTS |
+					 WHOLE_SECONDS | SHORT_INODE,
+	PER_OSR5 =		0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+	PER_WYSEV386 =		0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+	PER_ISCR4 =		0x0005 | STICKY_TIMEOUTS,
+	PER_BSD =		0x0006,
+	PER_SUNOS =		0x0006 | STICKY_TIMEOUTS,
+	PER_XENIX =		0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+	PER_LINUX32 =		0x0008,
+	PER_LINUX32_3GB =	0x0008 | ADDR_LIMIT_3GB,
+	PER_IRIX32 =		0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+	PER_IRIXN32 =		0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+	PER_IRIX64 =		0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+	PER_RISCOS =		0x000c,
+	PER_SOLARIS =		0x000d | STICKY_TIMEOUTS,
+	PER_UW7 =		0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+	PER_OSF4 =		0x000f,			 /* OSF/1 v4 */
+	PER_HPUX =		0x0010,
+	PER_MASK =		0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define get_personality(infop)	(((infop)->personality) & PER_MASK)
+
 struct image_info {
 	target_ulong	load_addr;
 	target_ulong	start_code;
@@ -116,7 +176,7 @@ struct linux_binprm {
 
 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);
+                                 target_ulong stringp, int push_ptr, int plen);
 int loader_exec(const char * filename, char ** argv, char ** envp,
              struct target_pt_regs * regs, struct image_info *infop);
 

Reply via email to