Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1eb87257da | ||
|
32ce63371a | ||
|
ec86b0fb3a | ||
|
1d346ae63a | ||
|
74cd30b811 | ||
|
7fb9a24e39 | ||
|
afeb6ee377 | ||
|
f29042b531 | ||
|
09bfb054fb | ||
|
2677e107e6 | ||
|
66cd58461d | ||
|
bb0ebb1f2d | ||
|
27c75a9a90 | ||
|
d0cd3b8d84 | ||
|
9af9eaaa76 | ||
|
8c8f42f76c | ||
|
51fe68905b | ||
|
7fe70ecc56 | ||
|
d03cda5923 | ||
|
30ac07d4f0 | ||
|
8857052055 | ||
|
ce11fedc6e | ||
|
43d4145a98 | ||
|
295defa5f1 | ||
|
f801f97e04 | ||
|
f48c3dd51a | ||
|
62296fe351 | ||
|
32f36bcefc | ||
|
bc8a22cc30 | ||
|
f631ef9bd2 | ||
|
f7341ff400 |
51
Changelog
51
Changelog
@@ -1,8 +1,59 @@
|
||||
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:
|
||||
|
||||
|
26
Makefile
26
Makefile
@@ -13,14 +13,20 @@ OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
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
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,ppc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
@@ -31,7 +37,6 @@ endif
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LDSCRIPT=$(ARCH).ld
|
||||
LIBS+=-lm
|
||||
|
||||
# profiling code
|
||||
@@ -40,7 +45,7 @@ LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
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)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
@@ -51,7 +56,7 @@ LIBOBJS+=i386-dis.o dis-buf.o
|
||||
all: qemu qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
@@ -100,18 +105,19 @@ qemu-doc.html: qemu-doc.texi
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
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\
|
||||
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\
|
||||
i386.ld ppc.ld s390.ld exec-i386.h exec-i386.c configure \
|
||||
ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \
|
||||
tests/Makefile\
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S\
|
||||
tests/hello.c tests/hello tests/sha1.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
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
@@ -127,10 +133,10 @@ tar:
|
||||
BINPATH=/usr/local/qemu-i386
|
||||
|
||||
tarbin:
|
||||
tar zcvf /tmp/qemu-i386-glibc21.tar.gz \
|
||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin
|
||||
tar zcvf /tmp/qemu-i386-wine.tar.gz \
|
||||
$(BINPATH)/X11R6 $(BINPATH)/wine
|
||||
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),)
|
||||
include .depend
|
||||
|
4
README
4
README
@@ -6,7 +6,7 @@ INSTALLATION
|
||||
|
||||
Type
|
||||
|
||||
./configure
|
||||
./configure --interp-prefix=/usr/local/qemu-i386
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
@@ -23,7 +23,7 @@ libraries installed on your PC. For example:
|
||||
./qemu -L / /bin/ls
|
||||
|
||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
LD_LIBRARY_PATH is not set:
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
|
10
TODO
10
TODO
@@ -1,10 +1,12 @@
|
||||
- fix thread locks
|
||||
- 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
|
||||
issues, fix 16 bit uid issues)
|
||||
- finish signal handing (fp87 state, more siginfo conversions)
|
||||
- verify thread support (clone() and various locks)
|
||||
- vm86 syscall support
|
||||
- overrides/16bit for string ops
|
||||
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
|
||||
- improved 16 bit support
|
||||
- make it self runnable (handle self modifying code, relocate stack
|
||||
and dyn loader)
|
||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
|
||||
|
19
configure
vendored
19
configure
vendored
@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
@@ -36,7 +37,7 @@ case "$cpu" in
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
;;
|
||||
"Power Macintosh"|ppc)
|
||||
"Power Macintosh"|ppc|ppc64)
|
||||
cpu="powerpc"
|
||||
;;
|
||||
mips)
|
||||
@@ -89,6 +90,8 @@ for opt do
|
||||
case "$opt" in
|
||||
--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`
|
||||
;;
|
||||
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
@@ -172,7 +175,7 @@ EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
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 "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -198,7 +201,7 @@ echo "# Automatically generated by configure - do not modify" > config.mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||
|
||||
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 "CC=$cc" >> config.mak
|
||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||
@@ -209,14 +212,22 @@ echo "CFLAGS=$CFLAGS" >> config.mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
echo "#define HOST_ARM 1" >> $TMPH
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> config.mak
|
||||
echo "#define HOST_PPC 1" >> $TMPH
|
||||
elif test "$cpu" = "mips" ; then
|
||||
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
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
@@ -260,4 +271,4 @@ else
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPH
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
|
36
cpu-i386.h
36
cpu-i386.h
@@ -68,24 +68,24 @@
|
||||
#define VIP_MASK 0x00100000
|
||||
#define ID_MASK 0x00200000
|
||||
|
||||
#define EXCP00_DIVZ 1
|
||||
#define EXCP01_SSTP 2
|
||||
#define EXCP02_NMI 3
|
||||
#define EXCP03_INT3 4
|
||||
#define EXCP04_INTO 5
|
||||
#define EXCP05_BOUND 6
|
||||
#define EXCP06_ILLOP 7
|
||||
#define EXCP07_PREX 8
|
||||
#define EXCP08_DBLE 9
|
||||
#define EXCP09_XERR 10
|
||||
#define EXCP0A_TSS 11
|
||||
#define EXCP0B_NOSEG 12
|
||||
#define EXCP0C_STACK 13
|
||||
#define EXCP0D_GPF 14
|
||||
#define EXCP0E_PAGE 15
|
||||
#define EXCP10_COPR 17
|
||||
#define EXCP11_ALGN 18
|
||||
#define EXCP12_MCHK 19
|
||||
#define EXCP00_DIVZ 0
|
||||
#define EXCP01_SSTP 1
|
||||
#define EXCP02_NMI 2
|
||||
#define EXCP03_INT3 3
|
||||
#define EXCP04_INTO 4
|
||||
#define EXCP05_BOUND 5
|
||||
#define EXCP06_ILLOP 6
|
||||
#define EXCP07_PREX 7
|
||||
#define EXCP08_DBLE 8
|
||||
#define EXCP09_XERR 9
|
||||
#define EXCP0A_TSS 10
|
||||
#define EXCP0B_NOSEG 11
|
||||
#define EXCP0C_STACK 12
|
||||
#define EXCP0D_GPF 13
|
||||
#define EXCP0E_PAGE 14
|
||||
#define EXCP10_COPR 16
|
||||
#define EXCP11_ALGN 17
|
||||
#define EXCP12_MCHK 18
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
|
||||
|
149
dis-asm.h
149
dis-asm.h
@@ -11,7 +11,152 @@
|
||||
|
||||
#include <stdio.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*, ...));
|
||||
|
||||
@@ -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_tic30 PARAMS ((bfd_vma, disassemble_info*));
|
||||
|
||||
#if 0
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
extern disassembler_ftype disassembler PARAMS ((bfd *));
|
||||
#endif
|
||||
|
||||
|
||||
/* This block of definitions is for particular callers who read instructions
|
||||
|
269
dyngen.c
269
dyngen.c
@@ -22,25 +22,62 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <elf.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "thunk.h"
|
||||
#include "config.h"
|
||||
|
||||
/* temporary fix to make it compile with old elf headers (XXX: use
|
||||
included elf.h in all cases) */
|
||||
#ifndef EM_390
|
||||
#define EM_S390 22 /* IBM S390 */
|
||||
#define R_390_8 1 /* Direct 8 bit. */
|
||||
#define R_390_16 3 /* Direct 16 bit. */
|
||||
#define R_390_32 4 /* Direct 32 bit. */
|
||||
/* 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"
|
||||
|
||||
/* all dynamically generated functions begin with this code */
|
||||
#define OP_PREFIX "op_"
|
||||
|
||||
int elf_must_swap(Elf32_Ehdr *h)
|
||||
int elf_must_swap(struct elfhdr *h)
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
@@ -62,19 +99,25 @@ void swab32s(uint32_t *p)
|
||||
*p = bswap32(*p);
|
||||
}
|
||||
|
||||
void swab64s(uint32_t *p)
|
||||
void swab64s(uint64_t *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_machine); /* Architecture */
|
||||
swab32s(&h-> e_version); /* Object file version */
|
||||
swab32s(&h-> e_entry); /* Entry point virtual address */
|
||||
swab32s(&h-> e_phoff); /* Program header table file offset */
|
||||
swab32s(&h-> e_shoff); /* Section header table file offset */
|
||||
swabls(&h-> e_entry); /* Entry point virtual address */
|
||||
swabls(&h-> e_phoff); /* Program header table file offset */
|
||||
swabls(&h-> e_shoff); /* Section header table file offset */
|
||||
swab32s(&h-> e_flags); /* Processor-specific flags */
|
||||
swab16s(&h-> e_ehsize); /* ELF header size in bytes */
|
||||
swab16s(&h-> e_phentsize); /* Program header table entry size */
|
||||
@@ -84,34 +127,33 @@ void elf_swap_ehdr(Elf32_Ehdr *h)
|
||||
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_type); /* Section type */
|
||||
swab32s(&h-> sh_flags); /* Section flags */
|
||||
swab32s(&h-> sh_addr); /* Section virtual addr at execution */
|
||||
swab32s(&h-> sh_offset); /* Section file offset */
|
||||
swab32s(&h-> sh_size); /* Section size in bytes */
|
||||
swabls(&h-> sh_flags); /* Section flags */
|
||||
swabls(&h-> sh_addr); /* Section virtual addr at execution */
|
||||
swabls(&h-> sh_offset); /* Section file offset */
|
||||
swabls(&h-> sh_size); /* Section size in bytes */
|
||||
swab32s(&h-> sh_link); /* Link to another section */
|
||||
swab32s(&h-> sh_info); /* Additional section information */
|
||||
swab32s(&h-> sh_addralign); /* Section alignment */
|
||||
swab32s(&h-> sh_entsize); /* Entry size if section holds table */
|
||||
swabls(&h-> sh_addralign); /* Section alignment */
|
||||
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_offset); /* Segment file offset */
|
||||
swab32s(&h->p_vaddr); /* Segment virtual address */
|
||||
swab32s(&h->p_paddr); /* Segment physical address */
|
||||
swab32s(&h->p_filesz); /* Segment size in file */
|
||||
swab32s(&h->p_memsz); /* Segment size in memory */
|
||||
swabls(&h->p_offset); /* Segment file offset */
|
||||
swabls(&h->p_vaddr); /* Segment virtual address */
|
||||
swabls(&h->p_paddr); /* Segment physical address */
|
||||
swabls(&h->p_filesz); /* Segment size in file */
|
||||
swabls(&h->p_memsz); /* Segment size in memory */
|
||||
swab32s(&h->p_flags); /* Segment flags */
|
||||
swab32s(&h->p_align); /* Segment alignment */
|
||||
swabls(&h->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
int do_swap;
|
||||
int e_machine;
|
||||
|
||||
uint16_t get16(uint16_t *p)
|
||||
{
|
||||
@@ -157,12 +199,12 @@ void __attribute__((noreturn)) error(const char *fmt, ...)
|
||||
}
|
||||
|
||||
|
||||
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr,
|
||||
const char *name)
|
||||
struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
const char *shname;
|
||||
Elf32_Shdr *sec;
|
||||
struct elf_shdr *sec;
|
||||
|
||||
for(i = 0; i < shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
@@ -209,20 +251,21 @@ int strstart(const char *str, const char *val, const char **ptr)
|
||||
#define MAX_ARGS 3
|
||||
|
||||
/* generate op code */
|
||||
void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type,
|
||||
Elf32_Sym *symtab, char *strtab, int gen_switch)
|
||||
void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
|
||||
ElfW(Sym) *symtab, char *strtab, int gen_switch)
|
||||
{
|
||||
int copy_size = 0;
|
||||
uint8_t *p_start, *p_end;
|
||||
int nb_args, i;
|
||||
int nb_args, i, n;
|
||||
uint8_t args_present[MAX_ARGS];
|
||||
const char *sym_name, *p;
|
||||
ELF_RELOC *rel;
|
||||
|
||||
/* compute exact size excluding return instruction */
|
||||
p_start = text + offset;
|
||||
p_end = p_start + size;
|
||||
switch(e_machine) {
|
||||
switch(ELF_ARCH) {
|
||||
case EM_386:
|
||||
{
|
||||
uint8_t *p;
|
||||
@@ -256,40 +299,20 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unsupported CPU (%d)", e_machine);
|
||||
}
|
||||
|
||||
/* compute the number of arguments by looking at the relocations */
|
||||
for(i = 0;i < MAX_ARGS; i++)
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
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[ELFW(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,24 +342,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
}
|
||||
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++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,13 +357,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
}
|
||||
|
||||
/* patch relocations */
|
||||
switch(e_machine) {
|
||||
case EM_386:
|
||||
#if defined(HOST_I386)
|
||||
{
|
||||
Elf32_Rel *rel;
|
||||
char name[256];
|
||||
int type;
|
||||
long addend;
|
||||
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;
|
||||
@@ -366,11 +374,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
addend = get32((uint32_t *)(text + rel->r_offset));
|
||||
switch(type) {
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
@@ -379,13 +387,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EM_PPC:
|
||||
#elif defined(HOST_PPC)
|
||||
{
|
||||
Elf32_Rela *rel;
|
||||
char name[256];
|
||||
int type;
|
||||
long addend;
|
||||
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;
|
||||
@@ -398,24 +404,24 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
case R_PPC_REL24:
|
||||
/* 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);
|
||||
break;
|
||||
default:
|
||||
@@ -424,13 +430,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EM_S390:
|
||||
#elif defined(HOST_S390)
|
||||
{
|
||||
Elf32_Rela *rel;
|
||||
char name[256];
|
||||
int type;
|
||||
long addend;
|
||||
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;
|
||||
@@ -443,15 +447,15 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
case R_390_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);
|
||||
break;
|
||||
case R_390_16:
|
||||
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);
|
||||
break;
|
||||
case R_390_8:
|
||||
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
|
||||
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
break;
|
||||
default:
|
||||
@@ -460,10 +464,9 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unsupported CPU for relocations (%d)", e_machine);
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
|
||||
fprintf(outfile, "}\n");
|
||||
fprintf(outfile, "break;\n\n");
|
||||
@@ -492,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 fd;
|
||||
Elf32_Ehdr ehdr;
|
||||
Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
|
||||
struct elfhdr ehdr;
|
||||
struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
|
||||
int i, j, nb_syms;
|
||||
Elf32_Sym *symtab, *sym;
|
||||
const char *cpu_name;
|
||||
ElfW(Sym) *symtab, *sym;
|
||||
char *shstr, *strtab;
|
||||
uint8_t *text;
|
||||
void *relocs;
|
||||
@@ -515,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_MAG2] != ELFMAG2
|
||||
|| ehdr.e_ident[EI_MAG3] != ELFMAG3
|
||||
|| ehdr.e_ident[EI_CLASS] != ELFCLASS32
|
||||
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
error("bad ELF header");
|
||||
}
|
||||
@@ -523,14 +524,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
do_swap = elf_must_swap(&ehdr);
|
||||
if (do_swap)
|
||||
elf_swap_ehdr(&ehdr);
|
||||
if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
|
||||
error("Unsupported ELF class");
|
||||
if (ehdr.e_type != ET_REL)
|
||||
error("ELF object file expected");
|
||||
if (ehdr.e_version != EV_CURRENT)
|
||||
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 */
|
||||
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) {
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
elf_swap_shdr(&shdr[i]);
|
||||
@@ -590,35 +594,12 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
if (do_swap) {
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
swab32s(&sym->st_name);
|
||||
swab32s(&sym->st_value);
|
||||
swab32s(&sym->st_size);
|
||||
swabls(&sym->st_value);
|
||||
swabls(&sym->st_size);
|
||||
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;
|
||||
case EM_S390:
|
||||
cpu_name = "s390";
|
||||
break;
|
||||
default:
|
||||
error("unsupported CPU (e_machine=%d)", e_machine);
|
||||
}
|
||||
|
||||
if (do_print_enum) {
|
||||
fprintf(outfile, "DEF(end, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
@@ -669,7 +650,7 @@ fprintf(outfile,
|
||||
);
|
||||
|
||||
/* generate a return */
|
||||
switch(e_machine) {
|
||||
switch(ELF_ARCH) {
|
||||
case EM_386:
|
||||
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
|
||||
break;
|
||||
@@ -679,8 +660,6 @@ fprintf(outfile,
|
||||
case EM_S390:
|
||||
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
|
||||
break;
|
||||
default:
|
||||
error("no return generation for cpu '%s'", cpu_name);
|
||||
}
|
||||
|
||||
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
|
||||
|
809
elf.h
809
elf.h
@@ -1,47 +1,25 @@
|
||||
/*
|
||||
* ELF register definitions..
|
||||
*/
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
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
|
||||
|
||||
|
||||
typedef uint32_t Elf32_Addr;
|
||||
/* 32-bit ELF base types. */
|
||||
typedef uint32_t Elf32_Addr;
|
||||
typedef uint16_t Elf32_Half;
|
||||
typedef uint32_t Elf32_Off;
|
||||
typedef int32_t Elf32_Sword;
|
||||
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 */
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
@@ -52,6 +30,13 @@ typedef uint32_t Elf32_Word;
|
||||
#define PT_PHDR 6
|
||||
#define PT_LOPROC 0x70000000
|
||||
#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 */
|
||||
#define ET_NONE 0
|
||||
@@ -59,8 +44,8 @@ typedef uint32_t Elf32_Word;
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
#define ET_LOPROC 5
|
||||
#define ET_HIPROC 6
|
||||
#define ET_LOPROC 0xff00
|
||||
#define ET_HIPROC 0xffff
|
||||
|
||||
/* These constants define the various ELF target machines */
|
||||
#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_SPARC64 11 /* SPARC v9 (not official) 64-bit */
|
||||
|
||||
#define EM_PARISC 15 /* HPPA */
|
||||
|
||||
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
|
||||
|
||||
#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
|
||||
@@ -90,6 +93,13 @@ typedef uint32_t Elf32_Word;
|
||||
*/
|
||||
#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 */
|
||||
#define DT_NULL 0
|
||||
@@ -118,6 +128,25 @@ typedef uint32_t Elf32_Word;
|
||||
#define DT_JMPREL 23
|
||||
#define DT_LOPROC 0x70000000
|
||||
#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 */
|
||||
#define STB_LOCAL 0
|
||||
@@ -130,8 +159,12 @@ typedef uint32_t Elf32_Word;
|
||||
#define STT_SECTION 3
|
||||
#define STT_FILE 4
|
||||
|
||||
#define ELF32_ST_BIND(x) ((x) >> 4)
|
||||
#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
|
||||
#define ELF_ST_BIND(x) ((x) >> 4)
|
||||
#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
|
||||
put on the initial stack */
|
||||
@@ -150,7 +183,9 @@ typedef uint32_t Elf32_Word;
|
||||
#define AT_EUID 12 /* effective uid */
|
||||
#define AT_GID 13 /* real 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{
|
||||
Elf32_Sword d_tag;
|
||||
@@ -161,10 +196,10 @@ typedef struct dynamic{
|
||||
} Elf32_Dyn;
|
||||
|
||||
typedef struct {
|
||||
unsigned long long d_tag; /* entry tag value */
|
||||
Elf64_Sxword d_tag; /* entry tag value */
|
||||
union {
|
||||
unsigned long long d_val;
|
||||
unsigned long long d_ptr;
|
||||
Elf64_Xword d_val;
|
||||
Elf64_Addr d_ptr;
|
||||
} d_un;
|
||||
} Elf64_Dyn;
|
||||
|
||||
@@ -172,6 +207,9 @@ typedef struct {
|
||||
#define ELF32_R_SYM(x) ((x) >> 8)
|
||||
#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_32 1
|
||||
#define R_386_PC32 2
|
||||
@@ -185,14 +223,559 @@ typedef struct {
|
||||
#define R_386_GOTPC 10
|
||||
#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 {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
} Elf32_Rel;
|
||||
|
||||
typedef struct elf64_rel {
|
||||
unsigned long long r_offset; /* Location at which to apply the action */
|
||||
unsigned long long r_info; /* index and type of relocation */
|
||||
Elf64_Addr r_offset; /* Location at which to apply the action */
|
||||
Elf64_Xword r_info; /* index and type of relocation */
|
||||
} Elf64_Rel;
|
||||
|
||||
typedef struct elf32_rela{
|
||||
@@ -202,9 +785,9 @@ typedef struct elf32_rela{
|
||||
} Elf32_Rela;
|
||||
|
||||
typedef struct elf64_rela {
|
||||
unsigned long long r_offset; /* Location at which to apply the action */
|
||||
unsigned long long r_info; /* index and type of relocation */
|
||||
unsigned long long r_addend; /* Constant addend used to compute value */
|
||||
Elf64_Addr r_offset; /* Location at which to apply the action */
|
||||
Elf64_Xword r_info; /* index and type of relocation */
|
||||
Elf64_Sxword r_addend; /* Constant addend used to compute value */
|
||||
} Elf64_Rela;
|
||||
|
||||
typedef struct elf32_sym{
|
||||
@@ -217,12 +800,12 @@ typedef struct elf32_sym{
|
||||
} Elf32_Sym;
|
||||
|
||||
typedef struct elf64_sym {
|
||||
unsigned int st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Type and binding attributes */
|
||||
unsigned char st_other; /* No defined meaning, 0 */
|
||||
unsigned short st_shndx; /* Associated section index */
|
||||
unsigned long long st_value; /* Value of the symbol */
|
||||
unsigned long long st_size; /* Associated symbol size */
|
||||
Elf64_Word st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Type and binding attributes */
|
||||
unsigned char st_other; /* No defined meaning, 0 */
|
||||
Elf64_Half st_shndx; /* Associated section index */
|
||||
Elf64_Addr st_value; /* Value of the symbol */
|
||||
Elf64_Xword st_size; /* Associated symbol size */
|
||||
} Elf64_Sym;
|
||||
|
||||
|
||||
@@ -247,19 +830,19 @@ typedef struct elf32_hdr{
|
||||
|
||||
typedef struct elf64_hdr {
|
||||
unsigned char e_ident[16]; /* ELF "magic number" */
|
||||
short int e_type;
|
||||
short unsigned int e_machine;
|
||||
int e_version;
|
||||
unsigned long long e_entry; /* Entry point virtual address */
|
||||
unsigned long long e_phoff; /* Program header table file offset */
|
||||
unsigned long long e_shoff; /* Section header table file offset */
|
||||
int e_flags;
|
||||
short int e_ehsize;
|
||||
short int e_phentsize;
|
||||
short int e_phnum;
|
||||
short int e_shentsize;
|
||||
short int e_shnum;
|
||||
short int e_shstrndx;
|
||||
Elf64_Half e_type;
|
||||
Elf64_Half e_machine;
|
||||
Elf64_Word e_version;
|
||||
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||
Elf64_Off e_phoff; /* Program header table file offset */
|
||||
Elf64_Off e_shoff; /* Section header table file offset */
|
||||
Elf64_Word e_flags;
|
||||
Elf64_Half e_ehsize;
|
||||
Elf64_Half e_phentsize;
|
||||
Elf64_Half e_phnum;
|
||||
Elf64_Half e_shentsize;
|
||||
Elf64_Half e_shnum;
|
||||
Elf64_Half e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
/* These constants define the permissions on sections in the program
|
||||
@@ -280,14 +863,14 @@ typedef struct elf32_phdr{
|
||||
} Elf32_Phdr;
|
||||
|
||||
typedef struct elf64_phdr {
|
||||
int p_type;
|
||||
int p_flags;
|
||||
unsigned long long p_offset; /* Segment file offset */
|
||||
unsigned long long p_vaddr; /* Segment virtual address */
|
||||
unsigned long long p_paddr; /* Segment physical address */
|
||||
unsigned long long p_filesz; /* Segment size in file */
|
||||
unsigned long long p_memsz; /* Segment size in memory */
|
||||
unsigned long long p_align; /* Segment alignment, file & memory */
|
||||
Elf64_Word p_type;
|
||||
Elf64_Word p_flags;
|
||||
Elf64_Off p_offset; /* Segment file offset */
|
||||
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf64_Addr p_paddr; /* Segment physical address */
|
||||
Elf64_Xword p_filesz; /* Segment size in file */
|
||||
Elf64_Xword p_memsz; /* Segment size in memory */
|
||||
Elf64_Xword p_align; /* Segment alignment, file & memory */
|
||||
} Elf64_Phdr;
|
||||
|
||||
/* sh_type */
|
||||
@@ -308,12 +891,17 @@ typedef struct elf64_phdr {
|
||||
#define SHT_HIPROC 0x7fffffff
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#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 */
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_EXECINSTR 0x4
|
||||
#define SHF_MASKPROC 0xf0000000
|
||||
#define SHF_MIPS_GPREL 0x10000000
|
||||
|
||||
/* special section indexes */
|
||||
#define SHN_UNDEF 0
|
||||
@@ -323,8 +911,9 @@ typedef struct elf64_phdr {
|
||||
#define SHN_ABS 0xfff1
|
||||
#define SHN_COMMON 0xfff2
|
||||
#define SHN_HIRESERVE 0xffff
|
||||
#define SHN_MIPS_ACCOMON 0xff00
|
||||
|
||||
typedef struct {
|
||||
typedef struct elf32_shdr {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
@@ -338,16 +927,16 @@ typedef struct {
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct elf64_shdr {
|
||||
unsigned int sh_name; /* Section name, index in string tbl */
|
||||
unsigned int sh_type; /* Type of section */
|
||||
unsigned long long sh_flags; /* Miscellaneous section attributes */
|
||||
unsigned long long sh_addr; /* Section virtual addr at execution */
|
||||
unsigned long long sh_offset; /* Section file offset */
|
||||
unsigned long long sh_size; /* Size of section in bytes */
|
||||
unsigned int sh_link; /* Index of another section */
|
||||
unsigned int sh_info; /* Additional section information */
|
||||
unsigned long long sh_addralign; /* Section alignment */
|
||||
unsigned long long sh_entsize; /* Entry size if section holds table */
|
||||
Elf64_Word sh_name; /* Section name, index in string tbl */
|
||||
Elf64_Word sh_type; /* Type of section */
|
||||
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
|
||||
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf64_Off sh_offset; /* Section file offset */
|
||||
Elf64_Xword sh_size; /* Size of section in bytes */
|
||||
Elf64_Word sh_link; /* Index of another section */
|
||||
Elf64_Word sh_info; /* Additional section information */
|
||||
Elf64_Xword sh_addralign; /* Section alignment */
|
||||
Elf64_Xword sh_entsize; /* Entry size if section holds table */
|
||||
} Elf64_Shdr;
|
||||
|
||||
#define EI_MAG0 0 /* e_ident[] indexes */
|
||||
@@ -384,6 +973,8 @@ typedef struct elf64_shdr {
|
||||
#define NT_PRFPREG 2
|
||||
#define NT_PRPSINFO 3
|
||||
#define NT_TASKSTRUCT 4
|
||||
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
|
||||
|
||||
|
||||
/* Note header in a PT_NOTE section */
|
||||
typedef struct elf32_note {
|
||||
@@ -393,33 +984,49 @@ typedef struct elf32_note {
|
||||
} Elf32_Nhdr;
|
||||
|
||||
/* 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 {
|
||||
unsigned int n_namesz; /* Name size */
|
||||
unsigned int n_descsz; /* Content size */
|
||||
unsigned int n_type; /* Content type */
|
||||
Elf64_Word n_namesz; /* Name size */
|
||||
Elf64_Word n_descsz; /* Content size */
|
||||
Elf64_Word n_type; /* Content type */
|
||||
} Elf64_Nhdr;
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
|
||||
extern Elf32_Dyn _DYNAMIC [];
|
||||
#define elfhdr elf32_hdr
|
||||
#define elf_phdr elf32_phdr
|
||||
#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
|
||||
|
||||
extern Elf64_Dyn _DYNAMIC [];
|
||||
#define elfhdr elf64_hdr
|
||||
#define elf_phdr elf64_phdr
|
||||
#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 /* _ELF_H */
|
||||
|
@@ -66,6 +66,7 @@ register unsigned int T1 asm("r25");
|
||||
register unsigned int A0 asm("r26");
|
||||
register struct CPUX86State *env asm("r27");
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#define reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
@@ -99,6 +100,12 @@ 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 */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
@@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
* the Intel manual for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "dis-asm.h"
|
||||
|
||||
#define MAXLEN 20
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
|
||||
|
||||
struct dis_private
|
||||
|
@@ -12,9 +12,114 @@
|
||||
|
||||
#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 "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 */
|
||||
#define ALPHA_PAGE_SIZE 4096
|
||||
@@ -41,8 +146,18 @@
|
||||
|
||||
#define DLINFO_ITEMS 12
|
||||
|
||||
/* Where we find X86 libraries... */
|
||||
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
||||
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
||||
|
||||
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();
|
||||
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
|
||||
@@ -245,42 +360,34 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
struct image_info * info)
|
||||
{
|
||||
unsigned long stack_base;
|
||||
unsigned long stack_base, size, error;
|
||||
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
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
|
||||
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
||||
perror("stk mmap");
|
||||
exit(-1);
|
||||
}
|
||||
size = x86_stack_size;
|
||||
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
|
||||
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||
error = (unsigned long)mmap4k(NULL,
|
||||
size + X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (error == -1) {
|
||||
perror("stk mmap");
|
||||
exit(-1);
|
||||
}
|
||||
else {
|
||||
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);
|
||||
}
|
||||
/* we reserve one extra page at the top of the stack as guard */
|
||||
mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
|
||||
|
||||
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
|
||||
if (bprm->loader) {
|
||||
bprm->loader += stack_base;
|
||||
}
|
||||
|
||||
stktop = stack_base;
|
||||
bprm->exec += stack_base;
|
||||
|
||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||
if (bprm->page[i]) {
|
||||
@@ -332,10 +439,11 @@ static void padzero(unsigned long elf_bss)
|
||||
}
|
||||
|
||||
static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
struct elfhdr * exec,
|
||||
unsigned long load_addr,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
struct elfhdr * exec,
|
||||
unsigned long load_addr,
|
||||
unsigned long load_bias,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong *argv, *envp, *dlinfo;
|
||||
target_ulong *sp;
|
||||
@@ -360,17 +468,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
put_user (tswapl(val), dlinfo++)
|
||||
|
||||
if (exec) { /* Put this here for an ELF program interpreter */
|
||||
NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
|
||||
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_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||
}
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
@@ -399,7 +507,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
{
|
||||
struct elf_phdr *elf_phdata = NULL;
|
||||
struct elf_phdr *eppnt;
|
||||
unsigned long load_addr;
|
||||
unsigned long load_addr = 0;
|
||||
int load_addr_set = 0;
|
||||
int retval;
|
||||
unsigned long last_bss, elf_bss;
|
||||
@@ -410,17 +518,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
last_bss = 0;
|
||||
error = 0;
|
||||
|
||||
/* We put this here so that mmap will search for the *first*
|
||||
* available memory...
|
||||
*/
|
||||
load_addr = INTERP_LOADADDR;
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_ehdr(interp_elf_ex);
|
||||
#endif
|
||||
/* First of all, some simple consistency checks */
|
||||
if ((interp_elf_ex->e_type != ET_EXEC &&
|
||||
interp_elf_ex->e_type != ET_DYN) ||
|
||||
interp_elf_ex->e_type != ET_DYN) ||
|
||||
!elf_check_arch(interp_elf_ex->e_machine)) {
|
||||
return ~0UL;
|
||||
}
|
||||
@@ -441,11 +544,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
* If the size of this structure has changed, then punt, since
|
||||
* we will be doing the wrong thing.
|
||||
*/
|
||||
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
|
||||
{
|
||||
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
|
||||
free(elf_phdata);
|
||||
return ~0UL;
|
||||
}
|
||||
}
|
||||
|
||||
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
@@ -465,6 +567,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
bswap_phdr(eppnt);
|
||||
}
|
||||
#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;
|
||||
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
|
||||
if (eppnt->p_type == PT_LOAD) {
|
||||
@@ -548,7 +665,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
struct elfhdr interp_elf_ex;
|
||||
struct exec interp_ex;
|
||||
int interpreter_fd = -1; /* avoid warning */
|
||||
unsigned long load_addr;
|
||||
unsigned long load_addr, load_bias;
|
||||
int load_addr_set = 0;
|
||||
unsigned int interpreter_type = INTERPRETER_NONE;
|
||||
unsigned char ibcs2_interpreter;
|
||||
@@ -568,6 +685,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
ibcs2_interpreter = 0;
|
||||
status = 0;
|
||||
load_addr = 0;
|
||||
load_bias = 0;
|
||||
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_ehdr(&elf_ex);
|
||||
@@ -637,8 +755,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
* is an a.out format binary
|
||||
*/
|
||||
|
||||
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+
|
||||
strlen(bprm->interp_prefix));
|
||||
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
|
||||
|
||||
if (elf_interpreter == NULL) {
|
||||
free (elf_phdata);
|
||||
@@ -646,12 +763,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
strcpy(elf_interpreter, bprm->interp_prefix);
|
||||
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd,
|
||||
elf_interpreter+strlen(bprm->interp_prefix),
|
||||
elf_ppnt->p_filesz);
|
||||
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
|
||||
}
|
||||
if(retval < 0) {
|
||||
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);
|
||||
#endif
|
||||
if (retval >= 0) {
|
||||
retval = open(elf_interpreter, O_RDONLY);
|
||||
retval = open(path(elf_interpreter), O_RDONLY);
|
||||
if(retval >= 0) {
|
||||
interpreter_fd = retval;
|
||||
}
|
||||
@@ -773,56 +887,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
* address.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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;
|
||||
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
||||
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
||||
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
||||
|
||||
mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr),
|
||||
(elf_ppnt->p_filesz +
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
||||
elf_prot,
|
||||
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
||||
bprm->fd,
|
||||
(elf_ppnt->p_offset -
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
||||
|
||||
if((unsigned long)mapped_addr == 0xffffffffffffffff) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
int elf_prot = 0;
|
||||
int elf_flags = 0;
|
||||
unsigned long error;
|
||||
|
||||
if (elf_ppnt->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
||||
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
||||
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
||||
elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
|
||||
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
|
||||
elf_flags |= MAP_FIXED;
|
||||
} else if (elf_ex.e_type == ET_DYN) {
|
||||
/* Try and get dynamic programs out of the way of the default mmap
|
||||
base, as well as whatever program they might try to exec. This
|
||||
is because the brk will follow the loader, and is not movable. */
|
||||
/* NOTE: for qemu, we do a big mmap to get enough space
|
||||
without 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);
|
||||
}
|
||||
|
||||
error = (unsigned long)mmap4k(
|
||||
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
|
||||
(elf_ppnt->p_filesz +
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
||||
elf_prot,
|
||||
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
||||
bprm->fd,
|
||||
(elf_ppnt->p_offset -
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
||||
if (error == -1) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef LOW_ELF_STACK
|
||||
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
||||
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
||||
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
||||
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
||||
#endif
|
||||
|
||||
if (!load_addr_set) {
|
||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||
load_addr_set = 1;
|
||||
}
|
||||
k = elf_ppnt->p_vaddr;
|
||||
if (k < start_code) start_code = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||
if (k > elf_bss) elf_bss = k;
|
||||
#if 1
|
||||
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;
|
||||
if (end_data < k) end_data = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||
if (k > elf_brk) elf_brk = k;
|
||||
}
|
||||
|
||||
if (!load_addr_set) {
|
||||
load_addr_set = 1;
|
||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||
if (elf_ex.e_type == ET_DYN) {
|
||||
load_bias += error -
|
||||
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
|
||||
load_addr += load_bias;
|
||||
}
|
||||
}
|
||||
k = elf_ppnt->p_vaddr;
|
||||
if (k < start_code)
|
||||
start_code = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||
if (k > elf_bss)
|
||||
elf_bss = k;
|
||||
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
||||
end_code = k;
|
||||
if (end_data < k)
|
||||
end_data = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||
if (k > elf_brk) elf_brk = k;
|
||||
}
|
||||
|
||||
elf_entry += load_bias;
|
||||
elf_bss += load_bias;
|
||||
elf_brk += load_bias;
|
||||
start_code += load_bias;
|
||||
end_code += load_bias;
|
||||
// start_data += load_bias;
|
||||
end_data += load_bias;
|
||||
|
||||
if (elf_interpreter) {
|
||||
if (interpreter_type & 1) {
|
||||
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
|
||||
@@ -856,7 +1000,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
bprm->argc,
|
||||
bprm->envc,
|
||||
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
|
||||
load_addr,
|
||||
load_addr, load_bias,
|
||||
interp_load_addr,
|
||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||
info);
|
||||
@@ -911,8 +1055,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
|
||||
|
||||
|
||||
int elf_exec(const char *interp_prefix,
|
||||
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 linux_binprm bprm;
|
||||
@@ -931,7 +1074,6 @@ int elf_exec(const char *interp_prefix,
|
||||
else {
|
||||
bprm.fd = retval;
|
||||
}
|
||||
bprm.interp_prefix = (char *)interp_prefix;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.sh_bang = 0;
|
||||
bprm.loader = 0;
|
||||
|
@@ -37,6 +37,8 @@
|
||||
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
|
||||
IOCTL(TIOCGETD, IOC_R, 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(FIONCLEX, 0, TYPE_NULL)
|
||||
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
|
||||
@@ -66,6 +68,7 @@
|
||||
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
|
||||
#endif
|
||||
|
||||
IOCTL(SIOCATMARK, 0, TYPE_NULL)
|
||||
IOCTL(SIOCADDRT, 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))
|
||||
|
@@ -32,13 +32,28 @@
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
|
||||
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
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
unsigned long x86_stack_size = 512 * 1024;
|
||||
unsigned long stktop;
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
{
|
||||
@@ -106,77 +121,172 @@ 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)
|
||||
{
|
||||
int err;
|
||||
int trapnr;
|
||||
uint8_t *pc;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
err = cpu_x86_exec(env);
|
||||
trapnr = cpu_x86_exec(env);
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
switch(err) {
|
||||
switch(trapnr) {
|
||||
case EXCP0D_GPF:
|
||||
if (env->eflags & VM_MASK) {
|
||||
TaskState *ts;
|
||||
int ret;
|
||||
#ifdef DEBUG_VM86
|
||||
printf("VM86 exception %04x:%08x %02x\n",
|
||||
env->segs[R_CS], env->eip, pc[0]);
|
||||
printf("VM86 exception %04x:%08x %02x %02x\n",
|
||||
env->segs[R_CS], env->eip, pc[0], pc[1]);
|
||||
#endif
|
||||
/* VM86 mode */
|
||||
ts = env->opaque;
|
||||
|
||||
/* XXX: add all cases */
|
||||
switch(pc[0]) {
|
||||
case 0xcd: /* int */
|
||||
env->eip += 2;
|
||||
ret = TARGET_VM86_INTx | (pc[1] << 8);
|
||||
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 */
|
||||
ret = TARGET_VM86_UNKNOWN;
|
||||
return_to_32bit(env, TARGET_VM86_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_VM86
|
||||
printf("ret=0x%x\n", ret);
|
||||
#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]);
|
||||
|
||||
/* restore 32 bit registers */
|
||||
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);
|
||||
|
||||
env->regs[R_EAX] = ret;
|
||||
} else {
|
||||
if (pc[0] == 0xcd && pc[1] == 0x80) {
|
||||
/* syscall */
|
||||
@@ -200,20 +310,28 @@ void cpu_loop(struct CPUX86State *env)
|
||||
}
|
||||
break;
|
||||
case EXCP00_DIVZ:
|
||||
/* division by zero */
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_FPE_INTDIV;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
if (env->eflags & VM_MASK) {
|
||||
do_int(env, trapnr);
|
||||
} else {
|
||||
/* division by zero */
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_FPE_INTDIV;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP04_INTO:
|
||||
case EXCP05_BOUND:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
if (env->eflags & VM_MASK) {
|
||||
do_int(env, trapnr);
|
||||
} else {
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP06_ILLOP:
|
||||
info.si_signo = SIGILL;
|
||||
@@ -226,8 +344,8 @@ void cpu_loop(struct CPUX86State *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n",
|
||||
(long)pc, err);
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
@@ -247,7 +365,7 @@ void usage(void)
|
||||
DEBUG_LOGFILE,
|
||||
interp_prefix,
|
||||
x86_stack_size);
|
||||
exit(1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
@@ -267,6 +385,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
loglevel = 0;
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
@@ -305,7 +424,7 @@ int main(int argc, char **argv)
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
exit(1);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
@@ -316,9 +435,12 @@ int main(int argc, char **argv)
|
||||
/* Zero out image_info */
|
||||
memset(info, 0, sizeof(struct image_info));
|
||||
|
||||
if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) {
|
||||
/* Scan interp_prefix dir for replacement files. */
|
||||
init_paths(interp_prefix);
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
exit(1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (loglevel) {
|
||||
|
142
linux-user/path.c
Normal file
142
linux-user/path.c
Normal 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;
|
||||
}
|
@@ -60,8 +60,7 @@ typedef struct TaskState {
|
||||
|
||||
extern TaskState *first_task_state;
|
||||
|
||||
int elf_exec(const char *interp_prefix,
|
||||
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);
|
||||
|
||||
void target_set_brk(char *new_brk);
|
||||
@@ -74,5 +73,7 @@ void cpu_loop(CPUX86State *env);
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
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
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
@@ -198,7 +199,7 @@ void __attribute((noreturn)) force_sig(int sig)
|
||||
{
|
||||
int host_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));
|
||||
#if 1
|
||||
_exit(-host_sig);
|
||||
@@ -223,7 +224,7 @@ int queue_signal(int sig, target_siginfo_t *info)
|
||||
target_ulong handler;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "queue_sigal: sig=%d\n",
|
||||
fprintf(stderr, "queue_signal: sig=%d\n",
|
||||
sig);
|
||||
#endif
|
||||
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)
|
||||
return;
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "gemu: got signal %d\n", sig);
|
||||
fprintf(stderr, "qemu: got signal %d\n", sig);
|
||||
dump_regs(puc);
|
||||
#endif
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
@@ -538,7 +539,6 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ void process_pending_signals(void *cpu_env)
|
||||
|
||||
handle_signal:
|
||||
#ifdef DEBUG_SIGNAL
|
||||
fprintf(stderr, "gemu: process signal %d\n", sig);
|
||||
fprintf(stderr, "qemu: process signal %d\n", sig);
|
||||
#endif
|
||||
/* dequeue signal */
|
||||
q = k->first;
|
||||
@@ -893,6 +893,14 @@ void process_pending_signals(void *cpu_env)
|
||||
end of the signal execution (see do_sigreturn) */
|
||||
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 */
|
||||
if (k->sa.sa_flags & TARGET_SA_SIGINFO)
|
||||
setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/times.h>
|
||||
//#include <sys/user.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
@@ -84,6 +85,10 @@ long do_rt_sigreturn(CPUX86State *env);
|
||||
#define __NR_sys_getdents64 __NR_getdents64
|
||||
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
|
||||
|
||||
#ifdef __alpha__
|
||||
#define __NR__llseek __NR_lseek
|
||||
#endif
|
||||
|
||||
#ifdef __NR_gettid
|
||||
_syscall0(int, gettid)
|
||||
#else
|
||||
@@ -100,6 +105,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
|
||||
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
|
||||
_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
|
||||
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
|
||||
#ifdef __NR_exit_group
|
||||
_syscall1(int,exit_group,int,error_code)
|
||||
#endif
|
||||
|
||||
extern int personality(int);
|
||||
extern int flock(int, int);
|
||||
@@ -1077,7 +1085,6 @@ int do_vm86(CPUX86State *env, long subfunction,
|
||||
}
|
||||
|
||||
ts->target_v86 = target_v86;
|
||||
|
||||
/* save current CPU regs */
|
||||
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
|
||||
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
|
||||
@@ -1208,7 +1215,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_open:
|
||||
ret = get_errno(open((const char *)arg1, arg2, arg3));
|
||||
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_close:
|
||||
ret = get_errno(close(arg1));
|
||||
@@ -1239,22 +1246,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_execve:
|
||||
{
|
||||
char **argp, **envp;
|
||||
int argc = 0, envc = 0;
|
||||
int argc, envc;
|
||||
uint32_t *p;
|
||||
char **q;
|
||||
|
||||
argc = 0;
|
||||
for (p = (void *)arg2; *p; p++)
|
||||
argc++;
|
||||
envc = 0;
|
||||
for (p = (void *)arg3; *p; p++)
|
||||
envc++;
|
||||
|
||||
argp = alloca(argc * sizeof(void *));
|
||||
envp = alloca(envc * sizeof(void *));
|
||||
argp = alloca((argc + 1) * sizeof(void *));
|
||||
envp = alloca((envc + 1) * sizeof(void *));
|
||||
|
||||
for (p = (void *)arg2, q = argp; *p; p++, q++)
|
||||
*q = (void *)tswap32(*p);
|
||||
*q = NULL;
|
||||
|
||||
for (p = (void *)arg3, q = envp; *p; p++, q++)
|
||||
*q = (void *)tswap32(*p);
|
||||
*q = NULL;
|
||||
|
||||
ret = get_errno(execve((const char *)arg1, argp, envp));
|
||||
}
|
||||
@@ -1363,7 +1375,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_times:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct target_tms *tmsp = (void *)arg1;
|
||||
struct tms tms;
|
||||
ret = get_errno(times(&tms));
|
||||
if (tmsp) {
|
||||
tmsp->tms_utime = tswapl(tms.tms_utime);
|
||||
tmsp->tms_stime = tswapl(tms.tms_stime);
|
||||
tmsp->tms_cutime = tswapl(tms.tms_cutime);
|
||||
tmsp->tms_cstime = tswapl(tms.tms_cstime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_prof:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_setgid:
|
||||
@@ -1680,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_oldlstat:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_readlink:
|
||||
ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3));
|
||||
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_uselib:
|
||||
goto unimplemented;
|
||||
@@ -1759,7 +1782,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
case TARGET_NR_statfs:
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_statfs((const char *)arg1, stfs));
|
||||
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
|
||||
convert_statfs:
|
||||
if (!is_error(ret)) {
|
||||
tswap32s(&stfs->f_type);
|
||||
@@ -1824,10 +1847,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_stat:
|
||||
ret = get_errno(stat((const char *)arg1, &st));
|
||||
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||
goto do_stat;
|
||||
case TARGET_NR_lstat:
|
||||
ret = get_errno(lstat((const char *)arg1, &st));
|
||||
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||
goto do_stat;
|
||||
case TARGET_NR_fstat:
|
||||
{
|
||||
@@ -1910,6 +1933,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_clone:
|
||||
ret = get_errno(do_fork(cpu_env, arg1, arg2));
|
||||
break;
|
||||
#ifdef __NR_exit_group
|
||||
/* new thread calls */
|
||||
case TARGET_NR_exit_group:
|
||||
ret = get_errno(exit_group(arg1));
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_setdomainname:
|
||||
ret = get_errno(setdomainname((const char *)arg1, arg2));
|
||||
break;
|
||||
@@ -2215,10 +2244,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_ftruncate64:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_stat64:
|
||||
ret = get_errno(stat((const char *)arg1, &st));
|
||||
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||
goto do_stat64;
|
||||
case TARGET_NR_lstat64:
|
||||
ret = get_errno(lstat((const char *)arg1, &st));
|
||||
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||
goto do_stat64;
|
||||
case TARGET_NR_fstat64:
|
||||
{
|
||||
@@ -2226,15 +2255,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
do_stat64:
|
||||
if (!is_error(ret)) {
|
||||
struct target_stat64 *target_st = (void *)arg2;
|
||||
memset(target_st, 0, sizeof(struct target_stat64));
|
||||
target_st->st_dev = tswap16(st.st_dev);
|
||||
target_st->st_ino = tswapl(st.st_ino);
|
||||
target_st->st_mode = tswap16(st.st_mode);
|
||||
target_st->st_nlink = tswap16(st.st_nlink);
|
||||
target_st->st_uid = tswap16(st.st_uid);
|
||||
target_st->st_gid = tswap16(st.st_gid);
|
||||
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
||||
target_st->__st_ino = tswapl(st.st_ino);
|
||||
#endif
|
||||
target_st->st_mode = tswap32(st.st_mode);
|
||||
target_st->st_nlink = tswap32(st.st_nlink);
|
||||
target_st->st_uid = tswapl(st.st_uid);
|
||||
target_st->st_gid = tswapl(st.st_gid);
|
||||
target_st->st_rdev = tswap16(st.st_rdev);
|
||||
/* XXX: better use of kernel struct */
|
||||
target_st->st_size = tswapl(st.st_size);
|
||||
target_st->st_size = tswap64(st.st_size);
|
||||
target_st->st_blksize = tswapl(st.st_blksize);
|
||||
target_st->st_blocks = tswapl(st.st_blocks);
|
||||
target_st->target_st_atime = tswapl(st.st_atime);
|
||||
|
@@ -39,6 +39,15 @@ struct target_itimerval {
|
||||
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 {
|
||||
target_long iov_base; /* Starting address */
|
||||
target_long iov_len; /* Number of bytes */
|
||||
|
143
op-i386.c
143
op-i386.c
@@ -412,6 +412,22 @@ void OPPROTO op_idivw_AX_T0(void)
|
||||
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)
|
||||
{
|
||||
unsigned int den, q, r;
|
||||
@@ -421,8 +437,12 @@ void OPPROTO op_divl_EAX_T0(void)
|
||||
den = T0;
|
||||
if (den == 0)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = div64(&q, num, den);
|
||||
#else
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
EAX = q;
|
||||
EDX = r;
|
||||
}
|
||||
@@ -436,8 +456,12 @@ void OPPROTO op_idivl_EAX_T0(void)
|
||||
den = T0;
|
||||
if (den == 0)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = idiv64(&q, num, den);
|
||||
#else
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
EAX = q;
|
||||
EDX = r;
|
||||
}
|
||||
@@ -611,6 +635,35 @@ void OPPROTO op_into(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -1234,7 +1287,8 @@ void OPPROTO op_set_cc_op(void)
|
||||
CC_OP = PARAM1;
|
||||
}
|
||||
|
||||
#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK)
|
||||
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
|
||||
#define FL_UPDATE_MASK16 (TF_MASK)
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void)
|
||||
{
|
||||
@@ -1243,7 +1297,56 @@ void OPPROTO op_movl_eflags_T0(void)
|
||||
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_MASK) | (eflags & FL_UPDATE_MASK);
|
||||
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 */
|
||||
@@ -1263,6 +1366,18 @@ void OPPROTO op_movl_T0_eflags(void)
|
||||
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)
|
||||
{
|
||||
DF = 1;
|
||||
@@ -1377,7 +1492,9 @@ CCTable cc_table[CC_OP_NB] = {
|
||||
[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
|
||||
/* use long double functions */
|
||||
@@ -1410,6 +1527,26 @@ extern CPU86_LDouble floor(CPU86_LDouble x);
|
||||
extern CPU86_LDouble ceil(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_NEAR 0x000
|
||||
#define RC_DOWN 0x400
|
||||
|
@@ -232,6 +232,10 @@ DEF(jmp_im, 1)
|
||||
DEF(int_im, 1)
|
||||
DEF(int3, 1)
|
||||
DEF(into, 0)
|
||||
DEF(cli, 0)
|
||||
DEF(sti, 0)
|
||||
DEF(cli_vm, 0)
|
||||
DEF(sti_vm, 1)
|
||||
DEF(boundw, 0)
|
||||
DEF(boundl, 0)
|
||||
DEF(cmpxchg8b, 0)
|
||||
@@ -551,8 +555,12 @@ DEF(setle_T0_cc, 0)
|
||||
DEF(xor_T0_1, 0)
|
||||
DEF(set_cc_op, 1)
|
||||
DEF(movl_eflags_T0, 0)
|
||||
DEF(movw_eflags_T0, 0)
|
||||
DEF(movw_eflags_T0_vm, 1)
|
||||
DEF(movl_eflags_T0_vm, 1)
|
||||
DEF(movb_eflags_T0, 0)
|
||||
DEF(movl_T0_eflags, 0)
|
||||
DEF(movl_T0_eflags_vm, 0)
|
||||
DEF(cld, 0)
|
||||
DEF(std, 0)
|
||||
DEF(clc, 0)
|
||||
|
@@ -609,6 +609,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
@@ -643,6 +644,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -670,6 +672,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
@@ -696,6 +699,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -36,6 +36,8 @@ User space LDT and GDT are emulated. VM86 mode is also supported
|
||||
|
||||
@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.
|
||||
|
||||
@@ -50,9 +52,7 @@ Current QEMU Limitations:
|
||||
|
||||
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
|
||||
|
||||
@item Not self virtualizable (yet). [You cannot launch qemu with qemu on the same CPU].
|
||||
|
||||
@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
|
||||
@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).
|
||||
|
||||
@@ -88,9 +88,14 @@ qemu -L / /bin/ls
|
||||
@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-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||
@code{LD_LIBRARY_PATH} is not set:
|
||||
|
||||
@example
|
||||
@@ -107,6 +112,11 @@ 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)
|
||||
@@ -122,7 +132,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@item Download the binary x86 Wine install
|
||||
(@file{qemu-i386-wine.tar.gz} on the QEMU web page).
|
||||
(@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
|
||||
@@ -302,6 +312,21 @@ 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
|
||||
|
@@ -302,7 +302,7 @@ struct target_stat64 {
|
||||
unsigned short st_dev;
|
||||
unsigned char __pad0[10];
|
||||
|
||||
#define STAT64_HAS_BROKEN_ST_INO 1
|
||||
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
|
||||
target_ulong __st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
@@ -427,8 +427,8 @@ typedef struct target_siginfo {
|
||||
pid_t _pid; /* which child */
|
||||
uid_t _uid; /* sender's uid */
|
||||
int _status; /* exit code */
|
||||
clock_t _utime;
|
||||
clock_t _stime;
|
||||
target_clock_t _utime;
|
||||
target_clock_t _stime;
|
||||
} _sigchld;
|
||||
|
||||
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
|
||||
@@ -572,8 +572,8 @@ struct target_pt_regs {
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#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_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
@@ -755,6 +755,11 @@ struct target_modify_ldt_ldt_s {
|
||||
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) */
|
||||
@@ -1060,3 +1065,5 @@ union target_semun {
|
||||
|
||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
|
||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
|
||||
|
||||
#define TARGET_SIOCATMARK 0x8905
|
||||
|
28
tests/.cvsignore
Normal file
28
tests/.cvsignore
Normal 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
|
@@ -6,7 +6,7 @@ LDFLAGS=
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||
endif
|
||||
TESTS+=sha1
|
||||
TESTS+=sha1 test_path
|
||||
|
||||
QEMU=../qemu
|
||||
|
||||
@@ -25,10 +25,14 @@ testsig: testsig.c
|
||||
testthread: testthread.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||
|
||||
test_path: test_path.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
./$@ || { rm $@; exit 1; }
|
||||
|
||||
# i386 emulation test (test various opcodes) */
|
||||
test-i386: test-i386.c test-i386-code16.S \
|
||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm
|
||||
|
||||
test: test-i386
|
||||
ifeq ($(ARCH),i386)
|
||||
|
195
tests/runcom.c
Normal file
195
tests/runcom.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags)
|
||||
void exec_op(int s2, int s0, int s1)
|
||||
{
|
||||
exec_opl(s2, s0, s1, 0);
|
||||
#ifdef OP_SHIFTD
|
||||
if (s1 <= 15)
|
||||
exec_opw(s2, s0, s1, 0);
|
||||
#else
|
||||
exec_opw(s2, s0, s1, 0);
|
||||
#endif
|
||||
#ifndef OP_NOBYTE
|
||||
exec_opb(s0, s1, 0);
|
||||
#endif
|
||||
|
152
tests/test_path.c
Normal file
152
tests/test_path.c
Normal 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;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
2
thunk.c
2
thunk.c
@@ -218,7 +218,7 @@ const argtype *thunk_convert(void *dst, const void *src,
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
if (target_to_host) {
|
||||
if (to_host) {
|
||||
*(uint64_t *)dst = tswap32(*(uint32_t *)src);
|
||||
} else {
|
||||
*(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
|
||||
|
18
thunk.h
18
thunk.h
@@ -94,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x)
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static void inline bswap16s(uint16_t *s)
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static void inline bswap32s(uint32_t *s)
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static void inline bswap64s(uint64_t *s)
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
@@ -126,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s)
|
||||
return bswap64(s);
|
||||
}
|
||||
|
||||
static void inline tswap16s(uint16_t *s)
|
||||
static inline void tswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static void inline tswap32s(uint32_t *s)
|
||||
static inline void tswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static void inline tswap64s(uint64_t *s)
|
||||
static inline void tswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
@@ -158,15 +158,15 @@ static inline uint64_t tswap64(uint64_t 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -1919,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
break;
|
||||
case 0x1a0: /* push fs */
|
||||
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);
|
||||
break;
|
||||
case 0x07: /* pop es */
|
||||
@@ -1932,7 +1932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x1a1: /* pop fs */
|
||||
case 0x1a9: /* pop gs */
|
||||
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);
|
||||
break;
|
||||
|
||||
@@ -2833,6 +2833,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
case 0xca: /* lret im */
|
||||
/* XXX: not restartable */
|
||||
val = ldsw(s->pc);
|
||||
s->pc += 2;
|
||||
/* pop offset */
|
||||
@@ -2853,6 +2854,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
case 0xcb: /* lret */
|
||||
/* XXX: not restartable */
|
||||
/* pop offset */
|
||||
gen_pop_T0(s);
|
||||
if (s->dflag == 0)
|
||||
@@ -2865,6 +2867,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_pop_update(s);
|
||||
s->is_jmp = 1;
|
||||
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 */
|
||||
{
|
||||
unsigned int next_eip;
|
||||
@@ -2978,12 +3009,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x9c: /* pushf */
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_movl_T0_eflags();
|
||||
if (s->vm86)
|
||||
gen_op_movl_T0_eflags_vm();
|
||||
else
|
||||
gen_op_movl_T0_eflags();
|
||||
gen_push_T0(s);
|
||||
break;
|
||||
case 0x9d: /* popf */
|
||||
gen_pop_T0(s);
|
||||
gen_op_movl_eflags_T0();
|
||||
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;
|
||||
break;
|
||||
@@ -3159,6 +3203,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_into();
|
||||
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++);
|
||||
@@ -3308,6 +3364,7 @@ static uint16_t opc_read_flags[NB_OPS] = {
|
||||
[INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
|
||||
|
||||
[INDEX_op_movl_T0_eflags] = CC_OSZAPC,
|
||||
[INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
|
||||
[INDEX_op_cmc] = CC_C,
|
||||
[INDEX_op_salc] = CC_C,
|
||||
|
||||
@@ -3356,7 +3413,10 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_daa] = CC_OSZAPC,
|
||||
|
||||
[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_vm] = CC_OSZAPC,
|
||||
[INDEX_op_clc] = CC_C,
|
||||
[INDEX_op_stc] = CC_C,
|
||||
[INDEX_op_cmc] = CC_C,
|
||||
|
Reference in New Issue
Block a user