diff --git a/Changelog b/Changelog index 783eb1d7a2b59b2c15a514032fbdddf81aabcf23..574ae5e6009c77851b3c8a0471f423eb8d5070bc 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.1.1: + + - glibc 2.2 compilation fixes + - added -s and -L options + - binary distribution of x86 glibc and wine + version 0.1: - initial public release. diff --git a/Makefile b/Makefile index cce9c7e82808a56534abdb67c65e598c32ad9fb1..169f9def809897a8aea9c88ce084b8d0f8e4f61a 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,15 @@ tar: ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) rm -rf /tmp/$(FILE) +# generate a binary distribution including the test binary environnment +BINPATH=/usr/local/qemu-i386 + +tarbin: + tar zcvf /tmp/qemu-i386-glibc21.tar.gz \ + $(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin + tar zcvf /tmp/qemu-i386-wine.tar.gz \ + $(BINPATH)/X11R6 $(BINPATH)/wine + ifneq ($(wildcard .depend),) include .depend endif diff --git a/README b/README index 52294323e8f043f06cb802c15d099f2b3e63b62f..34061434a06ce681b73f4d424752ecf48b232489 100644 --- a/README +++ b/README @@ -15,8 +15,22 @@ Type make install -to install qemu in /usr/local/bin +to install QEMU in /usr/local/bin +* On x86 you should be able to launch any program by using the +libraries installed on your PC. For example: + + ./qemu -L / /bin/ls + +* On non x86 CPUs, you need first to download at least an x86 glibc +(qemu-i386-glibc21.tar.gz on the qemu web page). Then you can launch +the precompiled 'ls' x86 executable: + + ./qemu /usr/local/qemu-i386/bin/ls + +You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is +automatically launched by the Linux kernel when you try to launch x86 +executables. Documentation ------------- diff --git a/VERSION b/VERSION index ceab6e11ece0bcec917c12e11d350946f085d549..17e51c385ea382d4f2ef124b7032c1604845622d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1 \ No newline at end of file +0.1.1 diff --git a/cpu-i386.h b/cpu-i386.h index dbd71c425812671be1bafcd9505aea9a31a99f5b..700370e71766a2daa739c2b53c0bbee18f974b0f 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -406,7 +406,7 @@ void cpu_x86_close(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); -/* you can call these signal handler from you SIGBUS and SIGSEGV +/* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ struct siginfo; diff --git a/exec-i386.c b/exec-i386.c index ec14ca090191b9d791bf6333b62ae8ac15ab2654..5dbe7fa5348148715e58fc8ac7b65f91e86fdcb5 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -485,6 +485,10 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, unsigned long pc; sigset_t *pold_set; +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#endif pc = uc->uc_mcontext.gregs[EIP]; pold_set = &uc->uc_sigmask; return handle_cpu_signal(pc, pold_set); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 44ac577c0c029bda1af0b9ec15014382e76ec594..817913df4581e99093421b596a423d49837d76f2 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -42,8 +42,7 @@ #define DLINFO_ITEMS 12 /* Where we find X86 libraries... */ -//#define X86_DEFAULT_LIB_DIR "/usr/x86/" -#define X86_DEFAULT_LIB_DIR "/" + //extern void * mmap4k(); #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) @@ -638,7 +637,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * is an a.out format binary */ - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR)); + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+ + strlen(bprm->interp_prefix)); if (elf_interpreter == NULL) { free (elf_phdata); @@ -646,11 +646,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r return -ENOMEM; } - strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR); + strcpy(elf_interpreter, bprm->interp_prefix); retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if(retval >= 0) { retval = read(bprm->fd, - elf_interpreter+strlen(X86_DEFAULT_LIB_DIR), + elf_interpreter+strlen(bprm->interp_prefix), elf_ppnt->p_filesz); } if(retval < 0) { @@ -911,7 +911,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r -int elf_exec(const char * filename, char ** argv, char ** envp, +int elf_exec(const char *interp_prefix, + const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop) { struct linux_binprm bprm; @@ -930,6 +931,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, else { bprm.fd = retval; } + bprm.interp_prefix = (char *)interp_prefix; bprm.filename = (char *)filename; bprm.sh_bang = 0; bprm.loader = 0; diff --git a/linux-user/main.c b/linux-user/main.c index 28999342668b9c39ff55fccf5966fc70e09ae33a..31743253bbaa36c3fcdd87ff0ddd52139e442a36 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -32,6 +32,7 @@ FILE *logfile = NULL; int loglevel; +const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386"; /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example @@ -172,9 +173,16 @@ void cpu_loop(struct CPUX86State *env) void usage(void) { printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu [-d] program [arguments...]\n" + "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" "Linux x86 emulator\n" - ); + "\n" + "-h print this help\n" + "-d activate log (logfile=%s)\n" + "-L path set the x86 elf interpreter prefix (default=%s)\n" + "-s size set the x86 stack size in bytes (default=%ld)\n", + DEBUG_LOGFILE, + interp_prefix, + x86_stack_size); exit(1); } @@ -188,15 +196,41 @@ int main(int argc, char **argv) struct image_info info1, *info = &info1; CPUX86State *env; int optind; - + const char *r; + if (argc <= 1) usage(); loglevel = 0; optind = 1; - if (argv[optind] && !strcmp(argv[optind], "-d")) { - loglevel = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + loglevel = 1; + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + x86_stack_size = strtol(r, (char **)&r, 0); + if (x86_stack_size <= 0) + usage(); + if (*r == 'M') + x86_stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + x86_stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else { + usage(); + } } + if (optind >= argc) + usage(); filename = argv[optind]; /* init debug */ @@ -215,7 +249,7 @@ int main(int argc, char **argv) /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); - if(elf_exec(filename, argv+optind, environ, regs, info) != 0) { + if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); exit(1); } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 862695511c472f8266abead468edc8a1e6671360..d4d93a42913be2be24760366a27b8c1dea54db18 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -33,7 +33,8 @@ struct image_info { int personality; }; -int elf_exec(const char * filename, char ** argv, char ** envp, +int elf_exec(const char *interp_prefix, + const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); void target_set_brk(char *new_brk); diff --git a/opreg_template.h b/opreg_template.h index d6453f95466b7fbd40433481934e95d060028fd5..f35a1bbc9502d7d4df24baaa477cc1cf4c2d9c6a 100644 --- a/opreg_template.h +++ b/opreg_template.h @@ -1,5 +1,23 @@ -/* templates for various register related operations */ - +/* + * i386 micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ void OPPROTO glue(op_movl_A0,REGNAME)(void) { A0 = REG; diff --git a/ops_template.h b/ops_template.h index 1a2380041210edfcb8aa3ef277c34a45dfe4540d..34f10cdf936e93a72de3370dd7a4618050f5684a 100644 --- a/ops_template.h +++ b/ops_template.h @@ -4,21 +4,20 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #define DATA_BITS (1 << (3 + SHIFT)) #define SHIFT_MASK (DATA_BITS - 1) #define SIGN_MASK (1 << (DATA_BITS - 1)) diff --git a/qemu-doc.texi b/qemu-doc.texi index a7b0ce9f708bce45396b17d376868bd73aea2220..fb9ed0ae90f629587a0d2b3fc17a03c47618037d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -73,26 +73,53 @@ maximum performances. @chapter Invocation +@section Quick Start + In order to launch a Linux process, QEMU needs the process executable -itself and all the target (x86) dynamic libraries used by it. Currently, -QEMU is not distributed with the necessary packages so that you can test -it easily on non x86 CPUs. +itself and all the target (x86) dynamic libraries used by it. + +@itemize -However, the statically x86 binary 'tests/hello' can be used to do a -first test: +@item On x86, you can just try to launch any process by using the native +libraries: @example -qemu tests/hello +qemu -L / /bin/ls @end example -@code{Hello world} should be printed on the terminal. +@code{-L /} tells that the x86 dynamic linker must be searched with a +@file{/} prefix. -If you are testing it on a x86 CPU, then you can test it on any process: -@example -qemu /bin/ls -l +@item On non x86 CPUs, you need first to download at least an x86 glibc +(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Then you can +launch the precompiled @file{ls} x86 executable: +@example +qemu /usr/local/qemu-i386/bin/ls +@end example +You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that QEMU is automatically +launched by the Linux kernel when you try to launch x86 executables. It +requires the @code{binfmt_misc} module in the Linux kernel. + +@end itemize + +@section Command line options + +@example +usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...] @end example +@table @samp +@item -h +Print the help +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -L path +Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) +@item -s size +Set the x86 stack size in bytes (default=524288) +@end table + @chapter QEMU Internals @section QEMU compared to other emulators diff --git a/tests/Makefile b/tests/Makefile index 495dbf3f4c97fbd2760ba2885c2fcad747b5f734..0d0fb9b956690487c61f62937d0f4df05d63a391 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -28,7 +28,7 @@ testthread: testthread.c # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm test: test-i386 ifeq ($(ARCH),i386) diff --git a/tests/testsig.c b/tests/testsig.c index d93f42806aeb3ce4a33e314d06e733cf5af9b9b1..27ea78c6a9a32e41e24373c81db9d8e4775b6ecb 100644 --- a/tests/testsig.c +++ b/tests/testsig.c @@ -15,21 +15,34 @@ void alarm_handler(int sig) alarm(1); } +#ifndef REG_EAX +#define REG_EAX EAX +#define REG_EBX EBX +#define REG_ECX ECX +#define REG_EDX EDX +#define REG_ESI ESI +#define REG_EDI EDI +#define REG_EBP EBP +#define REG_ESP ESP +#define REG_EIP EIP +#define REG_EFL EFL +#endif + void dump_regs(struct ucontext *uc) { printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" "EFL=%08x EIP=%08x\n", - uc->uc_mcontext.gregs[EAX], - uc->uc_mcontext.gregs[EBX], - uc->uc_mcontext.gregs[ECX], - uc->uc_mcontext.gregs[EDX], - uc->uc_mcontext.gregs[ESI], - uc->uc_mcontext.gregs[EDI], - uc->uc_mcontext.gregs[EBP], - uc->uc_mcontext.gregs[ESP], - uc->uc_mcontext.gregs[EFL], - uc->uc_mcontext.gregs[EIP]); + uc->uc_mcontext.gregs[REG_EAX], + uc->uc_mcontext.gregs[REG_EBX], + uc->uc_mcontext.gregs[REG_ECX], + uc->uc_mcontext.gregs[REG_EDX], + uc->uc_mcontext.gregs[REG_ESI], + uc->uc_mcontext.gregs[REG_EDI], + uc->uc_mcontext.gregs[REG_EBP], + uc->uc_mcontext.gregs[REG_ESP], + uc->uc_mcontext.gregs[REG_EFL], + uc->uc_mcontext.gregs[REG_EIP]); } void sig_handler(int sig, siginfo_t *info, void *puc)