Compare commits

...

53 Commits

Author SHA1 Message Date
bellard
1eb87257da update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@97 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 01:12:28 +00:00
bellard
32ce63371a path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@96 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:16:16 +00:00
bellard
ec86b0fb3a stat patches - path patches - added exit_group() syscall
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@95 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:15:04 +00:00
bellard
1d346ae63a added prefix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@94 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:14:24 +00:00
bellard
74cd30b811 RH9 fix - path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@93 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:41 +00:00
bellard
7fb9a24e39 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@92 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:04 +00:00
bellard
afeb6ee377 suppressed undefined shldw shrdw
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@91 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:12:54 +00:00
bellard
f29042b531 TIOCGPTN and TIOCSPTLCK ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@90 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:12:45 +00:00
bellard
09bfb054fb first self virtualizable version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:40 +00:00
bellard
2677e107e6 warning fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@88 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:27 +00:00
bellard
66cd58461d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@87 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:58 +00:00
bellard
bb0ebb1f2d ISO C fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@86 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:33 +00:00
bellard
27c75a9a90 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@85 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:35:21 +00:00
bellard
d0cd3b8d84 64 bit fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@84 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:35:13 +00:00
bellard
9af9eaaa76 endian fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@83 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:41 +00:00
bellard
8c8f42f76c clock_t fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@82 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:27 +00:00
bellard
51fe68905b powerpc div and rint fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@81 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:14 +00:00
bellard
7fe70ecc56 powerpc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@80 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:40 +00:00
bellard
d03cda5923 alpha fix - powerpc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@79 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:21 +00:00
bellard
30ac07d4f0 moved i386 specific stuff outside elf.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@78 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:03 +00:00
bellard
8857052055 more cpu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@77 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:32:32 +00:00
bellard
ce11fedc6e 64 bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@76 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:32:22 +00:00
bellard
43d4145a98 bfd.h dependancy removed
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@75 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:44 +00:00
bellard
295defa5f1 alpha addition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@74 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:29 +00:00
bellard
f801f97e04 personality fix - i386 interpreter fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@73 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:06 +00:00
bellard
f48c3dd51a -statis for test-i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@72 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:30:39 +00:00
bellard
62296fe351 added runcom test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@71 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:41:51 +00:00
bellard
32f36bcefc added SIOCATMARK and times() syscall
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@70 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:29:48 +00:00
bellard
bc8a22cc30 better vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@69 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:02:40 +00:00
bellard
f631ef9bd2 better vm86 support - added iret - fixed push/pop fs/gs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:01:16 +00:00
bellard
f7341ff400 fixed execve bug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@67 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:00:25 +00:00
bellard
fd429f2f6c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@66 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 20:59:46 +00:00
bellard
fb3e5849bb s390 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@65 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:32:36 +00:00
bellard
7854b05654 endian fixes by Ulrich weigand
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@64 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:22:23 +00:00
bellard
500dab07e8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@63 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:58:09 +00:00
bellard
f6630e791b version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@62 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:48 +00:00
bellard
168485b75b wine help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@61 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:34 +00:00
bellard
5cd4393b14 first vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:36 +00:00
bellard
7ed601b782 more syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@59 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:05 +00:00
bellard
d1f2367bc0 changed flag names
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@58 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:34 +00:00
bellard
851e67a1b4 primitive vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@57 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:14 +00:00
bellard
fc2b4c4879 eflags update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@56 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:52:44 +00:00
bellard
9c605cb135 added cmpxchg8b, cpuid, bound, eflags support, vm86 mode, 16bit/override string ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@55 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:51:35 +00:00
bellard
24f9e90b0e 16bit/override support in string operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@54 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:50:40 +00:00
bellard
a4a0ffdb2b added cmpxchg8b, cpuid, bound, eflags support, vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@53 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:49:21 +00:00
bellard
0ea00c9a3c added number of arguments
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@52 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:47:34 +00:00
bellard
e1d4294a45 more tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@51 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:45:07 +00:00
bellard
c3c7c29246 added runcom
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@50 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:44:42 +00:00
bellard
31bb950be6 xchg lock, xlat instr
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@49 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-26 22:33:47 +00:00
bellard
8083a3e508 dirent fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@48 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:12:16 +00:00
bellard
644c433cb3 ld.so load fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@47 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:00:36 +00:00
bellard
d691f66983 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
2003-03-24 21:58:34 +00:00
bellard
386405f786 documentation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@45 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 21:28:45 +00:00
40 changed files with 5212 additions and 1550 deletions

View File

@@ -1,3 +1,60 @@
version 0.1.6:
- automatic library search system. QEMU can now work with unpatched
ELF dynamic loader and libc (Rusty Russell).
- ISO C warning fixes (Alistair Strachan)
- first self-virtualizable version (works only as long as the
translation cache is not flushed)
- RH9 fixes
version 0.1.5:
- ppc64 support + personality() patch (Rusty Russell)
- first Alpha CPU patches (Falk Hueffner)
- removed bfd.h dependancy
- fixed shrd, shld, idivl and divl on PowerPC.
- fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
version 0.1.4:
- more accurate VM86 emulation (can launch small DOS 16 bit
executables in wine).
- fixed push/pop fs/gs
- added iret instruction.
- added times() syscall and SIOCATMARK ioctl.
version 0.1.3:
- S390 support (Ulrich Weigand)
- glibc 2.3.x compile fix (Ulrich Weigand)
- socketcall endian fix (Ulrich Weigand)
- struct sockaddr endian fix (Ulrich Weigand)
- sendmsg/recvmsg endian fix (Ulrich Weigand)
- execve endian fix (Ulrich Weigand)
- fdset endian fix (Ulrich Weigand)
- partial setsockopt syscall support (Ulrich Weigand)
- more accurate pushf/popf emulation
- first partial vm86() syscall support (can be used with runcom example).
- added bound, cmpxchg8b, cpuid instructions
- added 16 bit addressing support/override for string operations
- poll() fix
version 0.1.2:
- compile fixes
- xlat instruction
- xchg instruction memory lock
- added simple vm86 example (not working with QEMU yet). The 54 byte
DOS executable 'pi_10.com' program was released by Bertram
Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
version 0.1.1:
- glibc 2.2 compilation fixes
- added -s and -L options
- binary distribution of x86 glibc and wine
- big endian fixes in ELF loader and getdents.
version 0.1: version 0.1:
- initial public release. - initial public release.

View File

@@ -13,10 +13,20 @@ OP_CFLAGS+= -falign-functions=0
else else
OP_CFLAGS+= -malign-functions=0 OP_CFLAGS+= -malign-functions=0
endif endif
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
endif endif
ifeq ($(ARCH),ppc) ifeq ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS) OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,ppc.ld
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,s390.ld
endif endif
ifeq ($(GCC_MAJOR),3) ifeq ($(GCC_MAJOR),3)
@@ -27,7 +37,6 @@ endif
######################################################### #########################################################
DEFINES+=-D_GNU_SOURCE DEFINES+=-D_GNU_SOURCE
LDSCRIPT=$(ARCH).ld
LIBS+=-lm LIBS+=-lm
# profiling code # profiling code
@@ -36,7 +45,7 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p main.o: CFLAGS+=-p
endif endif
OBJS= elfload.o main.o syscall.o signal.o OBJS= elfload.o main.o syscall.o signal.o path.o
SRCS:= $(OBJS:.o=.c) SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a OBJS+= libqemu.a
@@ -47,7 +56,7 @@ LIBOBJS+=i386-dis.o dis-buf.o
all: qemu qemu-doc.html all: qemu qemu-doc.html
qemu: $(OBJS) qemu: $(OBJS)
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
depend: $(SRCS) depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend $(CC) -MM $(CFLAGS) $^ 1>.depend
@@ -94,19 +103,21 @@ qemu-doc.html: qemu-doc.texi
texi2html -monolithic -number $< texi2html -monolithic -number $<
FILES= \ FILES= \
README COPYING COPYING.LIB TODO Changelog VERSION \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
dyngen.c ioctls.h ops_template.h syscall_types.h\ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
Makefile elf.h linux_bin.h segment.h thunk.c\ Makefile elf.h thunk.c\
elfload.c main.c signal.c thunk.h\ elfload.c main.c signal.c thunk.h\
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-asm.h gen-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
i386.ld ppc.ld exec-i386.h exec-i386.c configure \ ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \
tests/Makefile\ tests/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h tests/test-i386-code16.S\ tests/test-i386-muldiv.h tests/test-i386-code16.S\
tests/hello.c tests/hello tests/sha1.c \ tests/hello.c tests/hello tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \ tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
qemu-doc.texi qemu-doc.html qemu-doc.texi qemu-doc.html
FILE=qemu-$(VERSION) FILE=qemu-$(VERSION)
@@ -118,6 +129,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-$(VERSION)-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
$(BINPATH)/wine
ifneq ($(wildcard .depend),) ifneq ($(wildcard .depend),)
include .depend include .depend
endif endif

22
README
View File

@@ -6,7 +6,7 @@ INSTALLATION
Type Type
./configure ./configure --interp-prefix=/usr/local/qemu-i386
make make
to build qemu and libqemu.a. to build qemu and libqemu.a.
@@ -15,8 +15,26 @@ 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-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
LD_LIBRARY_PATH is not set:
unset LD_LIBRARY_PATH
Then you can launch the precompiled 'ls' x86 executable:
./qemu /usr/local/qemu-i386/bin/ls-i386
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
------------- -------------

10
TODO
View File

@@ -1,10 +1,12 @@
- fix thread locks
- optimize translated cache chaining (DLL PLT-like system) - optimize translated cache chaining (DLL PLT-like system)
- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID)
- fix x86 stack allocation
- fix iret/lret restarting
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues) issues, fix 16 bit uid issues)
- finish signal handing (fp87 state, more siginfo conversions) - finish signal handing (fp87 state, more siginfo conversions)
- verify thread support (clone() and various locks) - verify thread support (clone() and various locks)
- vm86 syscall support - make it self runnable (handle self modifying code, relocate stack
- overrides/16bit for string ops and dyn loader)
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
- improved 16 bit support
- fix FPU exceptions (in particular: gen_op_fpush not before mem load) - fix FPU exceptions (in particular: gen_op_fpush not before mem load)

View File

@@ -1 +1 @@
0.1 0.1.6

26
configure vendored
View File

@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters # default parameters
prefix="/usr/local" prefix="/usr/local"
interp_prefix="/usr/gnemul/qemu-i386"
cross_prefix="" cross_prefix=""
cc="gcc" cc="gcc"
host_cc="gcc" host_cc="gcc"
@@ -36,12 +37,15 @@ case "$cpu" in
alpha) alpha)
cpu="alpha" cpu="alpha"
;; ;;
"Power Macintosh"|ppc) "Power Macintosh"|ppc|ppc64)
cpu="powerpc" cpu="powerpc"
;; ;;
mips) mips)
cpu="mips" cpu="mips"
;; ;;
s390)
cpu="s390"
;;
*) *)
cpu="unknown" cpu="unknown"
;; ;;
@@ -86,6 +90,8 @@ for opt do
case "$opt" in case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2` --prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;; ;;
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2` --source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;; ;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
@@ -137,7 +143,7 @@ fi
else else
# if cross compiling, cannot launch a program, so make a static guess # if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
bigendian="yes" bigendian="yes"
fi fi
@@ -169,7 +175,7 @@ EOF
echo "Standard options:" echo "Standard options:"
echo " --help print this message" echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]" echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " for audio/video/image support" echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
echo "" echo ""
echo "Advanced options (experts only):" echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]" echo " --source-path=PATH path of source code [$source_path]"
@@ -195,7 +201,7 @@ echo "# Automatically generated by configure - do not modify" > config.mak
echo "/* Automatically generated by configure - do not modify */" > $TMPH echo "/* Automatically generated by configure - do not modify */" > $TMPH
echo "prefix=$prefix" >> config.mak echo "prefix=$prefix" >> config.mak
echo "#define CONFIG_QEMU_PREFIX \"$prefix\"" >> $TMPH echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
echo "MAKE=$make" >> config.mak echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak echo "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak echo "GCC_MAJOR=$gcc_major" >> config.mak
@@ -206,12 +212,22 @@ echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak echo "LDFLAGS=$LDFLAGS" >> config.mak
if test "$cpu" = "x86" ; then if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
elif test "$cpu" = "armv4l" ; then elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
elif test "$cpu" = "powerpc" ; then elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak echo "ARCH=ppc" >> config.mak
echo "#define HOST_PPC 1" >> $TMPH
elif test "$cpu" = "mips" ; then elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak echo "ARCH=mips" >> config.mak
echo "#define HOST_MIPS 1" >> $TMPH
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
echo "#define HOST_S390 1" >> $TMPH
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> config.mak
echo "#define HOST_ALPHA 1" >> $TMPH
else else
echo "Unsupported CPU" echo "Unsupported CPU"
exit 1 exit 1
@@ -255,4 +271,4 @@ else
echo "config.h is unchanged" echo "config.h is unchanged"
fi fi
rm -f $TMPH rm -f $TMPO $TMPC $TMPE $TMPS $TMPH

View File

@@ -48,6 +48,7 @@
#define R_FS 4 #define R_FS 4
#define R_GS 5 #define R_GS 5
/* eflags masks */
#define CC_C 0x0001 #define CC_C 0x0001
#define CC_P 0x0004 #define CC_P 0x0004
#define CC_A 0x0010 #define CC_A 0x0010
@@ -55,34 +56,36 @@
#define CC_S 0x0080 #define CC_S 0x0080
#define CC_O 0x0800 #define CC_O 0x0800
#define TRAP_FLAG 0x0100 #define TF_MASK 0x00000100
#define INTERRUPT_FLAG 0x0200 #define IF_MASK 0x00000200
#define DIRECTION_FLAG 0x0400 #define DF_MASK 0x00000400
#define IOPL_FLAG_MASK 0x3000 #define IOPL_MASK 0x00003000
#define NESTED_FLAG 0x4000 #define NT_MASK 0x00004000
#define BYTE_FL 0x8000 /* Intel reserved! */ #define RF_MASK 0x00010000
#define RF_FLAG 0x10000 #define VM_MASK 0x00020000
#define VM_FLAG 0x20000 #define AC_MASK 0x00040000
/* AC 0x40000 */ #define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
#define EXCP00_DIVZ 1 #define EXCP00_DIVZ 0
#define EXCP01_SSTP 2 #define EXCP01_SSTP 1
#define EXCP02_NMI 3 #define EXCP02_NMI 2
#define EXCP03_INT3 4 #define EXCP03_INT3 3
#define EXCP04_INTO 5 #define EXCP04_INTO 4
#define EXCP05_BOUND 6 #define EXCP05_BOUND 5
#define EXCP06_ILLOP 7 #define EXCP06_ILLOP 6
#define EXCP07_PREX 8 #define EXCP07_PREX 7
#define EXCP08_DBLE 9 #define EXCP08_DBLE 8
#define EXCP09_XERR 10 #define EXCP09_XERR 9
#define EXCP0A_TSS 11 #define EXCP0A_TSS 10
#define EXCP0B_NOSEG 12 #define EXCP0B_NOSEG 11
#define EXCP0C_STACK 13 #define EXCP0C_STACK 12
#define EXCP0D_GPF 14 #define EXCP0D_GPF 13
#define EXCP0E_PAGE 15 #define EXCP0E_PAGE 14
#define EXCP10_COPR 17 #define EXCP10_COPR 16
#define EXCP11_ALGN 18 #define EXCP11_ALGN 17
#define EXCP12_MCHK 19 #define EXCP12_MCHK 18
#define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_INTERRUPT 256 /* async interruption */
@@ -158,7 +161,9 @@ typedef struct CPUX86State {
/* standard registers */ /* standard registers */
uint32_t regs[8]; uint32_t regs[8];
uint32_t eip; uint32_t eip;
uint32_t eflags; uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
store elsewhere */
/* emulator internal eflags handling */ /* emulator internal eflags handling */
uint32_t cc_src; uint32_t cc_src;
@@ -183,13 +188,13 @@ typedef struct CPUX86State {
SegmentDescriptorTable ldt; SegmentDescriptorTable ldt;
SegmentDescriptorTable idt; SegmentDescriptorTable idt;
/* various CPU modes */
int vm86;
/* exception/interrupt handling */ /* exception/interrupt handling */
jmp_buf jmp_env; jmp_buf jmp_env;
int exception_index; int exception_index;
int interrupt_request; int interrupt_request;
/* user data */
void *opaque;
} CPUX86State; } CPUX86State;
/* all CPU memory access use these macros */ /* all CPU memory access use these macros */
@@ -406,7 +411,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;
@@ -418,7 +423,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
#define GEN_FLAG_CODE32_SHIFT 0 #define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1 #define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_SS32_SHIFT 2 #define GEN_FLAG_SS32_SHIFT 2
#define GEN_FLAG_ST_SHIFT 3 #define GEN_FLAG_VM_SHIFT 3
#define GEN_FLAG_ST_SHIFT 4
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, int *gen_code_size_ptr,

149
dis-asm.h
View File

@@ -11,7 +11,152 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "bfd.h" #include <inttypes.h>
#define PARAMS(x) x
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef uint8_t bfd_byte;
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
bfd_target_coff_flavour,
bfd_target_ecoff_flavour,
bfd_target_elf_flavour,
bfd_target_ieee_flavour,
bfd_target_nlm_flavour,
bfd_target_oasys_flavour,
bfd_target_tekhex_flavour,
bfd_target_srec_flavour,
bfd_target_ihex_flavour,
bfd_target_som_flavour,
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
bfd_target_evax_flavour
};
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known */
bfd_arch_obscure, /* Arch known, not one of these */
bfd_arch_m68k, /* Motorola 68xxx */
#define bfd_mach_m68000 1
#define bfd_mach_m68008 2
#define bfd_mach_m68010 3
#define bfd_mach_m68020 4
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
lower number indicates a machine type that
only accepts a subset of the instructions
available to machines with higher numbers.
The exception is the "ca", which is
incompatible with all other machines except
"core". */
#define bfd_mach_i960_core 1
#define bfd_mach_i960_ka_sa 2
#define bfd_mach_i960_kb_sb 3
#define bfd_mach_i960_mc 4
#define bfd_mach_i960_xa 5
#define bfd_mach_i960_ca 6
#define bfd_mach_i960_jx 7
#define bfd_mach_i960_hx 8
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */
#define bfd_mach_sparc_v9 6
#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
#define bfd_mach_mips4000 4000
#define bfd_mach_mips4010 4010
#define bfd_mach_mips4100 4100
#define bfd_mach_mips4300 4300
#define bfd_mach_mips4400 4400
#define bfd_mach_mips4600 4600
#define bfd_mach_mips4650 4650
#define bfd_mach_mips5000 5000
#define bfd_mach_mips6000 6000
#define bfd_mach_mips8000 8000
#define bfd_mach_mips10000 10000
#define bfd_mach_mips16 16
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */
bfd_arch_romp, /* IBM ROMP PC/RT */
bfd_arch_alliant, /* Alliant */
bfd_arch_convex, /* Convex */
bfd_arch_m88k, /* Motorola 88xxx */
bfd_arch_pyramid, /* Pyramid Technology */
bfd_arch_h8300, /* Hitachi H8/300 */
#define bfd_mach_h8300 1
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
bfd_arch_z8k, /* Zilog Z8000 */
#define bfd_mach_z8001 1
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 0
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
bfd_arch_alpha, /* Dec Alpha */
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_2 1
#define bfd_mach_arm_2a 2
#define bfd_mach_arm_3 3
#define bfd_mach_arm_3M 4
#define bfd_mach_arm_4 5
#define bfd_mach_arm_4T 6
bfd_arch_ns32k, /* National Semiconductors ns32000 */
bfd_arch_w65, /* WDC 65816 */
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
bfd_arch_v850, /* NEC V850 */
#define bfd_mach_v850 0
bfd_arch_arc, /* Argonaut RISC Core */
#define bfd_mach_arc_base 0
bfd_arch_m32r, /* Mitsubishi M32R/D */
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
bfd_arch_last
};
typedef struct symbol_cache_entry
{
const char *name;
union
{
PTR p;
bfd_vma i;
} udata;
} asymbol;
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
@@ -176,8 +321,10 @@ extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */ /* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler PARAMS ((bfd *)); extern disassembler_ftype disassembler PARAMS ((bfd *));
#endif
/* This block of definitions is for particular callers who read instructions /* This block of definitions is for particular callers who read instructions

272
dyngen.c
View File

@@ -22,16 +22,62 @@
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <inttypes.h> #include <inttypes.h>
#include <elf.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include "config.h"
/* elf format definitions. We use these macros to test the CPU to
allow cross compilation (this tool must be ran on the build
platform) */
#if defined(HOST_I386)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_386
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
#undef ELF_USES_RELOCA
#elif defined(HOST_PPC)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_PPC
#define elf_check_arch(x) ((x) == EM_PPC)
#define ELF_USES_RELOCA
#elif defined(HOST_S390)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_S390
#define elf_check_arch(x) ((x) == EM_S390)
#define ELF_USES_RELOCA
#elif defined(HOST_ALPHA)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_ALPHA
#define elf_check_arch(x) ((x) == EM_ALPHA)
#define ELF_USES_RELOCA
#else
#error unsupported CPU - please update the code
#endif
#if ELF_CLASS == ELFCLASS32
typedef int32_t host_long;
typedef uint32_t host_ulong;
#else
typedef int64_t host_long;
typedef uint64_t host_ulong;
#endif
#include "elf.h"
#include "thunk.h" #include "thunk.h"
/* all dynamically generated functions begin with this code */ /* all dynamically generated functions begin with this code */
#define OP_PREFIX "op_" #define OP_PREFIX "op_"
int elf_must_swap(Elf32_Ehdr *h) int elf_must_swap(struct elfhdr *h)
{ {
union { union {
uint32_t i; uint32_t i;
@@ -53,19 +99,25 @@ void swab32s(uint32_t *p)
*p = bswap32(*p); *p = bswap32(*p);
} }
void swab64s(uint32_t *p) void swab64s(uint64_t *p)
{ {
*p = bswap64(*p); *p = bswap64(*p);
} }
void elf_swap_ehdr(Elf32_Ehdr *h) #if ELF_CLASS == ELFCLASS32
#define swabls(x) swab32s(x)
#else
#define swabls(x) swab64s(x)
#endif
void elf_swap_ehdr(struct elfhdr *h)
{ {
swab16s(&h->e_type); /* Object file type */ swab16s(&h->e_type); /* Object file type */
swab16s(&h-> e_machine); /* Architecture */ swab16s(&h-> e_machine); /* Architecture */
swab32s(&h-> e_version); /* Object file version */ swab32s(&h-> e_version); /* Object file version */
swab32s(&h-> e_entry); /* Entry point virtual address */ swabls(&h-> e_entry); /* Entry point virtual address */
swab32s(&h-> e_phoff); /* Program header table file offset */ swabls(&h-> e_phoff); /* Program header table file offset */
swab32s(&h-> e_shoff); /* Section header table file offset */ swabls(&h-> e_shoff); /* Section header table file offset */
swab32s(&h-> e_flags); /* Processor-specific flags */ swab32s(&h-> e_flags); /* Processor-specific flags */
swab16s(&h-> e_ehsize); /* ELF header size in bytes */ swab16s(&h-> e_ehsize); /* ELF header size in bytes */
swab16s(&h-> e_phentsize); /* Program header table entry size */ swab16s(&h-> e_phentsize); /* Program header table entry size */
@@ -75,34 +127,33 @@ void elf_swap_ehdr(Elf32_Ehdr *h)
swab16s(&h-> e_shstrndx); /* Section header string table index */ swab16s(&h-> e_shstrndx); /* Section header string table index */
} }
void elf_swap_shdr(Elf32_Shdr *h) void elf_swap_shdr(struct elf_shdr *h)
{ {
swab32s(&h-> sh_name); /* Section name (string tbl index) */ swab32s(&h-> sh_name); /* Section name (string tbl index) */
swab32s(&h-> sh_type); /* Section type */ swab32s(&h-> sh_type); /* Section type */
swab32s(&h-> sh_flags); /* Section flags */ swabls(&h-> sh_flags); /* Section flags */
swab32s(&h-> sh_addr); /* Section virtual addr at execution */ swabls(&h-> sh_addr); /* Section virtual addr at execution */
swab32s(&h-> sh_offset); /* Section file offset */ swabls(&h-> sh_offset); /* Section file offset */
swab32s(&h-> sh_size); /* Section size in bytes */ swabls(&h-> sh_size); /* Section size in bytes */
swab32s(&h-> sh_link); /* Link to another section */ swab32s(&h-> sh_link); /* Link to another section */
swab32s(&h-> sh_info); /* Additional section information */ swab32s(&h-> sh_info); /* Additional section information */
swab32s(&h-> sh_addralign); /* Section alignment */ swabls(&h-> sh_addralign); /* Section alignment */
swab32s(&h-> sh_entsize); /* Entry size if section holds table */ swabls(&h-> sh_entsize); /* Entry size if section holds table */
} }
void elf_swap_phdr(Elf32_Phdr *h) void elf_swap_phdr(struct elf_phdr *h)
{ {
swab32s(&h->p_type); /* Segment type */ swab32s(&h->p_type); /* Segment type */
swab32s(&h->p_offset); /* Segment file offset */ swabls(&h->p_offset); /* Segment file offset */
swab32s(&h->p_vaddr); /* Segment virtual address */ swabls(&h->p_vaddr); /* Segment virtual address */
swab32s(&h->p_paddr); /* Segment physical address */ swabls(&h->p_paddr); /* Segment physical address */
swab32s(&h->p_filesz); /* Segment size in file */ swabls(&h->p_filesz); /* Segment size in file */
swab32s(&h->p_memsz); /* Segment size in memory */ swabls(&h->p_memsz); /* Segment size in memory */
swab32s(&h->p_flags); /* Segment flags */ swab32s(&h->p_flags); /* Segment flags */
swab32s(&h->p_align); /* Segment alignment */ swabls(&h->p_align); /* Segment alignment */
} }
int do_swap; int do_swap;
int e_machine;
uint16_t get16(uint16_t *p) uint16_t get16(uint16_t *p)
{ {
@@ -148,12 +199,12 @@ void __attribute__((noreturn)) error(const char *fmt, ...)
} }
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr, struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
const char *name) const char *name)
{ {
int i; int i;
const char *shname; const char *shname;
Elf32_Shdr *sec; struct elf_shdr *sec;
for(i = 0; i < shnum; i++) { for(i = 0; i < shnum; i++) {
sec = &shdr[i]; sec = &shdr[i];
@@ -200,20 +251,21 @@ int strstart(const char *str, const char *val, const char **ptr)
#define MAX_ARGS 3 #define MAX_ARGS 3
/* generate op code */ /* generate op code */
void gen_code(const char *name, unsigned long offset, unsigned long size, void gen_code(const char *name, host_ulong offset, host_ulong size,
FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type, FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
Elf32_Sym *symtab, char *strtab, int gen_switch) ElfW(Sym) *symtab, char *strtab, int gen_switch)
{ {
int copy_size = 0; int copy_size = 0;
uint8_t *p_start, *p_end; uint8_t *p_start, *p_end;
int nb_args, i; int nb_args, i, n;
uint8_t args_present[MAX_ARGS]; uint8_t args_present[MAX_ARGS];
const char *sym_name, *p; const char *sym_name, *p;
ELF_RELOC *rel;
/* compute exact size excluding return instruction */ /* compute exact size excluding return instruction */
p_start = text + offset; p_start = text + offset;
p_end = p_start + size; p_end = p_start + size;
switch(e_machine) { switch(ELF_ARCH) {
case EM_386: case EM_386:
{ {
uint8_t *p; uint8_t *p;
@@ -236,20 +288,26 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
copy_size = p - p_start; copy_size = p - p_start;
} }
break; break;
default: case EM_S390:
error("unsupported CPU (%d)", e_machine); {
uint8_t *p;
p = (void *)(p_end - 2);
if (p == p_start)
error("empty code for %s", name);
if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
error("br %r14 expected at the end of %s", name);
copy_size = p - p_start;
}
break;
} }
/* compute the number of arguments by looking at the relocations */ /* compute the number of arguments by looking at the relocations */
for(i = 0;i < MAX_ARGS; i++) for(i = 0;i < MAX_ARGS; i++)
args_present[i] = 0; args_present[i] = 0;
if (reloc_sh_type == SHT_REL) {
Elf32_Rel *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) { if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10); n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS) if (n >= MAX_ARGS)
@@ -258,21 +316,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
} }
} }
} else {
Elf32_Rela *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
}
}
}
nb_args = 0; nb_args = 0;
while (nb_args < MAX_ARGS && args_present[nb_args]) while (nb_args < MAX_ARGS && args_present[nb_args])
@@ -282,7 +325,9 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
error("inconsistent argument numbering in %s", name); error("inconsistent argument numbering in %s", name);
} }
if (gen_switch) { if (gen_switch == 2) {
fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
} else if (gen_switch == 1) {
/* output C code */ /* output C code */
fprintf(outfile, "case INDEX_%s: {\n", name); fprintf(outfile, "case INDEX_%s: {\n", name);
@@ -297,8 +342,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
fprintf(outfile, " extern void %s();\n", name); fprintf(outfile, " extern void %s();\n", name);
if (reloc_sh_type == SHT_REL) {
Elf32_Rel *rel;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
@@ -307,17 +350,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
} }
} }
} else {
Elf32_Rela *rel;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (!strstart(sym_name, "__op_param", &p)) {
fprintf(outfile, "extern char %s;\n", sym_name);
}
}
}
}
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
for(i = 0; i < nb_args; i++) { for(i = 0; i < nb_args; i++) {
@@ -325,13 +357,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
/* patch relocations */ /* patch relocations */
switch(e_machine) { #if defined(HOST_I386)
case EM_386:
{ {
Elf32_Rel *rel;
char name[256]; char name[256];
int type; int type;
long addend; int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
@@ -344,11 +374,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
addend = get32((uint32_t *)(text + rel->r_offset)); addend = get32((uint32_t *)(text + rel->r_offset));
switch(type) { switch(type) {
case R_386_32: case R_386_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend); rel->r_offset - offset, name, addend);
break; break;
case R_386_PC32: case R_386_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n", fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
rel->r_offset - offset, name, rel->r_offset - offset, addend); rel->r_offset - offset, name, rel->r_offset - offset, addend);
break; break;
default: default:
@@ -357,13 +387,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
} }
} }
break; #elif defined(HOST_PPC)
case EM_PPC:
{ {
Elf32_Rela *rel;
char name[256]; char name[256];
int type; int type;
long addend; int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
@@ -376,24 +404,24 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
addend = rel->r_addend; addend = rel->r_addend;
switch(type) { switch(type) {
case R_PPC_ADDR32: case R_PPC_ADDR32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend); rel->r_offset - offset, name, addend);
break; break;
case R_PPC_ADDR16_LO: case R_PPC_ADDR16_LO:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n", fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
rel->r_offset - offset, name, addend); rel->r_offset - offset, name, addend);
break; break;
case R_PPC_ADDR16_HI: case R_PPC_ADDR16_HI:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n", fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
rel->r_offset - offset, name, addend); rel->r_offset - offset, name, addend);
break; break;
case R_PPC_ADDR16_HA: case R_PPC_ADDR16_HA:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n", fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
rel->r_offset - offset, name, addend); rel->r_offset - offset, name, addend);
break; break;
case R_PPC_REL24: case R_PPC_REL24:
/* warning: must be at 32 MB distancy */ /* warning: must be at 32 MB distancy */
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n", fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend); rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
break; break;
default: default:
@@ -402,10 +430,43 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
} }
} }
} }
#elif defined(HOST_S390)
{
char name[256];
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_390_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
break;
case R_390_16:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
break;
case R_390_8:
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
break; break;
default: default:
error("unsupported CPU for relocations (%d)", e_machine); error("unsupported s390 relocation (%d)", type);
} }
}
}
}
#else
#error unsupported CPU
#endif
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size); fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
fprintf(outfile, "}\n"); fprintf(outfile, "}\n");
fprintf(outfile, "break;\n\n"); fprintf(outfile, "break;\n\n");
@@ -434,11 +495,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
int load_elf(const char *filename, FILE *outfile, int do_print_enum) int load_elf(const char *filename, FILE *outfile, int do_print_enum)
{ {
int fd; int fd;
Elf32_Ehdr ehdr; struct elfhdr ehdr;
Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
int i, j, nb_syms; int i, j, nb_syms;
Elf32_Sym *symtab, *sym; ElfW(Sym) *symtab, *sym;
const char *cpu_name;
char *shstr, *strtab; char *shstr, *strtab;
uint8_t *text; uint8_t *text;
void *relocs; void *relocs;
@@ -457,7 +517,6 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|| ehdr.e_ident[EI_MAG1] != ELFMAG1 || ehdr.e_ident[EI_MAG1] != ELFMAG1
|| ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG2] != ELFMAG2
|| ehdr.e_ident[EI_MAG3] != ELFMAG3 || ehdr.e_ident[EI_MAG3] != ELFMAG3
|| ehdr.e_ident[EI_CLASS] != ELFCLASS32
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT) { || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
error("bad ELF header"); error("bad ELF header");
} }
@@ -465,14 +524,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
do_swap = elf_must_swap(&ehdr); do_swap = elf_must_swap(&ehdr);
if (do_swap) if (do_swap)
elf_swap_ehdr(&ehdr); elf_swap_ehdr(&ehdr);
if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
error("Unsupported ELF class");
if (ehdr.e_type != ET_REL) if (ehdr.e_type != ET_REL)
error("ELF object file expected"); error("ELF object file expected");
if (ehdr.e_version != EV_CURRENT) if (ehdr.e_version != EV_CURRENT)
error("Invalid ELF version"); error("Invalid ELF version");
e_machine = ehdr.e_machine; if (!elf_check_arch(ehdr.e_machine))
error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
/* read section headers */ /* read section headers */
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr)); shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
if (do_swap) { if (do_swap) {
for(i = 0; i < ehdr.e_shnum; i++) { for(i = 0; i < ehdr.e_shnum; i++) {
elf_swap_shdr(&shdr[i]); elf_swap_shdr(&shdr[i]);
@@ -532,39 +594,20 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
if (do_swap) { if (do_swap) {
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
swab32s(&sym->st_name); swab32s(&sym->st_name);
swab32s(&sym->st_value); swabls(&sym->st_value);
swab32s(&sym->st_size); swabls(&sym->st_size);
swab16s(&sym->st_shndx); swab16s(&sym->st_shndx);
} }
} }
switch(e_machine) {
case EM_386:
cpu_name = "i386";
break;
case EM_PPC:
cpu_name = "ppc";
break;
case EM_MIPS:
cpu_name = "mips";
break;
case EM_ARM:
cpu_name = "arm";
break;
case EM_SPARC:
cpu_name = "sparc";
break;
default:
error("unsupported CPU (e_machine=%d)", e_machine);
}
if (do_print_enum) { if (do_print_enum) {
fprintf(outfile, "DEF(end)\n"); fprintf(outfile, "DEF(end, 0)\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name, *p; const char *name, *p;
name = strtab + sym->st_name; name = strtab + sym->st_name;
if (strstart(name, OP_PREFIX, &p)) { if (strstart(name, OP_PREFIX, &p)) {
fprintf(outfile, "DEF(%s)\n", p); gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2);
} }
} }
} else { } else {
@@ -607,15 +650,16 @@ fprintf(outfile,
); );
/* generate a return */ /* generate a return */
switch(e_machine) { switch(ELF_ARCH) {
case EM_386: case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
break; break;
case EM_PPC: case EM_PPC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n"); fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
break; break;
default: case EM_S390:
error("no return generation for cpu '%s'", cpu_name); fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
break;
} }
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n"); fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");

803
elf.h
View File

@@ -1,47 +1,25 @@
/* #ifndef _ELF_H
* ELF register definitions.. #define _ELF_H
*/
#include <inttypes.h> #include <inttypes.h>
typedef uint32_t elf_greg_t; /* 32-bit ELF base types. */
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB;
#define ELF_ARCH EM_386
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
starts %edx contains a pointer to a function which might be
registered using `atexit'. This provides a mean for the
dynamic linker to call DT_FINI functions for shared libraries
that have been loaded before the code runs.
A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half; typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword; typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
/* These constants are for the segment types stored in the image headers */ /* These constants are for the segment types stored in the image headers */
#define PT_NULL 0 #define PT_NULL 0
#define PT_LOAD 1 #define PT_LOAD 1
@@ -52,6 +30,13 @@ typedef uint32_t Elf32_Word;
#define PT_PHDR 6 #define PT_PHDR 6
#define PT_LOPROC 0x70000000 #define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff #define PT_HIPROC 0x7fffffff
#define PT_MIPS_REGINFO 0x70000000
/* Flags in the e_flags field of the header */
#define EF_MIPS_NOREORDER 0x00000001
#define EF_MIPS_PIC 0x00000002
#define EF_MIPS_CPIC 0x00000004
#define EF_MIPS_ARCH 0xf0000000
/* These constants define the different elf file types */ /* These constants define the different elf file types */
#define ET_NONE 0 #define ET_NONE 0
@@ -59,8 +44,8 @@ typedef uint32_t Elf32_Word;
#define ET_EXEC 2 #define ET_EXEC 2
#define ET_DYN 3 #define ET_DYN 3
#define ET_CORE 4 #define ET_CORE 4
#define ET_LOPROC 5 #define ET_LOPROC 0xff00
#define ET_HIPROC 6 #define ET_HIPROC 0xffff
/* These constants define the various ELF target machines */ /* These constants define the various ELF target machines */
#define EM_NONE 0 #define EM_NONE 0
@@ -76,13 +61,31 @@ typedef uint32_t Elf32_Word;
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */
#define EM_PARISC 15 /* HPPA */ #define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_PPC 20 /* PowerPC */ #define EM_PPC 20 /* PowerPC */
#define EM_PPC64 21 /* PowerPC64 */
#define EM_ARM 40 /* ARM */
#define EM_SH 42 /* SuperH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_IA_64 50 /* HP/Intel IA-64 */
#define EM_X86_64 62 /* AMD x86-64 */
#define EM_S390 22 /* IBM S/390 */
#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
#define EM_V850 87 /* NEC v850 */
#define EM_H8_300H 47 /* Hitachi H8/300H */
#define EM_H8S 48 /* Hitachi H8S */
/* /*
* This is an interim value that we will use until the committee comes * This is an interim value that we will use until the committee comes
@@ -90,6 +93,13 @@ typedef uint32_t Elf32_Word;
*/ */
#define EM_ALPHA 0x9026 #define EM_ALPHA 0x9026
/* Bogus old v850 magic number, used by old tools. */
#define EM_CYGNUS_V850 0x9080
/*
* This is the old interim value for S/390 architecture
*/
#define EM_S390_OLD 0xA390
/* This is the info that is needed to parse the dynamic section of the file */ /* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0 #define DT_NULL 0
@@ -118,6 +128,25 @@ typedef uint32_t Elf32_Word;
#define DT_JMPREL 23 #define DT_JMPREL 23
#define DT_LOPROC 0x70000000 #define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff #define DT_HIPROC 0x7fffffff
#define DT_MIPS_RLD_VERSION 0x70000001
#define DT_MIPS_TIME_STAMP 0x70000002
#define DT_MIPS_ICHECKSUM 0x70000003
#define DT_MIPS_IVERSION 0x70000004
#define DT_MIPS_FLAGS 0x70000005
#define RHF_NONE 0
#define RHF_HARDWAY 1
#define RHF_NOTPOT 2
#define DT_MIPS_BASE_ADDRESS 0x70000006
#define DT_MIPS_CONFLICT 0x70000008
#define DT_MIPS_LIBLIST 0x70000009
#define DT_MIPS_LOCAL_GOTNO 0x7000000a
#define DT_MIPS_CONFLICTNO 0x7000000b
#define DT_MIPS_LIBLISTNO 0x70000010
#define DT_MIPS_SYMTABNO 0x70000011
#define DT_MIPS_UNREFEXTNO 0x70000012
#define DT_MIPS_GOTSYM 0x70000013
#define DT_MIPS_HIPAGENO 0x70000014
#define DT_MIPS_RLD_MAP 0x70000016
/* This info is needed when parsing the symbol table */ /* This info is needed when parsing the symbol table */
#define STB_LOCAL 0 #define STB_LOCAL 0
@@ -130,8 +159,12 @@ typedef uint32_t Elf32_Word;
#define STT_SECTION 3 #define STT_SECTION 3
#define STT_FILE 4 #define STT_FILE 4
#define ELF32_ST_BIND(x) ((x) >> 4) #define ELF_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
/* Symbolic values for the entries in the auxiliary table /* Symbolic values for the entries in the auxiliary table
put on the initial stack */ put on the initial stack */
@@ -150,7 +183,9 @@ typedef uint32_t Elf32_Word;
#define AT_EUID 12 /* effective uid */ #define AT_EUID 12 /* effective uid */
#define AT_GID 13 /* real gid */ #define AT_GID 13 /* real gid */
#define AT_EGID 14 /* effective gid */ #define AT_EGID 14 /* effective gid */
#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17 /* frequency at which times() increments */
typedef struct dynamic{ typedef struct dynamic{
Elf32_Sword d_tag; Elf32_Sword d_tag;
@@ -161,10 +196,10 @@ typedef struct dynamic{
} Elf32_Dyn; } Elf32_Dyn;
typedef struct { typedef struct {
unsigned long long d_tag; /* entry tag value */ Elf64_Sxword d_tag; /* entry tag value */
union { union {
unsigned long long d_val; Elf64_Xword d_val;
unsigned long long d_ptr; Elf64_Addr d_ptr;
} d_un; } d_un;
} Elf64_Dyn; } Elf64_Dyn;
@@ -172,6 +207,9 @@ typedef struct {
#define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff) #define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define R_386_NONE 0 #define R_386_NONE 0
#define R_386_32 1 #define R_386_32 1
#define R_386_PC32 2 #define R_386_PC32 2
@@ -185,14 +223,559 @@ typedef struct {
#define R_386_GOTPC 10 #define R_386_GOTPC 10
#define R_386_NUM 11 #define R_386_NUM 11
#define R_MIPS_NONE 0
#define R_MIPS_16 1
#define R_MIPS_32 2
#define R_MIPS_REL32 3
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6
#define R_MIPS_GPREL16 7
#define R_MIPS_LITERAL 8
#define R_MIPS_GOT16 9
#define R_MIPS_PC16 10
#define R_MIPS_CALL16 11
#define R_MIPS_GPREL32 12
/* The remaining relocs are defined on Irix, although they are not
in the MIPS ELF ABI. */
#define R_MIPS_UNUSED1 13
#define R_MIPS_UNUSED2 14
#define R_MIPS_UNUSED3 15
#define R_MIPS_SHIFT5 16
#define R_MIPS_SHIFT6 17
#define R_MIPS_64 18
#define R_MIPS_GOT_DISP 19
#define R_MIPS_GOT_PAGE 20
#define R_MIPS_GOT_OFST 21
/*
* The following two relocation types are specified in the MIPS ABI
* conformance guide version 1.2 but not yet in the psABI.
*/
#define R_MIPS_GOTHI16 22
#define R_MIPS_GOTLO16 23
#define R_MIPS_SUB 24
#define R_MIPS_INSERT_A 25
#define R_MIPS_INSERT_B 26
#define R_MIPS_DELETE 27
#define R_MIPS_HIGHER 28
#define R_MIPS_HIGHEST 29
/*
* The following two relocation types are specified in the MIPS ABI
* conformance guide version 1.2 but not yet in the psABI.
*/
#define R_MIPS_CALLHI16 30
#define R_MIPS_CALLLO16 31
/*
* This range is reserved for vendor specific relocations.
*/
#define R_MIPS_LOVENDOR 100
#define R_MIPS_HIVENDOR 127
/*
* Sparc ELF relocation types
*/
#define R_SPARC_NONE 0
#define R_SPARC_8 1
#define R_SPARC_16 2
#define R_SPARC_32 3
#define R_SPARC_DISP8 4
#define R_SPARC_DISP16 5
#define R_SPARC_DISP32 6
#define R_SPARC_WDISP30 7
#define R_SPARC_WDISP22 8
#define R_SPARC_HI22 9
#define R_SPARC_22 10
#define R_SPARC_13 11
#define R_SPARC_LO10 12
#define R_SPARC_GOT10 13
#define R_SPARC_GOT13 14
#define R_SPARC_GOT22 15
#define R_SPARC_PC10 16
#define R_SPARC_PC22 17
#define R_SPARC_WPLT30 18
#define R_SPARC_COPY 19
#define R_SPARC_GLOB_DAT 20
#define R_SPARC_JMP_SLOT 21
#define R_SPARC_RELATIVE 22
#define R_SPARC_UA32 23
#define R_SPARC_PLT32 24
#define R_SPARC_HIPLT22 25
#define R_SPARC_LOPLT10 26
#define R_SPARC_PCPLT32 27
#define R_SPARC_PCPLT22 28
#define R_SPARC_PCPLT10 29
#define R_SPARC_10 30
#define R_SPARC_11 31
#define R_SPARC_64 32
#define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41
#define R_SPARC_7 43
#define R_SPARC_5 44
#define R_SPARC_6 45
/* Bits present in AT_HWCAP, primarily for Sparc32. */
#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
#define HWCAP_SPARC_STBAR 2
#define HWCAP_SPARC_SWAP 4
#define HWCAP_SPARC_MULDIV 8
#define HWCAP_SPARC_V9 16
#define HWCAP_SPARC_ULTRA3 32
/*
* 68k ELF relocation types
*/
#define R_68K_NONE 0
#define R_68K_32 1
#define R_68K_16 2
#define R_68K_8 3
#define R_68K_PC32 4
#define R_68K_PC16 5
#define R_68K_PC8 6
#define R_68K_GOT32 7
#define R_68K_GOT16 8
#define R_68K_GOT8 9
#define R_68K_GOT32O 10
#define R_68K_GOT16O 11
#define R_68K_GOT8O 12
#define R_68K_PLT32 13
#define R_68K_PLT16 14
#define R_68K_PLT8 15
#define R_68K_PLT32O 16
#define R_68K_PLT16O 17
#define R_68K_PLT8O 18
#define R_68K_COPY 19
#define R_68K_GLOB_DAT 20
#define R_68K_JMP_SLOT 21
#define R_68K_RELATIVE 22
/*
* Alpha ELF relocation types
*/
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
#define R_ALPHA_BRSGP 28
#define R_ALPHA_TLSGD 29
#define R_ALPHA_TLS_LDM 30
#define R_ALPHA_DTPMOD64 31
#define R_ALPHA_GOTDTPREL 32
#define R_ALPHA_DTPREL64 33
#define R_ALPHA_DTPRELHI 34
#define R_ALPHA_DTPRELLO 35
#define R_ALPHA_DTPREL16 36
#define R_ALPHA_GOTTPREL 37
#define R_ALPHA_TPREL64 38
#define R_ALPHA_TPRELHI 39
#define R_ALPHA_TPRELLO 40
#define R_ALPHA_TPREL16 41
#define SHF_ALPHA_GPREL 0x10000000
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1 /* 32bit absolute address */
#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
#define R_PPC_ADDR16 3 /* 16bit absolute address */
#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
#define R_PPC_ADDR14_BRTAKEN 8
#define R_PPC_ADDR14_BRNTAKEN 9
#define R_PPC_REL24 10 /* PC relative 26 bit */
#define R_PPC_REL14 11 /* PC relative 16 bit */
#define R_PPC_REL14_BRTAKEN 12
#define R_PPC_REL14_BRNTAKEN 13
#define R_PPC_GOT16 14
#define R_PPC_GOT16_LO 15
#define R_PPC_GOT16_HI 16
#define R_PPC_GOT16_HA 17
#define R_PPC_PLTREL24 18
#define R_PPC_COPY 19
#define R_PPC_GLOB_DAT 20
#define R_PPC_JMP_SLOT 21
#define R_PPC_RELATIVE 22
#define R_PPC_LOCAL24PC 23
#define R_PPC_UADDR32 24
#define R_PPC_UADDR16 25
#define R_PPC_REL32 26
#define R_PPC_PLT32 27
#define R_PPC_PLTREL32 28
#define R_PPC_PLT16_LO 29
#define R_PPC_PLT16_HI 30
#define R_PPC_PLT16_HA 31
#define R_PPC_SDAREL16 32
#define R_PPC_SECTOFF 33
#define R_PPC_SECTOFF_LO 34
#define R_PPC_SECTOFF_HI 35
#define R_PPC_SECTOFF_HA 36
/* Keep this the last entry. */
#define R_PPC_NUM 37
/* ARM specific declarations */
/* Processor specific flags for the ELF header e_flags field. */
#define EF_ARM_RELEXEC 0x01
#define EF_ARM_HASENTRY 0x02
#define EF_ARM_INTERWORK 0x04
#define EF_ARM_APCS_26 0x08
#define EF_ARM_APCS_FLOAT 0x10
#define EF_ARM_PIC 0x20
#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */
#define EF_NEW_ABI 0x80
#define EF_OLD_ABI 0x100
/* Additional symbol types for Thumb */
#define STT_ARM_TFUNC 0xd
/* ARM-specific values for sh_flags */
#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
in the input to a link step */
/* ARM-specific program header flags */
#define PF_ARM_SB 0x10000000 /* Segment contains the location
addressed by the static base */
/* ARM relocs. */
#define R_ARM_NONE 0 /* No reloc */
#define R_ARM_PC24 1 /* PC relative 26 bit branch */
#define R_ARM_ABS32 2 /* Direct 32 bit */
#define R_ARM_REL32 3 /* PC relative 32 bit */
#define R_ARM_PC13 4
#define R_ARM_ABS16 5 /* Direct 16 bit */
#define R_ARM_ABS12 6 /* Direct 12 bit */
#define R_ARM_THM_ABS5 7
#define R_ARM_ABS8 8 /* Direct 8 bit */
#define R_ARM_SBREL32 9
#define R_ARM_THM_PC22 10
#define R_ARM_THM_PC8 11
#define R_ARM_AMP_VCALL9 12
#define R_ARM_SWI24 13
#define R_ARM_THM_SWI8 14
#define R_ARM_XPC25 15
#define R_ARM_THM_XPC22 16
#define R_ARM_COPY 20 /* Copy symbol at runtime */
#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
#define R_ARM_RELATIVE 23 /* Adjust by program base */
#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
#define R_ARM_GOT32 26 /* 32 bit GOT entry */
#define R_ARM_PLT32 27 /* 32 bit PLT address */
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
#define R_ARM_THM_PC9 103 /* thumb conditional branch */
#define R_ARM_RXPC25 249
#define R_ARM_RSBREL32 250
#define R_ARM_THM_RPC22 251
#define R_ARM_RREL32 252
#define R_ARM_RABS22 253
#define R_ARM_RPC24 254
#define R_ARM_RBASE 255
/* Keep this the last entry. */
#define R_ARM_NUM 256
/* s390 relocations defined by the ABIs */
#define R_390_NONE 0 /* No reloc. */
#define R_390_8 1 /* Direct 8 bit. */
#define R_390_12 2 /* Direct 12 bit. */
#define R_390_16 3 /* Direct 16 bit. */
#define R_390_32 4 /* Direct 32 bit. */
#define R_390_PC32 5 /* PC relative 32 bit. */
#define R_390_GOT12 6 /* 12 bit GOT offset. */
#define R_390_GOT32 7 /* 32 bit GOT offset. */
#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
#define R_390_COPY 9 /* Copy symbol at runtime. */
#define R_390_GLOB_DAT 10 /* Create GOT entry. */
#define R_390_JMP_SLOT 11 /* Create PLT entry. */
#define R_390_RELATIVE 12 /* Adjust by program base. */
#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */
#define R_390_GOT16 15 /* 16 bit GOT offset. */
#define R_390_PC16 16 /* PC relative 16 bit. */
#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
#define R_390_64 22 /* Direct 64 bit. */
#define R_390_PC64 23 /* PC relative 64 bit. */
#define R_390_GOT64 24 /* 64 bit GOT offset. */
#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
#define R_390_TLS_GDCALL 38 /* Tag for function call in general
dynamic TLS code. */
#define R_390_TLS_LDCALL 39 /* Tag for function call in local
dynamic TLS code. */
#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
thread local data. */
#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
thread local data. */
#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
negated static TLS block offset. */
#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
block. */
#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
block. */
#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS
block. */
/* Keep this the last entry. */
#define R_390_NUM 57
/* x86-64 relocation types */
#define R_X86_64_NONE 0 /* No reloc */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative
offset to GOT */
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
#define R_X86_64_16 12 /* Direct 16 bit zero extended */
#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
#define R_X86_64_8 14 /* Direct 8 bit sign extended */
#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
#define R_X86_64_NUM 16
/* Legal values for e_flags field of Elf64_Ehdr. */
#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
/* HPPA specific definitions. */
/* Legal values for e_flags field of Elf32_Ehdr. */
#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
prediction. */
#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
/* Additional section indeces. */
#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
symbols in ANSI C. */
#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
/* Legal values for sh_type field of Elf32_Shdr. */
#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
/* Legal values for sh_flags field of Elf32_Shdr. */
#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
#define STT_HP_OPAQUE (STT_LOOS + 0x1)
#define STT_HP_STUB (STT_LOOS + 0x2)
/* HPPA relocs. */
#define R_PARISC_NONE 0 /* No reloc. */
#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
#define R_PARISC_FPTR64 64 /* 64 bits function address. */
#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
#define R_PARISC_LORESERVE 128
#define R_PARISC_COPY 128 /* Copy relocation. */
#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
#define R_PARISC_HIRESERVE 255
/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
#define PT_HP_TLS (PT_LOOS + 0x0)
#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
#define PT_HP_PARALLEL (PT_LOOS + 0x10)
#define PT_HP_FASTBIND (PT_LOOS + 0x11)
#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
#define PT_HP_STACK (PT_LOOS + 0x14)
#define PT_PARISC_ARCHEXT 0x70000000
#define PT_PARISC_UNWIND 0x70000001
/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
#define PF_PARISC_SBP 0x08000000
#define PF_HP_PAGE_SIZE 0x00100000
#define PF_HP_FAR_SHARED 0x00200000
#define PF_HP_NEAR_SHARED 0x00400000
#define PF_HP_CODE 0x01000000
#define PF_HP_MODIFY 0x02000000
#define PF_HP_LAZYSWAP 0x04000000
#define PF_HP_SBP 0x08000000
typedef struct elf32_rel { typedef struct elf32_rel {
Elf32_Addr r_offset; Elf32_Addr r_offset;
Elf32_Word r_info; Elf32_Word r_info;
} Elf32_Rel; } Elf32_Rel;
typedef struct elf64_rel { typedef struct elf64_rel {
unsigned long long r_offset; /* Location at which to apply the action */ Elf64_Addr r_offset; /* Location at which to apply the action */
unsigned long long r_info; /* index and type of relocation */ Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel; } Elf64_Rel;
typedef struct elf32_rela{ typedef struct elf32_rela{
@@ -202,9 +785,9 @@ typedef struct elf32_rela{
} Elf32_Rela; } Elf32_Rela;
typedef struct elf64_rela { typedef struct elf64_rela {
unsigned long long r_offset; /* Location at which to apply the action */ Elf64_Addr r_offset; /* Location at which to apply the action */
unsigned long long r_info; /* index and type of relocation */ Elf64_Xword r_info; /* index and type of relocation */
unsigned long long r_addend; /* Constant addend used to compute value */ Elf64_Sxword r_addend; /* Constant addend used to compute value */
} Elf64_Rela; } Elf64_Rela;
typedef struct elf32_sym{ typedef struct elf32_sym{
@@ -217,12 +800,12 @@ typedef struct elf32_sym{
} Elf32_Sym; } Elf32_Sym;
typedef struct elf64_sym { typedef struct elf64_sym {
unsigned int st_name; /* Symbol name, index in string tbl */ Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */ unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */ unsigned char st_other; /* No defined meaning, 0 */
unsigned short st_shndx; /* Associated section index */ Elf64_Half st_shndx; /* Associated section index */
unsigned long long st_value; /* Value of the symbol */ Elf64_Addr st_value; /* Value of the symbol */
unsigned long long st_size; /* Associated symbol size */ Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym; } Elf64_Sym;
@@ -247,19 +830,19 @@ typedef struct elf32_hdr{
typedef struct elf64_hdr { typedef struct elf64_hdr {
unsigned char e_ident[16]; /* ELF "magic number" */ unsigned char e_ident[16]; /* ELF "magic number" */
short int e_type; Elf64_Half e_type;
short unsigned int e_machine; Elf64_Half e_machine;
int e_version; Elf64_Word e_version;
unsigned long long e_entry; /* Entry point virtual address */ Elf64_Addr e_entry; /* Entry point virtual address */
unsigned long long e_phoff; /* Program header table file offset */ Elf64_Off e_phoff; /* Program header table file offset */
unsigned long long e_shoff; /* Section header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */
int e_flags; Elf64_Word e_flags;
short int e_ehsize; Elf64_Half e_ehsize;
short int e_phentsize; Elf64_Half e_phentsize;
short int e_phnum; Elf64_Half e_phnum;
short int e_shentsize; Elf64_Half e_shentsize;
short int e_shnum; Elf64_Half e_shnum;
short int e_shstrndx; Elf64_Half e_shstrndx;
} Elf64_Ehdr; } Elf64_Ehdr;
/* These constants define the permissions on sections in the program /* These constants define the permissions on sections in the program
@@ -280,14 +863,14 @@ typedef struct elf32_phdr{
} Elf32_Phdr; } Elf32_Phdr;
typedef struct elf64_phdr { typedef struct elf64_phdr {
int p_type; Elf64_Word p_type;
int p_flags; Elf64_Word p_flags;
unsigned long long p_offset; /* Segment file offset */ Elf64_Off p_offset; /* Segment file offset */
unsigned long long p_vaddr; /* Segment virtual address */ Elf64_Addr p_vaddr; /* Segment virtual address */
unsigned long long p_paddr; /* Segment physical address */ Elf64_Addr p_paddr; /* Segment physical address */
unsigned long long p_filesz; /* Segment size in file */ Elf64_Xword p_filesz; /* Segment size in file */
unsigned long long p_memsz; /* Segment size in memory */ Elf64_Xword p_memsz; /* Segment size in memory */
unsigned long long p_align; /* Segment alignment, file & memory */ Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr; } Elf64_Phdr;
/* sh_type */ /* sh_type */
@@ -308,12 +891,17 @@ typedef struct elf64_phdr {
#define SHT_HIPROC 0x7fffffff #define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000 #define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff #define SHT_HIUSER 0xffffffff
#define SHT_MIPS_LIST 0x70000000
#define SHT_MIPS_CONFLICT 0x70000002
#define SHT_MIPS_GPTAB 0x70000003
#define SHT_MIPS_UCODE 0x70000004
/* sh_flags */ /* sh_flags */
#define SHF_WRITE 0x1 #define SHF_WRITE 0x1
#define SHF_ALLOC 0x2 #define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4 #define SHF_EXECINSTR 0x4
#define SHF_MASKPROC 0xf0000000 #define SHF_MASKPROC 0xf0000000
#define SHF_MIPS_GPREL 0x10000000
/* special section indexes */ /* special section indexes */
#define SHN_UNDEF 0 #define SHN_UNDEF 0
@@ -323,8 +911,9 @@ typedef struct elf64_phdr {
#define SHN_ABS 0xfff1 #define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2 #define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff #define SHN_HIRESERVE 0xffff
#define SHN_MIPS_ACCOMON 0xff00
typedef struct { typedef struct elf32_shdr {
Elf32_Word sh_name; Elf32_Word sh_name;
Elf32_Word sh_type; Elf32_Word sh_type;
Elf32_Word sh_flags; Elf32_Word sh_flags;
@@ -338,16 +927,16 @@ typedef struct {
} Elf32_Shdr; } Elf32_Shdr;
typedef struct elf64_shdr { typedef struct elf64_shdr {
unsigned int sh_name; /* Section name, index in string tbl */ Elf64_Word sh_name; /* Section name, index in string tbl */
unsigned int sh_type; /* Type of section */ Elf64_Word sh_type; /* Type of section */
unsigned long long sh_flags; /* Miscellaneous section attributes */ Elf64_Xword sh_flags; /* Miscellaneous section attributes */
unsigned long long sh_addr; /* Section virtual addr at execution */ Elf64_Addr sh_addr; /* Section virtual addr at execution */
unsigned long long sh_offset; /* Section file offset */ Elf64_Off sh_offset; /* Section file offset */
unsigned long long sh_size; /* Size of section in bytes */ Elf64_Xword sh_size; /* Size of section in bytes */
unsigned int sh_link; /* Index of another section */ Elf64_Word sh_link; /* Index of another section */
unsigned int sh_info; /* Additional section information */ Elf64_Word sh_info; /* Additional section information */
unsigned long long sh_addralign; /* Section alignment */ Elf64_Xword sh_addralign; /* Section alignment */
unsigned long long sh_entsize; /* Entry size if section holds table */ Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr; } Elf64_Shdr;
#define EI_MAG0 0 /* e_ident[] indexes */ #define EI_MAG0 0 /* e_ident[] indexes */
@@ -384,6 +973,8 @@ typedef struct elf64_shdr {
#define NT_PRFPREG 2 #define NT_PRFPREG 2
#define NT_PRPSINFO 3 #define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4 #define NT_TASKSTRUCT 4
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
/* Note header in a PT_NOTE section */ /* Note header in a PT_NOTE section */
typedef struct elf32_note { typedef struct elf32_note {
@@ -393,33 +984,49 @@ typedef struct elf32_note {
} Elf32_Nhdr; } Elf32_Nhdr;
/* Note header in a PT_NOTE section */ /* Note header in a PT_NOTE section */
/*
* For now we use the 32 bit version of the structure until we figure
* out whether we need anything better. Note - on the Alpha, "unsigned int"
* is only 32 bits.
*/
typedef struct elf64_note { typedef struct elf64_note {
unsigned int n_namesz; /* Name size */ Elf64_Word n_namesz; /* Name size */
unsigned int n_descsz; /* Content size */ Elf64_Word n_descsz; /* Content size */
unsigned int n_type; /* Content type */ Elf64_Word n_type; /* Content type */
} Elf64_Nhdr; } Elf64_Nhdr;
#define ELF_START_MMAP 0x80000000
#if ELF_CLASS == ELFCLASS32 #if ELF_CLASS == ELFCLASS32
extern Elf32_Dyn _DYNAMIC [];
#define elfhdr elf32_hdr #define elfhdr elf32_hdr
#define elf_phdr elf32_phdr #define elf_phdr elf32_phdr
#define elf_note elf32_note #define elf_note elf32_note
#define elf_shdr elf32_shdr
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf32_Rela
#else
# define ELF_RELOC Elf32_Rel
#endif
#else #else
extern Elf64_Dyn _DYNAMIC [];
#define elfhdr elf64_hdr #define elfhdr elf64_hdr
#define elf_phdr elf64_phdr #define elf_phdr elf64_phdr
#define elf_note elf64_note #define elf_note elf64_note
#define elf_shdr elf64_shdr
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf64_Rela
#else
# define ELF_RELOC Elf64_Rel
#endif
#endif /* ELF_CLASS */
#ifndef ElfW
# if ELF_CLASS == ELFCLASS32
# define ElfW(x) Elf32_ ## x
# define ELFW(x) ELF32_ ## x
# else
# define ElfW(x) Elf64_ ## x
# define ELFW(x) ELF64_ ## x
# endif
#endif #endif
#endif /* _ELF_H */

View File

@@ -87,6 +87,20 @@ static inline int testandset (int *p)
} }
#endif #endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
int global_cpu_lock = 0; int global_cpu_lock = 0;
void cpu_lock(void) void cpu_lock(void)
@@ -330,9 +344,10 @@ int cpu_x86_exec(CPUX86State *env1)
#endif #endif
/* put eflags in CPU temporary format */ /* put eflags in CPU temporary format */
T0 = env->eflags; CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
op_movl_eflags_T0(); DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS; CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
env->interrupt_request = 0; env->interrupt_request = 0;
/* prepare setjmp context for exception handling */ /* prepare setjmp context for exception handling */
@@ -354,6 +369,7 @@ int cpu_x86_exec(CPUX86State *env1)
(unsigned long)env->seg_cache[R_ES].base | (unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) << (unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT; GEN_FLAG_ADDSEG_SHIFT;
flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
cs_base = env->seg_cache[R_CS].base; cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip; pc = cs_base + env->eip;
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
@@ -390,8 +406,7 @@ int cpu_x86_exec(CPUX86State *env1)
ret = env->exception_index; ret = env->exception_index;
/* restore flags in standard format */ /* restore flags in standard format */
op_movl_T0_eflags(); env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
env->eflags = T0;
/* restore global registers */ /* restore global registers */
#ifdef reg_EAX #ifdef reg_EAX
@@ -485,7 +500,11 @@ 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;
pc = uc->uc_mcontext.gregs[EIP]; #ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#endif
pc = uc->uc_mcontext.gregs[REG_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);
#else #else

View File

@@ -66,6 +66,7 @@ register unsigned int T1 asm("r25");
register unsigned int A0 asm("r26"); register unsigned int A0 asm("r26");
register struct CPUX86State *env asm("r27"); register struct CPUX86State *env asm("r27");
#define USE_INT_TO_FLOAT_HELPERS #define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#define reg_EAX #define reg_EAX
#define reg_ECX #define reg_ECX
#define reg_EDX #define reg_EDX
@@ -93,6 +94,18 @@ register unsigned int T1 asm("l1");
register unsigned int A0 asm("l2"); register unsigned int A0 asm("l2");
register struct CPUX86State *env asm("l3"); register struct CPUX86State *env asm("l3");
#endif #endif
#ifdef __s390__
register unsigned int T0 asm("r7");
register unsigned int T1 asm("r8");
register unsigned int A0 asm("r9");
register struct CPUX86State *env asm("r10");
#endif
#ifdef __alpha__
register unsigned int T0 asm("$9");
register unsigned int T1 asm("$10");
register unsigned int A0 asm("$11");
register struct CPUX86State *env asm("$12");
#endif
/* force GCC to generate only one epilog at the end of the function */ /* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile (""); #define FORCE_RET() asm volatile ("");

View File

@@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
* the Intel manual for details. * the Intel manual for details.
*/ */
#include <stdlib.h>
#include <setjmp.h>
#include "dis-asm.h" #include "dis-asm.h"
#define MAXLEN 20 #define MAXLEN 20
#include <setjmp.h>
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
struct dis_private struct dis_private

View File

@@ -12,9 +12,114 @@
#include "qemu.h" #include "qemu.h"
#include "linux_bin.h" #ifdef TARGET_I386
#define ELF_START_MMAP 0x80000000
typedef uint32_t elf_greg_t;
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
starts %edx contains a pointer to a function which might be
registered using `atexit'. This provides a mean for the
dynamic linker to call DT_FINI functions for shared libraries
that have been loaded before the code runs.
A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#include "elf.h" #include "elf.h"
#include "segment.h"
/*
* MAX_ARG_PAGES defines the number of pages allocated for arguments
* and envelope for the new program. 32 should suffice, this gives
* a maximum env+arg of 128kB w/4KB pages!
*/
#define MAX_ARG_PAGES 32
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
char buf[128];
unsigned long page[MAX_ARG_PAGES];
unsigned long p;
int sh_bang;
int fd;
int e_uid, e_gid;
int argc, envc;
char * filename; /* Name of binary */
unsigned long loader, exec;
int dont_iput; /* binfmt handler has put inode */
};
struct exec
{
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
unsigned int a_text; /* length of text, in bytes */
unsigned int a_data; /* length of data, in bytes */
unsigned int a_bss; /* length of uninitialized data area, in bytes */
unsigned int a_syms; /* length of symbol table data in file, in bytes */
unsigned int a_entry; /* start address */
unsigned int a_trsize; /* length of relocation info for text, in bytes */
unsigned int a_drsize; /* length of relocation info for data, in bytes */
};
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
#define OMAGIC 0407
#define NMAGIC 0410
#define ZMAGIC 0413
#define QMAGIC 0314
#define X86_STACK_TOP 0x7d000000
/* max code+data+bss space allocated to elf interpreter */
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
/* 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 */ /* Necessary parameters */
#define ALPHA_PAGE_SIZE 4096 #define ALPHA_PAGE_SIZE 4096
@@ -41,9 +146,18 @@
#define DLINFO_ITEMS 12 #define DLINFO_ITEMS 12
/* Where we find X86 libraries... */ #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
//#define X86_DEFAULT_LIB_DIR "/usr/x86/" #define get_user(ptr) (typeof(*ptr))(*(ptr))
#define X86_DEFAULT_LIB_DIR "/"
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
//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)
@@ -246,42 +360,34 @@ static int prepare_binprm(struct linux_binprm *bprm)
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
struct image_info * info) struct image_info * info)
{ {
unsigned long stack_base; unsigned long stack_base, size, error;
int i; int i;
extern unsigned long stktop;
stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
bprm->loader += stack_base;
}
bprm->exec += stack_base;
/* Create enough stack to hold everything. If we don't use /* Create enough stack to hold everything. If we don't use
* it for args, we'll use it for something else... * it for args, we'll use it for something else...
*/ */
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so size = x86_stack_size;
we allocate a bigger stack. Need a better solution, for example if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
by remapping the process stack directly at the right place */ size = MAX_ARG_PAGES*X86_PAGE_SIZE;
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { error = (unsigned long)mmap4k(NULL,
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (error == -1) {
perror("stk mmap"); perror("stk mmap");
exit(-1); exit(-1);
} }
} /* we reserve one extra page at the top of the stack as guard */
else { mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("stk mmap");
exit(-1);
}
}
stktop = stack_base; stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
bprm->loader += stack_base;
}
bprm->exec += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
if (bprm->page[i]) { if (bprm->page[i]) {
@@ -335,6 +441,7 @@ static void padzero(unsigned long elf_bss)
static unsigned int * create_elf_tables(char *p, int argc, int envc, static unsigned int * create_elf_tables(char *p, int argc, int envc,
struct elfhdr * exec, struct elfhdr * exec,
unsigned long load_addr, unsigned long load_addr,
unsigned long load_bias,
unsigned long interp_load_addr, int ibcs, unsigned long interp_load_addr, int ibcs,
struct image_info *info) struct image_info *info)
{ {
@@ -361,20 +468,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user (tswapl(val), dlinfo++) put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */ if (exec) { /* Put this here for an ELF program interpreter */
struct elf_phdr * eppnt; NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
eppnt = (struct elf_phdr *)((unsigned long)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_PHDR, (unsigned int)(load_addr + exec->e_phoff)); NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
} }
NEW_AUX_ENT (AT_NULL, 0); NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT #undef NEW_AUX_ENT
@@ -403,7 +507,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
{ {
struct elf_phdr *elf_phdata = NULL; struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt; struct elf_phdr *eppnt;
unsigned long load_addr; unsigned long load_addr = 0;
int load_addr_set = 0; int load_addr_set = 0;
int retval; int retval;
unsigned long last_bss, elf_bss; unsigned long last_bss, elf_bss;
@@ -414,11 +518,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
last_bss = 0; last_bss = 0;
error = 0; error = 0;
/* We put this here so that mmap will search for the *first* #ifdef BSWAP_NEEDED
* available memory... bswap_ehdr(interp_elf_ex);
*/ #endif
load_addr = INTERP_LOADADDR;
/* First of all, some simple consistency checks */ /* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC && if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) || interp_elf_ex->e_type != ET_DYN) ||
@@ -426,6 +528,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ~0UL; return ~0UL;
} }
/* Now read in all of the header information */ /* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
@@ -441,8 +544,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
* If the size of this structure has changed, then punt, since * If the size of this structure has changed, then punt, since
* we will be doing the wrong thing. * we will be doing the wrong thing.
*/ */
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
{
free(elf_phdata); free(elf_phdata);
return ~0UL; return ~0UL;
} }
@@ -453,7 +555,6 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
(char *) elf_phdata, (char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
} }
if (retval < 0) { if (retval < 0) {
perror("load_elf_interp"); perror("load_elf_interp");
exit(-1); exit(-1);
@@ -466,6 +567,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
bswap_phdr(eppnt); bswap_phdr(eppnt);
} }
#endif #endif
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid harcoding the interpreter load
address in qemu, we allocate a big enough memory zone */
error = (unsigned long)mmap4k(NULL, 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; eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if (eppnt->p_type == PT_LOAD) { if (eppnt->p_type == PT_LOAD) {
@@ -549,7 +665,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
struct elfhdr interp_elf_ex; struct elfhdr interp_elf_ex;
struct exec interp_ex; struct exec interp_ex;
int interpreter_fd = -1; /* avoid warning */ int interpreter_fd = -1; /* avoid warning */
unsigned long load_addr; unsigned long load_addr, load_bias;
int load_addr_set = 0; int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE; unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter; unsigned char ibcs2_interpreter;
@@ -569,6 +685,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
ibcs2_interpreter = 0; ibcs2_interpreter = 0;
status = 0; status = 0;
load_addr = 0; load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
#ifdef BSWAP_NEEDED #ifdef BSWAP_NEEDED
bswap_ehdr(&elf_ex); bswap_ehdr(&elf_ex);
@@ -638,7 +755,7 @@ 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);
if (elf_interpreter == NULL) { if (elf_interpreter == NULL) {
free (elf_phdata); free (elf_phdata);
@@ -646,12 +763,9 @@ 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);
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, elf_ppnt->p_filesz);
elf_interpreter+strlen(X86_DEFAULT_LIB_DIR),
elf_ppnt->p_filesz);
} }
if(retval < 0) { if(retval < 0) {
perror("load_elf_binary2"); perror("load_elf_binary2");
@@ -673,7 +787,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
printf("Using ELF interpreter %s\n", elf_interpreter); printf("Using ELF interpreter %s\n", elf_interpreter);
#endif #endif
if (retval >= 0) { if (retval >= 0) {
retval = open(elf_interpreter, O_RDONLY); retval = open(path(elf_interpreter), O_RDONLY);
if(retval >= 0) { if(retval >= 0) {
interpreter_fd = retval; interpreter_fd = retval;
} }
@@ -773,16 +887,38 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
* address. * address.
*/ */
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
if (elf_ppnt->p_type == PT_LOAD) {
int elf_prot = 0; 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_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 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 harcoding any address */
error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
}
load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
}
mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), error = (unsigned long)mmap4k(
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
(elf_ppnt->p_filesz + (elf_ppnt->p_filesz +
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot, elf_prot,
@@ -790,38 +926,46 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
bprm->fd, bprm->fd,
(elf_ppnt->p_offset - (elf_ppnt->p_offset -
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
if (error == -1) {
if((unsigned long)mapped_addr == 0xffffffffffffffff) {
perror("mmap"); perror("mmap");
exit(-1); exit(-1);
} }
#ifdef LOW_ELF_STACK #ifdef LOW_ELF_STACK
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
#endif #endif
if (!load_addr_set) { if (!load_addr_set) {
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
load_addr_set = 1; load_addr_set = 1;
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
}
} }
k = elf_ppnt->p_vaddr; k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k; if (k < start_code)
start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss) elf_bss = k; if (k > elf_bss)
#if 1 elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k) if ((elf_ppnt->p_flags & PF_X) && end_code < k)
#else
if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
#endif
end_code = k; end_code = k;
if (end_data < k) end_data = k; if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk) elf_brk = k; 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 (elf_interpreter) {
if (interpreter_type & 1) { if (interpreter_type & 1) {
@@ -856,7 +1000,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
bprm->argc, bprm->argc,
bprm->envc, bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr, load_addr, load_bias,
interp_load_addr, interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1), (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
info); info);

View File

@@ -37,6 +37,8 @@
IOCTL(TIOCNOTTY, 0, TYPE_NULL) IOCTL(TIOCNOTTY, 0, TYPE_NULL)
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
IOCTL(FIOCLEX, 0, TYPE_NULL) IOCTL(FIOCLEX, 0, TYPE_NULL)
IOCTL(FIONCLEX, 0, TYPE_NULL) IOCTL(FIONCLEX, 0, TYPE_NULL)
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT)) IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
@@ -66,6 +68,7 @@
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
#endif #endif
IOCTL(SIOCATMARK, 0, TYPE_NULL)
IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))

View File

@@ -32,12 +32,28 @@
FILE *logfile = NULL; FILE *logfile = NULL;
int loglevel; int loglevel;
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
/* for recent libc, we add these dummies symbol which are not declared
when generating a linked object (bug in ld ?) */
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
long __init_array_start[0];
long __init_array_end[0];
long __fini_array_start[0];
long __fini_array_end[0];
#endif
#endif
/* 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
by remapping the process stack directly at the right place */ by remapping the process stack directly at the right place */
unsigned long x86_stack_size = 512 * 1024; unsigned long x86_stack_size = 512 * 1024;
unsigned long stktop;
void gemu_log(const char *fmt, ...) void gemu_log(const char *fmt, ...)
{ {
@@ -103,17 +119,175 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
uint64_t gdt_table[6]; uint64_t gdt_table[6];
//#define DEBUG_VM86
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
{
return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(CPUX86State *env, int val)
{
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) |
((env->regs[R_ESP] - 2) & 0xffff);
*(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val;
}
static inline unsigned int get_vflags(CPUX86State *env)
{
unsigned int eflags;
eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
if (eflags & VIF_MASK)
eflags |= IF_MASK;
return eflags;
}
void save_v86_state(CPUX86State *env)
{
TaskState *ts = env->opaque;
#ifdef DEBUG_VM86
printf("save_v86_state\n");
#endif
/* put the VM86 registers in the userspace register structure */
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
ts->target_v86->regs.eip = tswap32(env->eip);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
ts->target_v86->regs.eflags = tswap32(env->eflags);
/* restore 32 bit registers */
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
env->eflags = ts->vm86_saved_regs.eflags;
env->eip = ts->vm86_saved_regs.eip;
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
}
/* return from vm86 mode to 32 bit. The vm86() syscall will return
'retval' */
static inline void return_to_32bit(CPUX86State *env, int retval)
{
#ifdef DEBUG_VM86
printf("return_to_32bit: ret=0x%x\n", retval);
#endif
save_v86_state(env);
env->regs[R_EAX] = retval;
}
/* handle VM86 interrupt (NOTE: the CPU core currently does not
support TSS interrupt revectoring, so this code is always executed) */
static void do_int(CPUX86State *env, int intno)
{
TaskState *ts = env->opaque;
uint32_t *int_ptr, segoffs;
if (env->segs[R_CS] == TARGET_BIOSSEG)
goto cannot_handle; /* XXX: I am not sure this is really useful */
if (is_revectored(intno, &ts->target_v86->int_revectored))
goto cannot_handle;
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
&ts->target_v86->int21_revectored))
goto cannot_handle;
int_ptr = (uint32_t *)(intno << 2);
segoffs = tswap32(*int_ptr);
if ((segoffs >> 16) == TARGET_BIOSSEG)
goto cannot_handle;
#ifdef DEBUG_VM86
printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
pushw(env, get_vflags(env));
pushw(env, env->segs[R_CS]);
pushw(env, env->eip);
/* goto interrupt handler */
env->eip = segoffs & 0xffff;
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
env->eflags &= ~(VIF_MASK | TF_MASK);
return;
cannot_handle:
#ifdef DEBUG_VM86
printf("VM86: return to 32 bits int 0x%x\n", intno);
#endif
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
}
void cpu_loop(struct CPUX86State *env) void cpu_loop(struct CPUX86State *env)
{ {
int err; int trapnr;
uint8_t *pc; uint8_t *pc;
target_siginfo_t info; target_siginfo_t info;
for(;;) { for(;;) {
err = cpu_x86_exec(env); trapnr = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip; pc = env->seg_cache[R_CS].base + env->eip;
switch(err) { switch(trapnr) {
case EXCP0D_GPF: case EXCP0D_GPF:
if (env->eflags & VM_MASK) {
#ifdef DEBUG_VM86
printf("VM86 exception %04x:%08x %02x %02x\n",
env->segs[R_CS], env->eip, pc[0], pc[1]);
#endif
/* VM86 mode */
switch(pc[0]) {
case 0xcd: /* int */
env->eip += 2;
do_int(env, pc[1]);
break;
case 0x66:
switch(pc[1]) {
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip += 2;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
goto vm86_gpf;
}
break;
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip++;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
vm86_gpf:
/* real VM86 GPF exception */
return_to_32bit(env, TARGET_VM86_UNKNOWN);
break;
}
} else {
if (pc[0] == 0xcd && pc[1] == 0x80) { if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */ /* syscall */
env->eip += 2; env->eip += 2;
@@ -133,22 +307,31 @@ void cpu_loop(struct CPUX86State *env)
info._sifields._sigfault._addr = 0; info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info); queue_signal(info.si_signo, &info);
} }
}
break; break;
case EXCP00_DIVZ: case EXCP00_DIVZ:
if (env->eflags & VM_MASK) {
do_int(env, trapnr);
} else {
/* division by zero */ /* division by zero */
info.si_signo = SIGFPE; info.si_signo = SIGFPE;
info.si_errno = 0; info.si_errno = 0;
info.si_code = TARGET_FPE_INTDIV; info.si_code = TARGET_FPE_INTDIV;
info._sifields._sigfault._addr = env->eip; info._sifields._sigfault._addr = env->eip;
queue_signal(info.si_signo, &info); queue_signal(info.si_signo, &info);
}
break; break;
case EXCP04_INTO: case EXCP04_INTO:
case EXCP05_BOUND: case EXCP05_BOUND:
if (env->eflags & VM_MASK) {
do_int(env, trapnr);
} else {
info.si_signo = SIGSEGV; info.si_signo = SIGSEGV;
info.si_errno = 0; info.si_errno = 0;
info.si_code = 0; info.si_code = 0;
info._sifields._sigfault._addr = 0; info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info); queue_signal(info.si_signo, &info);
}
break; break;
case EXCP06_ILLOP: case EXCP06_ILLOP:
info.si_signo = SIGILL; info.si_signo = SIGILL;
@@ -161,8 +344,8 @@ void cpu_loop(struct CPUX86State *env)
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */
break; break;
default: default:
fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, err); (long)pc, trapnr);
abort(); abort();
} }
process_pending_signals(env); process_pending_signals(env);
@@ -172,31 +355,68 @@ 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"
exit(1); "-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);
} }
/* XXX: currently only used for async signals (see signal.c) */ /* XXX: currently only used for async signals (see signal.c) */
CPUX86State *global_env; CPUX86State *global_env;
/* used to free thread contexts */
TaskState *first_task_state;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char *filename; const char *filename;
struct target_pt_regs regs1, *regs = &regs1; struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1; struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
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 */
@@ -204,7 +424,7 @@ int main(int argc, char **argv)
logfile = fopen(DEBUG_LOGFILE, "w"); logfile = fopen(DEBUG_LOGFILE, "w");
if (!logfile) { if (!logfile) {
perror(DEBUG_LOGFILE); perror(DEBUG_LOGFILE);
exit(1); _exit(1);
} }
setvbuf(logfile, NULL, _IOLBF, 0); setvbuf(logfile, NULL, _IOLBF, 0);
} }
@@ -215,9 +435,12 @@ 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));
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
printf("Error loading %s\n", filename); printf("Error loading %s\n", filename);
exit(1); _exit(1);
} }
if (loglevel) { if (loglevel) {
@@ -238,6 +461,11 @@ int main(int argc, char **argv)
env = cpu_x86_init(); env = cpu_x86_init();
global_env = env; global_env = env;
/* build Task State */
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
/* linux register setup */ /* linux register setup */
env->regs[R_EAX] = regs->eax; env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx; env->regs[R_EBX] = regs->ebx;

142
linux-user/path.c Normal file
View File

@@ -0,0 +1,142 @@
/* Code to mangle pathnames into those matching a given prefix.
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
The assumption is that this area does not change.
*/
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "qemu.h"
struct pathelem
{
/* Name of this, eg. lib */
char *name;
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
char *pathname;
struct pathelem *parent;
/* Children */
unsigned int num_entries;
struct pathelem *entries[0];
};
static struct pathelem *base;
/* First N chars of S1 match S2, and S2 is N chars long. */
static int strneq(const char *s1, unsigned int n, const char *s2)
{
unsigned int i;
for (i = 0; i < n; i++)
if (s1[i] != s2[i])
return 0;
return s2[i] == 0;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name);
static struct pathelem *new_entry(const char *root,
struct pathelem *parent,
const char *name)
{
struct pathelem *new = malloc(sizeof(*new));
new->name = strdup(name);
asprintf(&new->pathname, "%s/%s", root, name);
new->num_entries = 0;
return new;
}
#define streq(a,b) (strcmp((a), (b)) == 0)
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
if ((dir = opendir(path->pathname)) != NULL) {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
path = add_entry(path, dirent->d_name);
}
}
closedir(dir);
}
return path;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name)
{
root->num_entries++;
root = realloc(root, sizeof(*root)
+ sizeof(root->entries[0])*root->num_entries);
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
root->entries[root->num_entries-1]
= add_dir_maybe(root->entries[root->num_entries-1]);
return root;
}
/* This needs to be done after tree is stabalized (ie. no more reallocs!). */
static void set_parents(struct pathelem *child, struct pathelem *parent)
{
unsigned int i;
child->parent = parent;
for (i = 0; i < child->num_entries; i++)
set_parents(child->entries[i], child);
}
void init_paths(const char *prefix)
{
if (prefix[0] != '/' ||
prefix[0] == '\0' ||
!strcmp(prefix, "/"))
return;
base = new_entry("", NULL, prefix+1);
base = add_dir_maybe(base);
set_parents(base, base);
}
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
static const char *
follow_path(const struct pathelem *cursor, const char *name)
{
unsigned int i, namelen;
name += strspn(name, "/");
namelen = strcspn(name, "/");
if (namelen == 0)
return cursor->pathname;
if (strneq(name, namelen, ".."))
return follow_path(cursor->parent, name + namelen);
if (strneq(name, namelen, "."))
return follow_path(cursor, name + namelen);
for (i = 0; i < cursor->num_entries; i++)
if (strneq(name, namelen, cursor->entries[i]->name))
return follow_path(cursor->entries[i], name + namelen);
/* Not found */
return NULL;
}
/* Look for path in emulation dir, otherwise return name. */
const char *path(const char *name)
{
/* Only do absolute paths: quick and dirty, but should mostly be OK.
Could do relative by tracking cwd. */
if (!base || name[0] != '/')
return name;
return follow_path(base, name) ?: name;
}

View File

@@ -33,6 +33,33 @@ struct image_info {
int personality; int personality;
}; };
/* Information about the current linux thread */
struct vm86_saved_state {
uint32_t eax; /* return code */
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t esp;
uint32_t eflags;
uint32_t eip;
uint16_t cs, ss, ds, es, fs, gs;
};
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
extern TaskState *first_task_state;
int elf_exec(const char * filename, char ** argv, char ** envp, int elf_exec(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);
@@ -46,5 +73,7 @@ void cpu_loop(CPUX86State *env);
void process_pending_signals(void *cpu_env); void process_pending_signals(void *cpu_env);
void signal_init(void); void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info); int queue_signal(int sig, target_siginfo_t *info);
void save_v86_state(CPUX86State *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
#endif #endif

View File

@@ -21,6 +21,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <sys/ucontext.h> #include <sys/ucontext.h>
@@ -198,7 +199,7 @@ void __attribute((noreturn)) force_sig(int sig)
{ {
int host_sig; int host_sig;
host_sig = target_to_host_signal(sig); host_sig = target_to_host_signal(sig);
fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig)); sig, strsignal(host_sig));
#if 1 #if 1
_exit(-host_sig); _exit(-host_sig);
@@ -223,7 +224,7 @@ int queue_signal(int sig, target_siginfo_t *info)
target_ulong handler; target_ulong handler;
#if defined(DEBUG_SIGNAL) #if defined(DEBUG_SIGNAL)
fprintf(stderr, "queue_sigal: sig=%d\n", fprintf(stderr, "queue_signal: sig=%d\n",
sig); sig);
#endif #endif
k = &sigact_table[sig - 1]; k = &sigact_table[sig - 1];
@@ -317,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
if (sig < 1 || sig > TARGET_NSIG) if (sig < 1 || sig > TARGET_NSIG)
return; return;
#if defined(DEBUG_SIGNAL) #if defined(DEBUG_SIGNAL)
fprintf(stderr, "gemu: got signal %d\n", sig); fprintf(stderr, "qemu: got signal %d\n", sig);
dump_regs(puc); dump_regs(puc);
#endif #endif
host_to_target_siginfo_noswap(&tinfo, info); host_to_target_siginfo_noswap(&tinfo, info);
@@ -538,7 +539,6 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
/* non-iBCS2 extensions.. */ /* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask); err |= __put_user(mask, &sc->oldmask);
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
return err; return err;
} }
@@ -570,8 +570,6 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
return (void *)((esp - frame_size) & -8ul); return (void *)((esp - frame_size) & -8ul);
} }
#define TF_MASK TRAP_FLAG
static void setup_frame(int sig, struct emulated_sigaction *ka, static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUX86State *env) target_sigset_t *set, CPUX86State *env)
{ {
@@ -861,7 +859,7 @@ void process_pending_signals(void *cpu_env)
handle_signal: handle_signal:
#ifdef DEBUG_SIGNAL #ifdef DEBUG_SIGNAL
fprintf(stderr, "gemu: process signal %d\n", sig); fprintf(stderr, "qemu: process signal %d\n", sig);
#endif #endif
/* dequeue signal */ /* dequeue signal */
q = k->first; q = k->first;
@@ -895,6 +893,14 @@ void process_pending_signals(void *cpu_env)
end of the signal execution (see do_sigreturn) */ end of the signal execution (see do_sigreturn) */
host_to_target_sigset(&target_old_set, &old_set); host_to_target_sigset(&target_old_set, &old_set);
/* if the CPU is in VM86 mode, we restore the 32 bit values */
#ifdef TARGET_I386
{
CPUX86State *env = cpu_env;
if (env->eflags & VM_MASK)
save_v86_state(env);
}
#endif
/* prepare the stack frame of the virtual CPU */ /* prepare the stack frame of the virtual CPU */
if (k->sa.sa_flags & TARGET_SA_SIGINFO) if (k->sa.sa_flags & TARGET_SA_SIGINFO)
setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,11 @@
#define SOCKOP_sendmsg 16 #define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17 #define SOCKOP_recvmsg 17
struct target_sockaddr {
uint16_t sa_family;
uint8_t sa_data[14];
};
struct target_timeval { struct target_timeval {
target_long tv_sec; target_long tv_sec;
target_long tv_usec; target_long tv_usec;
@@ -34,6 +39,15 @@ struct target_itimerval {
struct target_timeval it_value; struct target_timeval it_value;
}; };
typedef target_long target_clock_t;
struct target_tms {
target_clock_t tms_utime;
target_clock_t tms_stime;
target_clock_t tms_cutime;
target_clock_t tms_cstime;
};
struct target_iovec { struct target_iovec {
target_long iov_base; /* Starting address */ target_long iov_base; /* Starting address */
target_long iov_len; /* Number of bytes */ target_long iov_len; /* Number of bytes */
@@ -49,6 +63,43 @@ struct target_msghdr {
unsigned int msg_flags; unsigned int msg_flags;
}; };
struct target_cmsghdr {
target_long cmsg_len;
int cmsg_level;
int cmsg_type;
};
#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
#define TARGET_CMSG_FIRSTHDR(mhdr) \
((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \
? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL)
#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \
& (size_t) ~(sizeof (target_long) - 1))
#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
+ TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
static __inline__ struct target_cmsghdr *
__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
{
if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr))
/* The kernel header does this so there may be a reason. */
return 0;
__cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg
+ TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))
|| ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))
> ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))))
/* No more entries. */
return 0;
return __cmsg;
}
struct target_rusage { struct target_rusage {
struct target_timeval ru_utime; /* user time used */ struct target_timeval ru_utime; /* user time used */
struct target_timeval ru_stime; /* system time used */ struct target_timeval ru_stime; /* system time used */

263
op-i386.c
View File

@@ -412,6 +412,22 @@ void OPPROTO op_idivw_AX_T0(void)
EDX = (EDX & 0xffff0000) | r; EDX = (EDX & 0xffff0000) | r;
} }
#ifdef BUGGY_GCC_DIV64
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
call it from another function */
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
{
*q_ptr = num / den;
return num % den;
}
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
{
*q_ptr = num / den;
return num % den;
}
#endif
void OPPROTO op_divl_EAX_T0(void) void OPPROTO op_divl_EAX_T0(void)
{ {
unsigned int den, q, r; unsigned int den, q, r;
@@ -421,8 +437,12 @@ void OPPROTO op_divl_EAX_T0(void)
den = T0; den = T0;
if (den == 0) if (den == 0)
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
#ifdef BUGGY_GCC_DIV64
r = div64(&q, num, den);
#else
q = (num / den); q = (num / den);
r = (num % den); r = (num % den);
#endif
EAX = q; EAX = q;
EDX = r; EDX = r;
} }
@@ -436,8 +456,12 @@ void OPPROTO op_idivl_EAX_T0(void)
den = T0; den = T0;
if (den == 0) if (den == 0)
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
#ifdef BUGGY_GCC_DIV64
r = idiv64(&q, num, den);
#else
q = (num / den); q = (num / den);
r = (num % den); r = (num % den);
#endif
EAX = q; EAX = q;
EDX = r; EDX = r;
} }
@@ -489,6 +513,11 @@ void OPPROTO op_addl_A0_im(void)
A0 += PARAM1; A0 += PARAM1;
} }
void OPPROTO op_addl_A0_AL(void)
{
A0 += (EAX & 0xff);
}
void OPPROTO op_andl_A0_ffff(void) void OPPROTO op_andl_A0_ffff(void)
{ {
A0 = A0 & 0xffff; A0 = A0 & 0xffff;
@@ -602,13 +631,80 @@ void OPPROTO op_into(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O) { if (eflags & CC_O) {
EIP = PARAM1;
raise_exception(EXCP04_INTO); raise_exception(EXCP04_INTO);
} else {
EIP = PARAM2;
} }
} }
/* XXX: add IOPL/CPL tests */
void OPPROTO op_cli(void)
{
raise_exception(EXCP0D_GPF);
}
/* XXX: add IOPL/CPL tests */
void OPPROTO op_sti(void)
{
raise_exception(EXCP0D_GPF);
}
/* vm86plus instructions */
void OPPROTO op_cli_vm(void)
{
env->eflags &= ~VIF_MASK;
}
void OPPROTO op_sti_vm(void)
{
env->eflags |= VIF_MASK;
if (env->eflags & VIP_MASK) {
EIP = PARAM1;
raise_exception(EXCP0D_GPF);
}
FORCE_RET();
}
void OPPROTO op_boundw(void)
{
int low, high, v;
low = ldsw((uint8_t *)A0);
high = ldsw((uint8_t *)A0 + 2);
v = (int16_t)T0;
if (v < low || v > high)
raise_exception(EXCP05_BOUND);
FORCE_RET();
}
void OPPROTO op_boundl(void)
{
int low, high, v;
low = ldl((uint8_t *)A0);
high = ldl((uint8_t *)A0 + 4);
v = T0;
if (v < low || v > high)
raise_exception(EXCP05_BOUND);
FORCE_RET();
}
void OPPROTO op_cmpxchg8b(void)
{
uint64_t d;
int eflags;
eflags = cc_table[CC_OP].compute_all();
d = ldq((uint8_t *)A0);
if (d == (((uint64_t)EDX << 32) | EAX)) {
stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
eflags |= CC_Z;
} else {
EDX = d >> 32;
EAX = d;
eflags &= ~CC_Z;
}
CC_SRC = eflags;
FORCE_RET();
}
/* string ops */ /* string ops */
#define ldul ldl #define ldul ldl
@@ -788,7 +884,8 @@ void op_addw_ESP_im(void)
#ifndef __i386__ #ifndef __i386__
uint64_t emu_time; uint64_t emu_time;
#endif #endif
void op_rdtsc(void)
void OPPROTO op_rdtsc(void)
{ {
uint64_t val; uint64_t val;
#ifdef __i386__ #ifdef __i386__
@@ -801,6 +898,51 @@ void op_rdtsc(void)
EDX = val >> 32; EDX = val >> 32;
} }
/* We simulate a pre-MMX pentium as in valgrind */
#define CPUID_FP87 (1 << 0)
#define CPUID_VME (1 << 1)
#define CPUID_DE (1 << 2)
#define CPUID_PSE (1 << 3)
#define CPUID_TSC (1 << 4)
#define CPUID_MSR (1 << 5)
#define CPUID_PAE (1 << 6)
#define CPUID_MCE (1 << 7)
#define CPUID_CX8 (1 << 8)
#define CPUID_APIC (1 << 9)
#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
#define CPUID_MTRR (1 << 12)
#define CPUID_PGE (1 << 13)
#define CPUID_MCA (1 << 14)
#define CPUID_CMOV (1 << 15)
/* ... */
#define CPUID_MMX (1 << 23)
#define CPUID_FXSR (1 << 24)
#define CPUID_SSE (1 << 25)
#define CPUID_SSE2 (1 << 26)
void helper_cpuid(void)
{
if (EAX == 0) {
EAX = 1; /* max EAX index supported */
EBX = 0x756e6547;
ECX = 0x6c65746e;
EDX = 0x49656e69;
} else {
/* EAX = 1 info */
EAX = 0x52b;
EBX = 0;
ECX = 0;
EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
CPUID_TSC | CPUID_MSR | CPUID_MCE |
CPUID_CX8;
}
}
void OPPROTO op_cpuid(void)
{
helper_cpuid();
}
/* bcd */ /* bcd */
/* XXX: exception */ /* XXX: exception */
@@ -933,6 +1075,7 @@ void OPPROTO op_das(void)
/* segment handling */ /* segment handling */
/* XXX: use static VM86 information */
void load_seg(int seg_reg, int selector) void load_seg(int seg_reg, int selector)
{ {
SegmentCache *sc; SegmentCache *sc;
@@ -943,7 +1086,7 @@ void load_seg(int seg_reg, int selector)
env->segs[seg_reg] = selector; env->segs[seg_reg] = selector;
sc = &env->seg_cache[seg_reg]; sc = &env->seg_cache[seg_reg];
if (env->vm86) { if (env->eflags & VM_MASK) {
sc->base = (void *)(selector << 4); sc->base = (void *)(selector << 4);
sc->limit = 0xffff; sc->limit = 0xffff;
sc->seg_32bit = 0; sc->seg_32bit = 0;
@@ -980,6 +1123,11 @@ void OPPROTO op_movl_T0_seg(void)
T0 = env->segs[PARAM1]; T0 = env->segs[PARAM1];
} }
void OPPROTO op_movl_A0_seg(void)
{
A0 = *(unsigned long *)((char *)env + PARAM1);
}
void OPPROTO op_addl_A0_seg(void) void OPPROTO op_addl_A0_seg(void)
{ {
A0 += *(unsigned long *)((char *)env + PARAM1); A0 += *(unsigned long *)((char *)env + PARAM1);
@@ -1139,10 +1287,66 @@ void OPPROTO op_set_cc_op(void)
CC_OP = PARAM1; CC_OP = PARAM1;
} }
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
#define FL_UPDATE_MASK16 (TF_MASK)
void OPPROTO op_movl_eflags_T0(void) void OPPROTO op_movl_eflags_T0(void)
{ {
CC_SRC = T0; int eflags;
DF = 1 - (2 * ((T0 >> 10) & 1)); eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32);
}
void OPPROTO op_movw_eflags_T0(void)
{
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
}
/* vm86 version */
void OPPROTO op_movw_eflags_T0_vm(void)
{
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) |
(eflags & FL_UPDATE_MASK16);
if (eflags & IF_MASK) {
env->eflags |= VIF_MASK;
if (env->eflags & VIP_MASK) {
EIP = PARAM1;
raise_exception(EXCP0D_GPF);
}
}
FORCE_RET();
}
void OPPROTO op_movl_eflags_T0_vm(void)
{
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) |
(eflags & FL_UPDATE_MASK32);
if (eflags & IF_MASK) {
env->eflags |= VIF_MASK;
if (env->eflags & VIP_MASK) {
EIP = PARAM1;
raise_exception(EXCP0D_GPF);
}
}
FORCE_RET();
} }
/* XXX: compute only O flag */ /* XXX: compute only O flag */
@@ -1150,13 +1354,28 @@ void OPPROTO op_movb_eflags_T0(void)
{ {
int of; int of;
of = cc_table[CC_OP].compute_all() & CC_O; of = cc_table[CC_OP].compute_all() & CC_O;
CC_SRC = T0 | of; CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of;
} }
void OPPROTO op_movl_T0_eflags(void) void OPPROTO op_movl_T0_eflags(void)
{ {
T0 = cc_table[CC_OP].compute_all(); int eflags;
T0 |= (DF & DIRECTION_FLAG); eflags = cc_table[CC_OP].compute_all();
eflags |= (DF & DF_MASK);
eflags |= env->eflags & ~(VM_MASK | RF_MASK);
T0 = eflags;
}
/* vm86 version */
void OPPROTO op_movl_T0_eflags_vm(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags |= (DF & DF_MASK);
eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
if (env->eflags & VIF_MASK)
eflags |= IF_MASK;
T0 = eflags;
} }
void OPPROTO op_cld(void) void OPPROTO op_cld(void)
@@ -1273,7 +1492,9 @@ CCTable cc_table[CC_OP_NB] = {
[CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, [CC_OP_SARL] = { compute_all_sarl, compute_c_shll },
}; };
/* floating point support */ /* floating point support. Some of the code for complicated x87
functions comes from the LGPL'ed x86 emulator found in the Willows
TWIN windows emulator. */
#ifdef USE_X86LDOUBLE #ifdef USE_X86LDOUBLE
/* use long double functions */ /* use long double functions */
@@ -1306,6 +1527,26 @@ extern CPU86_LDouble floor(CPU86_LDouble x);
extern CPU86_LDouble ceil(CPU86_LDouble x); extern CPU86_LDouble ceil(CPU86_LDouble x);
extern CPU86_LDouble rint(CPU86_LDouble x); extern CPU86_LDouble rint(CPU86_LDouble x);
#if defined(__powerpc__)
extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble);
/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
double qemu_rint(double x)
{
double y = 4503599627370496.0;
if (fabs(x) >= y)
return x;
if (x < 0)
y = -y;
y = (x + y) - y;
if (y == 0.0)
y = copysign(y, x);
return y;
}
#define rint qemu_rint
#endif
#define RC_MASK 0xc00 #define RC_MASK 0xc00
#define RC_NEAR 0x000 #define RC_NEAR 0x000
#define RC_DOWN 0x400 #define RC_DOWN 0x400

245
op_string.h Normal file
View File

@@ -0,0 +1,245 @@
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
}
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
INC_SI();
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
glue(st, SUFFIX)(DI_ADDR, EAX);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (CX != 0) {
glue(st, SUFFIX)(DI_ADDR, EAX);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
inc = (DF << SHIFT);
INC_SI();
}
/* don't know if it is used */
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_DI();
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(dx, v);
inc = (DF << SHIFT);
INC_SI();
}
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(dx, v);
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)(DI_ADDR, v);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
#undef STRING_SUFFIX
#undef SI_ADDR
#undef DI_ADDR
#undef INC_SI
#undef INC_DI
#undef CX
#undef DEC_CX

1178
opc-i386.h

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -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))
@@ -610,6 +609,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
CC_DST = T0; CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT; CC_OP = CC_OP_SARB + SHIFT;
} }
FORCE_RET();
} }
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
@@ -644,6 +644,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
CC_DST = T0; CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT; CC_OP = CC_OP_SARB + SHIFT;
} }
FORCE_RET();
} }
#endif #endif
@@ -671,6 +672,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
CC_DST = T0; CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT; CC_OP = CC_OP_SHLB + SHIFT;
} }
FORCE_RET();
} }
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
@@ -697,6 +699,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
CC_DST = T0; CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT; CC_OP = CC_OP_SARB + SHIFT;
} }
FORCE_RET();
} }
#endif #endif
@@ -807,238 +810,37 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#endif #endif
/* string operations */ /* string operations */
/* XXX: maybe use lower level instructions to ease exception handling */ /* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
void OPPROTO glue(op_movs, SUFFIX)(void) #define STRING_SUFFIX _fast
{ #define SI_ADDR (void *)ESI
int v; #define DI_ADDR (void *)EDI
v = glue(ldu, SUFFIX)((void *)ESI); #define INC_SI() ESI += inc
glue(st, SUFFIX)((void *)EDI, v); #define INC_DI() EDI += inc
ESI += (DF << SHIFT); #define CX ECX
EDI += (DF << SHIFT); #define DEC_CX() ECX--
} #include "op_string.h"
void OPPROTO glue(op_rep_movs, SUFFIX)(void) #define STRING_SUFFIX _a32
{ #define SI_ADDR (uint8_t *)A0 + ESI
int v, inc; #define DI_ADDR env->seg_cache[R_ES].base + EDI
inc = (DF << SHIFT); #define INC_SI() ESI += inc
while (ECX != 0) { #define INC_DI() EDI += inc
v = glue(ldu, SUFFIX)((void *)ESI); #define CX ECX
glue(st, SUFFIX)((void *)EDI, v); #define DEC_CX() ECX--
ESI += inc; #include "op_string.h"
EDI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_stos, SUFFIX)(void) #define STRING_SUFFIX _a16
{ #define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
glue(st, SUFFIX)((void *)EDI, EAX); #define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff)
EDI += (DF << SHIFT); #define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
} #define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
#define CX (ECX & 0xffff)
void OPPROTO glue(op_rep_stos, SUFFIX)(void) #define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
{ #include "op_string.h"
int inc;
inc = (DF << SHIFT);
while (ECX != 0) {
glue(st, SUFFIX)((void *)EDI, EAX);
EDI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_lods, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += (DF << SHIFT);
}
/* don't know if it is used */
void OPPROTO glue(op_rep_lods, SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_scas, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)EDI);
EDI += (DF << SHIFT);
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(op_repz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)EDI);
EDI += inc;
ECX--;
if (v1 != v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_repnz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)EDI);
EDI += inc;
ECX--;
if (v1 == v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_cmps, SUFFIX)(void)
{
int v1, v2;
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += (DF << SHIFT);
EDI += (DF << SHIFT);
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(op_repz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += inc;
EDI += inc;
ECX--;
if (v1 != v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_repnz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += inc;
EDI += inc;
ECX--;
if (v1 == v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
/* port I/O */ /* port I/O */
void OPPROTO glue(op_outs, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)((void *)ESI);
glue(cpu_x86_out, SUFFIX)(dx, v);
ESI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_outs, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
glue(cpu_x86_out, SUFFIX)(dx, v);
ESI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_ins, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_ins, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
{ {
glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK); glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK);

407
qemu-doc.texi Normal file
View File

@@ -0,0 +1,407 @@
\input texinfo @c -*- texinfo -*-
@settitle QEMU x86 Emulator Reference Documentation
@titlepage
@sp 7
@center @titlefont{QEMU x86 Emulator Reference Documentation}
@sp 3
@end titlepage
@chapter Introduction
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
processes on non-x86 Linux architectures such as PowerPC or ARM. By
using dynamic translation it achieves a reasonnable speed while being
easy to port on new host CPUs. Its main goal is to be able to launch the
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on
non-x86 CPUs.
QEMU features:
@itemize
@item User space only x86 emulator.
@item Currently ported on i386, PowerPC and S390.
@item Using dynamic translation to native code for reasonnable speed.
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
User space LDT and GDT are emulated. VM86 mode is also supported
(experimental).
@item Generic Linux system call converter, including most ioctls.
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
@item Accurate signal handling by remapping host signals to virtual x86 signals.
@item QEMU can emulate itself on x86 (experimental).
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
in other projects.
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
It can be used to test other x86 virtual CPUs.
@end itemize
Current QEMU Limitations:
@itemize
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
@item No SSE/MMX support (yet).
@item No x86-64 support.
@item Some Linux syscalls are missing.
@item The x86 segment limits and access rights are not tested at every
memory access (and will never be to have good performances).
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
10 byte @code{long double}s of x86 for floating point emulation to get
maximum performances.
@end itemize
@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.
@itemize
@item On x86, you can just try to launch any process by using the native
libraries:
@example
qemu -L / /bin/ls
@end example
@code{-L /} tells that the x86 dynamic linker must be searched with a
@file{/} prefix.
@item Since QEMU is also a linux process, you can launch qemu with qemu:
@example
qemu -L / qemu -L / /bin/ls
@end example
@item On non x86 CPUs, you need first to download at least an x86 glibc
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
@code{LD_LIBRARY_PATH} is not set:
@example
unset LD_LIBRARY_PATH
@end example
Then you can launch the precompiled @file{ls} x86 executable:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@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.
@item The x86 version of QEMU is also included. You can try weird things such as:
@example
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
@end example
@end itemize
@section Wine launch (Currently only tested when emulating x86 on x86)
@itemize
@item Ensure that you have a working QEMU with the x86 glibc
distribution (see previous section). In order to verify it, you must be
able to do:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
@item Download the binary x86 Wine install
(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
@item Configure Wine on your account. Look at the provided script
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
@item Then you can try the example @file{putty.exe}:
@example
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
@end example
@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
Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that
you cannot launch an operating system with it. The benefit is that it is
simpler and faster due to the fact that some of the low level CPU state
can be ignored (in particular, no virtual memory needs to be emulated).
Like Valgrind [2], QEMU does user space emulation and dynamic
translation. Valgrind is mainly a memory debugger while QEMU has no
support for it (QEMU could be used to detect out of bound memory accesses
as Valgrind, but it has no support to track uninitialised data as
Valgrind does). Valgrind dynamic translator generates better code than
QEMU (in particular it does register allocation) but it is closely tied
to an x86 host.
EM86 [4] is the closest project to QEMU (and QEMU still uses some of its
code, in particular the ELF file loader). EM86 was limited to an alpha
host and used a proprietary and slow interpreter (the interpreter part
of the FX!32 Digital Win32 code translator [5]).
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
Wine but includes a protected mode x86 interpreter to launch x86 Windows
executables. Such an approach as greater potential because most of the
Windows API is executed natively but it is far more difficult to develop
because all the data structures and function parameters exchanged
between the API and the x86 code must be converted.
@section Portable dynamic translation
QEMU is a dynamic translator. When it first encounters a piece of code,
it converts it to the host instruction set. Usually dynamic translators
are very complicated and highly CPU dependant. QEMU uses some tricks
which make it relatively easily portable and simple while achieving good
performances.
The basic idea is to split every x86 instruction into fewer simpler
instructions. Each simple instruction is implemented by a piece of C
code (see @file{op-i386.c}). Then a compile time tool (@file{dyngen})
takes the corresponding object file (@file{op-i386.o}) to generate a
dynamic code generator which concatenates the simple instructions to
build a function (see @file{op-i386.h:dyngen_code()}).
In essence, the process is similar to [1], but more work is done at
compile time.
A key idea to get optimal performances is that constant parameters can
be passed to the simple operations. For that purpose, dummy ELF
relocations are generated with gcc for each constant parameter. Then,
the tool (@file{dyngen}) can locate the relocations and generate the
appriopriate C code to resolve them when building the dynamic code.
That way, QEMU is no more difficult to port than a dynamic linker.
To go even faster, GCC static register variables are used to keep the
state of the virtual CPU.
@section Register allocation
Since QEMU uses fixed simple instructions, no efficient register
allocation can be done. However, because RISC CPUs have a lot of
register, most of the virtual CPU state can be put in registers without
doing complicated register allocation.
@section Condition code optimisations
Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a
critical point to get good performances. QEMU uses lazy condition code
evaluation: instead of computing the condition codes after each x86
instruction, it just stores one operand (called @code{CC_SRC}), the
result (called @code{CC_DST}) and the type of operation (called
@code{CC_OP}).
@code{CC_OP} is almost never explicitely set in the generated code
because it is known at translation time.
In order to increase performances, a backward pass is performed on the
generated simple instructions (see
@code{translate-i386.c:optimize_flags()}). When it can be proved that
the condition codes are not needed by the next instructions, no
condition codes are computed at all.
@section CPU state optimisations
The x86 CPU has many internal states which change the way it evaluates
instructions. In order to achieve a good speed, the translation phase
considers that some state information of the virtual x86 CPU cannot
change in it. For example, if the SS, DS and ES segments have a zero
base, then the translator does not even generate an addition for the
segment base.
[The FPU stack pointer register is not handled that way yet].
@section Translation cache
A 2MByte cache holds the most recently used translations. For
simplicity, it is completely flushed when it is full. A translation unit
contains just a single basic block (a block of x86 instructions
terminated by a jump or by a virtual CPU state change which the
translator cannot deduce statically).
[Currently, the translated code is not patched if it jumps to another
translated code].
@section Exception support
longjmp() is used when an exception such as division by zero is
encountered. The host SIGSEGV and SIGBUS signal handlers are used to get
invalid memory accesses.
[Currently, the virtual CPU cannot retrieve the exact CPU state in some
exceptions, although it could except for the @code{EFLAGS} register].
@section Linux system call translation
QEMU includes a generic system call translator for Linux. It means that
the parameters of the system calls can be converted to fix the
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
type description system (see @file{ioctls.h} and @file{thunk.c}).
@section Linux signals
Normal and real-time signals are queued along with their information
(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt
request is done to the virtual CPU. When it is interrupted, one queued
signal is handled by generating a stack frame in the virtual CPU as the
Linux kernel does. The @code{sigreturn()} system call is emulated to return
from the virtual signal handler.
Some signals (such as SIGALRM) directly come from the host. Other
signals are synthetized from the virtual CPU exceptions such as SIGFPE
when a division by zero is done (see @code{main.c:cpu_loop()}).
The blocked signal mask is still handled by the host Linux kernel so
that most signal system calls can be redirected directly to the host
Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system
calls need to be fully emulated (see @file{signal.c}).
@section clone() system call and threads
The Linux clone() system call is usually used to create a thread. QEMU
uses the host clone() system call so that real host threads are created
for each emulated thread. One virtual CPU instance is created for each
thread.
The virtual x86 CPU atomic operations are emulated with a global lock so
that their semantic is preserved.
@section Self-virtualization
QEMU was conceived so that ultimately it can emulate itself. Althought
it is not very useful, it is an important test to show the power of the
emulator.
Achieving self-virtualization is not easy because there may be address
space conflicts. QEMU solves this problem by being an ELF shared object
as the ld-linux.so ELF interpreter. That way, it can be relocated at
load time.
Since self-modifying code is not supported yet, QEMU cannot self
virtualize itself in case of translation cache flush. This limitation
will be suppressed soon.
@section Bibliography
@table @asis
@item [1]
@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing
direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio
Riccardi.
@item [2]
@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source
memory debugger for x86-GNU/Linux, by Julian Seward.
@item [3]
@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project,
by Kevin Lawton et al.
@item [4]
@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86
x86 emulator on Alpha-Linux.
@item [5]
@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf},
DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
Chernoff and Ray Hookway.
@item [6]
@url{http://www.willows.com/}, Windows API library emulation from
Willows Software.
@end table
@chapter Regression Tests
In the directory @file{tests/}, various interesting x86 testing programs
are available. There are used for regression testing.
@section @file{hello}
Very simple statically linked x86 program, just to test QEMU during a
port to a new host CPU.
@section @file{test-i386}
This program executes most of the 16 bit and 32 bit x86 instructions and
generates a text output. It can be compared with the output obtained with
a real CPU or another emulator. The target @code{make test} runs this
program and a @code{diff} on the generated output.
The Linux system call @code{modify_ldt()} is used to create x86 selectors
to test some 16 bit addressing and 32 bit with segmentation cases.
@section @file{testsig}
This program tests various signal cases, including SIGFPE, SIGSEGV and
SIGILL.
@section @file{testclone}
Tests the @code{clone()} system call (basic test).
@section @file{testthread}
Tests the glibc threads (more complicated than @code{clone()} because signals
are also used).
@section @file{sha1}
It is a simple benchmark. Care must be taken to interpret the results
because it mostly tests the ability of the virtual CPU to optimize the
@code{rol} x86 instruction and the condition code computations.
@section @file{runcom}
A very simple MSDOS emulator to test the Linux vm86() system call
emulation. The excellent 54 byte @file{pi_10.com} PI number calculator
can be launched with it. @file{pi_10.com} was written by Bertram
Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}).

View File

@@ -237,6 +237,36 @@
#define TARGET_NR_removexattr 235 #define TARGET_NR_removexattr 235
#define TARGET_NR_lremovexattr 236 #define TARGET_NR_lremovexattr 236
#define TARGET_NR_fremovexattr 237 #define TARGET_NR_fremovexattr 237
#define TARGET_NR_tkill 238
#define TARGET_NR_sendfile64 239
#define TARGET_NR_futex 240
#define TARGET_NR_sched_setaffinity 241
#define TARGET_NR_sched_getaffinity 242
#define TARGET_NR_set_thread_area 243
#define TARGET_NR_get_thread_area 244
#define TARGET_NR_io_setup 245
#define TARGET_NR_io_destroy 246
#define TARGET_NR_io_getevents 247
#define TARGET_NR_io_submit 248
#define TARGET_NR_io_cancel 249
#define TARGET_NR_fadvise64 250
#define TARGET_NR_exit_group 252
#define TARGET_NR_lookup_dcookie 253
#define TARGET_NR_epoll_create 254
#define TARGET_NR_epoll_ctl 255
#define TARGET_NR_epoll_wait 256
#define TARGET_NR_remap_file_pages 257
#define TARGET_NR_set_tid_address 258
#define TARGET_NR_timer_create 259
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
#define TARGET_SIG_BLOCK 0 /* for blocking signals */ #define TARGET_SIG_BLOCK 0 /* for blocking signals */
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ #define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
@@ -255,11 +285,11 @@ struct target_stat {
target_ulong st_size; target_ulong st_size;
target_ulong st_blksize; target_ulong st_blksize;
target_ulong st_blocks; target_ulong st_blocks;
target_ulong st_atime; target_ulong target_st_atime;
target_ulong __unused1; target_ulong __unused1;
target_ulong st_mtime; target_ulong target_st_mtime;
target_ulong __unused2; target_ulong __unused2;
target_ulong st_ctime; target_ulong target_st_ctime;
target_ulong __unused3; target_ulong __unused3;
target_ulong __unused4; target_ulong __unused4;
target_ulong __unused5; target_ulong __unused5;
@@ -272,7 +302,7 @@ struct target_stat64 {
unsigned short st_dev; unsigned short st_dev;
unsigned char __pad0[10]; unsigned char __pad0[10];
#define STAT64_HAS_BROKEN_ST_INO 1 #define TARGET_STAT64_HAS_BROKEN_ST_INO 1
target_ulong __st_ino; target_ulong __st_ino;
unsigned int st_mode; unsigned int st_mode;
@@ -290,13 +320,13 @@ struct target_stat64 {
target_ulong st_blocks; /* Number 512-byte blocks allocated. */ target_ulong st_blocks; /* Number 512-byte blocks allocated. */
target_ulong __pad4; /* future possible st_blocks high bits */ target_ulong __pad4; /* future possible st_blocks high bits */
target_ulong st_atime; target_ulong target_st_atime;
target_ulong __pad5; target_ulong __pad5;
target_ulong st_mtime; target_ulong target_st_mtime;
target_ulong __pad6; target_ulong __pad6;
target_ulong st_ctime; target_ulong target_st_ctime;
target_ulong __pad7; /* will be high 32 bits of ctime someday */ target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino; unsigned long long st_ino;
@@ -397,8 +427,8 @@ typedef struct target_siginfo {
pid_t _pid; /* which child */ pid_t _pid; /* which child */
uid_t _uid; /* sender's uid */ uid_t _uid; /* sender's uid */
int _status; /* exit code */ int _status; /* exit code */
clock_t _utime; target_clock_t _utime;
clock_t _stime; target_clock_t _stime;
} _sigchld; } _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -542,8 +572,8 @@ struct target_pt_regs {
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ #define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ #define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ #define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451 #define TARGET_FIOCLEX 0x5451
@@ -714,6 +744,10 @@ struct target_termios {
#define TARGET_LDT_ENTRIES 8192 #define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8 #define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 6
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
struct target_modify_ldt_ldt_s { struct target_modify_ldt_ldt_s {
unsigned int entry_number; unsigned int entry_number;
target_ulong base_addr; target_ulong base_addr;
@@ -721,6 +755,187 @@ struct target_modify_ldt_ldt_s {
unsigned int flags; unsigned int flags;
}; };
/* vm86 defines */
#define TARGET_BIOSSEG 0x0f000
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
/*
* Additional return values when invoking new vm86()
*/
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
/*
* function codes when invoking new vm86()
*/
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
#define TARGET_VM86_ENTER 1
#define TARGET_VM86_ENTER_NO_BYPASS 2
#define TARGET_VM86_REQUEST_IRQ 3
#define TARGET_VM86_FREE_IRQ 4
#define TARGET_VM86_GET_IRQ_BITS 5
#define TARGET_VM86_GET_AND_RESET_IRQ 6
/*
* This is the stack-layout seen by the user space program when we have
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
* is 'kernel_vm86_regs' (see below).
*/
struct target_vm86_regs {
/*
* normal regs, with special meaning for the segment descriptors..
*/
target_long ebx;
target_long ecx;
target_long edx;
target_long esi;
target_long edi;
target_long ebp;
target_long eax;
target_long __null_ds;
target_long __null_es;
target_long __null_fs;
target_long __null_gs;
target_long orig_eax;
target_long eip;
unsigned short cs, __csh;
target_long eflags;
target_long esp;
unsigned short ss, __ssh;
/*
* these are specific to v86 mode:
*/
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
};
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
struct target_vm86_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
};
/*
* flags masks
*/
#define TARGET_VM86_SCREEN_BITMAP 0x0001
struct target_vm86plus_info_struct {
target_ulong flags;
#define TARGET_force_return_for_pic (1 << 0)
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
};
struct target_vm86plus_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
struct target_vm86plus_info_struct vm86plus;
};
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct alpha_msgbuf {
long mtype;
char mtext[4096];
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
unsigned int __pad; /* really void* */
};
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */ /* soundcard defines (XXX: move them to generic file syscall_defs.h) */
#define TARGET_SNDCTL_COPR_HALT 0xc0144307 #define TARGET_SNDCTL_COPR_HALT 0xc0144307
@@ -850,3 +1065,5 @@ struct target_modify_ldt_ldt_s {
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201 #define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202 #define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
#define TARGET_SIOCATMARK 0x8905

28
tests/.cvsignore Normal file
View File

@@ -0,0 +1,28 @@
gmon.out
testsig
hello
sha1.test.c
sha1.c
op.c
test-i386
sha1
testclone
interp.h
interploop.c
.gdb_history
cachegrind.out
interp.c
interp
testthread
test-i386.s
test-i386.ref
sha1-i386
runcom
debug.com
test-i386.out
speed.txt
test-i386.ref.P3
pi_10.com
test-i386.ref.P4
ldso.c
test_path

View File

@@ -4,9 +4,9 @@ CFLAGS=-Wall -O2 -g
LDFLAGS= LDFLAGS=
ifeq ($(ARCH),i386) ifeq ($(ARCH),i386)
TESTS=testclone testsig testthread sha1-i386 test-i386 TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
endif endif
TESTS+=sha1 TESTS+=sha1 test_path
QEMU=../qemu QEMU=../qemu
@@ -25,6 +25,10 @@ testsig: testsig.c
testthread: testthread.c testthread: testthread.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
test_path: test_path.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
./$@ || { rm $@; exit 1; }
# 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
@@ -48,5 +52,9 @@ speed: sha1 sha1-i386
time ./sha1 time ./sha1
time $(QEMU) ./sha1-i386 time $(QEMU) ./sha1-i386
# vm86 test
runcom: runcom.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean: clean:
rm -f *~ *.o $(TESTS) rm -f *~ *.o $(TESTS)

195
tests/runcom.c Normal file
View File

@@ -0,0 +1,195 @@
/*
* Simple example of use of vm86: launch a basic .com DOS executable
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>
#include <linux/unistd.h>
#include <asm/vm86.h>
//#define SIGTEST
#undef __syscall_return
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
#define COM_BASE_ADDR 0x10100
void usage(void)
{
printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n"
"usage: runcom file.com\n"
"VM86 Run simple .com DOS executables (linux vm86 test mode)\n");
exit(1);
}
static inline void set_bit(uint8_t *a, unsigned int bit)
{
a[bit / 8] |= (1 << (bit % 8));
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(struct vm86_regs *r, int val)
{
r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
*(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
}
void dump_regs(struct vm86_regs *r)
{
fprintf(stderr,
"EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
"ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
"EIP=%08lx EFL=%08lx\n"
"CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n",
r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
r->eip, r->eflags,
r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
}
#ifdef SIGTEST
void alarm_handler(int sig)
{
fprintf(stderr, "alarm signal=%d\n", sig);
alarm(1);
}
#endif
int main(int argc, char **argv)
{
uint8_t *vm86_mem;
const char *filename;
int fd, ret, seg;
struct vm86plus_struct ctx;
struct vm86_regs *r;
if (argc != 2)
usage();
filename = argv[1];
vm86_mem = mmap((void *)0x00000000, 0x110000,
PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if (vm86_mem == MAP_FAILED) {
perror("mmap");
exit(1);
}
#ifdef SIGTEST
{
struct sigaction act;
act.sa_handler = alarm_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
alarm(1);
}
#endif
/* load the MSDOS .com executable */
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
exit(1);
}
ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
if (ret < 0) {
perror("read");
exit(1);
}
close(fd);
memset(&ctx, 0, sizeof(ctx));
/* init basic registers */
r = &ctx.regs;
r->eip = 0x100;
r->esp = 0xfffe;
seg = (COM_BASE_ADDR - 0x100) >> 4;
r->cs = seg;
r->ss = seg;
r->ds = seg;
r->es = seg;
r->fs = seg;
r->gs = seg;
r->eflags = (IF_MASK | IOPL_MASK);
/* put return code */
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
*seg_to_linear(r->cs, 0) = 0xb4; /* mov ah, $0 */
*seg_to_linear(r->cs, 1) = 0x00;
*seg_to_linear(r->cs, 2) = 0xcd; /* int $0x21 */
*seg_to_linear(r->cs, 3) = 0x21;
pushw(&ctx.regs, 0x0000);
/* the value of these registers seem to be assumed by pi_10.com */
r->esi = 0x100;
r->ecx = 0xff;
r->ebp = 0x0900;
r->edi = 0xfffe;
for(;;) {
ret = vm86(VM86_ENTER, &ctx);
switch(VM86_TYPE(ret)) {
case VM86_INTx:
{
int int_num, ah;
int_num = VM86_ARG(ret);
if (int_num != 0x21)
goto unknown_int;
ah = (r->eax >> 8) & 0xff;
switch(ah) {
case 0x00: /* exit */
exit(0);
case 0x02: /* write char */
{
uint8_t c = r->edx;
write(1, &c, 1);
}
break;
case 0x09: /* write string */
{
uint8_t c;
for(;;) {
c = *seg_to_linear(r->ds, r->edx);
if (c == '$')
break;
write(1, &c, 1);
}
r->eax = (r->eax & ~0xff) | '$';
}
break;
default:
unknown_int:
fprintf(stderr, "unsupported int 0x%02x\n", int_num);
dump_regs(&ctx.regs);
// exit(1);
}
}
break;
case VM86_SIGNAL:
/* a signal came, we just ignore that */
break;
case VM86_STI:
break;
default:
fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
dump_regs(&ctx.regs);
exit(1);
}
}
}

View File

@@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags)
void exec_op(int s2, int s0, int s1) void exec_op(int s2, int s0, int s1)
{ {
exec_opl(s2, s0, s1, 0); exec_opl(s2, s0, s1, 0);
#ifdef OP_SHIFTD
if (s1 <= 15)
exec_opw(s2, s0, s1, 0); exec_opw(s2, s0, s1, 0);
#else
exec_opw(s2, s0, s1, 0);
#endif
#ifndef OP_NOBYTE #ifndef OP_NOBYTE
exec_opb(s0, s1, 0); exec_opb(s0, s1, 0);
#endif #endif

View File

@@ -714,6 +714,10 @@ void test_segs(void)
long long ldt_table[3]; long long ldt_table[3];
int res, res2; int res, res2;
char tmp; char tmp;
struct {
uint32_t offset;
uint16_t seg;
} __attribute__((packed)) segoff;
ldt.entry_number = 1; ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1; ldt.base_addr = (unsigned long)&seg_data1;
@@ -772,6 +776,14 @@ void test_segs(void)
: "r" (MK_SEL(1)), "r" (&tmp)); : "r" (MK_SEL(1)), "r" (&tmp));
printf("DS[1] = %02x\n", res); printf("DS[1] = %02x\n", res);
printf("SS[tmp] = %02x\n", res2); printf("SS[tmp] = %02x\n", res2);
segoff.seg = MK_SEL(2);
segoff.offset = 0xabcdef12;
asm volatile("lfs %2, %0\n\t"
"movl %%fs, %1\n\t"
: "=r" (res), "=g" (res2)
: "m" (segoff));
printf("FS:reg = %04x:%08x\n", res2, res);
} }
/* 16 bit code test */ /* 16 bit code test */
@@ -812,6 +824,71 @@ void test_code16(void)
printf("func3() = 0x%08x\n", res); printf("func3() = 0x%08x\n", res);
} }
void test_misc(void)
{
char table[256];
int res, i;
for(i=0;i<256;i++) table[i] = 256 - i;
res = 0x12345678;
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
printf("xlat: EAX=%08x\n", res);
}
uint8_t str_buffer[4096];
#define TEST_STRING1(OP, size, DF, REP)\
{\
int esi, edi, eax, ecx, eflags;\
\
esi = (long)(str_buffer + sizeof(str_buffer) / 2);\
edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\
eax = 0x12345678;\
ecx = 17;\
\
asm volatile ("pushl $0\n\t"\
"popf\n\t"\
DF "\n\t"\
REP #OP size "\n\t"\
"cld\n\t"\
"pushf\n\t"\
"popl %4\n\t"\
: "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\
: "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\
printf("%-10s ESI=%08x EDI=%08x EAX=%08x ECX=%08x EFL=%04x\n",\
REP #OP size, esi, edi, eax, ecx,\
eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\
}
#define TEST_STRING(OP, REP)\
TEST_STRING1(OP, "b", "", REP);\
TEST_STRING1(OP, "w", "", REP);\
TEST_STRING1(OP, "l", "", REP);\
TEST_STRING1(OP, "b", "std", REP);\
TEST_STRING1(OP, "w", "std", REP);\
TEST_STRING1(OP, "l", "std", REP)
void test_string(void)
{
int i;
for(i = 0;i < sizeof(str_buffer); i++)
str_buffer[i] = i + 0x56;
TEST_STRING(stos, "");
TEST_STRING(stos, "rep ");
TEST_STRING(lods, ""); /* to verify stos */
TEST_STRING(lods, "rep ");
TEST_STRING(movs, "");
TEST_STRING(movs, "rep ");
TEST_STRING(lods, ""); /* to verify stos */
/* XXX: better tests */
TEST_STRING(scas, "");
TEST_STRING(scas, "repz ");
TEST_STRING(scas, "repnz ");
TEST_STRING(cmps, "");
TEST_STRING(cmps, "repz ");
TEST_STRING(cmps, "repnz ");
}
static void *call_end __init_call = NULL; static void *call_end __init_call = NULL;
@@ -831,6 +908,8 @@ int main(int argc, char **argv)
test_floats(); test_floats();
test_bcd(); test_bcd();
test_xchg(); test_xchg();
test_string();
test_misc();
test_lea(); test_lea();
test_segs(); test_segs();
test_code16(); test_code16();

152
tests/test_path.c Normal file
View File

@@ -0,0 +1,152 @@
/* Test path override code */
#define _GNU_SOURCE
#include "../path.c"
#include <stdarg.h>
#include <sys/stat.h>
#include <fcntl.h>
/* Any log message kills the test. */
void gemu_log(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "FATAL: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
#define NO_CHANGE(_path) \
do { \
if (strcmp(path(_path), _path) != 0) return __LINE__; \
} while(0)
#define CHANGE_TO(_path, _newpath) \
do { \
if (strcmp(path(_path), _newpath) != 0) return __LINE__; \
} while(0)
static void cleanup(void)
{
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5");
rmdir("/tmp/qemu-test_path/DIR1/DIR2");
rmdir("/tmp/qemu-test_path/DIR1/DIR3");
rmdir("/tmp/qemu-test_path/DIR1");
rmdir("/tmp/qemu-test_path");
}
static unsigned int do_test(void)
{
if (mkdir("/tmp/qemu-test_path", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0)
return __LINE__;
init_paths("/tmp/qemu-test_path");
NO_CHANGE("/tmp");
NO_CHANGE("/tmp/");
NO_CHANGE("/tmp/qemu-test_path");
NO_CHANGE("/tmp/qemu-test_path/");
NO_CHANGE("/tmp/qemu-test_path/D");
NO_CHANGE("/tmp/qemu-test_path/DI");
NO_CHANGE("/tmp/qemu-test_path/DIR");
NO_CHANGE("/tmp/qemu-test_path/DIR1");
NO_CHANGE("/tmp/qemu-test_path/DIR1/");
NO_CHANGE("/D");
NO_CHANGE("/DI");
NO_CHANGE("/DIR");
NO_CHANGE("/DIR2");
NO_CHANGE("/DIR1.");
CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1");
NO_CHANGE("/DIR1/D");
NO_CHANGE("/DIR1/DI");
NO_CHANGE("/DIR1/DIR");
NO_CHANGE("/DIR1/DIR1");
CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3");
CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3");
NO_CHANGE("/DIR1/DIR2/F");
NO_CHANGE("/DIR1/DIR2/FI");
NO_CHANGE("/DIR1/DIR2/FIL");
NO_CHANGE("/DIR1/DIR2/FIL.");
CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2");
CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3");
CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4");
CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5");
NO_CHANGE("/DIR1/DIR2/FILE6");
NO_CHANGE("/DIR1/DIR2/FILE/X");
CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
NO_CHANGE("/DIR1/DIR2/../DIR1");
NO_CHANGE("/DIR1/DIR2/../FILE");
CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
return 0;
}
int main(int argc, char *argv[])
{
int ret;
ret = do_test();
cleanup();
if (ret) {
fprintf(stderr, "test_path: failed on line %i\n", ret);
return 1;
}
return 0;
}

View File

@@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <inttypes.h> #include <inttypes.h>

View File

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

View File

@@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <inttypes.h> #include <inttypes.h>

View File

@@ -218,7 +218,7 @@ const argtype *thunk_convert(void *dst, const void *src,
case TYPE_LONG: case TYPE_LONG:
case TYPE_ULONG: case TYPE_ULONG:
case TYPE_PTRVOID: case TYPE_PTRVOID:
if (target_to_host) { if (to_host) {
*(uint64_t *)dst = tswap32(*(uint32_t *)src); *(uint64_t *)dst = tswap32(*(uint32_t *)src);
} else { } else {
*(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff); *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);

18
thunk.h
View File

@@ -94,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x)
return bswap_64(x); return bswap_64(x);
} }
static void inline bswap16s(uint16_t *s) static inline void bswap16s(uint16_t *s)
{ {
*s = bswap16(*s); *s = bswap16(*s);
} }
static void inline bswap32s(uint32_t *s) static inline void bswap32s(uint32_t *s)
{ {
*s = bswap32(*s); *s = bswap32(*s);
} }
static void inline bswap64s(uint64_t *s) static inline void bswap64s(uint64_t *s)
{ {
*s = bswap64(*s); *s = bswap64(*s);
} }
@@ -126,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s)
return bswap64(s); return bswap64(s);
} }
static void inline tswap16s(uint16_t *s) static inline void tswap16s(uint16_t *s)
{ {
*s = bswap16(*s); *s = bswap16(*s);
} }
static void inline tswap32s(uint32_t *s) static inline void tswap32s(uint32_t *s)
{ {
*s = bswap32(*s); *s = bswap32(*s);
} }
static void inline tswap64s(uint64_t *s) static inline void tswap64s(uint64_t *s)
{ {
*s = bswap64(*s); *s = bswap64(*s);
} }
@@ -158,15 +158,15 @@ static inline uint64_t tswap64(uint64_t s)
return s; return s;
} }
static void inline tswap16s(uint16_t *s) static inline void tswap16s(uint16_t *s)
{ {
} }
static void inline tswap32s(uint32_t *s) static inline void tswap32s(uint32_t *s)
{ {
} }
static void inline tswap64s(uint64_t *s) static inline void tswap64s(uint64_t *s)
{ {
} }

View File

@@ -50,6 +50,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
} }
#endif #endif
#ifdef __s390__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __powerpc__ #ifdef __powerpc__
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ #define MIN_CACHE_LINE_SIZE 8 /* conservative value */
@@ -76,21 +82,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop)
extern FILE *logfile; extern FILE *logfile;
extern int loglevel; extern int loglevel;
#define PREFIX_REPZ 1 #define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 2 #define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 4 #define PREFIX_LOCK 0x04
#define PREFIX_CS 8 #define PREFIX_DATA 0x08
#define PREFIX_SS 0x10 #define PREFIX_ADR 0x10
#define PREFIX_DS 0x20 #define PREFIX_FWAIT 0x20
#define PREFIX_ES 0x40
#define PREFIX_FS 0x80
#define PREFIX_GS 0x100
#define PREFIX_DATA 0x200
#define PREFIX_ADR 0x400
#define PREFIX_FWAIT 0x800
typedef struct DisasContext { typedef struct DisasContext {
/* current insn context */ /* current insn context */
int override; /* -1 if no override */
int prefix; int prefix;
int aflag, dflag; int aflag, dflag;
uint8_t *pc; /* pc = eip + cs_base */ uint8_t *pc; /* pc = eip + cs_base */
@@ -103,6 +104,7 @@ typedef struct DisasContext {
int cc_op; /* current CC operation */ int cc_op; /* current CC operation */
int addseg; /* non zero if either DS/ES/SS have a non zero base */ int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */ int f_st; /* currently unused */
int vm86; /* vm86 mode */
} DisasContext; } DisasContext;
/* i386 arith/logic operations */ /* i386 arith/logic operations */
@@ -130,7 +132,7 @@ enum {
}; };
enum { enum {
#define DEF(s) INDEX_op_ ## s, #define DEF(s, n) INDEX_op_ ## s,
#include "opc-i386.h" #include "opc-i386.h"
#undef DEF #undef DEF
NB_OPS, NB_OPS,
@@ -556,76 +558,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = {
gen_op_stl_T0_A0, gen_op_stl_T0_A0,
}; };
static GenOpFunc *gen_op_movs[6] = { /* the _a32 and _a16 string operations use A0 as the base register. */
gen_op_movsb,
gen_op_movsw, #define STRINGOP(x) \
gen_op_movsl, gen_op_ ## x ## b_fast, \
gen_op_rep_movsb, gen_op_ ## x ## w_fast, \
gen_op_rep_movsw, gen_op_ ## x ## l_fast, \
gen_op_rep_movsl, gen_op_ ## x ## b_a32, \
gen_op_ ## x ## w_a32, \
gen_op_ ## x ## l_a32, \
gen_op_ ## x ## b_a16, \
gen_op_ ## x ## w_a16, \
gen_op_ ## x ## l_a16,
static GenOpFunc *gen_op_movs[9 * 2] = {
STRINGOP(movs)
STRINGOP(rep_movs)
}; };
static GenOpFunc *gen_op_stos[6] = { static GenOpFunc *gen_op_stos[9 * 2] = {
gen_op_stosb, STRINGOP(stos)
gen_op_stosw, STRINGOP(rep_stos)
gen_op_stosl,
gen_op_rep_stosb,
gen_op_rep_stosw,
gen_op_rep_stosl,
}; };
static GenOpFunc *gen_op_lods[6] = { static GenOpFunc *gen_op_lods[9 * 2] = {
gen_op_lodsb, STRINGOP(lods)
gen_op_lodsw, STRINGOP(rep_lods)
gen_op_lodsl,
gen_op_rep_lodsb,
gen_op_rep_lodsw,
gen_op_rep_lodsl,
}; };
static GenOpFunc *gen_op_scas[9] = { static GenOpFunc *gen_op_scas[9 * 3] = {
gen_op_scasb, STRINGOP(scas)
gen_op_scasw, STRINGOP(repz_scas)
gen_op_scasl, STRINGOP(repnz_scas)
gen_op_repz_scasb,
gen_op_repz_scasw,
gen_op_repz_scasl,
gen_op_repnz_scasb,
gen_op_repnz_scasw,
gen_op_repnz_scasl,
}; };
static GenOpFunc *gen_op_cmps[9] = { static GenOpFunc *gen_op_cmps[9 * 3] = {
gen_op_cmpsb, STRINGOP(cmps)
gen_op_cmpsw, STRINGOP(repz_cmps)
gen_op_cmpsl, STRINGOP(repnz_cmps)
gen_op_repz_cmpsb,
gen_op_repz_cmpsw,
gen_op_repz_cmpsl,
gen_op_repnz_cmpsb,
gen_op_repnz_cmpsw,
gen_op_repnz_cmpsl,
}; };
static GenOpFunc *gen_op_ins[6] = { static GenOpFunc *gen_op_ins[9 * 2] = {
gen_op_insb, STRINGOP(ins)
gen_op_insw, STRINGOP(rep_ins)
gen_op_insl,
gen_op_rep_insb,
gen_op_rep_insw,
gen_op_rep_insl,
}; };
static GenOpFunc *gen_op_outs[6] = { static GenOpFunc *gen_op_outs[9 * 2] = {
gen_op_outsb, STRINGOP(outs)
gen_op_outsw, STRINGOP(rep_outs)
gen_op_outsl,
gen_op_rep_outsb,
gen_op_rep_outsw,
gen_op_rep_outsl,
}; };
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
{
int index, override;
override = s->override;
if (s->aflag) {
/* 32 bit address */
if (s->addseg && override < 0)
override = R_DS;
if (override >= 0) {
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
index = 3 + ot;
} else {
index = ot;
}
} else {
if (override < 0)
override = R_DS;
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
/* 16 address, always override */
index = 6 + ot;
}
func[index]();
}
static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func)
{
int index;
if (s->aflag) {
if (s->addseg) {
index = 3 + ot;
} else {
index = ot;
}
} else {
index = 6 + ot;
}
func[index]();
}
static GenOpFunc *gen_op_in[3] = { static GenOpFunc *gen_op_in[3] = {
gen_op_inb_T0_T1, gen_op_inb_T0_T1,
gen_op_inw_T0_T1, gen_op_inw_T0_T1,
@@ -849,26 +875,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
int opreg; int opreg;
int mod, rm, code, override, must_add_seg; int mod, rm, code, override, must_add_seg;
/* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ override = s->override;
override = -1;
must_add_seg = s->addseg; must_add_seg = s->addseg;
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | if (override >= 0)
PREFIX_ES | PREFIX_FS | PREFIX_GS)) {
if (s->prefix & PREFIX_ES)
override = R_ES;
else if (s->prefix & PREFIX_CS)
override = R_CS;
else if (s->prefix & PREFIX_SS)
override = R_SS;
else if (s->prefix & PREFIX_DS)
override = R_DS;
else if (s->prefix & PREFIX_FS)
override = R_FS;
else
override = R_GS;
must_add_seg = 1; must_add_seg = 1;
}
mod = (modrm >> 6) & 3; mod = (modrm >> 6) & 3;
rm = modrm & 7; rm = modrm & 7;
@@ -1343,7 +1353,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
prefixes = 0; prefixes = 0;
aflag = s->code32; aflag = s->code32;
dflag = s->code32; dflag = s->code32;
// cur_pc = s->pc; /* for insn generation */ s->override = -1;
next_byte: next_byte:
b = ldub(s->pc); b = ldub(s->pc);
s->pc++; s->pc++;
@@ -1359,22 +1369,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
prefixes |= PREFIX_LOCK; prefixes |= PREFIX_LOCK;
goto next_byte; goto next_byte;
case 0x2e: case 0x2e:
prefixes |= PREFIX_CS; s->override = R_CS;
goto next_byte; goto next_byte;
case 0x36: case 0x36:
prefixes |= PREFIX_SS; s->override = R_SS;
goto next_byte; goto next_byte;
case 0x3e: case 0x3e:
prefixes |= PREFIX_DS; s->override = R_DS;
goto next_byte; goto next_byte;
case 0x26: case 0x26:
prefixes |= PREFIX_ES; s->override = R_ES;
goto next_byte; goto next_byte;
case 0x64: case 0x64:
prefixes |= PREFIX_FS; s->override = R_FS;
goto next_byte; goto next_byte;
case 0x65: case 0x65:
prefixes |= PREFIX_GS; s->override = R_GS;
goto next_byte; goto next_byte;
case 0x66: case 0x66:
prefixes |= PREFIX_DATA; prefixes |= PREFIX_DATA;
@@ -1830,6 +1840,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} }
s->cc_op = CC_OP_SUBB + ot; s->cc_op = CC_OP_SUBB + ot;
break; break;
case 0x1c7: /* cmpxchg8b */
modrm = ldub(s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_cmpxchg8b();
s->cc_op = CC_OP_EFLAGS;
break;
/**************************/ /**************************/
/* push/pop */ /* push/pop */
@@ -1898,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break; break;
case 0x1a0: /* push fs */ case 0x1a0: /* push fs */
case 0x1a8: /* push gs */ case 0x1a8: /* push gs */
gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); gen_op_movl_T0_seg((b >> 3) & 7);
gen_push_T0(s); gen_push_T0(s);
break; break;
case 0x07: /* pop es */ case 0x07: /* pop es */
@@ -1911,7 +1932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x1a1: /* pop fs */ case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */ case 0x1a9: /* pop gs */
gen_pop_T0(s); gen_pop_T0(s);
gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); gen_movl_seg_T0(s, (b >> 3) & 7);
gen_pop_update(s); gen_pop_update(s);
break; break;
@@ -2027,8 +2048,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
modrm = ldub(s->pc++); modrm = ldub(s->pc++);
reg = (modrm >> 3) & 7; reg = (modrm >> 3) & 7;
/* we must ensure that no segment is added */ /* we must ensure that no segment is added */
s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | s->override = -1;
PREFIX_ES | PREFIX_FS | PREFIX_GS);
val = s->addseg; val = s->addseg;
s->addseg = 0; s->addseg = 0;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
@@ -2050,26 +2070,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
offset_addr = insn_get(s, OT_WORD); offset_addr = insn_get(s, OT_WORD);
gen_op_movl_A0_im(offset_addr); gen_op_movl_A0_im(offset_addr);
/* handle override */ /* handle override */
/* XXX: factorize that */
{ {
int override, must_add_seg; int override, must_add_seg;
override = R_DS;
must_add_seg = s->addseg; must_add_seg = s->addseg;
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | if (s->override >= 0) {
PREFIX_ES | PREFIX_FS | PREFIX_GS)) { override = s->override;
if (s->prefix & PREFIX_ES)
override = R_ES;
else if (s->prefix & PREFIX_CS)
override = R_CS;
else if (s->prefix & PREFIX_SS)
override = R_SS;
else if (s->prefix & PREFIX_DS)
override = R_DS;
else if (s->prefix & PREFIX_FS)
override = R_FS;
else
override = R_GS;
must_add_seg = 1; must_add_seg = 1;
} else {
override = R_DS;
} }
if (must_add_seg) { if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
@@ -2083,7 +2091,29 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_st_T0_A0[ot](); gen_op_st_T0_A0[ot]();
} }
break; break;
case 0xd7: /* xlat */
gen_op_movl_A0_reg[R_EBX]();
gen_op_addl_A0_AL();
if (s->aflag == 0)
gen_op_andl_A0_ffff();
/* handle override */
{
int override, must_add_seg;
must_add_seg = s->addseg;
override = R_DS;
if (s->override >= 0) {
override = s->override;
must_add_seg = 1;
} else {
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
}
}
gen_op_ldub_T0_A0();
gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
break;
case 0xb0 ... 0xb7: /* mov R, Ib */ case 0xb0 ... 0xb7: /* mov R, Ib */
val = insn_get(s, OT_BYTE); val = insn_get(s, OT_BYTE);
gen_op_movl_T0_im(val); gen_op_movl_T0_im(val);
@@ -2121,8 +2151,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} else { } else {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_mov_TN_reg[ot][0][reg](); gen_op_mov_TN_reg[ot][0][reg]();
/* for xchg, lock is implicit */
if (!(prefixes & PREFIX_LOCK))
gen_op_lock();
gen_op_ld_T1_A0[ot](); gen_op_ld_T1_A0[ot]();
gen_op_st_T0_A0[ot](); gen_op_st_T0_A0[ot]();
if (!(prefixes & PREFIX_LOCK))
gen_op_unlock();
gen_op_mov_reg_T1[ot][reg](); gen_op_mov_reg_T1[ot][reg]();
} }
break; break;
@@ -2147,6 +2182,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
mod = (modrm >> 6) & 3; mod = (modrm >> 6) & 3;
if (mod == 3) if (mod == 3)
goto illegal_op; goto illegal_op;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_ld_T1_A0[ot](); gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
/* load the segment first to handle exceptions properly */ /* load the segment first to handle exceptions properly */
@@ -2620,16 +2656,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break; break;
/************************/ /************************/
/* string ops */ /* string ops */
case 0xa4: /* movsS */ case 0xa4: /* movsS */
case 0xa5: case 0xa5:
if ((b & 1) == 0) if ((b & 1) == 0)
ot = OT_BYTE; ot = OT_BYTE;
else else
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) { if (prefixes & PREFIX_REPZ) {
gen_op_movs[3 + ot](); gen_string_ds(s, ot, gen_op_movs + 9);
} else { } else {
gen_op_movs[ot](); gen_string_ds(s, ot, gen_op_movs);
} }
break; break;
@@ -2639,10 +2677,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
ot = OT_BYTE; ot = OT_BYTE;
else else
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) { if (prefixes & PREFIX_REPZ) {
gen_op_stos[3 + ot](); gen_string_es(s, ot, gen_op_stos + 9);
} else { } else {
gen_op_stos[ot](); gen_string_es(s, ot, gen_op_stos);
} }
break; break;
case 0xac: /* lodsS */ case 0xac: /* lodsS */
@@ -2652,9 +2691,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else else
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) { if (prefixes & PREFIX_REPZ) {
gen_op_lods[3 + ot](); gen_string_ds(s, ot, gen_op_lods + 9);
} else { } else {
gen_op_lods[ot](); gen_string_ds(s, ot, gen_op_lods);
} }
break; break;
case 0xae: /* scasS */ case 0xae: /* scasS */
@@ -2666,15 +2705,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if (prefixes & PREFIX_REPNZ) { if (prefixes & PREFIX_REPNZ) {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_scas[6 + ot](); gen_string_es(s, ot, gen_op_scas + 9 * 2);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else if (prefixes & PREFIX_REPZ) { } else if (prefixes & PREFIX_REPZ) {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_scas[3 + ot](); gen_string_es(s, ot, gen_op_scas + 9);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else { } else {
gen_op_scas[ot](); gen_string_es(s, ot, gen_op_scas);
s->cc_op = CC_OP_SUBB + ot; s->cc_op = CC_OP_SUBB + ot;
} }
break; break;
@@ -2688,21 +2727,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if (prefixes & PREFIX_REPNZ) { if (prefixes & PREFIX_REPNZ) {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_cmps[6 + ot](); gen_string_ds(s, ot, gen_op_cmps + 9 * 2);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else if (prefixes & PREFIX_REPZ) { } else if (prefixes & PREFIX_REPZ) {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_cmps[3 + ot](); gen_string_ds(s, ot, gen_op_cmps + 9);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else { } else {
gen_op_cmps[ot](); gen_string_ds(s, ot, gen_op_cmps);
s->cc_op = CC_OP_SUBB + ot; s->cc_op = CC_OP_SUBB + ot;
} }
break; break;
/************************/
/* port I/O */
case 0x6c: /* insS */ case 0x6c: /* insS */
case 0x6d: case 0x6d:
if ((b & 1) == 0) if ((b & 1) == 0)
@@ -2710,9 +2746,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else else
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) { if (prefixes & PREFIX_REPZ) {
gen_op_ins[3 + ot](); gen_string_es(s, ot, gen_op_ins + 9);
} else { } else {
gen_op_ins[ot](); gen_string_es(s, ot, gen_op_ins);
} }
break; break;
case 0x6e: /* outsS */ case 0x6e: /* outsS */
@@ -2722,11 +2758,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else else
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) { if (prefixes & PREFIX_REPZ) {
gen_op_outs[3 + ot](); gen_string_ds(s, ot, gen_op_outs + 9);
} else { } else {
gen_op_outs[ot](); gen_string_ds(s, ot, gen_op_outs);
} }
break; break;
/************************/
/* port I/O */
case 0xe4: case 0xe4:
case 0xe5: case 0xe5:
if ((b & 1) == 0) if ((b & 1) == 0)
@@ -2794,6 +2833,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xca: /* lret im */ case 0xca: /* lret im */
/* XXX: not restartable */
val = ldsw(s->pc); val = ldsw(s->pc);
s->pc += 2; s->pc += 2;
/* pop offset */ /* pop offset */
@@ -2814,6 +2854,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xcb: /* lret */ case 0xcb: /* lret */
/* XXX: not restartable */
/* pop offset */ /* pop offset */
gen_pop_T0(s); gen_pop_T0(s);
if (s->dflag == 0) if (s->dflag == 0)
@@ -2826,6 +2867,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_pop_update(s); gen_pop_update(s);
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xcf: /* iret */
/* XXX: not restartable */
/* pop offset */
gen_pop_T0(s);
if (s->dflag == 0)
gen_op_andl_T0_ffff();
gen_op_jmp_T0();
gen_pop_update(s);
/* pop selector */
gen_pop_T0(s);
gen_movl_seg_T0(s, R_CS);
gen_pop_update(s);
/* pop eflags */
gen_pop_T0(s);
if (s->dflag) {
if (s->vm86)
gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
else
gen_op_movl_eflags_T0();
} else {
if (s->vm86)
gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
else
gen_op_movw_eflags_T0();
}
gen_pop_update(s);
s->cc_op = CC_OP_EFLAGS;
s->is_jmp = 1;
break;
case 0xe8: /* call im */ case 0xe8: /* call im */
{ {
unsigned int next_eip; unsigned int next_eip;
@@ -2939,12 +3009,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x9c: /* pushf */ case 0x9c: /* pushf */
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
if (s->vm86)
gen_op_movl_T0_eflags_vm();
else
gen_op_movl_T0_eflags(); gen_op_movl_T0_eflags();
gen_push_T0(s); gen_push_T0(s);
break; break;
case 0x9d: /* popf */ case 0x9d: /* popf */
gen_pop_T0(s); gen_pop_T0(s);
if (s->dflag) {
if (s->vm86)
gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
else
gen_op_movl_eflags_T0(); gen_op_movl_eflags_T0();
} else {
if (s->vm86)
gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
else
gen_op_movw_eflags_T0();
}
gen_pop_update(s); gen_pop_update(s);
s->cc_op = CC_OP_EFLAGS; s->cc_op = CC_OP_EFLAGS;
break; break;
@@ -3112,14 +3195,39 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0xcd: /* int N */ case 0xcd: /* int N */
val = ldub(s->pc++); val = ldub(s->pc++);
/* XXX: currently we ignore the interrupt number */ /* XXX: currently we ignore the interrupt number */
gen_op_int_im((long)pc_start); gen_op_int_im(pc_start - s->cs_base);
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xce: /* into */ case 0xce: /* into */
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_into((long)pc_start, (long)s->pc); gen_op_into();
s->is_jmp = 1; break;
case 0xfa: /* cli */
if (s->vm86)
gen_op_cli_vm();
else
gen_op_cli();
break;
case 0xfb: /* sti */
if (s->vm86)
gen_op_sti_vm(pc_start - s->cs_base);
else
gen_op_sti();
break;
case 0x62: /* bound */
ot = dflag ? OT_LONG : OT_WORD;
modrm = ldub(s->pc++);
reg = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
gen_op_mov_reg_T0[ot][reg]();
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
if (ot == OT_WORD)
gen_op_boundw();
else
gen_op_boundl();
break; break;
case 0x1c8 ... 0x1cf: /* bswap reg */ case 0x1c8 ... 0x1cf: /* bswap reg */
reg = b & 7; reg = b & 7;
@@ -3150,11 +3258,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x131: /* rdtsc */ case 0x131: /* rdtsc */
gen_op_rdtsc(); gen_op_rdtsc();
break; break;
#if 0
case 0x1a2: /* cpuid */ case 0x1a2: /* cpuid */
gen_insn0(OP_ASM); gen_op_cpuid();
break; break;
#endif
default: default:
goto illegal_op; goto illegal_op;
} }
@@ -3258,6 +3364,7 @@ static uint16_t opc_read_flags[NB_OPS] = {
[INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
[INDEX_op_movl_T0_eflags] = CC_OSZAPC, [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
[INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
[INDEX_op_cmc] = CC_C, [INDEX_op_cmc] = CC_C,
[INDEX_op_salc] = CC_C, [INDEX_op_salc] = CC_C,
@@ -3306,7 +3413,10 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_daa] = CC_OSZAPC, [INDEX_op_daa] = CC_OSZAPC,
[INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
[INDEX_op_movw_eflags_T0] = CC_OSZAPC,
[INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_movl_eflags_T0] = CC_OSZAPC, [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
[INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_clc] = CC_C, [INDEX_op_clc] = CC_C,
[INDEX_op_stc] = CC_C, [INDEX_op_stc] = CC_C,
[INDEX_op_cmc] = CC_C, [INDEX_op_cmc] = CC_C,
@@ -3361,28 +3471,30 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC, [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC, [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
[INDEX_op_scasb] = CC_OSZAPC, #undef STRINGOP
[INDEX_op_scasw] = CC_OSZAPC, #define STRINGOP(x) \
[INDEX_op_scasl] = CC_OSZAPC, [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \
[INDEX_op_repz_scasb] = CC_OSZAPC, [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \
[INDEX_op_repz_scasw] = CC_OSZAPC, [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \
[INDEX_op_repz_scasl] = CC_OSZAPC, [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \
[INDEX_op_repnz_scasb] = CC_OSZAPC, [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \
[INDEX_op_repnz_scasw] = CC_OSZAPC, [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \
[INDEX_op_repnz_scasl] = CC_OSZAPC, [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC,
[INDEX_op_cmpsb] = CC_OSZAPC, STRINGOP(scas)
[INDEX_op_cmpsw] = CC_OSZAPC, STRINGOP(repz_scas)
[INDEX_op_cmpsl] = CC_OSZAPC, STRINGOP(repnz_scas)
[INDEX_op_repz_cmpsb] = CC_OSZAPC, STRINGOP(cmps)
[INDEX_op_repz_cmpsw] = CC_OSZAPC, STRINGOP(repz_cmps)
[INDEX_op_repz_cmpsl] = CC_OSZAPC, STRINGOP(repnz_cmps)
[INDEX_op_repnz_cmpsb] = CC_OSZAPC,
[INDEX_op_repnz_cmpsw] = CC_OSZAPC,
[INDEX_op_repnz_cmpsl] = CC_OSZAPC,
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchg8b] = CC_Z,
}; };
/* simpler form of an operation if no flags need to be generated */ /* simpler form of an operation if no flags need to be generated */
@@ -3457,21 +3569,36 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
static const char *op_str[] = { static const char *op_str[] = {
#define DEF(s) #s, #define DEF(s, n) #s,
#include "opc-i386.h" #include "opc-i386.h"
#undef DEF #undef DEF
}; };
static void dump_ops(const uint16_t *opc_buf) static uint8_t op_nb_args[] = {
#define DEF(s, n) n,
#include "opc-i386.h"
#undef DEF
};
static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
{ {
const uint16_t *opc_ptr; const uint16_t *opc_ptr;
int c; const uint32_t *opparam_ptr;
int c, n, i;
opc_ptr = opc_buf; opc_ptr = opc_buf;
opparam_ptr = opparam_buf;
for(;;) { for(;;) {
c = *opc_ptr++; c = *opc_ptr++;
fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]); n = op_nb_args[c];
fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]);
for(i = 0; i < n; i++) {
fprintf(logfile, " 0x%x", opparam_ptr[i]);
}
fprintf(logfile, "\n");
if (c == INDEX_op_end) if (c == INDEX_op_end)
break; break;
opparam_ptr += n;
} }
} }
@@ -3509,6 +3636,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC; dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base; dc->cs_base = cs_base;
@@ -3572,7 +3700,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
fprintf(logfile, "\n"); fprintf(logfile, "\n");
fprintf(logfile, "OP:\n"); fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf); dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n"); fprintf(logfile, "\n");
} }
#endif #endif
@@ -3583,7 +3711,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
if (loglevel) { if (loglevel) {
fprintf(logfile, "AFTER FLAGS OPT:\n"); fprintf(logfile, "AFTER FLAGS OPT:\n");
dump_ops(gen_opc_buf); dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n"); fprintf(logfile, "\n");
} }
#endif #endif
@@ -3645,8 +3773,8 @@ CPUX86State *cpu_x86_init(void)
for(i = 0;i < 8; i++) for(i = 0;i < 8; i++)
env->fptags[i] = 1; env->fptags[i] = 1;
env->fpuc = 0x37f; env->fpuc = 0x37f;
/* flags setup */ /* flags setup : we activate the IRQs by default as in user mode */
env->eflags = 0; env->eflags = 0x2 | IF_MASK;
/* init various static tables */ /* init various static tables */
if (!inited) { if (!inited) {