glibc2.2 fixes - more command line options - misc doc fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@46 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
386405f786
commit
d691f66983
@ -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:
|
version 0.1:
|
||||||
|
|
||||||
- initial public release.
|
- initial public release.
|
||||||
|
9
Makefile
9
Makefile
@ -118,6 +118,15 @@ tar:
|
|||||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||||
rm -rf /tmp/$(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),)
|
ifneq ($(wildcard .depend),)
|
||||||
include .depend
|
include .depend
|
||||||
endif
|
endif
|
||||||
|
16
README
16
README
@ -15,8 +15,22 @@ Type
|
|||||||
|
|
||||||
make install
|
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
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -406,7 +406,7 @@ void cpu_x86_close(CPUX86State *s);
|
|||||||
/* needed to load some predefinied segment registers */
|
/* needed to load some predefinied segment registers */
|
||||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
|
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
|
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||||
is returned if the signal was handled by the virtual CPU. */
|
is returned if the signal was handled by the virtual CPU. */
|
||||||
struct siginfo;
|
struct siginfo;
|
||||||
|
@ -485,6 +485,10 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
sigset_t *pold_set;
|
sigset_t *pold_set;
|
||||||
|
|
||||||
|
#ifndef REG_EIP
|
||||||
|
/* for glibc 2.1 */
|
||||||
|
#define REG_EIP EIP
|
||||||
|
#endif
|
||||||
pc = uc->uc_mcontext.gregs[EIP];
|
pc = uc->uc_mcontext.gregs[EIP];
|
||||||
pold_set = &uc->uc_sigmask;
|
pold_set = &uc->uc_sigmask;
|
||||||
return handle_cpu_signal(pc, pold_set);
|
return handle_cpu_signal(pc, pold_set);
|
||||||
|
@ -42,8 +42,7 @@
|
|||||||
#define DLINFO_ITEMS 12
|
#define DLINFO_ITEMS 12
|
||||||
|
|
||||||
/* Where we find X86 libraries... */
|
/* Where we find X86 libraries... */
|
||||||
//#define X86_DEFAULT_LIB_DIR "/usr/x86/"
|
|
||||||
#define X86_DEFAULT_LIB_DIR "/"
|
|
||||||
|
|
||||||
//extern void * mmap4k();
|
//extern void * mmap4k();
|
||||||
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
|
#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
|
* 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) {
|
if (elf_interpreter == NULL) {
|
||||||
free (elf_phdata);
|
free (elf_phdata);
|
||||||
@ -646,11 +646,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
return -ENOMEM;
|
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);
|
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
|
||||||
if(retval >= 0) {
|
if(retval >= 0) {
|
||||||
retval = read(bprm->fd,
|
retval = read(bprm->fd,
|
||||||
elf_interpreter+strlen(X86_DEFAULT_LIB_DIR),
|
elf_interpreter+strlen(bprm->interp_prefix),
|
||||||
elf_ppnt->p_filesz);
|
elf_ppnt->p_filesz);
|
||||||
}
|
}
|
||||||
if(retval < 0) {
|
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 target_pt_regs * regs, struct image_info *infop)
|
||||||
{
|
{
|
||||||
struct linux_binprm bprm;
|
struct linux_binprm bprm;
|
||||||
@ -930,6 +931,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
|||||||
else {
|
else {
|
||||||
bprm.fd = retval;
|
bprm.fd = retval;
|
||||||
}
|
}
|
||||||
|
bprm.interp_prefix = (char *)interp_prefix;
|
||||||
bprm.filename = (char *)filename;
|
bprm.filename = (char *)filename;
|
||||||
bprm.sh_bang = 0;
|
bprm.sh_bang = 0;
|
||||||
bprm.loader = 0;
|
bprm.loader = 0;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
FILE *logfile = NULL;
|
FILE *logfile = NULL;
|
||||||
int loglevel;
|
int loglevel;
|
||||||
|
const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
|
||||||
|
|
||||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||||
we allocate a bigger stack. Need a better solution, for example
|
we allocate a bigger stack. Need a better solution, for example
|
||||||
@ -172,9 +173,16 @@ void cpu_loop(struct CPUX86State *env)
|
|||||||
void usage(void)
|
void usage(void)
|
||||||
{
|
{
|
||||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
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"
|
"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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,15 +196,41 @@ int main(int argc, char **argv)
|
|||||||
struct image_info info1, *info = &info1;
|
struct image_info info1, *info = &info1;
|
||||||
CPUX86State *env;
|
CPUX86State *env;
|
||||||
int optind;
|
int optind;
|
||||||
|
const char *r;
|
||||||
|
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
usage();
|
usage();
|
||||||
loglevel = 0;
|
loglevel = 0;
|
||||||
optind = 1;
|
optind = 1;
|
||||||
if (argv[optind] && !strcmp(argv[optind], "-d")) {
|
for(;;) {
|
||||||
loglevel = 1;
|
if (optind >= argc)
|
||||||
|
break;
|
||||||
|
r = argv[optind];
|
||||||
|
if (r[0] != '-')
|
||||||
|
break;
|
||||||
optind++;
|
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];
|
filename = argv[optind];
|
||||||
|
|
||||||
/* init debug */
|
/* init debug */
|
||||||
@ -215,7 +249,7 @@ int main(int argc, char **argv)
|
|||||||
/* Zero out image_info */
|
/* Zero out image_info */
|
||||||
memset(info, 0, sizeof(struct 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);
|
printf("Error loading %s\n", filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ struct image_info {
|
|||||||
int personality;
|
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);
|
struct target_pt_regs * regs, struct image_info *infop);
|
||||||
|
|
||||||
void target_set_brk(char *new_brk);
|
void target_set_brk(char *new_brk);
|
||||||
|
@ -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)
|
void OPPROTO glue(op_movl_A0,REGNAME)(void)
|
||||||
{
|
{
|
||||||
A0 = REG;
|
A0 = REG;
|
||||||
|
@ -4,21 +4,20 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003 Fabrice Bellard
|
* Copyright (c) 2003 Fabrice Bellard
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This library is free software; you can redistribute it and/or
|
||||||
* it under the terms of the GNU General Public License as published by
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* License as published by the Free Software Foundation; either
|
||||||
* (at your option) any later version.
|
* version 2 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DATA_BITS (1 << (3 + SHIFT))
|
#define DATA_BITS (1 << (3 + SHIFT))
|
||||||
#define SHIFT_MASK (DATA_BITS - 1)
|
#define SHIFT_MASK (DATA_BITS - 1)
|
||||||
#define SIGN_MASK (1 << (DATA_BITS - 1))
|
#define SIGN_MASK (1 << (DATA_BITS - 1))
|
||||||
|
@ -73,25 +73,52 @@ maximum performances.
|
|||||||
|
|
||||||
@chapter Invocation
|
@chapter Invocation
|
||||||
|
|
||||||
|
@section Quick Start
|
||||||
|
|
||||||
In order to launch a Linux process, QEMU needs the process executable
|
In order to launch a Linux process, QEMU needs the process executable
|
||||||
itself and all the target (x86) dynamic libraries used by it. Currently,
|
itself and all the target (x86) dynamic libraries used by it.
|
||||||
QEMU is not distributed with the necessary packages so that you can test
|
|
||||||
it easily on non x86 CPUs.
|
|
||||||
|
|
||||||
However, the statically x86 binary 'tests/hello' can be used to do a
|
@itemize
|
||||||
first test:
|
|
||||||
|
@item On x86, you can just try to launch any process by using the native
|
||||||
|
libraries:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
qemu tests/hello
|
qemu -L / /bin/ls
|
||||||
@end example
|
@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
|
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
||||||
qemu /bin/ls -l
|
(@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
|
@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
|
@chapter QEMU Internals
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ testthread: testthread.c
|
|||||||
# i386 emulation test (test various opcodes) */
|
# i386 emulation test (test various opcodes) */
|
||||||
test-i386: test-i386.c test-i386-code16.S \
|
test-i386: test-i386.c test-i386-code16.S \
|
||||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
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
|
test: test-i386
|
||||||
ifeq ($(ARCH),i386)
|
ifeq ($(ARCH),i386)
|
||||||
|
@ -15,21 +15,34 @@ void alarm_handler(int sig)
|
|||||||
alarm(1);
|
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)
|
void dump_regs(struct ucontext *uc)
|
||||||
{
|
{
|
||||||
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||||
"EFL=%08x EIP=%08x\n",
|
"EFL=%08x EIP=%08x\n",
|
||||||
uc->uc_mcontext.gregs[EAX],
|
uc->uc_mcontext.gregs[REG_EAX],
|
||||||
uc->uc_mcontext.gregs[EBX],
|
uc->uc_mcontext.gregs[REG_EBX],
|
||||||
uc->uc_mcontext.gregs[ECX],
|
uc->uc_mcontext.gregs[REG_ECX],
|
||||||
uc->uc_mcontext.gregs[EDX],
|
uc->uc_mcontext.gregs[REG_EDX],
|
||||||
uc->uc_mcontext.gregs[ESI],
|
uc->uc_mcontext.gregs[REG_ESI],
|
||||||
uc->uc_mcontext.gregs[EDI],
|
uc->uc_mcontext.gregs[REG_EDI],
|
||||||
uc->uc_mcontext.gregs[EBP],
|
uc->uc_mcontext.gregs[REG_EBP],
|
||||||
uc->uc_mcontext.gregs[ESP],
|
uc->uc_mcontext.gregs[REG_ESP],
|
||||||
uc->uc_mcontext.gregs[EFL],
|
uc->uc_mcontext.gregs[REG_EFL],
|
||||||
uc->uc_mcontext.gregs[EIP]);
|
uc->uc_mcontext.gregs[REG_EIP]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||||
|
Loading…
Reference in New Issue
Block a user