qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
@ 2007-10-07 12:45 Blue Swirl
  2007-10-07 14:01 ` J. Mayer
  2007-10-07 16:21 ` Thiemo Seufer
  0 siblings, 2 replies; 9+ messages in thread
From: Blue Swirl @ 2007-10-07 12:45 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 977 bytes --]

Hi,

This patch adds support for loading a 32 bit ELF file in the 64 bit
user mode emulator. This means that qemu-sparc64 can be used to
execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
This format is used by Solaris/Sparc and maybe by Debian in the
future.

Other targets shouldn't be affected, but I have done only compile
testing. Any comments?

$ cat helloworld.c
#define __KERNEL__
#include <asm/unistd.h>
static int errno;
static __inline__ _syscall1(void,exit,int,exitval)
static inline _syscall3(int,write,int,fd,const char *,buf,long,count)

int _start()
{
  write(2, "Hello World!\n", sizeof("Hello World!\n"));
  exit(0);
}
$ gcc -o helloworld.sparc32plus helloworld.c -g -Wa,-xarch=v9b -Wa,-32
-m32 -mcpu=ultrasparc -static -nostdlib
$ file helloworld.sparc32plus
helloworld.sparc32plus: ELF 32-bit MSB executable, SPARC32PLUS, V8+
Required, version 1 (SYSV), statically linked, not stripped
$ ./qemu-sparc64 ./helloworld.sparc32plus
Hello World!

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: elfload_32_and_64.diff --]
[-- Type: text/x-diff; name="elfload_32_and_64.diff", Size: 66117 bytes --]

Index: qemu/linux-user/elfload.c
===================================================================
--- qemu.orig/linux-user/elfload.c	2007-10-07 08:49:55.000000000 +0000
+++ qemu/linux-user/elfload.c	2007-10-07 12:17:56.000000000 +0000
@@ -48,7 +48,6 @@
 #define ELF_START_MMAP 0x2aaaaab000ULL
 #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
 
-#define ELF_CLASS      ELFCLASS64
 #define ELF_DATA       ELFDATA2LSB
 #define ELF_ARCH       EM_X86_64
 
@@ -71,7 +70,6 @@
 /*
  * These are used to set parameters in the core dumps.
  */
-#define ELF_CLASS	ELFCLASS32
 #define ELF_DATA	ELFDATA2LSB
 #define ELF_ARCH	EM_386
 
@@ -102,7 +100,6 @@
 
 #define elf_check_arch(x) ( (x) == EM_ARM )
 
-#define ELF_CLASS	ELFCLASS32
 #ifdef TARGET_WORDS_BIGENDIAN
 #define ELF_DATA	ELFDATA2MSB
 #else
@@ -153,9 +150,8 @@
 
 #define ELF_START_MMAP 0x80000000
 
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 )
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
 
-#define ELF_CLASS   ELFCLASS64
 #define ELF_DATA    ELFDATA2MSB
 #define ELF_ARCH    EM_SPARCV9
 
@@ -167,7 +163,10 @@
     regs->pc = infop->entry;
     regs->npc = regs->pc + 4;
     regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+    if (infop->is_64bits)
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+    else
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
 }
 
 #else
@@ -175,7 +174,6 @@
 
 #define elf_check_arch(x) ( (x) == EM_SPARC )
 
-#define ELF_CLASS   ELFCLASS32
 #define ELF_DATA    ELFDATA2MSB
 #define ELF_ARCH    EM_SPARC
 
@@ -199,14 +197,10 @@
 
 #define elf_check_arch(x) ( (x) == EM_PPC64 )
 
-#define ELF_CLASS	ELFCLASS64
-
 #else
 
 #define elf_check_arch(x) ( (x) == EM_PPC )
 
-#define ELF_CLASS	ELFCLASS32
-
 #endif
 
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -287,11 +281,6 @@
 
 #define elf_check_arch(x) ( (x) == EM_MIPS )
 
-#ifdef TARGET_MIPS64
-#define ELF_CLASS   ELFCLASS64
-#else
-#define ELF_CLASS   ELFCLASS32
-#endif
 #ifdef TARGET_WORDS_BIGENDIAN
 #define ELF_DATA	ELFDATA2MSB
 #else
@@ -317,7 +306,6 @@
 
 #define elf_check_arch(x) ( (x) == EM_SH )
 
-#define ELF_CLASS ELFCLASS32
 #define ELF_DATA  ELFDATA2LSB
 #define ELF_ARCH  EM_SH
 
@@ -339,7 +327,6 @@
 
 #define elf_check_arch(x) ( (x) == EM_68K )
 
-#define ELF_CLASS	ELFCLASS32
 #define ELF_DATA	ELFDATA2MSB
 #define ELF_ARCH	EM_68K
 
@@ -364,7 +351,6 @@
 
 #define elf_check_arch(x) ( (x) == ELF_ARCH )
 
-#define ELF_CLASS      ELFCLASS64
 #define ELF_DATA       ELFDATA2MSB
 #define ELF_ARCH       EM_ALPHA
 
@@ -391,6 +377,7 @@
 #define ELF_HWCAP 0
 #endif
 
+#define ELF_CLASS       ELFCLASS32
 #include "elf.h"
 
 struct exec
@@ -457,59 +444,6 @@
 
 static int load_aout_interp(void * exptr, int interp_fd);
 
-#ifdef BSWAP_NEEDED
-static void bswap_ehdr(struct elfhdr *ehdr)
-{
-    bswap16s(&ehdr->e_type);			/* Object file type */
-    bswap16s(&ehdr->e_machine);		/* Architecture */
-    bswap32s(&ehdr->e_version);		/* Object file version */
-    bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
-    bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
-    bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
-    bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
-    bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
-    bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
-    bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
-}
-
-static void bswap_phdr(struct elf_phdr *phdr)
-{
-    bswap32s(&phdr->p_type);			/* Segment type */
-    bswaptls(&phdr->p_offset);		/* Segment file offset */
-    bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
-    bswaptls(&phdr->p_paddr);		/* Segment physical address */
-    bswaptls(&phdr->p_filesz);		/* Segment size in file */
-    bswaptls(&phdr->p_memsz);		/* Segment size in memory */
-    bswap32s(&phdr->p_flags);		/* Segment flags */
-    bswaptls(&phdr->p_align);		/* Segment alignment */
-}
-
-static void bswap_shdr(struct elf_shdr *shdr)
-{
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswaptls(&shdr->sh_flags);
-    bswaptls(&shdr->sh_addr);
-    bswaptls(&shdr->sh_offset);
-    bswaptls(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswaptls(&shdr->sh_addralign);
-    bswaptls(&shdr->sh_entsize);
-}
-
-static void bswap_sym(struct elf_sym *sym)
-{
-    bswap32s(&sym->st_name);
-    bswaptls(&sym->st_value);
-    bswaptls(&sym->st_size);
-    bswap16s(&sym->st_shndx);
-}
-#endif
-
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
  * memory to free pages in kernel mem. These are in a format ready
@@ -566,8 +500,8 @@
     return p;
 }
 
-unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
-					      struct image_info * info)
+static unsigned long setup_arg_pages(target_ulong p, struct linux_binprm *bprm,
+                                     struct image_info * info)
 {
     target_ulong stack_base, size, error;
     int i;
@@ -658,700 +592,52 @@
         }
 }
 
-
-static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
-                                       struct elfhdr * exec,
-                                       unsigned long load_addr,
-                                       unsigned long load_bias,
-                                       unsigned long interp_load_addr, int ibcs,
-                                       struct image_info *info)
-{
-        target_ulong sp;
-        int size;
-        target_ulong u_platform;
-        const char *k_platform;
-        const int n = sizeof(target_ulong);
-
-        sp = p;
-        u_platform = 0;
-        k_platform = ELF_PLATFORM;
-        if (k_platform) {
-            size_t len = strlen(k_platform) + 1;
-            sp -= (len + n - 1) & ~(n - 1);
-            u_platform = sp;
-            memcpy_to_target(sp, k_platform, len);
-        }
-	/*
-	 * Force 16 byte _final_ alignment here for generality.
-	 */
-        sp = sp &~ (target_ulong)15;
-        size = (DLINFO_ITEMS + 1) * 2;
-        if (k_platform)
-          size += 2;
-#ifdef DLINFO_ARCH_ITEMS
-	size += DLINFO_ARCH_ITEMS * 2;
-#endif
-        size += envc + argc + 2;
-	size += (!ibcs ? 3 : 1);	/* argc itself */
-        size *= n;
-        if (size & 15)
-            sp -= 16 - (size & 15);
-
-#define NEW_AUX_ENT(id, val) do { \
-            sp -= n; tputl(sp, val); \
-            sp -= n; tputl(sp, id); \
-          } while(0)
-        NEW_AUX_ENT (AT_NULL, 0);
-
-        /* There must be exactly DLINFO_ITEMS entries here.  */
-        NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
-        NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
-        NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
-        NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
-        NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
-        NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
-        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
-        NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
-        NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
-        NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
-        NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
-        NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
-        if (k_platform)
-            NEW_AUX_ENT(AT_PLATFORM, u_platform);
-#ifdef ARCH_DLINFO
-	/*
-	 * ARCH_DLINFO must come last so platform specific code can enforce
-	 * special alignment requirements on the AUXV if necessary (eg. PPC).
-	 */
-        ARCH_DLINFO;
-#endif
-#undef NEW_AUX_ENT
-
-        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
-        return sp;
-}
-
-
-static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
-				     int interpreter_fd,
-				     unsigned long *interp_load_addr)
-{
-	struct elf_phdr *elf_phdata  =  NULL;
-	struct elf_phdr *eppnt;
-	unsigned long load_addr = 0;
-	int load_addr_set = 0;
-	int retval;
-	unsigned long last_bss, elf_bss;
-	unsigned long error;
-	int i;
-
-	elf_bss = 0;
-	last_bss = 0;
-	error = 0;
-
-#ifdef BSWAP_NEEDED
-        bswap_ehdr(interp_elf_ex);
-#endif
-	/* First of all, some simple consistency checks */
-	if ((interp_elf_ex->e_type != ET_EXEC &&
-             interp_elf_ex->e_type != ET_DYN) ||
-	   !elf_check_arch(interp_elf_ex->e_machine)) {
-		return ~0UL;
-	}
-
-
-	/* Now read in all of the header information */
-
-	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
-	    return ~0UL;
-
-	elf_phdata =  (struct elf_phdr *)
-		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
-	if (!elf_phdata)
-	  return ~0UL;
-
-	/*
-	 * If the size of this structure has changed, then punt, since
-	 * we will be doing the wrong thing.
-	 */
-	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
-	    free(elf_phdata);
-	    return ~0UL;
-        }
-
-	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
-	if(retval >= 0) {
-	    retval = read(interpreter_fd,
-			   (char *) elf_phdata,
-			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-	}
-	if (retval < 0) {
-		perror("load_elf_interp");
-		exit(-1);
-		free (elf_phdata);
-		return retval;
- 	}
-#ifdef BSWAP_NEEDED
-	eppnt = elf_phdata;
-	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-            bswap_phdr(eppnt);
-        }
-#endif
-
-        if (interp_elf_ex->e_type == ET_DYN) {
-            /* in order to avoid hardcoding the interpreter load
-               address in qemu, we allocate a big enough memory zone */
-            error = target_mmap(0, INTERP_MAP_SIZE,
-                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
-                                -1, 0);
-            if (error == -1) {
-                perror("mmap");
-                exit(-1);
-            }
-            load_addr = error;
-            load_addr_set = 1;
-        }
-
-	eppnt = elf_phdata;
-	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-	  if (eppnt->p_type == PT_LOAD) {
-	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-	    int elf_prot = 0;
-	    unsigned long vaddr = 0;
-	    unsigned long k;
-
-	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-	    	elf_type |= MAP_FIXED;
-	    	vaddr = eppnt->p_vaddr;
-	    }
-	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
-		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
-		 elf_prot,
-		 elf_type,
-		 interpreter_fd,
-		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
-	    if (error == -1) {
-	      /* Real error */
-	      close(interpreter_fd);
-	      free(elf_phdata);
-	      return ~0UL;
-	    }
-
-	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-	      load_addr = error;
-	      load_addr_set = 1;
-	    }
-
-	    /*
-	     * Find the end of the file  mapping for this phdr, and keep
-	     * track of the largest address we see for this.
-	     */
-	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-	    if (k > elf_bss) elf_bss = k;
-
-	    /*
-	     * Do the same thing for the memory mapping - between
-	     * elf_bss and last_bss is the bss section.
-	     */
-	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-	    if (k > last_bss) last_bss = k;
-	  }
-
-	/* Now use mmap to map the library into memory. */
-
-	close(interpreter_fd);
-
-	/*
-	 * Now fill out the bss section.  First pad the last page up
-	 * to the page boundary, and then perform a mmap to make sure
-	 * that there are zeromapped pages up to and including the last
-	 * bss page.
-	 */
-	padzero(elf_bss, last_bss);
-	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
-
-	/* Map the last of the bss segment */
-	if (last_bss > elf_bss) {
-            target_mmap(elf_bss, last_bss-elf_bss,
-                        PROT_READ|PROT_WRITE|PROT_EXEC,
-                        MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-	}
-	free(elf_phdata);
-
-	*interp_load_addr = load_addr;
-	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
-}
-
-/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
-{
-    unsigned int i;
-    struct elf_shdr sechdr, symtab, strtab;
-    char *strings;
-    struct syminfo *s;
-#if (ELF_CLASS == ELFCLASS64)
-    // Disas uses 32 bit symbols
-    struct elf32_sym *syms32 = NULL;
-    struct elf_sym *sym;
-#endif
-
-    lseek(fd, hdr->e_shoff, SEEK_SET);
-    for (i = 0; i < hdr->e_shnum; i++) {
-	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
-	    return;
-#ifdef BSWAP_NEEDED
-	bswap_shdr(&sechdr);
-#endif
-	if (sechdr.sh_type == SHT_SYMTAB) {
-	    symtab = sechdr;
-	    lseek(fd, hdr->e_shoff
-		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
-	    if (read(fd, &strtab, sizeof(strtab))
-		!= sizeof(strtab))
-		return;
-#ifdef BSWAP_NEEDED
-	    bswap_shdr(&strtab);
-#endif
-	    goto found;
-	}
-    }
-    return; /* Shouldn't happen... */
-
- found:
-    /* Now know where the strtab and symtab are.  Snarf them. */
-    s = malloc(sizeof(*s));
-    s->disas_symtab = malloc(symtab.sh_size);
-#if (ELF_CLASS == ELFCLASS64)
-    syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
-                    * sizeof(struct elf32_sym));
-#endif
-    s->disas_strtab = strings = malloc(strtab.sh_size);
-    if (!s->disas_symtab || !s->disas_strtab)
-	return;
-
-    lseek(fd, symtab.sh_offset, SEEK_SET);
-    if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
-	return;
-
-    for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
-#ifdef BSWAP_NEEDED
-	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
-#endif
-#if (ELF_CLASS == ELFCLASS64)
-        sym = s->disas_symtab + sizeof(struct elf_sym)*i;
-        syms32[i].st_name = sym->st_name;
-        syms32[i].st_info = sym->st_info;
-        syms32[i].st_other = sym->st_other;
-        syms32[i].st_shndx = sym->st_shndx;
-        syms32[i].st_value = sym->st_value & 0xffffffff;
-        syms32[i].st_size = sym->st_size & 0xffffffff;
-#endif
-    }
-
-#if (ELF_CLASS == ELFCLASS64)
-    free(s->disas_symtab);
-    s->disas_symtab = syms32;
-#endif
-    lseek(fd, strtab.sh_offset, SEEK_SET);
-    if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
-	return;
-    s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
-    s->next = syminfos;
-    syminfos = s;
-}
+#ifndef glue
+#define xglue(x, y)     x ## y
+#define glue(x, y)      xglue(x, y)
+#define stringify(s)    tostring(s)
+#define tostring(s)     #s
+#endif
+
+#define elf_word        uint32_t
+#define bswapSZs        bswap32s
+#define SZ              32
+#include "elfload_ops.h"
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef bswapSZs
+#undef SZ
+#define elfhdr          elf64_hdr
+#define elf_phdr        elf64_phdr
+#define elf_shdr        elf64_shdr
+#define elf_sym         elf64_sym
+#define elf_note        elf64_note
+#define elf_word        uint64_t
+#define bswapSZs        bswap64s
+#define SZ              64
+#include "elfload_ops.h"
 
 int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                     struct image_info * info)
 {
-    struct elfhdr elf_ex;
-    struct elfhdr interp_elf_ex;
-    struct exec interp_ex;
-    int interpreter_fd = -1; /* avoid warning */
-    unsigned long load_addr, load_bias;
-    int load_addr_set = 0;
-    unsigned int interpreter_type = INTERPRETER_NONE;
-    unsigned char ibcs2_interpreter;
-    int i;
-    unsigned long mapped_addr;
-    struct elf_phdr * elf_ppnt;
-    struct elf_phdr *elf_phdata;
-    unsigned long elf_bss, k, elf_brk;
+    struct elfhdr *elf_ex;
     int retval;
-    char * elf_interpreter;
-    unsigned long elf_entry, interp_load_addr = 0;
-    int status;
-    unsigned long start_code, end_code, end_data;
-    unsigned long reloc_func_desc = 0;
-    unsigned long elf_stack;
-    char passed_fileno[6];
-
-    ibcs2_interpreter = 0;
-    status = 0;
-    load_addr = 0;
-    load_bias = 0;
-    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-#ifdef BSWAP_NEEDED
-    bswap_ehdr(&elf_ex);
-#endif
-
-    /* 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) {
-	return -ENOMEM;
+    elf_ex = (struct elfhdr *) bprm->buf;          /* exec-header */
+    if (elf_ex->e_ident[EI_CLASS] == ELFCLASS64) {
+        info->is_64bits = 1;
+        retval = load_elf_binary64(bprm, regs, info);
+    } else {
+        info->is_64bits = 0;
+        retval = load_elf_binary32(bprm, regs, info);
     }
 
-    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
-    if(retval > 0) {
-	retval = read(bprm->fd, (char *) elf_phdata,
-				elf_ex.e_phentsize * elf_ex.e_phnum);
-    }
-
-    if (retval < 0) {
-	perror("load_elf_binary");
-	exit(-1);
-	free (elf_phdata);
-	return -errno;
-    }
-
-#ifdef BSWAP_NEEDED
-    elf_ppnt = elf_phdata;
-    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
-        bswap_phdr(elf_ppnt);
-    }
-#endif
-    elf_ppnt = elf_phdata;
-
-    elf_bss = 0;
-    elf_brk = 0;
-
-
-    elf_stack = ~0UL;
-    elf_interpreter = NULL;
-    start_code = ~0UL;
-    end_code = 0;
-    end_data = 0;
-
-    for(i=0;i < elf_ex.e_phnum; i++) {
-	if (elf_ppnt->p_type == PT_INTERP) {
-	    if ( elf_interpreter != NULL )
-	    {
-		free (elf_phdata);
-		free(elf_interpreter);
-		close(bprm->fd);
-		return -EINVAL;
-	    }
-
-	    /* This is the program interpreter used for
-	     * shared libraries - for now assume that this
-	     * is an a.out format binary
-	     */
-
-	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
-	    if (elf_interpreter == NULL) {
-		free (elf_phdata);
-		close(bprm->fd);
-		return -ENOMEM;
-	    }
-
-	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
-	    if(retval >= 0) {
-		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
-	    }
-	    if(retval < 0) {
-	 	perror("load_elf_binary2");
-		exit(-1);
-	    }
-
-	    /* If the program interpreter is one of these two,
-	       then assume an iBCS2 image. Otherwise assume
-	       a native linux image. */
-
-	    /* JRP - Need to add X86 lib dir stuff here... */
-
-	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
-	      ibcs2_interpreter = 1;
-	    }
-
-#if 0
-	    printf("Using ELF interpreter %s\n", elf_interpreter);
-#endif
-	    if (retval >= 0) {
-		retval = open(path(elf_interpreter), O_RDONLY);
-		if(retval >= 0) {
-		    interpreter_fd = retval;
-		}
-		else {
-		    perror(elf_interpreter);
-		    exit(-1);
-		    /* retval = -errno; */
-		}
-	    }
-
-	    if (retval >= 0) {
-		retval = lseek(interpreter_fd, 0, SEEK_SET);
-		if(retval >= 0) {
-		    retval = read(interpreter_fd,bprm->buf,128);
-		}
-	    }
-	    if (retval >= 0) {
-		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
-		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
-	    }
-	    if (retval < 0) {
-		perror("load_elf_binary3");
-		exit(-1);
-		free (elf_phdata);
-		free(elf_interpreter);
-		close(bprm->fd);
-		return retval;
-	    }
-	}
-	elf_ppnt++;
-    }
-
-    /* Some simple consistency checks for the interpreter */
-    if (elf_interpreter){
-	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
-	/* Now figure out which format our binary is */
-	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
-	    	(N_MAGIC(interp_ex) != QMAGIC)) {
-	  interpreter_type = INTERPRETER_ELF;
-	}
-
-	if (interp_elf_ex.e_ident[0] != 0x7f ||
-	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
-	    interpreter_type &= ~INTERPRETER_ELF;
-	}
-
-	if (!interpreter_type) {
-	    free(elf_interpreter);
-	    free(elf_phdata);
-	    close(bprm->fd);
-	    return -ELIBBAD;
-	}
-    }
-
-    /* OK, we are done with that, now set up the arg stuff,
-       and then start this sucker up */
-
-    {
-	char * passed_p;
-
-	if (interpreter_type == INTERPRETER_AOUT) {
-	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
-	    passed_p = passed_fileno;
-
-	    if (elf_interpreter) {
-		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
-		bprm->argc++;
-	    }
-	}
-	if (!bprm->p) {
-	    if (elf_interpreter) {
-	        free(elf_interpreter);
-	    }
-	    free (elf_phdata);
-	    close(bprm->fd);
-	    return -E2BIG;
-	}
-    }
-
-    /* OK, This is the point of no return */
-    info->end_data = 0;
-    info->end_code = 0;
-    info->start_mmap = (unsigned long)ELF_START_MMAP;
-    info->mmap = 0;
-    elf_entry = (unsigned long) elf_ex.e_entry;
-
-    /* Do this so that we can load the interpreter, if need be.  We will
-       change some of these later */
-    info->rss = 0;
-    bprm->p = setup_arg_pages(bprm->p, bprm, info);
-    info->start_stack = bprm->p;
-
-    /* Now we do a little grungy work by mmaping the ELF image into
-     * the correct location in memory.  At this point, we assume that
-     * the image should be loaded at fixed address, not at a variable
-     * address.
-     */
-
-    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
-        int elf_prot = 0;
-        int elf_flags = 0;
-        unsigned long error;
-
-	if (elf_ppnt->p_type != PT_LOAD)
-            continue;
-
-        if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-        if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-        if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-        elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
-        if (elf_ex.e_type == ET_EXEC || load_addr_set) {
-            elf_flags |= MAP_FIXED;
-        } else if (elf_ex.e_type == ET_DYN) {
-            /* Try and get dynamic programs out of the way of the default mmap
-               base, as well as whatever program they might try to exec.  This
-               is because the brk will follow the loader, and is not movable.  */
-            /* NOTE: for qemu, we do a big mmap to get enough space
-               without hardcoding any address */
-            error = target_mmap(0, ET_DYN_MAP_SIZE,
-                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
-                                -1, 0);
-            if (error == -1) {
-                perror("mmap");
-                exit(-1);
-            }
-            load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
-        }
-
-        error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
-                            (elf_ppnt->p_filesz +
-                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
-                            elf_prot,
-                            (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
-                            bprm->fd,
-                            (elf_ppnt->p_offset -
-                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-        if (error == -1) {
-            perror("mmap");
-            exit(-1);
-        }
-
-#ifdef LOW_ELF_STACK
-        if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
-            elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
-#endif
-
-        if (!load_addr_set) {
-            load_addr_set = 1;
-            load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
-            if (elf_ex.e_type == ET_DYN) {
-                load_bias += error -
-                    TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
-                load_addr += load_bias;
-                reloc_func_desc = load_bias;
-            }
-        }
-        k = elf_ppnt->p_vaddr;
-        if (k < start_code)
-            start_code = k;
-        k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-        if (k > elf_bss)
-            elf_bss = k;
-        if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
-            end_code = k;
-        if (end_data < k)
-            end_data = k;
-        k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-        if (k > elf_brk) elf_brk = k;
-    }
-
-    elf_entry += load_bias;
-    elf_bss += load_bias;
-    elf_brk += load_bias;
-    start_code += load_bias;
-    end_code += load_bias;
-    //    start_data += load_bias;
-    end_data += load_bias;
-
-    if (elf_interpreter) {
-	if (interpreter_type & 1) {
-	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
-	}
-	else if (interpreter_type & 2) {
-	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
-					    &interp_load_addr);
-	}
-        reloc_func_desc = interp_load_addr;
-
-	close(interpreter_fd);
-	free(elf_interpreter);
-
-	if (elf_entry == ~0UL) {
-	    printf("Unable to load interpreter\n");
-	    free(elf_phdata);
-	    exit(-1);
-	    return 0;
-	}
-    }
-
-    free(elf_phdata);
-
-    if (loglevel)
-	load_symbols(&elf_ex, bprm->fd);
-
-    if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
-    info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-
-#ifdef LOW_ELF_STACK
-    info->start_stack = bprm->p = elf_stack - 4;
-#endif
-    bprm->p = create_elf_tables(bprm->p,
-		    bprm->argc,
-		    bprm->envc,
-                    &elf_ex,
-                    load_addr, load_bias,
-		    interp_load_addr,
-		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
-		    info);
-    info->load_addr = reloc_func_desc;
-    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;
-
-    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
-       sections */
-    set_brk(elf_bss, elf_brk);
-
-    padzero(elf_bss, elf_brk);
-
-#if 0
-    printf("(start_brk) %x\n" , info->start_brk);
-    printf("(end_code) %x\n" , info->end_code);
-    printf("(start_code) %x\n" , info->start_code);
-    printf("(end_data) %x\n" , info->end_data);
-    printf("(start_stack) %x\n" , info->start_stack);
-    printf("(brk) %x\n" , info->brk);
-#endif
-
-    if ( info->personality == PER_SVR4 )
-    {
-	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
-	       and some applications "depend" upon this behavior.
-	       Since we do not have the power to recompile these, we
-	       emulate the SVr4 behavior.  Sigh.  */
-	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
-                                      MAP_FIXED | MAP_PRIVATE, -1, 0);
-    }
-
-    info->entry = elf_entry;
-
-    return 0;
+    return retval;
 }
 
 static int load_aout_interp(void * exptr, int interp_fd)
Index: qemu/linux-user/elfload_ops.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/linux-user/elfload_ops.h	2007-10-07 11:44:09.000000000 +0000
@@ -0,0 +1,749 @@
+#ifdef BSWAP_NEEDED
+static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);            /* Object file type */
+    bswap16s(&ehdr->e_machine);         /* Architecture */
+    bswap32s(&ehdr->e_version);         /* Object file version */
+    bswapSZs(&ehdr->e_entry);           /* Entry point virtual address */
+    bswapSZs(&ehdr->e_phoff);           /* Program header table file offset */
+    bswapSZs(&ehdr->e_shoff);           /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
+}
+
+static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
+{
+    bswap32s(&phdr->p_type);            /* Segment type */
+    bswapSZs(&phdr->p_offset);          /* Segment file offset */
+    bswapSZs(&phdr->p_vaddr);           /* Segment virtual address */
+    bswapSZs(&phdr->p_paddr);           /* Segment physical address */
+    bswapSZs(&phdr->p_filesz);          /* Segment size in file */
+    bswapSZs(&phdr->p_memsz);           /* Segment size in memory */
+    bswap32s(&phdr->p_flags);           /* Segment flags */
+    bswapSZs(&phdr->p_align);           /* Segment alignment */
+}
+
+static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswapSZs(&shdr->sh_flags);
+    bswapSZs(&shdr->sh_addr);
+    bswapSZs(&shdr->sh_offset);
+    bswapSZs(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswapSZs(&shdr->sh_addralign);
+    bswapSZs(&shdr->sh_entsize);
+}
+
+static void glue(bswap_sym, SZ)(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswapSZs(&sym->st_value);
+    bswapSZs(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+#endif
+
+static unsigned long glue(create_elf_tables, SZ)(target_ulong p, int argc,
+                                                 int envc,
+                                                 struct elfhdr *exec,
+                                                 unsigned long load_addr,
+                                                 unsigned long load_bias,
+                                                 unsigned long interp_load_addr,
+                                                 int ibcs,
+                                                 struct image_info *info)
+{
+    target_ulong sp;
+    int size;
+    target_ulong u_platform;
+    const char *k_platform;
+    const int n = sizeof(target_ulong);
+
+    sp = p;
+    u_platform = 0;
+    k_platform = ELF_PLATFORM;
+    if (k_platform) {
+        size_t len = strlen(k_platform) + 1;
+        sp -= (len + n - 1) & ~(n - 1);
+        u_platform = sp;
+        memcpy_to_target(sp, k_platform, len);
+    }
+    /*
+     * Force 16 byte _final_ alignment here for generality.
+     */
+    sp = sp & ~(target_ulong)15;
+    size = (DLINFO_ITEMS + 1) * 2;
+    if (k_platform)
+        size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+    size += DLINFO_ARCH_ITEMS * 2;
+#endif
+    size += envc + argc + 2;
+    size += (!ibcs ? 3 : 1);    /* argc itself */
+    size *= n;
+    if (size & 15)
+        sp -= 16 - (size & 15);
+
+#define NEW_AUX_ENT(id, val) do {   \
+        sp -= n; tputl(sp, val);    \
+        sp -= n; tputl(sp, id);     \
+    } while (0)
+
+    NEW_AUX_ENT (AT_NULL, 0);
+
+    /* There must be exactly DLINFO_ITEMS entries here.  */
+    NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
+    NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
+    NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
+    NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
+    NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
+    NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
+    NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+    NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
+    NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
+    NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
+    NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
+    NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
+    if (k_platform)
+        NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+    /*
+     * ARCH_DLINFO must come last so platform specific code can enforce
+     * special alignment requirements on the AUXV if necessary (eg. PPC).
+     */
+    ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+    sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+    return sp;
+}
+
+static unsigned long glue(load_elf_interp, SZ)(struct elfhdr *interp_elf_ex,
+                                               int interpreter_fd,
+                                               unsigned long *interp_load_addr)
+{
+    struct elf_phdr *elf_phdata  =  NULL;
+    struct elf_phdr *eppnt;
+    unsigned long load_addr = 0;
+    int load_addr_set = 0;
+    int retval;
+    unsigned long last_bss, elf_bss;
+    unsigned long error;
+    int i;
+
+    elf_bss = 0;
+    last_bss = 0;
+    error = 0;
+
+#ifdef BSWAP_NEEDED
+    glue(bswap_ehdr, SZ)(interp_elf_ex);
+#endif
+    /* First of all, some simple consistency checks */
+    if ((interp_elf_ex->e_type != ET_EXEC &&
+         interp_elf_ex->e_type != ET_DYN) ||
+        !elf_check_arch(interp_elf_ex->e_machine)) {
+        return ~0UL;
+    }
+
+    /* Now read in all of the header information */
+
+    if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+        return ~0UL;
+
+    elf_phdata =  (struct elf_phdr *)
+        malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+
+    if (!elf_phdata)
+        return ~0UL;
+
+    /*
+     * If the size of this structure has changed, then punt, since
+     * we will be doing the wrong thing.
+     */
+    if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+        free(elf_phdata);
+        return ~0UL;
+    }
+
+    retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
+    if (retval >= 0) {
+        retval = read(interpreter_fd,
+                      (char *) elf_phdata,
+                      sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+    }
+    if (retval < 0) {
+        perror("load_elf_interp");
+        exit(-1);
+        free (elf_phdata);
+        return retval;
+    }
+#ifdef BSWAP_NEEDED
+    eppnt = elf_phdata;
+    for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
+        glue(bswap_phdr, SZ)(eppnt);
+    }
+#endif
+
+    if (interp_elf_ex->e_type == ET_DYN) {
+        /* in order to avoid hardcoding the interpreter load
+           address in qemu, we allocate a big enough memory zone */
+        error = target_mmap(0, INTERP_MAP_SIZE,
+                            PROT_NONE, MAP_PRIVATE | MAP_ANON,
+                            -1, 0);
+        if (error == -1) {
+            perror("mmap");
+            exit(-1);
+        }
+        load_addr = error;
+        load_addr_set = 1;
+    }
+
+    eppnt = elf_phdata;
+    for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+        if (eppnt->p_type == PT_LOAD) {
+            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+            int elf_prot = 0;
+            unsigned long vaddr = 0;
+            unsigned long k;
+
+            if (eppnt->p_flags & PF_R)
+                elf_prot =  PROT_READ;
+            if (eppnt->p_flags & PF_W)
+                elf_prot |= PROT_WRITE;
+            if (eppnt->p_flags & PF_X)
+                elf_prot |= PROT_EXEC;
+            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                elf_type |= MAP_FIXED;
+                vaddr = eppnt->p_vaddr;
+            }
+            error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr),
+                 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+                 elf_prot,
+                 elf_type,
+                 interpreter_fd,
+                 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+            if (error == -1) {
+                /* Real error */
+                close(interpreter_fd);
+                free(elf_phdata);
+                return ~0UL;
+            }
+
+            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                load_addr = error;
+                load_addr_set = 1;
+            }
+
+            /*
+             * Find the end of the file  mapping for this phdr, and keep
+             * track of the largest address we see for this.
+             */
+            k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+            if (k > elf_bss)
+                elf_bss = k;
+
+            /*
+             * Do the same thing for the memory mapping - between
+             * elf_bss and last_bss is the bss section.
+             */
+            k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+            if (k > last_bss)
+                last_bss = k;
+        }
+
+    /* Now use mmap to map the library into memory. */
+
+    close(interpreter_fd);
+
+    /*
+     * Now fill out the bss section.  First pad the last page up
+     * to the page boundary, and then perform a mmap to make sure
+     * that there are zeromapped pages up to and including the last
+     * bss page.
+     */
+    padzero(elf_bss, last_bss);
+    /* What we have mapped so far */
+    elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1);
+
+    /* Map the last of the bss segment */
+    if (last_bss > elf_bss) {
+        target_mmap(elf_bss, last_bss-elf_bss,
+                    PROT_READ | PROT_WRITE | PROT_EXEC,
+                    MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    }
+    free(elf_phdata);
+
+    *interp_load_addr = load_addr;
+    return ((unsigned long)interp_elf_ex->e_entry) + load_addr;
+}
+
+/* Best attempt to load symbols from this ELF object. */
+static void glue(load_symbols, SZ)(struct elfhdr *hdr, int fd)
+{
+    unsigned int i;
+    struct elf_shdr sechdr, symtab, strtab;
+    char *strings;
+    struct syminfo *s;
+#if (ELF_CLASS == ELFCLASS64)
+    // Disas uses 32 bit symbols
+    struct elf32_sym *syms32 = NULL;
+    struct elf_sym *sym;
+#endif
+
+    lseek(fd, hdr->e_shoff, SEEK_SET);
+    for (i = 0; i < hdr->e_shnum; i++) {
+        if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
+            return;
+#ifdef BSWAP_NEEDED
+        glue(bswap_shdr, SZ)(&sechdr);
+#endif
+        if (sechdr.sh_type == SHT_SYMTAB) {
+            symtab = sechdr;
+            lseek(fd, hdr->e_shoff
+                  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
+            if (read(fd, &strtab, sizeof(strtab))
+                != sizeof(strtab))
+                return;
+#ifdef BSWAP_NEEDED
+            glue(bswap_shdr, SZ)(&strtab);
+#endif
+            goto found;
+        }
+    }
+    return; /* Shouldn't happen... */
+
+ found:
+    /* Now know where the strtab and symtab are.  Snarf them. */
+    s = malloc(sizeof(*s));
+    s->disas_symtab = malloc(symtab.sh_size);
+#if (ELF_CLASS == ELFCLASS64)
+    syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
+                    * sizeof(struct elf32_sym));
+#endif
+    s->disas_strtab = strings = malloc(strtab.sh_size);
+    if (!s->disas_symtab || !s->disas_strtab)
+        return;
+
+    lseek(fd, symtab.sh_offset, SEEK_SET);
+    if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
+        return;
+
+    for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
+#ifdef BSWAP_NEEDED
+        glue(bswap_sym, SZ)(s->disas_symtab + sizeof(struct elf_sym)*i);
+#endif
+#if (ELF_CLASS == ELFCLASS64)
+        sym = s->disas_symtab + sizeof(struct elf_sym)*i;
+        syms32[i].st_name = sym->st_name;
+        syms32[i].st_info = sym->st_info;
+        syms32[i].st_other = sym->st_other;
+        syms32[i].st_shndx = sym->st_shndx;
+        syms32[i].st_value = sym->st_value & 0xffffffff;
+        syms32[i].st_size = sym->st_size & 0xffffffff;
+#endif
+    }
+
+#if (ELF_CLASS == ELFCLASS64)
+    free(s->disas_symtab);
+    s->disas_symtab = syms32;
+#endif
+    lseek(fd, strtab.sh_offset, SEEK_SET);
+    if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
+        return;
+    s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
+    s->next = syminfos;
+    syminfos = s;
+}
+
+static int glue(load_elf_binary, SZ)(struct linux_binprm *bprm,
+                                     struct target_pt_regs *regs,
+                                     struct image_info *info)
+{
+    struct elfhdr elf_ex;
+    struct elfhdr interp_elf_ex;
+    struct exec interp_ex;
+    int interpreter_fd = -1; /* avoid warning */
+    unsigned long load_addr, load_bias;
+    int load_addr_set = 0;
+    unsigned int interpreter_type = INTERPRETER_NONE;
+    unsigned char ibcs2_interpreter;
+    int i;
+    unsigned long mapped_addr;
+    struct elf_phdr * elf_ppnt;
+    struct elf_phdr *elf_phdata;
+    unsigned long elf_bss, k, elf_brk;
+    int retval;
+    char * elf_interpreter;
+    unsigned long elf_entry, interp_load_addr = 0;
+    int status;
+    unsigned long start_code, end_code, end_data;
+    unsigned long reloc_func_desc = 0;
+    unsigned long elf_stack;
+    char passed_fileno[6];
+
+    ibcs2_interpreter = 0;
+    status = 0;
+    load_addr = 0;
+    load_bias = 0;
+    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
+#ifdef BSWAP_NEEDED
+    glue(bswap_ehdr, SZ)(&elf_ex);
+#endif
+
+    /* 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) {
+        return -ENOMEM;
+    }
+
+    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
+    if (retval > 0) {
+        retval = read(bprm->fd, (char *)elf_phdata,
+                      elf_ex.e_phentsize * elf_ex.e_phnum);
+    }
+
+    if (retval < 0) {
+        perror("load_elf_binary");
+        exit(-1);
+    }
+
+#ifdef BSWAP_NEEDED
+    elf_ppnt = elf_phdata;
+    for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+        glue(bswap_phdr, SZ)(elf_ppnt);
+    }
+#endif
+    elf_ppnt = elf_phdata;
+
+    elf_bss = 0;
+    elf_brk = 0;
+
+
+    elf_stack = ~0UL;
+    elf_interpreter = NULL;
+    start_code = ~0UL;
+    end_code = 0;
+    end_data = 0;
+
+    for (i = 0; i < elf_ex.e_phnum; i++) {
+        if (elf_ppnt->p_type == PT_INTERP) {
+            if (elf_interpreter != NULL) {
+                free (elf_phdata);
+                free(elf_interpreter);
+                close(bprm->fd);
+                return -EINVAL;
+            }
+
+            /* This is the program interpreter used for
+             * shared libraries - for now assume that this
+             * is an a.out format binary
+             */
+            elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
+
+            if (elf_interpreter == NULL) {
+                free (elf_phdata);
+                close(bprm->fd);
+                return -ENOMEM;
+            }
+
+            retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
+            if (retval >= 0) {
+                retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
+            }
+            if (retval < 0) {
+                perror("load_elf_binary2");
+                exit(-1);
+            }
+
+            /* If the program interpreter is one of these two,
+               then assume an iBCS2 image. Otherwise assume
+               a native linux image. */
+
+            /* JRP - Need to add X86 lib dir stuff here... */
+
+            if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+                strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+                ibcs2_interpreter = 1;
+            }
+
+#if 0
+            printf("Using ELF interpreter %s\n", elf_interpreter);
+#endif
+            if (retval >= 0) {
+                retval = open(path(elf_interpreter), O_RDONLY);
+                if (retval >= 0) {
+                    interpreter_fd = retval;
+                } else {
+                    perror(elf_interpreter);
+                    exit(-1);
+                }
+            }
+
+            if (retval >= 0) {
+                retval = lseek(interpreter_fd, 0, SEEK_SET);
+                if (retval >= 0) {
+                    retval = read(interpreter_fd, bprm->buf, 128);
+                }
+            }
+            if (retval >= 0) {
+                interp_ex = *((struct exec *)bprm->buf); /* aout exec-header */
+                interp_elf_ex = *((struct elfhdr *)bprm->buf); /* elf exec-header */
+            }
+            if (retval < 0) {
+                perror("load_elf_binary3");
+                exit(-1);
+            }
+        }
+        elf_ppnt++;
+    }
+
+    /* Some simple consistency checks for the interpreter */
+    if (elf_interpreter) {
+        interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+
+        /* Now figure out which format our binary is */
+        if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
+            (N_MAGIC(interp_ex) != QMAGIC)) {
+            interpreter_type = INTERPRETER_ELF;
+        }
+
+        if (interp_elf_ex.e_ident[0] != 0x7f ||
+            strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) {
+            interpreter_type &= ~INTERPRETER_ELF;
+        }
+
+        if (!interpreter_type) {
+            free(elf_interpreter);
+            free(elf_phdata);
+            close(bprm->fd);
+            return -ELIBBAD;
+        }
+    }
+
+    /* OK, we are done with that, now set up the arg stuff,
+       and then start this sucker up */
+
+    {
+        char *passed_p;
+
+        if (interpreter_type == INTERPRETER_AOUT) {
+            snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
+            passed_p = passed_fileno;
+
+            if (elf_interpreter) {
+                bprm->p = copy_elf_strings(1, &passed_p, bprm->page, bprm->p);
+                bprm->argc++;
+            }
+        }
+        if (!bprm->p) {
+            if (elf_interpreter) {
+                free(elf_interpreter);
+            }
+            free (elf_phdata);
+            close(bprm->fd);
+            return -E2BIG;
+        }
+    }
+
+    /* OK, This is the point of no return */
+    info->end_data = 0;
+    info->end_code = 0;
+    info->start_mmap = (unsigned long)ELF_START_MMAP;
+    info->mmap = 0;
+    elf_entry = (unsigned long) elf_ex.e_entry;
+
+    /* Do this so that we can load the interpreter, if need be.  We will
+       change some of these later */
+    info->rss = 0;
+    bprm->p = setup_arg_pages(bprm->p, bprm, info);
+    info->start_stack = bprm->p;
+
+    /* Now we do a little grungy work by mmaping the ELF image into
+     * the correct location in memory.  At this point, we assume that
+     * the image should be loaded at fixed address, not at a variable
+     * address.
+     */
+
+    for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+        int elf_prot = 0;
+        int elf_flags = 0;
+        unsigned long error;
+
+        if (elf_ppnt->p_type != PT_LOAD)
+            continue;
+
+        if (elf_ppnt->p_flags & PF_R)
+            elf_prot |= PROT_READ;
+        if (elf_ppnt->p_flags & PF_W)
+            elf_prot |= PROT_WRITE;
+        if (elf_ppnt->p_flags & PF_X)
+            elf_prot |= PROT_EXEC;
+        elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
+        if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+            elf_flags |= MAP_FIXED;
+        } else if (elf_ex.e_type == ET_DYN) {
+            /* Try and get dynamic programs out of the way of the default mmap
+               base, as well as whatever program they might try to exec.  This
+               is because the brk will follow the loader, and is not movable.  */
+            /* NOTE: for qemu, we do a big mmap to get enough space
+               without hardcoding any address */
+            error = target_mmap(0, ET_DYN_MAP_SIZE,
+                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
+                                -1, 0);
+            if (error == -1) {
+                perror("mmap");
+                exit(-1);
+            }
+            load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
+        }
+
+        error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
+                            (elf_ppnt->p_filesz +
+                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+                            elf_prot,
+                            (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
+                            bprm->fd,
+                            (elf_ppnt->p_offset -
+                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+        if (error == -1) {
+            perror("mmap");
+            exit(-1);
+        }
+
+#ifdef LOW_ELF_STACK
+        if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
+            elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
+#endif
+
+        if (!load_addr_set) {
+            load_addr_set = 1;
+            load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+            if (elf_ex.e_type == ET_DYN) {
+                load_bias += error -
+                    TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
+                load_addr += load_bias;
+                reloc_func_desc = load_bias;
+            }
+        }
+        k = elf_ppnt->p_vaddr;
+        if (k < start_code)
+            start_code = k;
+        k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+        if (k > elf_bss)
+            elf_bss = k;
+        if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+            end_code = k;
+        if (end_data < k)
+            end_data = k;
+        k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+        if (k > elf_brk)
+            elf_brk = k;
+    }
+
+    elf_entry += load_bias;
+    elf_bss += load_bias;
+    elf_brk += load_bias;
+    start_code += load_bias;
+    end_code += load_bias;
+    //    start_data += load_bias;
+    end_data += load_bias;
+
+    if (elf_interpreter) {
+        if (interpreter_type & 1) {
+            elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
+        }
+        else if (interpreter_type & 2) {
+            elf_entry = glue(load_elf_interp, SZ)(&interp_elf_ex, interpreter_fd,
+                                                  &interp_load_addr);
+        }
+        reloc_func_desc = interp_load_addr;
+
+        close(interpreter_fd);
+        free(elf_interpreter);
+
+        if (elf_entry == ~0UL) {
+            printf("Unable to load interpreter\n");
+            free(elf_phdata);
+            exit(-1);
+        }
+    }
+
+    free(elf_phdata);
+
+    if (loglevel)
+        glue(load_symbols, SZ)(&elf_ex, bprm->fd);
+
+    if (interpreter_type != INTERPRETER_AOUT)
+        close(bprm->fd);
+    info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
+
+#ifdef LOW_ELF_STACK
+    info->start_stack = bprm->p = elf_stack - 4;
+#endif
+    bprm->p = glue(create_elf_tables, SZ)(bprm->p,
+                                          bprm->argc,
+                                          bprm->envc,
+                                          &elf_ex,
+                                          load_addr, load_bias,
+                                          interp_load_addr,
+                                          (interpreter_type ==
+                                           INTERPRETER_AOUT ? 0 : 1),
+                                          info);
+    info->load_addr = reloc_func_desc;
+    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;
+
+    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
+       sections */
+    set_brk(elf_bss, elf_brk);
+
+    padzero(elf_bss, elf_brk);
+
+#if 0
+    printf("(start_brk) %x\n" , info->start_brk);
+    printf("(end_code) %x\n" , info->end_code);
+    printf("(start_code) %x\n" , info->start_code);
+    printf("(end_data) %x\n" , info->end_data);
+    printf("(start_stack) %x\n" , info->start_stack);
+    printf("(brk) %x\n" , info->brk);
+#endif
+
+    if (info->personality == PER_SVR4) {
+        /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+           and some applications "depend" upon this behavior.
+           Since we do not have the power to recompile these, we
+           emulate the SVr4 behavior.  Sigh.  */
+        mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+                                  MAP_FIXED | MAP_PRIVATE, -1, 0);
+    }
+
+    info->entry = elf_entry;
+
+    return 0;
+}
Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c	2007-10-07 10:55:45.000000000 +0000
+++ qemu/linux-user/main.c	2007-10-07 10:55:54.000000000 +0000
@@ -564,6 +564,7 @@
         case 0x88:
         case 0x90:
 #else
+        case 0x110:
         case 0x16d:
 #endif
             ret = do_syscall (env, env->gregs[1],
Index: qemu/linux-user/qemu.h
===================================================================
--- qemu.orig/linux-user/qemu.h	2007-10-07 10:50:05.000000000 +0000
+++ qemu/linux-user/qemu.h	2007-10-07 10:51:09.000000000 +0000
@@ -33,6 +33,7 @@
         target_ulong    data_offset;
         char            **host_argv;
 	int		personality;
+        int             is_64bits;
 };
 
 #ifdef TARGET_I386
Index: qemu/linux-user/sparc64/syscall_nr.h
===================================================================
--- qemu.orig/linux-user/sparc64/syscall_nr.h	2007-10-07 11:01:06.000000000 +0000
+++ qemu/linux-user/sparc64/syscall_nr.h	2007-10-07 11:11:58.000000000 +0000
@@ -29,11 +29,11 @@
 #define TARGET_NR_sigaltstack	 28 /* Common					   */
 #define TARGET_NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
 #define TARGET_NR_utime               30 /* Implemented via utimes() under SunOS        */
-/* #define TARGET_NR_lchown32         31    Linux sparc32 specific                      */
-/* #define TARGET_NR_fchown32         32    Linux sparc32 specific                      */
+#define TARGET_NR_lchown32            31 /* Linux sparc32 specific                      */
+#define TARGET_NR_fchown32            32 /* Linux sparc32 specific                      */
 #define TARGET_NR_access              33 /* Common                                      */
 #define TARGET_NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
-/* #define TARGET_NR_chown32          35    Linux sparc32 specific                      */
+#define TARGET_NR_chown32             35 /*  Linux sparc32 specific                     */
 #define TARGET_NR_sync                36 /* Common                                      */
 #define TARGET_NR_kill                37 /* Common                                      */
 #define TARGET_NR_stat                38 /* Common                                      */
@@ -42,7 +42,7 @@
 #define TARGET_NR_dup                 41 /* Common                                      */
 #define TARGET_NR_pipe                42 /* Common                                      */
 #define TARGET_NR_times               43 /* Implemented via getrusage() in SunOS        */
-/* #define TARGET_NR_getuid32         44    Linux sparc32 specific                      */
+#define TARGET_NR_getuid32            44 /* Linux sparc32 specific                      */
 #define TARGET_NR_umount2             45 /* Linux Specific                              */
 #define TARGET_NR_setgid              46 /* Implemented via setregid() in SunOS         */
 #define TARGET_NR_getgid              47 /* Common                                      */
@@ -51,48 +51,48 @@
 #define TARGET_NR_getegid             50 /* SunOS calls getgid()                        */
 #define TARGET_NR_acct                51 /* Common                                      */
 #define TARGET_NR_memory_ordering	 52 /* Linux Specific				   */
-/* #define TARGET_NR_getgid32         53    Linux sparc32 specific                      */
+#define TARGET_NR_getgid32            53 /* Linux sparc32 specific                      */
 #define TARGET_NR_ioctl               54 /* Common                                      */
 #define TARGET_NR_reboot              55 /* Common                                      */
-/* #define TARGET_NR_mmap2		 56    Linux sparc32 Specific                      */
+#define TARGET_NR_mmap2		      56 /* Linux sparc32 Specific                      */
 #define TARGET_NR_symlink             57 /* Common                                      */
 #define TARGET_NR_readlink            58 /* Common                                      */
 #define TARGET_NR_execve              59 /* Common                                      */
 #define TARGET_NR_umask               60 /* Common                                      */
 #define TARGET_NR_chroot              61 /* Common                                      */
 #define TARGET_NR_fstat               62 /* Common                                      */
-/* #define TARGET_NR_fstat64          63    Linux sparc32 Specific                      */
+#define TARGET_NR_fstat64             63 /* Linux sparc32 Specific                      */
 #define TARGET_NR_getpagesize         64 /* Common                                      */
 #define TARGET_NR_msync               65 /* Common in newer 1.3.x revs...               */
 #define TARGET_NR_vfork               66 /* Common                                      */
 #define TARGET_NR_pread64             67 /* Linux Specific                              */
 #define TARGET_NR_pwrite64            68 /* Linux Specific                              */
-/* #define TARGET_NR_geteuid32        69    Linux sparc32, sbrk under SunOS             */
-/* #define TARGET_NR_getegid32        70    Linux sparc32, sstk under SunOS             */
+#define TARGET_NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
+#define TARGET_NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
 #define TARGET_NR_mmap                71 /* Common                                      */
-/* #define TARGET_NR_setreuid32       72    Linux sparc32, vadvise under SunOS          */
+#define TARGET_NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
 #define TARGET_NR_munmap              73 /* Common                                      */
 #define TARGET_NR_mprotect            74 /* Common                                      */
 #define TARGET_NR_madvise             75 /* Common                                      */
 #define TARGET_NR_vhangup             76 /* Common                                      */
-/* #define TARGET_NR_truncate64       77    Linux sparc32 Specific			   */
+#define TARGET_NR_truncate64          77 /* Linux sparc32 Specific			*/
 #define TARGET_NR_mincore             78 /* Common                                      */
 #define TARGET_NR_getgroups           79 /* Common                                      */
 #define TARGET_NR_setgroups           80 /* Common                                      */
 #define TARGET_NR_getpgrp             81 /* Common                                      */
-/* #define TARGET_NR_setgroups32      82    Linux sparc32, setpgrp under SunOS          */
+#define TARGET_NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
 #define TARGET_NR_setitimer           83 /* Common                                      */
-/* #define TARGET_NR_ftruncate64      84    Linux sparc32 Specific			   */
+#define TARGET_NR_ftruncate64         84 /* Linux sparc32 Specific                      */
 #define TARGET_NR_swapon              85 /* Common                                      */
 #define TARGET_NR_getitimer           86 /* Common                                      */
-/* #define TARGET_NR_setuid32         87    Linux sparc32, gethostname under SunOS      */
+#define TARGET_NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
 #define TARGET_NR_sethostname         88 /* Common                                      */
-/* #define TARGET_NR_setgid32         89    Linux sparc32, getdtablesize under SunOS    */
+#define TARGET_NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
 #define TARGET_NR_dup2                90 /* Common                                      */
-/* #define TARGET_NR_setfsuid32       91    Linux sparc32, getdopt under SunOS          */
+#define TARGET_NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
 #define TARGET_NR_fcntl               92 /* Common                                      */
 #define TARGET_NR_select              93 /* Common                                      */
-/* #define TARGET_NR_setfsgid32       94    Linux sparc32, setdopt under SunOS          */
+#define TARGET_NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
 #define TARGET_NR_fsync               95 /* Common                                      */
 #define TARGET_NR_setpriority         96 /* Common                                      */
 #define TARGET_NR_socket              97 /* Common                                      */
@@ -110,10 +110,10 @@
 #define TARGET_NR_getresuid          109 /* Linux Specific, sigblock under SunOS	   */
 #define TARGET_NR_setresgid          110 /* Linux Specific, sigsetmask under SunOS	   */
 #define TARGET_NR_getresgid          111 /* Linux Specific, sigpause under SunOS	   */
-/* #define TARGET_NR_setregid32       75    Linux sparc32, sigstack under SunOS         */
+/* #define TARGET_NR_setregid32          75  Linux sparc32, sigstack under SunOS         */
 #define TARGET_NR_recvmsg            113 /* Common                                      */
 #define TARGET_NR_sendmsg            114 /* Common                                      */
-/* #define TARGET_NR_getgroups32     115    Linux sparc32, vtrace under SunOS           */
+#define TARGET_NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
 #define TARGET_NR_gettimeofday       116 /* Common                                      */
 #define TARGET_NR_getrusage          117 /* Common                                      */
 #define TARGET_NR_getsockopt         118 /* Common                                      */
@@ -130,14 +130,14 @@
 #define TARGET_NR_truncate           129 /* Common                                      */
 #define TARGET_NR_ftruncate          130 /* Common                                      */
 #define TARGET_NR_flock              131 /* Common                                      */
-/* #define TARGET_NR_lstat64		132    Linux sparc32 Specific                      */
+#define TARGET_NR_lstat64	     132 /* Linux sparc32 Specific                      */
 #define TARGET_NR_sendto             133 /* Common                                      */
 #define TARGET_NR_shutdown           134 /* Common                                      */
 #define TARGET_NR_socketpair         135 /* Common                                      */
 #define TARGET_NR_mkdir              136 /* Common                                      */
 #define TARGET_NR_rmdir              137 /* Common                                      */
 #define TARGET_NR_utimes             138 /* SunOS Specific                              */
-/* #define TARGET_NR_stat64		139    Linux sparc32 Specific			   */
+#define TARGET_NR_stat64	     139 /* Linux sparc32 Specific			   */
 #define TARGET_NR_sendfile64         140 /* adjtime under SunOS                         */
 #define TARGET_NR_getpeername        141 /* Common                                      */
 #define TARGET_NR_futex              142 /* gethostid under SunOS                       */
@@ -153,7 +153,7 @@
 /* #define TARGET_NR_putmsg          152    SunOS Specific                              */
 #define TARGET_NR_poll               153 /* Common                                      */
 #define TARGET_NR_getdents64		154 /* Linux specific				   */
-/* #define TARGET_NR_fcntl64         155    Linux sparc32 Specific                      */
+#define TARGET_NR_fcntl64            155 /* Linux sparc32 Specific                      */
 /* #define TARGET_NR_getdirentries   156    SunOS Specific                              */
 #define TARGET_NR_statfs             157 /* Common                                      */
 #define TARGET_NR_fstatfs            158 /* Common                                      */
@@ -229,9 +229,7 @@
 #define TARGET_NR_setfsuid           228 /* Linux Specific                              */
 #define TARGET_NR_setfsgid           229 /* Linux Specific                              */
 #define TARGET_NR__newselect         230 /* Linux Specific                              */
-#ifdef __KERNEL__
-#define TARGET_NR_time		231 /* Linux sparc32                               */
-#endif
+#define TARGET_NR_time               231 /* Linux sparc32                               */
 /* #define TARGET_NR_oldstat         232    Linux Specific                              */
 #define TARGET_NR_stime              233 /* Linux Specific                              */
 #define TARGET_NR_statfs64           234 /* Linux Specific                              */

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 12:45 [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user Blue Swirl
@ 2007-10-07 14:01 ` J. Mayer
  2007-10-07 14:38   ` Blue Swirl
  2007-10-07 16:21 ` Thiemo Seufer
  1 sibling, 1 reply; 9+ messages in thread
From: J. Mayer @ 2007-10-07 14:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Blue Swirl

On Sun, 2007-10-07 at 15:45 +0300, Blue Swirl wrote:
> Hi,

Hi,

> This patch adds support for loading a 32 bit ELF file in the 64 bit
> user mode emulator. This means that qemu-sparc64 can be used to
> execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
> This format is used by Solaris/Sparc and maybe by Debian in the
> future.
> 
> Other targets shouldn't be affected, but I have done only compile
> testing. Any comments?

The idea of loading 32 bits executables on 64 bits target seems great.
Then, I got two remarks about this patch:
- it seems that it does not take care about my patch. As I was to commit
it today, I wonder if I still should do it. But then, your patch lacks
some bugifxes (start_data not properly computed and TARGET_LONG_BITS !=
HOST_LONG_BITS problems).
- it seems that quite all the ELF loader code is affected by your patch.
I think (maybe too naively) that adding functions to read the ELF infos
should be sufficient, ie add a read_elf_ehdr, ..., functions and a few
patches in the create_elf_table function. Then, all informations nedded
to load a 32 bits executable can be kept into the 64 bits structures. As
the kernel does not duplicate the code to handle this case, I think Qemu
loader should be kept as simple as the kernel one, and the elfload_ops.h
seems to me to be useless. In fact, Qemu loader could (should ?) even be
the same code than the kernel one with just a few helpers for endianness
swaps and the needed fixes to avoid confusions between host_long and
target_long...

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 14:01 ` J. Mayer
@ 2007-10-07 14:38   ` Blue Swirl
  2007-10-07 14:49     ` J. Mayer
  0 siblings, 1 reply; 9+ messages in thread
From: Blue Swirl @ 2007-10-07 14:38 UTC (permalink / raw)
  To: J. Mayer; +Cc: qemu-devel

On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> On Sun, 2007-10-07 at 15:45 +0300, Blue Swirl wrote:
> > Hi,
>
> Hi,
>
> > This patch adds support for loading a 32 bit ELF file in the 64 bit
> > user mode emulator. This means that qemu-sparc64 can be used to
> > execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
> > This format is used by Solaris/Sparc and maybe by Debian in the
> > future.
> >
> > Other targets shouldn't be affected, but I have done only compile
> > testing. Any comments?
>
> The idea of loading 32 bits executables on 64 bits target seems great.
> Then, I got two remarks about this patch:
> - it seems that it does not take care about my patch. As I was to commit
> it today, I wonder if I still should do it. But then, your patch lacks
> some bugifxes (start_data not properly computed and TARGET_LONG_BITS !=
> HOST_LONG_BITS problems).

Well, I thought that you had already applied the patch.

> - it seems that quite all the ELF loader code is affected by your patch.
> I think (maybe too naively) that adding functions to read the ELF infos
> should be sufficient, ie add a read_elf_ehdr, ..., functions and a few
> patches in the create_elf_table function. Then, all informations nedded
> to load a 32 bits executable can be kept into the 64 bits structures. As
> the kernel does not duplicate the code to handle this case, I think Qemu
> loader should be kept as simple as the kernel one, and the elfload_ops.h
> seems to me to be useless. In fact, Qemu loader could (should ?) even be
> the same code than the kernel one with just a few helpers for endianness
> swaps and the needed fixes to avoid confusions between host_long and
> target_long...

Sparc64 Linux handles 32 bit ELF binaries (both V8 = 32 bit insn and
V9 = 64 bit insn) in arch/sparc64/kernel/binfmt_elf32.c, which
#includes fs/binfmt_elf.c.
64 bit V9 binaries are handled by fs/binfmt_elf.c.

In Qemu we can't do it like this, because V9 instruction emulator must
be used to handle also the 32 bit ELF. The same effect could be
achieved in Qemu for example by adding new file elfload_32.c, which
would include elfload.c after defining the ELF classes etc. This would
need some rearranging in elfload.c so that the ELF parameters can be
overridden. I'm not sure this would be much cleaner than my version
using glue().

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 14:38   ` Blue Swirl
@ 2007-10-07 14:49     ` J. Mayer
  2007-10-07 15:15       ` Blue Swirl
  0 siblings, 1 reply; 9+ messages in thread
From: J. Mayer @ 2007-10-07 14:49 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On Sun, 2007-10-07 at 17:38 +0300, Blue Swirl wrote:
> On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> > On Sun, 2007-10-07 at 15:45 +0300, Blue Swirl wrote:
> > > Hi,
> >
> > Hi,
> >
> > > This patch adds support for loading a 32 bit ELF file in the 64 bit
> > > user mode emulator. This means that qemu-sparc64 can be used to
> > > execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
> > > This format is used by Solaris/Sparc and maybe by Debian in the
> > > future.
> > >
> > > Other targets shouldn't be affected, but I have done only compile
> > > testing. Any comments?
> >
> > The idea of loading 32 bits executables on 64 bits target seems great.
> > Then, I got two remarks about this patch:
> > - it seems that it does not take care about my patch. As I was to commit
> > it today, I wonder if I still should do it. But then, your patch lacks
> > some bugifxes (start_data not properly computed and TARGET_LONG_BITS !=
> > HOST_LONG_BITS problems).
> 
> Well, I thought that you had already applied the patch.

OK, do you agree that I apply it and you take the changes in yours ?

> 
> > - it seems that quite all the ELF loader code is affected by your patch.
> > I think (maybe too naively) that adding functions to read the ELF infos
> > should be sufficient, ie add a read_elf_ehdr, ..., functions and a few
> > patches in the create_elf_table function. Then, all informations nedded
> > to load a 32 bits executable can be kept into the 64 bits structures. As
> > the kernel does not duplicate the code to handle this case, I think Qemu
> > loader should be kept as simple as the kernel one, and the elfload_ops.h
> > seems to me to be useless. In fact, Qemu loader could (should ?) even be
> > the same code than the kernel one with just a few helpers for endianness
> > swaps and the needed fixes to avoid confusions between host_long and
> > target_long...
> 
> Sparc64 Linux handles 32 bit ELF binaries (both V8 = 32 bit insn and
> V9 = 64 bit insn) in arch/sparc64/kernel/binfmt_elf32.c, which
> #includes fs/binfmt_elf.c.
> 64 bit V9 binaries are handled by fs/binfmt_elf.c.
> 
> In Qemu we can't do it like this, because V9 instruction emulator must
> be used to handle also the 32 bit ELF. The same effect could be
> achieved in Qemu for example by adding new file elfload_32.c, which
> would include elfload.c after defining the ELF classes etc. This would
> need some rearranging in elfload.c so that the ELF parameters can be
> overridden. I'm not sure this would be much cleaner than my version
> using glue().

OK, then if the kernel duplicates the compiled code, it means that this
way of doing might be the proper one. Couldn't you do something closest
to what the kernel do, ie moving the per target definitions located at
the top of elfload.c somewhere else and add a elfload_32.c file that
would include elfload.c redefining all needed variable types, ... ? This
just to keep the code as close as possible to the kernel one, even if it
functionnaly changes nothing...

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 14:49     ` J. Mayer
@ 2007-10-07 15:15       ` Blue Swirl
  2007-10-07 15:46         ` J. Mayer
  0 siblings, 1 reply; 9+ messages in thread
From: Blue Swirl @ 2007-10-07 15:15 UTC (permalink / raw)
  To: J. Mayer; +Cc: qemu-devel

On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> On Sun, 2007-10-07 at 17:38 +0300, Blue Swirl wrote:
> > On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> > > On Sun, 2007-10-07 at 15:45 +0300, Blue Swirl wrote:
> > > > Hi,
> > >
> > > Hi,
> > >
> > > > This patch adds support for loading a 32 bit ELF file in the 64 bit
> > > > user mode emulator. This means that qemu-sparc64 can be used to
> > > > execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
> > > > This format is used by Solaris/Sparc and maybe by Debian in the
> > > > future.
> > > >
> > > > Other targets shouldn't be affected, but I have done only compile
> > > > testing. Any comments?
> > >
> > > The idea of loading 32 bits executables on 64 bits target seems great.
> > > Then, I got two remarks about this patch:
> > > - it seems that it does not take care about my patch. As I was to commit
> > > it today, I wonder if I still should do it. But then, your patch lacks
> > > some bugifxes (start_data not properly computed and TARGET_LONG_BITS !=
> > > HOST_LONG_BITS problems).
> >
> > Well, I thought that you had already applied the patch.
>
> OK, do you agree that I apply it and you take the changes in yours ?

Yes, the patch looks OK (haven't tested it) and if something still
breaks, we can fix it.

> >
> > > - it seems that quite all the ELF loader code is affected by your patch.
> > > I think (maybe too naively) that adding functions to read the ELF infos
> > > should be sufficient, ie add a read_elf_ehdr, ..., functions and a few
> > > patches in the create_elf_table function. Then, all informations nedded
> > > to load a 32 bits executable can be kept into the 64 bits structures. As
> > > the kernel does not duplicate the code to handle this case, I think Qemu
> > > loader should be kept as simple as the kernel one, and the elfload_ops.h
> > > seems to me to be useless. In fact, Qemu loader could (should ?) even be
> > > the same code than the kernel one with just a few helpers for endianness
> > > swaps and the needed fixes to avoid confusions between host_long and
> > > target_long...
> >
> > Sparc64 Linux handles 32 bit ELF binaries (both V8 = 32 bit insn and
> > V9 = 64 bit insn) in arch/sparc64/kernel/binfmt_elf32.c, which
> > #includes fs/binfmt_elf.c.
> > 64 bit V9 binaries are handled by fs/binfmt_elf.c.
> >
> > In Qemu we can't do it like this, because V9 instruction emulator must
> > be used to handle also the 32 bit ELF. The same effect could be
> > achieved in Qemu for example by adding new file elfload_32.c, which
> > would include elfload.c after defining the ELF classes etc. This would
> > need some rearranging in elfload.c so that the ELF parameters can be
> > overridden. I'm not sure this would be much cleaner than my version
> > using glue().
>
> OK, then if the kernel duplicates the compiled code, it means that this
> way of doing might be the proper one. Couldn't you do something closest
> to what the kernel do, ie moving the per target definitions located at
> the top of elfload.c somewhere else and add a elfload_32.c file that
> would include elfload.c redefining all needed variable types, ... ? This
> just to keep the code as close as possible to the kernel one, even if it
> functionnaly changes nothing...

I'll try if that works. It could be a better approach after all.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 15:15       ` Blue Swirl
@ 2007-10-07 15:46         ` J. Mayer
  0 siblings, 0 replies; 9+ messages in thread
From: J. Mayer @ 2007-10-07 15:46 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On Sun, 2007-10-07 at 18:15 +0300, Blue Swirl wrote:
> On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> > On Sun, 2007-10-07 at 17:38 +0300, Blue Swirl wrote:
> > > On 10/7/07, J. Mayer <l_indien@magic.fr> wrote:
> > > > On Sun, 2007-10-07 at 15:45 +0300, Blue Swirl wrote:
> > > > > Hi,
> > > >
> > > > Hi,
> > > >
> > > > > This patch adds support for loading a 32 bit ELF file in the 64 bit
> > > > > user mode emulator. This means that qemu-sparc64 can be used to
> > > > > execute 32 bit ELF files containing V9 instructions (SPARC32PLUS).
> > > > > This format is used by Solaris/Sparc and maybe by Debian in the
> > > > > future.
> > > > >
> > > > > Other targets shouldn't be affected, but I have done only compile
> > > > > testing. Any comments?
> > > >
> > > > The idea of loading 32 bits executables on 64 bits target seems great.
> > > > Then, I got two remarks about this patch:
> > > > - it seems that it does not take care about my patch. As I was to commit
> > > > it today, I wonder if I still should do it. But then, your patch lacks
> > > > some bugifxes (start_data not properly computed and TARGET_LONG_BITS !=
> > > > HOST_LONG_BITS problems).
> > >
> > > Well, I thought that you had already applied the patch.
> >
> > OK, do you agree that I apply it and you take the changes in yours ?
> 
> Yes, the patch looks OK (haven't tested it) and if something still
> breaks, we can fix it.

OK, as there were no other remarks, I will apply it now.

> > > > - it seems that quite all the ELF loader code is affected by your patch.
> > > > I think (maybe too naively) that adding functions to read the ELF infos
> > > > should be sufficient, ie add a read_elf_ehdr, ..., functions and a few
> > > > patches in the create_elf_table function. Then, all informations nedded
> > > > to load a 32 bits executable can be kept into the 64 bits structures. As
> > > > the kernel does not duplicate the code to handle this case, I think Qemu
> > > > loader should be kept as simple as the kernel one, and the elfload_ops.h
> > > > seems to me to be useless. In fact, Qemu loader could (should ?) even be
> > > > the same code than the kernel one with just a few helpers for endianness
> > > > swaps and the needed fixes to avoid confusions between host_long and
> > > > target_long...
> > >
> > > Sparc64 Linux handles 32 bit ELF binaries (both V8 = 32 bit insn and
> > > V9 = 64 bit insn) in arch/sparc64/kernel/binfmt_elf32.c, which
> > > #includes fs/binfmt_elf.c.
> > > 64 bit V9 binaries are handled by fs/binfmt_elf.c.
> > >
> > > In Qemu we can't do it like this, because V9 instruction emulator must
> > > be used to handle also the 32 bit ELF. The same effect could be
> > > achieved in Qemu for example by adding new file elfload_32.c, which
> > > would include elfload.c after defining the ELF classes etc. This would
> > > need some rearranging in elfload.c so that the ELF parameters can be
> > > overridden. I'm not sure this would be much cleaner than my version
> > > using glue().
> >
> > OK, then if the kernel duplicates the compiled code, it means that this
> > way of doing might be the proper one. Couldn't you do something closest
> > to what the kernel do, ie moving the per target definitions located at
> > the top of elfload.c somewhere else and add a elfload_32.c file that
> > would include elfload.c redefining all needed variable types, ... ? This
> > just to keep the code as close as possible to the kernel one, even if it
> > functionnaly changes nothing...
> 
> I'll try if that works. It could be a better approach after all.

OK, I think that would be great...

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 12:45 [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user Blue Swirl
  2007-10-07 14:01 ` J. Mayer
@ 2007-10-07 16:21 ` Thiemo Seufer
  2007-10-07 17:07   ` Blue Swirl
  1 sibling, 1 reply; 9+ messages in thread
From: Thiemo Seufer @ 2007-10-07 16:21 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Blue Swirl wrote:
[snip]
> Index: qemu/linux-user/qemu.h
> ===================================================================
> --- qemu.orig/linux-user/qemu.h	2007-10-07 10:50:05.000000000 +0000
> +++ qemu/linux-user/qemu.h	2007-10-07 10:51:09.000000000 +0000
> @@ -33,6 +33,7 @@
>          target_ulong    data_offset;
>          char            **host_argv;
>  	int		personality;
> +        int             is_64bits;
>  };

I think the 64bit-ness should be part of the personality. In the end,
we need a notion of the ABI in use, not just a specific cpu feature flag.

(MIPS Linux has working support for 4 ABIs, and it could be up to a
dozen different variants counting the unimplemented bits.)


Thiemo

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 16:21 ` Thiemo Seufer
@ 2007-10-07 17:07   ` Blue Swirl
  2007-10-07 17:35     ` J. Mayer
  0 siblings, 1 reply; 9+ messages in thread
From: Blue Swirl @ 2007-10-07 17:07 UTC (permalink / raw)
  To: Thiemo Seufer, J. Mayer; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 794 bytes --]

On 10/7/07, Thiemo Seufer <ths@networkno.de> wrote:
> Blue Swirl wrote:
> [snip]
> > Index: qemu/linux-user/qemu.h
> > ===================================================================
> > --- qemu.orig/linux-user/qemu.h       2007-10-07 10:50:05.000000000 +0000
> > +++ qemu/linux-user/qemu.h    2007-10-07 10:51:09.000000000 +0000
> > @@ -33,6 +33,7 @@
> >          target_ulong    data_offset;
> >          char            **host_argv;
> >       int             personality;
> > +        int             is_64bits;
> >  };
>
> I think the 64bit-ness should be part of the personality. In the end,
> we need a notion of the ABI in use, not just a specific cpu feature flag.

Good point. I've updated the patch to use the personality field
instead, for that I updated the personality stuff.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: elfload32.diff --]
[-- Type: text/x-diff; name="elfload32.diff", Size: 20881 bytes --]

Index: qemu/linux-user/elfload.c
===================================================================
--- qemu.orig/linux-user/elfload.c	2007-10-07 17:02:34.000000000 +0000
+++ qemu/linux-user/elfload.c	2007-10-07 17:02:54.000000000 +0000
@@ -12,6 +12,66 @@
 #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)
+
 /* this flag is uneffective under linux too, should be deleted */
 #ifndef MAP_DENYWRITE
 #define MAP_DENYWRITE 0
@@ -154,7 +214,7 @@
 
 #define ELF_START_MMAP 0x80000000
 
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 )
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
 
 #define ELF_CLASS   ELFCLASS64
 #define ELF_DATA    ELFDATA2MSB
@@ -168,7 +228,10 @@
     regs->pc = infop->entry;
     regs->npc = regs->pc + 4;
     regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
 }
 
 #else
@@ -392,6 +455,13 @@
 #define ELF_HWCAP 0
 #endif
 
+#ifdef OVERRIDE_ELF_CLASS
+#undef ELF_CLASS
+#define ELF_CLASS OVERRIDE_ELF_CLASS
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
 #include "elf.h"
 
 struct exec
@@ -419,25 +489,6 @@
 /* max code+data+bss+brk space allocated to ET_DYN executables */
 #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
 
-/* from personality.h */
-
-/* Flags for bug emulation. These occupy the top three bytes. */
-#define STICKY_TIMEOUTS		0x4000000
-#define WHOLE_SECONDS		0x2000000
-
-/* Personality types. These go in the low byte. Avoid using the top bit,
- * it will conflict with error returns.
- */
-#define PER_MASK		(0x00ff)
-#define PER_LINUX		(0x0000)
-#define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
-#define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
-#define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
-#define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
-#define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
-#define PER_BSD			(0x0006)
-#define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
-
 /* Necessary parameters */
 #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
 #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
@@ -567,8 +618,8 @@
     return p;
 }
 
-target_ulong setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
-                             struct image_info * info)
+static target_ulong setup_arg_pages(target_ulong p, struct linux_binprm *bprm,
+                                    struct image_info *info)
 {
     target_ulong stack_base, size, error;
     int i;
Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c	2007-10-07 17:02:34.000000000 +0000
+++ qemu/linux-user/main.c	2007-10-07 17:02:54.000000000 +0000
@@ -564,6 +564,7 @@
         case 0x88:
         case 0x90:
 #else
+        case 0x110:
         case 0x16d:
 #endif
             ret = do_syscall (env, env->gregs[1],
Index: qemu/linux-user/qemu.h
===================================================================
--- qemu.orig/linux-user/qemu.h	2007-10-07 17:02:34.000000000 +0000
+++ qemu/linux-user/qemu.h	2007-10-07 17:02:54.000000000 +0000
@@ -124,6 +124,11 @@
                     struct image_info * info);
 int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                     struct image_info * info);
+#ifdef TARGET_HAS_ELFLOAD32
+int load_elf_binary_multi(struct linux_binprm *bprm,
+                          struct target_pt_regs *regs,
+                          struct image_info *info);
+#endif
 
 void memcpy_to_target(target_ulong dest, const void *src,
                       unsigned long len);
Index: qemu/linux-user/sparc64/syscall_nr.h
===================================================================
--- qemu.orig/linux-user/sparc64/syscall_nr.h	2007-10-07 17:02:34.000000000 +0000
+++ qemu/linux-user/sparc64/syscall_nr.h	2007-10-07 17:02:54.000000000 +0000
@@ -29,11 +29,11 @@
 #define TARGET_NR_sigaltstack	 28 /* Common					   */
 #define TARGET_NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
 #define TARGET_NR_utime               30 /* Implemented via utimes() under SunOS        */
-/* #define TARGET_NR_lchown32         31    Linux sparc32 specific                      */
-/* #define TARGET_NR_fchown32         32    Linux sparc32 specific                      */
+#define TARGET_NR_lchown32            31 /* Linux sparc32 specific                      */
+#define TARGET_NR_fchown32            32 /* Linux sparc32 specific                      */
 #define TARGET_NR_access              33 /* Common                                      */
 #define TARGET_NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
-/* #define TARGET_NR_chown32          35    Linux sparc32 specific                      */
+#define TARGET_NR_chown32             35 /*  Linux sparc32 specific                     */
 #define TARGET_NR_sync                36 /* Common                                      */
 #define TARGET_NR_kill                37 /* Common                                      */
 #define TARGET_NR_stat                38 /* Common                                      */
@@ -42,7 +42,7 @@
 #define TARGET_NR_dup                 41 /* Common                                      */
 #define TARGET_NR_pipe                42 /* Common                                      */
 #define TARGET_NR_times               43 /* Implemented via getrusage() in SunOS        */
-/* #define TARGET_NR_getuid32         44    Linux sparc32 specific                      */
+#define TARGET_NR_getuid32            44 /* Linux sparc32 specific                      */
 #define TARGET_NR_umount2             45 /* Linux Specific                              */
 #define TARGET_NR_setgid              46 /* Implemented via setregid() in SunOS         */
 #define TARGET_NR_getgid              47 /* Common                                      */
@@ -51,48 +51,48 @@
 #define TARGET_NR_getegid             50 /* SunOS calls getgid()                        */
 #define TARGET_NR_acct                51 /* Common                                      */
 #define TARGET_NR_memory_ordering	 52 /* Linux Specific				   */
-/* #define TARGET_NR_getgid32         53    Linux sparc32 specific                      */
+#define TARGET_NR_getgid32            53 /* Linux sparc32 specific                      */
 #define TARGET_NR_ioctl               54 /* Common                                      */
 #define TARGET_NR_reboot              55 /* Common                                      */
-/* #define TARGET_NR_mmap2		 56    Linux sparc32 Specific                      */
+#define TARGET_NR_mmap2		      56 /* Linux sparc32 Specific                      */
 #define TARGET_NR_symlink             57 /* Common                                      */
 #define TARGET_NR_readlink            58 /* Common                                      */
 #define TARGET_NR_execve              59 /* Common                                      */
 #define TARGET_NR_umask               60 /* Common                                      */
 #define TARGET_NR_chroot              61 /* Common                                      */
 #define TARGET_NR_fstat               62 /* Common                                      */
-/* #define TARGET_NR_fstat64          63    Linux sparc32 Specific                      */
+#define TARGET_NR_fstat64             63 /* Linux sparc32 Specific                      */
 #define TARGET_NR_getpagesize         64 /* Common                                      */
 #define TARGET_NR_msync               65 /* Common in newer 1.3.x revs...               */
 #define TARGET_NR_vfork               66 /* Common                                      */
 #define TARGET_NR_pread64             67 /* Linux Specific                              */
 #define TARGET_NR_pwrite64            68 /* Linux Specific                              */
-/* #define TARGET_NR_geteuid32        69    Linux sparc32, sbrk under SunOS             */
-/* #define TARGET_NR_getegid32        70    Linux sparc32, sstk under SunOS             */
+#define TARGET_NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
+#define TARGET_NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
 #define TARGET_NR_mmap                71 /* Common                                      */
-/* #define TARGET_NR_setreuid32       72    Linux sparc32, vadvise under SunOS          */
+#define TARGET_NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
 #define TARGET_NR_munmap              73 /* Common                                      */
 #define TARGET_NR_mprotect            74 /* Common                                      */
 #define TARGET_NR_madvise             75 /* Common                                      */
 #define TARGET_NR_vhangup             76 /* Common                                      */
-/* #define TARGET_NR_truncate64       77    Linux sparc32 Specific			   */
+#define TARGET_NR_truncate64          77 /* Linux sparc32 Specific			*/
 #define TARGET_NR_mincore             78 /* Common                                      */
 #define TARGET_NR_getgroups           79 /* Common                                      */
 #define TARGET_NR_setgroups           80 /* Common                                      */
 #define TARGET_NR_getpgrp             81 /* Common                                      */
-/* #define TARGET_NR_setgroups32      82    Linux sparc32, setpgrp under SunOS          */
+#define TARGET_NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
 #define TARGET_NR_setitimer           83 /* Common                                      */
-/* #define TARGET_NR_ftruncate64      84    Linux sparc32 Specific			   */
+#define TARGET_NR_ftruncate64         84 /* Linux sparc32 Specific                      */
 #define TARGET_NR_swapon              85 /* Common                                      */
 #define TARGET_NR_getitimer           86 /* Common                                      */
-/* #define TARGET_NR_setuid32         87    Linux sparc32, gethostname under SunOS      */
+#define TARGET_NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
 #define TARGET_NR_sethostname         88 /* Common                                      */
-/* #define TARGET_NR_setgid32         89    Linux sparc32, getdtablesize under SunOS    */
+#define TARGET_NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
 #define TARGET_NR_dup2                90 /* Common                                      */
-/* #define TARGET_NR_setfsuid32       91    Linux sparc32, getdopt under SunOS          */
+#define TARGET_NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
 #define TARGET_NR_fcntl               92 /* Common                                      */
 #define TARGET_NR_select              93 /* Common                                      */
-/* #define TARGET_NR_setfsgid32       94    Linux sparc32, setdopt under SunOS          */
+#define TARGET_NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
 #define TARGET_NR_fsync               95 /* Common                                      */
 #define TARGET_NR_setpriority         96 /* Common                                      */
 #define TARGET_NR_socket              97 /* Common                                      */
@@ -110,10 +110,10 @@
 #define TARGET_NR_getresuid          109 /* Linux Specific, sigblock under SunOS	   */
 #define TARGET_NR_setresgid          110 /* Linux Specific, sigsetmask under SunOS	   */
 #define TARGET_NR_getresgid          111 /* Linux Specific, sigpause under SunOS	   */
-/* #define TARGET_NR_setregid32       75    Linux sparc32, sigstack under SunOS         */
+/* #define TARGET_NR_setregid32          75  Linux sparc32, sigstack under SunOS         */
 #define TARGET_NR_recvmsg            113 /* Common                                      */
 #define TARGET_NR_sendmsg            114 /* Common                                      */
-/* #define TARGET_NR_getgroups32     115    Linux sparc32, vtrace under SunOS           */
+#define TARGET_NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
 #define TARGET_NR_gettimeofday       116 /* Common                                      */
 #define TARGET_NR_getrusage          117 /* Common                                      */
 #define TARGET_NR_getsockopt         118 /* Common                                      */
@@ -130,14 +130,14 @@
 #define TARGET_NR_truncate           129 /* Common                                      */
 #define TARGET_NR_ftruncate          130 /* Common                                      */
 #define TARGET_NR_flock              131 /* Common                                      */
-/* #define TARGET_NR_lstat64		132    Linux sparc32 Specific                      */
+#define TARGET_NR_lstat64	     132 /* Linux sparc32 Specific                      */
 #define TARGET_NR_sendto             133 /* Common                                      */
 #define TARGET_NR_shutdown           134 /* Common                                      */
 #define TARGET_NR_socketpair         135 /* Common                                      */
 #define TARGET_NR_mkdir              136 /* Common                                      */
 #define TARGET_NR_rmdir              137 /* Common                                      */
 #define TARGET_NR_utimes             138 /* SunOS Specific                              */
-/* #define TARGET_NR_stat64		139    Linux sparc32 Specific			   */
+#define TARGET_NR_stat64	     139 /* Linux sparc32 Specific			   */
 #define TARGET_NR_sendfile64         140 /* adjtime under SunOS                         */
 #define TARGET_NR_getpeername        141 /* Common                                      */
 #define TARGET_NR_futex              142 /* gethostid under SunOS                       */
@@ -153,7 +153,7 @@
 /* #define TARGET_NR_putmsg          152    SunOS Specific                              */
 #define TARGET_NR_poll               153 /* Common                                      */
 #define TARGET_NR_getdents64		154 /* Linux specific				   */
-/* #define TARGET_NR_fcntl64         155    Linux sparc32 Specific                      */
+#define TARGET_NR_fcntl64            155 /* Linux sparc32 Specific                      */
 /* #define TARGET_NR_getdirentries   156    SunOS Specific                              */
 #define TARGET_NR_statfs             157 /* Common                                      */
 #define TARGET_NR_fstatfs            158 /* Common                                      */
@@ -229,9 +229,7 @@
 #define TARGET_NR_setfsuid           228 /* Linux Specific                              */
 #define TARGET_NR_setfsgid           229 /* Linux Specific                              */
 #define TARGET_NR__newselect         230 /* Linux Specific                              */
-#ifdef __KERNEL__
-#define TARGET_NR_time		231 /* Linux sparc32                               */
-#endif
+#define TARGET_NR_time               231 /* Linux sparc32                               */
 /* #define TARGET_NR_oldstat         232    Linux Specific                              */
 #define TARGET_NR_stime              233 /* Linux Specific                              */
 #define TARGET_NR_statfs64           234 /* Linux Specific                              */
Index: qemu/linux-user/elfload32.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/linux-user/elfload32.c	2007-10-07 17:02:54.000000000 +0000
@@ -0,0 +1,30 @@
+#define OVERRIDE_ELF_CLASS ELFCLASS32
+#define load_elf_binary load_elf_binary32
+#define do_init_thread do_init_thread32
+
+#include "elfload.c"
+
+#undef load_elf_binary
+#undef do_init_thread
+
+int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+
+int load_elf_binary_multi(struct linux_binprm *bprm,
+                          struct target_pt_regs *regs,
+                          struct image_info *info)
+{
+    struct elfhdr *elf_ex;
+    int retval;
+
+    elf_ex = (struct elfhdr *) bprm->buf;          /* exec-header */
+    if (elf_ex->e_ident[EI_CLASS] == ELFCLASS64) {
+        retval = load_elf_binary(bprm, regs, info);
+    } else {
+        retval = load_elf_binary32(bprm, regs, info);
+        if (personality(info->personality) == PER_LINUX)
+            info->personality = PER_LINUX32;
+    }
+
+    return retval;
+}
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target	2007-10-07 17:02:34.000000000 +0000
+++ qemu/Makefile.target	2007-10-07 17:02:54.000000000 +0000
@@ -254,6 +254,10 @@
 ifdef TARGET_HAS_BFLT
 OBJS+= flatload.o
 endif
+ifdef TARGET_HAS_ELFLOAD32
+OBJS+= elfload32.o
+elfload32.o: elfload.c
+endif
 
 ifeq ($(TARGET_ARCH), i386)
 OBJS+= vm86.o
Index: qemu/configure
===================================================================
--- qemu.orig/configure	2007-10-07 17:02:34.000000000 +0000
+++ qemu/configure	2007-10-07 17:02:54.000000000 +0000
@@ -993,6 +993,7 @@
 echo "#include \"../config-host.h\"" >> $config_h
 
 bflt="no"
+elfload32="no"
 interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
 echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
 
@@ -1017,6 +1018,7 @@
   echo "#define TARGET_ARCH \"sparc64\"" >> $config_h
   echo "#define TARGET_SPARC 1" >> $config_h
   echo "#define TARGET_SPARC64 1" >> $config_h
+  elfload32="yes"
 elif test "$target_cpu" = "ppc" ; then
   echo "TARGET_ARCH=ppc" >> $config_mak
   echo "#define TARGET_ARCH \"ppc\"" >> $config_h
@@ -1100,6 +1102,11 @@
   echo "TARGET_HAS_BFLT=yes" >> $config_mak
   echo "#define TARGET_HAS_BFLT 1" >> $config_h
 fi
+# 32 bit ELF loader in addition to native 64 bit loader?
+if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
+  echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak
+  echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
+fi
 # sdl defines
 
 if test "$target_user_only" = "no"; then
Index: qemu/linux-user/linuxload.c
===================================================================
--- qemu.orig/linux-user/linuxload.c	2007-10-07 17:02:34.000000000 +0000
+++ qemu/linux-user/linuxload.c	2007-10-07 17:02:54.000000000 +0000
@@ -169,7 +169,11 @@
                 && bprm.buf[1] == 'E'
                 && bprm.buf[2] == 'L'
                 && bprm.buf[3] == 'F') {
+#ifndef TARGET_HAS_ELFLOAD32
             retval = load_elf_binary(&bprm,regs,infop);
+#else
+            retval = load_elf_binary_multi(&bprm, regs, infop);
+#endif
 #if defined(TARGET_HAS_BFLT)
         } else if (bprm.buf[0] == 'b'
                 && bprm.buf[1] == 'F'

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user
  2007-10-07 17:07   ` Blue Swirl
@ 2007-10-07 17:35     ` J. Mayer
  0 siblings, 0 replies; 9+ messages in thread
From: J. Mayer @ 2007-10-07 17:35 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On Sun, 2007-10-07 at 20:07 +0300, Blue Swirl wrote:
> On 10/7/07, Thiemo Seufer <ths@networkno.de> wrote:
> > Blue Swirl wrote:
> > [snip]
> > > Index: qemu/linux-user/qemu.h
> > > ===================================================================
> > > --- qemu.orig/linux-user/qemu.h       2007-10-07 10:50:05.000000000 +0000
> > > +++ qemu/linux-user/qemu.h    2007-10-07 10:51:09.000000000 +0000
> > > @@ -33,6 +33,7 @@
> > >          target_ulong    data_offset;
> > >          char            **host_argv;
> > >       int             personality;
> > > +        int             is_64bits;
> > >  };
> >
> > I think the 64bit-ness should be part of the personality. In the end,
> > we need a notion of the ABI in use, not just a specific cpu feature flag.
> 
> Good point. I've updated the patch to use the personality field
> instead, for that I updated the personality stuff.

Well done !
I really like this new version as it is far less intrusive. And I guess
it can quite easily be used by other 64 bits targets.

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-10-07 17:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-07 12:45 [Qemu-devel] [RFC, PATCH] Support for loading 32 bit ELF files for 64 bit linux-user Blue Swirl
2007-10-07 14:01 ` J. Mayer
2007-10-07 14:38   ` Blue Swirl
2007-10-07 14:49     ` J. Mayer
2007-10-07 15:15       ` Blue Swirl
2007-10-07 15:46         ` J. Mayer
2007-10-07 16:21 ` Thiemo Seufer
2007-10-07 17:07   ` Blue Swirl
2007-10-07 17:35     ` J. Mayer

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).