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