From: "J. Mayer" <l_indien@magic.fr>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] RFC: fix run of 32 bits Linux executables on 64 bits targets
Date: Wed, 10 Oct 2007 09:42:08 +0200 [thread overview]
Message-ID: <1192002128.9976.186.camel@rapid> (raw)
[-- Attachment #1: Type: text/plain, Size: 724 bytes --]
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 <l_indien@magic.fr>
Never organized
[-- Attachment #2: linux_per32.diff --]
[-- Type: text/x-patch, Size: 13737 bytes --]
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);
next reply other threads:[~2007-10-10 7:42 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-10 7:42 J. Mayer [this message]
2007-10-10 8:18 ` [Qemu-devel] RFC: fix run of 32 bits Linux executables on 64 bits targets Fabrice Bellard
2007-10-10 16:09 ` Blue Swirl
2007-10-10 17:49 ` Thiemo Seufer
2007-10-10 18:40 ` Fabrice Bellard
2007-10-10 19:02 ` Blue Swirl
2007-10-10 21:51 ` J. Mayer
2007-10-11 15:17 ` Thiemo Seufer
2007-10-11 15:47 ` Blue Swirl
2007-10-11 16:00 ` Thiemo Seufer
2007-10-11 19:26 ` Blue Swirl
2007-10-11 22:00 ` J. Mayer
2007-10-12 16:21 ` Blue Swirl
2007-10-12 18:42 ` Thiemo Seufer
2007-10-12 19:37 ` Blue Swirl
2007-10-12 20:24 ` Thiemo Seufer
2007-10-10 16:01 ` Blue Swirl
2007-10-10 18:42 ` J. Mayer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1192002128.9976.186.camel@rapid \
--to=l_indien@magic.fr \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).