Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ef693a032 | ||
|
|
b03c60f351 | ||
|
|
9de5e440b9 | ||
|
|
66fb9763af | ||
|
|
1b6b029e40 | ||
|
|
612384d771 | ||
|
|
dab2ed991a | ||
|
|
e591824733 | ||
|
|
04369ff2f5 | ||
|
|
68decc7c7f | ||
|
|
dc99065b5f | ||
|
|
ca735206e0 | ||
|
|
5dd9488c09 | ||
|
|
60cd49d5d7 | ||
|
|
a300e69170 | ||
|
|
1a9353d258 | ||
|
|
6dbad63eef | ||
|
|
27362c82e9 | ||
|
|
55480af80e | ||
|
|
7d13299d07 | ||
|
|
1017ebe9cb | ||
|
|
77f8dd5add | ||
|
|
c5e9815da4 | ||
|
|
9d8e9c0993 | ||
|
|
d57c4e0120 | ||
|
|
4b74fe1f00 | ||
|
|
586314f2aa | ||
|
|
0ecfa9930c | ||
|
|
ba1c6e37fc | ||
|
|
927f621e79 | ||
|
|
367e86e847 | ||
|
|
7bfdb6d18c | ||
|
|
379ca80d34 | ||
|
|
4d1135e486 | ||
|
|
5147f5aac0 | ||
|
|
766a487abf | ||
|
|
72f0390014 | ||
|
|
b17780d521 | ||
|
|
3431395696 | ||
|
|
01ffc75bc9 | ||
|
|
31e31b8a24 | ||
|
|
e63c3dc74b |
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -1,36 +1,122 @@
|
||||
include config.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
|
||||
LIBS=
|
||||
DEFINES=-DHAVE_BYTESWAP_H
|
||||
|
||||
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
|
||||
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
|
||||
i386/dis8086.o i386/emu-ldt.o
|
||||
OBJS+= elfload.o main.o thunk.o syscall.o
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
endif
|
||||
|
||||
SRCS = $(OBJS:.o=.c)
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
all: gemu
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
gemu: $(OBJS)
|
||||
$(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS)
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LDSCRIPT=$(ARCH).ld
|
||||
LIBS+=-lm
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o signal.o
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=i386-dis.o dis-buf.o
|
||||
|
||||
all: qemu qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
dyngen: dyngen.c
|
||||
$(HOST_CC) -O2 -Wall -g $< -o $@
|
||||
|
||||
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h
|
||||
|
||||
op-i386.h: op-i386.o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
|
||||
$(MAKE) -C tests clean
|
||||
rm -f *.o *.a *~ qemu dyngen TAGS
|
||||
|
||||
hello: hello.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
distclean: clean
|
||||
rm -f config.mak config.h
|
||||
|
||||
test1: test1.c
|
||||
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
install: qemu
|
||||
install -m 755 -s qemu $(prefix)/bin
|
||||
|
||||
test2: test2.c
|
||||
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
# various test targets
|
||||
test speed: qemu
|
||||
make -C tests $@
|
||||
|
||||
TAGS:
|
||||
etags *.[ch] i386/*.[ch]
|
||||
|
||||
# documentation
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
FILES= \
|
||||
README COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
dyngen.c ioctls.h ops_template.h syscall_types.h\
|
||||
Makefile elf.h linux_bin.h segment.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-buf.c i386-dis.c opreg_template.h syscall_defs.h\
|
||||
i386.ld ppc.ld exec-i386.h exec-i386.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 \
|
||||
qemu-doc.texi qemu-doc.html
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
mkdir -p /tmp/$(FILE)
|
||||
cp -P $(FILES) /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
The QEMU x86 emulator
|
||||
---------------------
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Type
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
|
||||
Type
|
||||
|
||||
make install
|
||||
|
||||
to install qemu in /usr/local/bin
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Read the documentation in qemu-doc.html.
|
||||
|
||||
|
||||
Fabrice Bellard.
|
||||
@@ -1,2 +1,10 @@
|
||||
- swap all elf paramters
|
||||
- fix printf for doubles (fp87.c bug ?)
|
||||
- optimize translated cache chaining (DLL PLT-like system)
|
||||
- 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
|
||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# qemu configure script (c) 2003 Fabrice Bellard
|
||||
#
|
||||
# set temporary file name
|
||||
if test ! -z "$TMPDIR" ; then
|
||||
TMPDIR1="${TMPDIR}"
|
||||
elif test ! -z "$TEMPDIR" ; then
|
||||
TMPDIR1="${TEMPDIR}"
|
||||
else
|
||||
TMPDIR1="/tmp"
|
||||
fi
|
||||
|
||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
cpu=`uname -m`
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="x86"
|
||||
;;
|
||||
armv4l)
|
||||
cpu="armv4l"
|
||||
;;
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
;;
|
||||
"Power Macintosh"|ppc)
|
||||
cpu="powerpc"
|
||||
;;
|
||||
mips)
|
||||
cpu="mips"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
esac
|
||||
gprof="no"
|
||||
bigendian="no"
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
case $targetos in
|
||||
BeOS)
|
||||
prefix="/boot/home/config"
|
||||
# helps building libavcodec
|
||||
CFLAGS="-O2 -DPIC"
|
||||
# no need for libm, but the inet stuff
|
||||
# Check for BONE
|
||||
if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then
|
||||
extralibs="-lbind -lsocket"
|
||||
else
|
||||
echo "Not sure building for net_server will succeed... good luck."
|
||||
extralibs="-lsocket"
|
||||
fi ;;
|
||||
BSD/OS)
|
||||
extralibs="-lpoll -lgnugetopt -lm"
|
||||
make="gmake"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
# find source path
|
||||
# XXX: we assume an absolute path is given when launching configure,
|
||||
# except in './configure' case.
|
||||
source_path=${0%configure}
|
||||
source_path=${source_path%/}
|
||||
source_path_used="yes"
|
||||
if test -z "$source_path" -o "$source_path" = "." ; then
|
||||
source_path=`pwd`
|
||||
source_path_used="no"
|
||||
fi
|
||||
|
||||
for opt do
|
||||
case "$opt" in
|
||||
--prefix=*) 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`
|
||||
;;
|
||||
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--make=*) make=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
|
||||
;;
|
||||
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
|
||||
;;
|
||||
--extra-libs=*) extralibs=${opt#--extra-libs=}
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Checking for CFLAGS
|
||||
if test -z "$CFLAGS"; then
|
||||
CFLAGS="-O2"
|
||||
fi
|
||||
|
||||
cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
|
||||
# ---
|
||||
# big/little endian test
|
||||
cat > $TMPC << EOF
|
||||
#include <inttypes.h>
|
||||
int main(int argc, char ** argv){
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPE $TMPC 2>/dev/null ; then
|
||||
$TMPE && bigendian="yes"
|
||||
else
|
||||
echo big/little test failed
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then
|
||||
bigendian="yes"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# check gcc version
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
|
||||
return 0;
|
||||
#else
|
||||
#error gcc < 3.2
|
||||
#endif
|
||||
}
|
||||
EOF
|
||||
|
||||
gcc_major="2"
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="3"
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
cat << EOF
|
||||
|
||||
Usage: configure [options]
|
||||
Options: [defaults in brackets after descriptions]
|
||||
|
||||
EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " for audio/video/image support"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "gprof enabled $gprof"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
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 "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||
echo "HOST_CC=$host_cc" >> config.mak
|
||||
echo "AR=$ar" >> config.mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
|
||||
echo "CFLAGS=$CFLAGS" >> config.mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> config.mak
|
||||
elif test "$cpu" = "mips" ; then
|
||||
echo "ARCH=mips" >> config.mak
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
fi
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> config.mak
|
||||
echo "#define HAVE_GPROF 1" >> $TMPH
|
||||
fi
|
||||
echo -n "VERSION=" >>config.mak
|
||||
head $source_path/VERSION >>config.mak
|
||||
echo "" >>config.mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $TMPH
|
||||
head $source_path/VERSION >> $TMPH
|
||||
echo "\"" >> $TMPH
|
||||
if test "$network" = "yes" ; then
|
||||
echo "#define CONFIG_NETWORK 1" >> $TMPH
|
||||
echo "CONFIG_NETWORK=yes" >> config.mak
|
||||
fi
|
||||
|
||||
# build tree in object directory if source path is different from current one
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
DIRS="tests"
|
||||
FILES="Makefile tests/Makefile"
|
||||
for dir in $DIRS ; do
|
||||
mkdir -p $dir
|
||||
done
|
||||
for f in $FILES ; do
|
||||
ln -sf $source_path/$f $f
|
||||
done
|
||||
fi
|
||||
echo "SRC_PATH=$source_path" >> config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
mv -f $TMPH config.h
|
||||
else
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPH
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* i386 virtual CPU header
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_I386_H
|
||||
#define CPU_I386_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define R_EAX 0
|
||||
#define R_ECX 1
|
||||
#define R_EDX 2
|
||||
#define R_EBX 3
|
||||
#define R_ESP 4
|
||||
#define R_EBP 5
|
||||
#define R_ESI 6
|
||||
#define R_EDI 7
|
||||
|
||||
#define R_AL 0
|
||||
#define R_CL 1
|
||||
#define R_DL 2
|
||||
#define R_BL 3
|
||||
#define R_AH 4
|
||||
#define R_CH 5
|
||||
#define R_DH 6
|
||||
#define R_BH 7
|
||||
|
||||
#define R_ES 0
|
||||
#define R_CS 1
|
||||
#define R_SS 2
|
||||
#define R_DS 3
|
||||
#define R_FS 4
|
||||
#define R_GS 5
|
||||
|
||||
#define CC_C 0x0001
|
||||
#define CC_P 0x0004
|
||||
#define CC_A 0x0010
|
||||
#define CC_Z 0x0040
|
||||
#define CC_S 0x0080
|
||||
#define CC_O 0x0800
|
||||
|
||||
#define TRAP_FLAG 0x0100
|
||||
#define INTERRUPT_FLAG 0x0200
|
||||
#define DIRECTION_FLAG 0x0400
|
||||
#define IOPL_FLAG_MASK 0x3000
|
||||
#define NESTED_FLAG 0x4000
|
||||
#define BYTE_FL 0x8000 /* Intel reserved! */
|
||||
#define RF_FLAG 0x10000
|
||||
#define VM_FLAG 0x20000
|
||||
/* AC 0x40000 */
|
||||
|
||||
#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 EXCP_INTERRUPT 256 /* async interruption */
|
||||
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
|
||||
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
|
||||
|
||||
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_ADDW,
|
||||
CC_OP_ADDL,
|
||||
|
||||
CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_ADCW,
|
||||
CC_OP_ADCL,
|
||||
|
||||
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_SUBW,
|
||||
CC_OP_SUBL,
|
||||
|
||||
CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_SBBW,
|
||||
CC_OP_SBBL,
|
||||
|
||||
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
|
||||
CC_OP_LOGICW,
|
||||
CC_OP_LOGICL,
|
||||
|
||||
CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
|
||||
CC_OP_INCW,
|
||||
CC_OP_INCL,
|
||||
|
||||
CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
|
||||
CC_OP_DECW,
|
||||
CC_OP_DECL,
|
||||
|
||||
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
|
||||
CC_OP_SHLW,
|
||||
CC_OP_SHLL,
|
||||
|
||||
CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
|
||||
CC_OP_SARW,
|
||||
CC_OP_SARL,
|
||||
|
||||
CC_OP_NB,
|
||||
};
|
||||
|
||||
#ifdef __i386__
|
||||
#define USE_X86LDOUBLE
|
||||
#endif
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
typedef long double CPU86_LDouble;
|
||||
#else
|
||||
typedef double CPU86_LDouble;
|
||||
#endif
|
||||
|
||||
typedef struct SegmentCache {
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
uint8_t seg_32bit;
|
||||
} SegmentCache;
|
||||
|
||||
typedef struct SegmentDescriptorTable {
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
/* this is the returned base when reading the register, just to
|
||||
avoid that the emulated program modifies it */
|
||||
unsigned long emu_base;
|
||||
} SegmentDescriptorTable;
|
||||
|
||||
typedef struct CPUX86State {
|
||||
/* standard registers */
|
||||
uint32_t regs[8];
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
|
||||
/* emulator internal eflags handling */
|
||||
uint32_t cc_src;
|
||||
uint32_t cc_dst;
|
||||
uint32_t cc_op;
|
||||
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
|
||||
|
||||
/* FPU state */
|
||||
unsigned int fpstt; /* top of stack index */
|
||||
unsigned int fpus;
|
||||
unsigned int fpuc;
|
||||
uint8_t fptags[8]; /* 0 = valid, 1 = empty */
|
||||
CPU86_LDouble fpregs[8];
|
||||
|
||||
/* emulator internal variables */
|
||||
CPU86_LDouble ft0;
|
||||
|
||||
/* segments */
|
||||
uint32_t segs[6]; /* selector values */
|
||||
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
|
||||
SegmentDescriptorTable gdt;
|
||||
SegmentDescriptorTable ldt;
|
||||
SegmentDescriptorTable idt;
|
||||
|
||||
/* various CPU modes */
|
||||
int vm86;
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
} CPUX86State;
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IN_OP_I386
|
||||
void cpu_x86_outb(int addr, int val);
|
||||
void cpu_x86_outw(int addr, int val);
|
||||
void cpu_x86_outl(int addr, int val);
|
||||
int cpu_x86_inb(int addr);
|
||||
int cpu_x86_inw(int addr);
|
||||
int cpu_x86_inl(int addr);
|
||||
#endif
|
||||
|
||||
CPUX86State *cpu_x86_init(void);
|
||||
int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_interrupt(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
|
||||
/* needed to load some predefinied segment registers */
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
|
||||
|
||||
/* you can call these signal handler from you SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
struct siginfo;
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
/* internal functions */
|
||||
|
||||
#define GEN_FLAG_CODE32_SHIFT 0
|
||||
#define GEN_FLAG_ADDSEG_SHIFT 1
|
||||
#define GEN_FLAG_SS32_SHIFT 2
|
||||
#define GEN_FLAG_ST_SHIFT 3
|
||||
|
||||
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
|
||||
int *gen_code_size_ptr,
|
||||
uint8_t *pc_start, uint8_t *cs_base, int flags);
|
||||
void cpu_x86_tblocks_init(void);
|
||||
|
||||
#endif /* CPU_I386_H */
|
||||
@@ -0,0 +1,238 @@
|
||||
/* Interface between the opcode library and its callers.
|
||||
Written by Cygnus Support, 1993.
|
||||
|
||||
The opcode library (libopcodes.a) provides instruction decoders for
|
||||
a large variety of instruction sets, callable with an identical
|
||||
interface, for making instruction-processing programs more independent
|
||||
of the instruction set being processed. */
|
||||
|
||||
#ifndef DIS_ASM_H
|
||||
#define DIS_ASM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bfd.h"
|
||||
|
||||
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
|
||||
|
||||
enum dis_insn_type {
|
||||
dis_noninsn, /* Not a valid instruction */
|
||||
dis_nonbranch, /* Not a branch instruction */
|
||||
dis_branch, /* Unconditional branch */
|
||||
dis_condbranch, /* Conditional branch */
|
||||
dis_jsr, /* Jump to subroutine */
|
||||
dis_condjsr, /* Conditional jump to subroutine */
|
||||
dis_dref, /* Data reference instruction */
|
||||
dis_dref2 /* Two data references in instruction */
|
||||
};
|
||||
|
||||
/* This struct is passed into the instruction decoding routine,
|
||||
and is passed back out into each callback. The various fields are used
|
||||
for conveying information from your main routine into your callbacks,
|
||||
for passing information into the instruction decoders (such as the
|
||||
addresses of the callback functions), or for passing information
|
||||
back from the instruction decoders to their callers.
|
||||
|
||||
It must be initialized before it is first passed; this can be done
|
||||
by hand, or using one of the initialization macros below. */
|
||||
|
||||
typedef struct disassemble_info {
|
||||
fprintf_ftype fprintf_func;
|
||||
FILE *stream;
|
||||
PTR application_data;
|
||||
|
||||
/* Target description. We could replace this with a pointer to the bfd,
|
||||
but that would require one. There currently isn't any such requirement
|
||||
so to avoid introducing one we record these explicitly. */
|
||||
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
|
||||
enum bfd_flavour flavour;
|
||||
/* The bfd_arch value. */
|
||||
enum bfd_architecture arch;
|
||||
/* The bfd_mach value. */
|
||||
unsigned long mach;
|
||||
/* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
|
||||
enum bfd_endian endian;
|
||||
|
||||
/* An array of pointers to symbols either at the location being disassembled
|
||||
or at the start of the function being disassembled. The array is sorted
|
||||
so that the first symbol is intended to be the one used. The others are
|
||||
present for any misc. purposes. This is not set reliably, but if it is
|
||||
not NULL, it is correct. */
|
||||
asymbol **symbols;
|
||||
/* Number of symbols in array. */
|
||||
int num_symbols;
|
||||
|
||||
/* For use by the disassembler.
|
||||
The top 16 bits are reserved for public use (and are documented here).
|
||||
The bottom 16 bits are for the internal use of the disassembler. */
|
||||
unsigned long flags;
|
||||
#define INSN_HAS_RELOC 0x80000000
|
||||
PTR private_data;
|
||||
|
||||
/* Function used to get bytes to disassemble. MEMADDR is the
|
||||
address of the stuff to be disassembled, MYADDR is the address to
|
||||
put the bytes in, and LENGTH is the number of bytes to read.
|
||||
INFO is a pointer to this struct.
|
||||
Returns an errno value or 0 for success. */
|
||||
int (*read_memory_func)
|
||||
PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info));
|
||||
|
||||
/* Function which should be called if we get an error that we can't
|
||||
recover from. STATUS is the errno value from read_memory_func and
|
||||
MEMADDR is the address that we were trying to read. INFO is a
|
||||
pointer to this struct. */
|
||||
void (*memory_error_func)
|
||||
PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
|
||||
|
||||
/* Function called to print ADDR. */
|
||||
void (*print_address_func)
|
||||
PARAMS ((bfd_vma addr, struct disassemble_info *info));
|
||||
|
||||
/* Function called to determine if there is a symbol at the given ADDR.
|
||||
If there is, the function returns 1, otherwise it returns 0.
|
||||
This is used by ports which support an overlay manager where
|
||||
the overlay number is held in the top part of an address. In
|
||||
some circumstances we want to include the overlay number in the
|
||||
address, (normally because there is a symbol associated with
|
||||
that address), but sometimes we want to mask out the overlay bits. */
|
||||
int (* symbol_at_address_func)
|
||||
PARAMS ((bfd_vma addr, struct disassemble_info * info));
|
||||
|
||||
/* These are for buffer_read_memory. */
|
||||
bfd_byte *buffer;
|
||||
bfd_vma buffer_vma;
|
||||
int buffer_length;
|
||||
|
||||
/* This variable may be set by the instruction decoder. It suggests
|
||||
the number of bytes objdump should display on a single line. If
|
||||
the instruction decoder sets this, it should always set it to
|
||||
the same value in order to get reasonable looking output. */
|
||||
int bytes_per_line;
|
||||
|
||||
/* the next two variables control the way objdump displays the raw data */
|
||||
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
|
||||
/* output will look like this:
|
||||
00: 00000000 00000000
|
||||
with the chunks displayed according to "display_endian". */
|
||||
int bytes_per_chunk;
|
||||
enum bfd_endian display_endian;
|
||||
|
||||
/* Results from instruction decoders. Not all decoders yet support
|
||||
this information. This info is set each time an instruction is
|
||||
decoded, and is only valid for the last such instruction.
|
||||
|
||||
To determine whether this decoder supports this information, set
|
||||
insn_info_valid to 0, decode an instruction, then check it. */
|
||||
|
||||
char insn_info_valid; /* Branch info has been set. */
|
||||
char branch_delay_insns; /* How many sequential insn's will run before
|
||||
a branch takes effect. (0 = normal) */
|
||||
char data_size; /* Size of data reference in insn, in bytes */
|
||||
enum dis_insn_type insn_type; /* Type of instruction */
|
||||
bfd_vma target; /* Target address of branch or dref, if known;
|
||||
zero if unknown. */
|
||||
bfd_vma target2; /* Second target address for dref2 */
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
||||
/* Standard disassemblers. Disassemble one instruction at the given
|
||||
target address. Return number of bytes processed. */
|
||||
typedef int (*disassembler_ftype)
|
||||
PARAMS((bfd_vma, disassemble_info *));
|
||||
|
||||
extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
|
||||
extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*));
|
||||
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*));
|
||||
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
extern disassembler_ftype disassembler PARAMS ((bfd *));
|
||||
|
||||
|
||||
/* This block of definitions is for particular callers who read instructions
|
||||
into a buffer before calling the instruction decoder. */
|
||||
|
||||
/* Here is a function which callers may wish to use for read_memory_func.
|
||||
It gets bytes from a buffer. */
|
||||
extern int buffer_read_memory
|
||||
PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
|
||||
|
||||
/* This function goes with buffer_read_memory.
|
||||
It prints a message using info->fprintf_func and info->stream. */
|
||||
extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
|
||||
|
||||
|
||||
/* Just print the address in hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
extern void generic_print_address
|
||||
PARAMS ((bfd_vma, struct disassemble_info *));
|
||||
|
||||
/* Always true. */
|
||||
extern int generic_symbol_at_address
|
||||
PARAMS ((bfd_vma, struct disassemble_info *));
|
||||
|
||||
/* Macro to initialize a disassemble_info struct. This should be called
|
||||
by all applications creating such a struct. */
|
||||
#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
|
||||
(INFO).flavour = bfd_target_unknown_flavour, \
|
||||
(INFO).arch = bfd_arch_unknown, \
|
||||
(INFO).mach = 0, \
|
||||
(INFO).endian = BFD_ENDIAN_UNKNOWN, \
|
||||
INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
|
||||
|
||||
/* Call this macro to initialize only the internal variables for the
|
||||
disassembler. Architecture dependent things such as byte order, or machine
|
||||
variant are not touched by this macro. This makes things much easier for
|
||||
GDB which must initialize these things seperatly. */
|
||||
|
||||
#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
|
||||
(INFO).fprintf_func = (FPRINTF_FUNC), \
|
||||
(INFO).stream = (STREAM), \
|
||||
(INFO).symbols = NULL, \
|
||||
(INFO).num_symbols = 0, \
|
||||
(INFO).buffer = NULL, \
|
||||
(INFO).buffer_vma = 0, \
|
||||
(INFO).buffer_length = 0, \
|
||||
(INFO).read_memory_func = buffer_read_memory, \
|
||||
(INFO).memory_error_func = perror_memory, \
|
||||
(INFO).print_address_func = generic_print_address, \
|
||||
(INFO).symbol_at_address_func = generic_symbol_at_address, \
|
||||
(INFO).flags = 0, \
|
||||
(INFO).bytes_per_line = 0, \
|
||||
(INFO).bytes_per_chunk = 0, \
|
||||
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
|
||||
(INFO).insn_info_valid = 0
|
||||
|
||||
#endif /* ! defined (DIS_ASM_H) */
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Disassemble from a buffer, for GNU.
|
||||
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "dis-asm.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%x is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* Generic Dynamic compiler generator
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <elf.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "thunk.h"
|
||||
|
||||
/* all dynamically generated functions begin with this code */
|
||||
#define OP_PREFIX "op_"
|
||||
|
||||
int elf_must_swap(Elf32_Ehdr *h)
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
uint8_t b[4];
|
||||
} swaptest;
|
||||
|
||||
swaptest.i = 1;
|
||||
return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
|
||||
(swaptest.b[0] == 0);
|
||||
}
|
||||
|
||||
void swab16s(uint16_t *p)
|
||||
{
|
||||
*p = bswap16(*p);
|
||||
}
|
||||
|
||||
void swab32s(uint32_t *p)
|
||||
{
|
||||
*p = bswap32(*p);
|
||||
}
|
||||
|
||||
void swab64s(uint32_t *p)
|
||||
{
|
||||
*p = bswap64(*p);
|
||||
}
|
||||
|
||||
void elf_swap_ehdr(Elf32_Ehdr *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 */
|
||||
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 */
|
||||
swab16s(&h-> e_phnum); /* Program header table entry count */
|
||||
swab16s(&h-> e_shentsize); /* Section header table entry size */
|
||||
swab16s(&h-> e_shnum); /* Section header table entry count */
|
||||
swab16s(&h-> e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
void elf_swap_shdr(Elf32_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 */
|
||||
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 */
|
||||
}
|
||||
|
||||
void elf_swap_phdr(Elf32_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 */
|
||||
swab32s(&h->p_flags); /* Segment flags */
|
||||
swab32s(&h->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
int do_swap;
|
||||
int e_machine;
|
||||
|
||||
uint16_t get16(uint16_t *p)
|
||||
{
|
||||
uint16_t val;
|
||||
val = *p;
|
||||
if (do_swap)
|
||||
val = bswap16(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t get32(uint32_t *p)
|
||||
{
|
||||
uint32_t val;
|
||||
val = *p;
|
||||
if (do_swap)
|
||||
val = bswap32(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void put16(uint16_t *p, uint16_t val)
|
||||
{
|
||||
if (do_swap)
|
||||
val = bswap16(val);
|
||||
*p = val;
|
||||
}
|
||||
|
||||
void put32(uint32_t *p, uint32_t val)
|
||||
{
|
||||
if (do_swap)
|
||||
val = bswap32(val);
|
||||
*p = val;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "dyngen: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
const char *shname;
|
||||
Elf32_Shdr *sec;
|
||||
|
||||
for(i = 0; i < shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if (!sec->sh_name)
|
||||
continue;
|
||||
shname = shstr + sec->sh_name;
|
||||
if (!strcmp(shname, name))
|
||||
return sec;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *load_data(int fd, long offset, unsigned int size)
|
||||
{
|
||||
char *data;
|
||||
|
||||
data = malloc(size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
if (read(fd, data, size) != size) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
int copy_size = 0;
|
||||
uint8_t *p_start, *p_end;
|
||||
int nb_args, i;
|
||||
uint8_t args_present[MAX_ARGS];
|
||||
const char *sym_name, *p;
|
||||
|
||||
/* compute exact size excluding return instruction */
|
||||
p_start = text + offset;
|
||||
p_end = p_start + size;
|
||||
switch(e_machine) {
|
||||
case EM_386:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = p_end - 1;
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
if (p[0] != 0xc3)
|
||||
error("ret expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
case EM_PPC:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 4);
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
if (get32((uint32_t *)p) != 0x4e800020)
|
||||
error("blr expected at the end of %s", name);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nb_args = 0;
|
||||
while (nb_args < MAX_ARGS && args_present[nb_args])
|
||||
nb_args++;
|
||||
for(i = nb_args; i < MAX_ARGS; i++) {
|
||||
if (args_present[i])
|
||||
error("inconsistent argument numbering in %s", name);
|
||||
}
|
||||
|
||||
if (gen_switch) {
|
||||
|
||||
/* output C code */
|
||||
fprintf(outfile, "case INDEX_%s: {\n", name);
|
||||
if (nb_args > 0) {
|
||||
fprintf(outfile, " long ");
|
||||
for(i = 0; i < nb_args; i++) {
|
||||
if (i != 0)
|
||||
fprintf(outfile, ", ");
|
||||
fprintf(outfile, "param%d", i + 1);
|
||||
}
|
||||
fprintf(outfile, ";\n");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
|
||||
for(i = 0; i < nb_args; i++) {
|
||||
fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
|
||||
}
|
||||
|
||||
/* patch relocations */
|
||||
switch(e_machine) {
|
||||
case EM_386:
|
||||
{
|
||||
Elf32_Rel *rel;
|
||||
char name[256];
|
||||
int type;
|
||||
long addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = get32((uint32_t *)(text + rel->r_offset));
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\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",
|
||||
rel->r_offset - offset, name, rel->r_offset - offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported i386 relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EM_PPC:
|
||||
{
|
||||
Elf32_Rela *rel;
|
||||
char name[256];
|
||||
int type;
|
||||
long addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
case R_PPC_ADDR32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\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",
|
||||
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",
|
||||
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",
|
||||
rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported powerpc relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unsupported CPU for relocations (%d)", e_machine);
|
||||
}
|
||||
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
|
||||
fprintf(outfile, "}\n");
|
||||
fprintf(outfile, "break;\n\n");
|
||||
} else {
|
||||
fprintf(outfile, "static inline void gen_%s(", name);
|
||||
if (nb_args == 0) {
|
||||
fprintf(outfile, "void");
|
||||
} else {
|
||||
for(i = 0; i < nb_args; i++) {
|
||||
if (i != 0)
|
||||
fprintf(outfile, ", ");
|
||||
fprintf(outfile, "long param%d", i + 1);
|
||||
}
|
||||
}
|
||||
fprintf(outfile, ")\n");
|
||||
fprintf(outfile, "{\n");
|
||||
for(i = 0; i < nb_args; i++) {
|
||||
fprintf(outfile, " *gen_opparam_ptr++ = param%d;\n", i + 1);
|
||||
}
|
||||
fprintf(outfile, " *gen_opc_ptr++ = INDEX_%s;\n", name);
|
||||
fprintf(outfile, "}\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* load an elf object file */
|
||||
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;
|
||||
int i, j, nb_syms;
|
||||
Elf32_Sym *symtab, *sym;
|
||||
const char *cpu_name;
|
||||
char *shstr, *strtab;
|
||||
uint8_t *text;
|
||||
void *relocs;
|
||||
int nb_relocs, reloc_sh_type;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
error("can't open file '%s'", filename);
|
||||
|
||||
/* Read ELF header. */
|
||||
if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
|
||||
error("unable to read file header");
|
||||
|
||||
/* Check ELF identification. */
|
||||
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|
||||
|| 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");
|
||||
}
|
||||
|
||||
do_swap = elf_must_swap(&ehdr);
|
||||
if (do_swap)
|
||||
elf_swap_ehdr(&ehdr);
|
||||
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;
|
||||
|
||||
/* read section headers */
|
||||
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr));
|
||||
if (do_swap) {
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
elf_swap_shdr(&shdr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
sec = &shdr[ehdr.e_shstrndx];
|
||||
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
|
||||
/* text section */
|
||||
|
||||
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
|
||||
if (!text_sec)
|
||||
error("could not find .text section");
|
||||
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
|
||||
|
||||
/* find text relocations, if any */
|
||||
nb_relocs = 0;
|
||||
relocs = NULL;
|
||||
reloc_sh_type = 0;
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
|
||||
sec->sh_info == (text_sec - shdr)) {
|
||||
reloc_sh_type = sec->sh_type;
|
||||
relocs = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
nb_relocs = sec->sh_size / sec->sh_entsize;
|
||||
if (do_swap) {
|
||||
if (sec->sh_type == SHT_REL) {
|
||||
Elf32_Rel *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swab32s(&rel->r_offset);
|
||||
swab32s(&rel->r_info);
|
||||
}
|
||||
} else {
|
||||
Elf32_Rela *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swab32s(&rel->r_offset);
|
||||
swab32s(&rel->r_info);
|
||||
swab32s(&rel->r_addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
|
||||
if (!symtab_sec)
|
||||
error("could not find .symtab section");
|
||||
strtab_sec = &shdr[symtab_sec->sh_link];
|
||||
|
||||
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
|
||||
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
|
||||
|
||||
nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym);
|
||||
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);
|
||||
swab16s(&sym->st_shndx);
|
||||
}
|
||||
}
|
||||
|
||||
switch(e_machine) {
|
||||
case EM_386:
|
||||
cpu_name = "i386";
|
||||
break;
|
||||
case EM_PPC:
|
||||
cpu_name = "ppc";
|
||||
break;
|
||||
case EM_MIPS:
|
||||
cpu_name = "mips";
|
||||
break;
|
||||
case EM_ARM:
|
||||
cpu_name = "arm";
|
||||
break;
|
||||
case EM_SPARC:
|
||||
cpu_name = "sparc";
|
||||
break;
|
||||
default:
|
||||
error("unsupported CPU (e_machine=%d)", e_machine);
|
||||
}
|
||||
|
||||
if (do_print_enum) {
|
||||
fprintf(outfile, "DEF(end)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name, *p;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, &p)) {
|
||||
fprintf(outfile, "DEF(%s)\n", p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* generate big code generation switch */
|
||||
fprintf(outfile,
|
||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||
" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
|
||||
"{\n"
|
||||
" uint8_t *gen_code_ptr;\n"
|
||||
" const uint16_t *opc_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n"
|
||||
" gen_code_ptr = gen_code_buf;\n"
|
||||
" opc_ptr = opc_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n"
|
||||
" for(;;) {\n"
|
||||
" switch(*opc_ptr++) {\n"
|
||||
);
|
||||
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, NULL)) {
|
||||
#if 0
|
||||
printf("%4d: %s pos=0x%08x len=%d\n",
|
||||
i, name, sym->st_value, sym->st_size);
|
||||
#endif
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile,
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" the_end:\n"
|
||||
);
|
||||
|
||||
/* generate a return */
|
||||
switch(e_machine) {
|
||||
case EM_386:
|
||||
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
|
||||
break;
|
||||
case EM_PPC:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
|
||||
break;
|
||||
default:
|
||||
error("no return generation for cpu '%s'", cpu_name);
|
||||
}
|
||||
|
||||
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
|
||||
fprintf(outfile, "}\n\n");
|
||||
|
||||
/* generate gen_xxx functions */
|
||||
/* XXX: suppress the use of these functions to simplify code */
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, NULL)) {
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("dyngen (c) 2003 Fabrice Bellard\n"
|
||||
"usage: dyngen [-o outfile] [-c] objfile\n"
|
||||
"Generate a dynamic code generator from an object file\n"
|
||||
"-c output enum of operations\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, do_print_enum;
|
||||
const char *filename, *outfilename;
|
||||
FILE *outfile;
|
||||
|
||||
outfilename = "out.c";
|
||||
do_print_enum = 0;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:c");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
outfilename = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
do_print_enum = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc)
|
||||
usage();
|
||||
filename = argv[optind];
|
||||
outfile = fopen(outfilename, "w");
|
||||
if (!outfile)
|
||||
error("could not open '%s'", outfilename);
|
||||
load_elf(filename, outfile, do_print_enum);
|
||||
fclose(outfile);
|
||||
return 0;
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
typedef uint32_t elf_greg_t;
|
||||
|
||||
#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(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;
|
||||
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* i386 emulator main execution loop
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
#define DEBUG_FLUSH
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
/* maximum total translate dcode allocated */
|
||||
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
/* threshold to flush the translated code buffer */
|
||||
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
|
||||
#define CODE_GEN_HASH_BITS 15
|
||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
||||
|
||||
typedef struct TranslationBlock {
|
||||
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
unsigned long cs_base; /* CS base for this block */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
struct TranslationBlock *hash_next; /* next matching block */
|
||||
} TranslationBlock;
|
||||
|
||||
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
|
||||
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
int nb_tbs;
|
||||
|
||||
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
uint8_t *code_gen_ptr;
|
||||
|
||||
/* thread support */
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
"0: lwarx %0,0,%1 ;"
|
||||
" xor. %0,%3,%0;"
|
||||
" bne 1f;"
|
||||
" stwcx. %2,0,%1;"
|
||||
" bne- 0b;"
|
||||
"1: "
|
||||
: "=&r" (ret)
|
||||
: "r" (p), "r" (1), "r" (0)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int global_cpu_lock = 0;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
while (testandset(&global_cpu_lock));
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
global_cpu_lock = 0;
|
||||
}
|
||||
|
||||
/* exception support */
|
||||
/* NOTE: not static to force relocation generation by GCC */
|
||||
void raise_exception(int exception_index)
|
||||
{
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
#ifdef reg_EAX
|
||||
env->regs[R_EAX] = EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
env->regs[R_ECX] = ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
env->regs[R_EDX] = EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
env->regs[R_EBX] = EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
env->regs[R_ESP] = ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
env->regs[R_EBP] = EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
env->regs[R_ESI] = ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
env->regs[R_EDI] = EDI;
|
||||
#endif
|
||||
env->exception_index = exception_index;
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_EXEC)
|
||||
static const char *cc_op_str[] = {
|
||||
"DYNAMIC",
|
||||
"EFLAGS",
|
||||
"MUL",
|
||||
"ADDB",
|
||||
"ADDW",
|
||||
"ADDL",
|
||||
"ADCB",
|
||||
"ADCW",
|
||||
"ADCL",
|
||||
"SUBB",
|
||||
"SUBW",
|
||||
"SUBL",
|
||||
"SBBB",
|
||||
"SBBW",
|
||||
"SBBL",
|
||||
"LOGICB",
|
||||
"LOGICW",
|
||||
"LOGICL",
|
||||
"INCB",
|
||||
"INCW",
|
||||
"INCL",
|
||||
"DECB",
|
||||
"DECW",
|
||||
"DECL",
|
||||
"SHLB",
|
||||
"SHLW",
|
||||
"SHLL",
|
||||
"SARB",
|
||||
"SARW",
|
||||
"SARL",
|
||||
};
|
||||
|
||||
static void cpu_x86_dump_state(FILE *f)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
eflags |= (DF & DIRECTION_FLAG);
|
||||
fprintf(f,
|
||||
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
|
||||
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
|
||||
"EIP=%08x\n",
|
||||
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
|
||||
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
|
||||
env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
|
||||
eflags & DIRECTION_FLAG ? 'D' : '-',
|
||||
eflags & CC_O ? 'O' : '-',
|
||||
eflags & CC_S ? 'S' : '-',
|
||||
eflags & CC_Z ? 'Z' : '-',
|
||||
eflags & CC_A ? 'A' : '-',
|
||||
eflags & CC_P ? 'P' : '-',
|
||||
eflags & CC_C ? 'C' : '-',
|
||||
env->eip);
|
||||
#if 1
|
||||
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
||||
(double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void cpu_x86_tblocks_init(void)
|
||||
{
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush all the translation blocks */
|
||||
static void tb_flush(void)
|
||||
{
|
||||
int i;
|
||||
#ifdef DEBUG_FLUSH
|
||||
printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
|
||||
code_gen_ptr - code_gen_buffer,
|
||||
nb_tbs,
|
||||
(code_gen_ptr - code_gen_buffer) / nb_tbs);
|
||||
#endif
|
||||
nb_tbs = 0;
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
|
||||
tb_hash[i] = NULL;
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
/* XXX: flush processor icache at this point */
|
||||
}
|
||||
|
||||
/* find a translation block in the translation cache. If not found,
|
||||
return NULL and the pointer to the last element of the list in pptb */
|
||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
unsigned long pc,
|
||||
unsigned long cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate a new translation block. flush the translation buffer if
|
||||
too many translation blocks or too much generated code */
|
||||
static inline TranslationBlock *tb_alloc(void)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
|
||||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
|
||||
tb_flush();
|
||||
tb = &tbs[nb_tbs++];
|
||||
return tb;
|
||||
}
|
||||
|
||||
int cpu_x86_exec(CPUX86State *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_A0;
|
||||
CPUX86State *saved_env;
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
int saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
int saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
int saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
int saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
int saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
int saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
int code_gen_size, ret;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
unsigned int flags;
|
||||
|
||||
/* first we save global registers */
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
saved_A0 = A0;
|
||||
saved_env = env;
|
||||
env = env1;
|
||||
#ifdef reg_EAX
|
||||
saved_EAX = EAX;
|
||||
EAX = env->regs[R_EAX];
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
saved_ECX = ECX;
|
||||
ECX = env->regs[R_ECX];
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
saved_EDX = EDX;
|
||||
EDX = env->regs[R_EDX];
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
saved_EBX = EBX;
|
||||
EBX = env->regs[R_EBX];
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
saved_ESP = ESP;
|
||||
ESP = env->regs[R_ESP];
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
saved_EBP = EBP;
|
||||
EBP = env->regs[R_EBP];
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
saved_ESI = ESI;
|
||||
ESI = env->regs[R_ESI];
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
saved_EDI = EDI;
|
||||
EDI = env->regs[R_EDI];
|
||||
#endif
|
||||
|
||||
/* put eflags in CPU temporary format */
|
||||
T0 = env->eflags;
|
||||
op_movl_eflags_T0();
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->interrupt_request = 0;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
for(;;) {
|
||||
if (env->interrupt_request) {
|
||||
raise_exception(EXCP_INTERRUPT);
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
cpu_x86_dump_state(logfile);
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
|
||||
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
|
||||
flags |= (((unsigned long)env->seg_cache[R_DS].base |
|
||||
(unsigned long)env->seg_cache[R_ES].base |
|
||||
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
cs_base = env->seg_cache[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
/* if no translated code available, then translate it now */
|
||||
/* XXX: very inefficient: we lock all the cpus when
|
||||
generating code */
|
||||
cpu_lock();
|
||||
tc_ptr = code_gen_ptr;
|
||||
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
|
||||
&code_gen_size, pc, cs_base, flags);
|
||||
/* if invalid instruction, signal it */
|
||||
if (ret != 0) {
|
||||
cpu_unlock();
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
}
|
||||
tb = tb_alloc();
|
||||
*ptb = tb;
|
||||
tb->pc = (unsigned long)pc;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->hash_next = NULL;
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
cpu_unlock();
|
||||
}
|
||||
/* execute the generated code */
|
||||
tc_ptr = tb->tc_ptr;
|
||||
gen_func = (void *)tc_ptr;
|
||||
gen_func();
|
||||
}
|
||||
}
|
||||
ret = env->exception_index;
|
||||
|
||||
/* restore flags in standard format */
|
||||
op_movl_T0_eflags();
|
||||
env->eflags = T0;
|
||||
|
||||
/* restore global registers */
|
||||
#ifdef reg_EAX
|
||||
EAX = saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
ECX = saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
EDX = saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
EBX = saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
ESP = saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
EBP = saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
ESI = saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
A0 = saved_A0;
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cpu_x86_interrupt(CPUX86State *s)
|
||||
{
|
||||
s->interrupt_request = 1;
|
||||
}
|
||||
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
load_seg(seg_reg, selector);
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
static inline int handle_cpu_signal(unsigned long pc,
|
||||
sigset_t *old_set)
|
||||
{
|
||||
#ifdef DEBUG_SIGNAL
|
||||
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
|
||||
pc, *(unsigned long *)old_set);
|
||||
#endif
|
||||
if (pc >= (unsigned long)code_gen_buffer &&
|
||||
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
/* XXX: need to compute virtual pc position by retranslating
|
||||
code. The rest of the CPU state should be correct. */
|
||||
raise_exception(EXCP0D_GPF);
|
||||
/* never comes here */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
sigset_t *pold_set;
|
||||
|
||||
pc = uc->uc_mcontext.gregs[EIP];
|
||||
pold_set = &uc->uc_sigmask;
|
||||
return handle_cpu_signal(pc, pold_set);
|
||||
#else
|
||||
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* i386 execution defines
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
#define NULL 0
|
||||
#include <fenv.h>
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
#ifdef __i386__
|
||||
register unsigned int T0 asm("ebx");
|
||||
register unsigned int T1 asm("esi");
|
||||
register unsigned int A0 asm("edi");
|
||||
register struct CPUX86State *env asm("ebp");
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
register unsigned int EAX asm("r16");
|
||||
register unsigned int ECX asm("r17");
|
||||
register unsigned int EDX asm("r18");
|
||||
register unsigned int EBX asm("r19");
|
||||
register unsigned int ESP asm("r20");
|
||||
register unsigned int EBP asm("r21");
|
||||
register unsigned int ESI asm("r22");
|
||||
register unsigned int EDI asm("r23");
|
||||
register unsigned int T0 asm("r24");
|
||||
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 reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
#define reg_EBX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#define reg_ESI
|
||||
#define reg_EDI
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
register unsigned int T0 asm("r4");
|
||||
register unsigned int T1 asm("r5");
|
||||
register unsigned int A0 asm("r6");
|
||||
register struct CPUX86State *env asm("r7");
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
register unsigned int T0 asm("s0");
|
||||
register unsigned int T1 asm("s1");
|
||||
register unsigned int A0 asm("s2");
|
||||
register struct CPUX86State *env asm("s3");
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
register unsigned int T0 asm("l0");
|
||||
register unsigned int T1 asm("l1");
|
||||
register unsigned int A0 asm("l2");
|
||||
register struct CPUX86State *env asm("l3");
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
|
||||
#ifndef reg_EAX
|
||||
#define EAX (env->regs[R_EAX])
|
||||
#endif
|
||||
#ifndef reg_ECX
|
||||
#define ECX (env->regs[R_ECX])
|
||||
#endif
|
||||
#ifndef reg_EDX
|
||||
#define EDX (env->regs[R_EDX])
|
||||
#endif
|
||||
#ifndef reg_EBX
|
||||
#define EBX (env->regs[R_EBX])
|
||||
#endif
|
||||
#ifndef reg_ESP
|
||||
#define ESP (env->regs[R_ESP])
|
||||
#endif
|
||||
#ifndef reg_EBP
|
||||
#define EBP (env->regs[R_EBP])
|
||||
#endif
|
||||
#ifndef reg_ESI
|
||||
#define ESI (env->regs[R_ESI])
|
||||
#endif
|
||||
#ifndef reg_EDI
|
||||
#define EDI (env->regs[R_EDI])
|
||||
#endif
|
||||
#define EIP (env->eip)
|
||||
#define DF (env->df)
|
||||
|
||||
#define CC_SRC (env->cc_src)
|
||||
#define CC_DST (env->cc_dst)
|
||||
#define CC_OP (env->cc_op)
|
||||
|
||||
/* float macros */
|
||||
#define FT0 (env->ft0)
|
||||
#define ST0 (env->fpregs[env->fpstt])
|
||||
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
|
||||
#define ST1 ST(1)
|
||||
|
||||
extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM1 ((long)(&__op_param1))
|
||||
#define PARAM2 ((long)(&__op_param2))
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
|
||||
#include "cpu-i386.h"
|
||||
|
||||
typedef struct CCTable {
|
||||
int (*compute_all)(void); /* return all the flags */
|
||||
int (*compute_c)(void); /* return the C flag */
|
||||
} CCTable;
|
||||
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector);
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void raise_exception(int exception_index);
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void);
|
||||
void OPPROTO op_movl_T0_eflags(void);
|
||||
+2299
File diff suppressed because it is too large
Load Diff
+22
-19
@@ -10,7 +10,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gemu.h"
|
||||
#include "qemu.h"
|
||||
|
||||
#include "linux_bin.h"
|
||||
#include "elf.h"
|
||||
@@ -261,6 +261,9 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
/* 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,
|
||||
@@ -335,9 +338,8 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
unsigned int *argv, *envp, *dlinfo;
|
||||
unsigned int *sp;
|
||||
char **alpha_envp;
|
||||
target_ulong *argv, *envp, *dlinfo;
|
||||
target_ulong *sp;
|
||||
|
||||
/*
|
||||
* Force 16 byte alignment here for generality.
|
||||
@@ -350,14 +352,13 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
sp -= argc+1;
|
||||
argv = sp;
|
||||
if (!ibcs) {
|
||||
put_user(envp,--sp);
|
||||
put_user(argv,--sp);
|
||||
put_user(tswapl((target_ulong)envp),--sp);
|
||||
put_user(tswapl((target_ulong)argv),--sp);
|
||||
}
|
||||
alpha_envp = (char **)malloc((envc+1) * sizeof(char *));
|
||||
|
||||
#define NEW_AUX_ENT(id, val) \
|
||||
put_user ((id), dlinfo++); \
|
||||
put_user ((val), dlinfo++)
|
||||
put_user (tswapl(id), dlinfo++); \
|
||||
put_user (tswapl(val), dlinfo++)
|
||||
|
||||
if (exec) { /* Put this here for an ELF program interpreter */
|
||||
struct elf_phdr * eppnt;
|
||||
@@ -377,22 +378,19 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
}
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
put_user((unsigned int)argc,--sp);
|
||||
put_user(tswapl(argc),--sp);
|
||||
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
while (argc-->0) {
|
||||
put_user(p,argv++);
|
||||
put_user(tswapl((target_ulong)p),argv++);
|
||||
while (get_user(p++)) /* nothing */ ;
|
||||
}
|
||||
put_user(0,argv);
|
||||
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
__environ = alpha_envp;
|
||||
while (envc-->0) {
|
||||
*alpha_envp++ = (char *)p;
|
||||
put_user(p,envp++);
|
||||
put_user(tswapl((target_ulong)p),envp++);
|
||||
while (get_user(p++)) /* nothing */ ;
|
||||
}
|
||||
put_user(0,envp);
|
||||
*alpha_envp = 0;
|
||||
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
return sp;
|
||||
}
|
||||
@@ -544,8 +542,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
|
||||
|
||||
|
||||
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
|
||||
struct image_info * info)
|
||||
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
{
|
||||
struct elfhdr elf_ex;
|
||||
struct elfhdr interp_elf_ex;
|
||||
@@ -581,7 +579,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
|
||||
/* First of all, some simple consistency checks */
|
||||
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
|
||||
(! elf_check_arch(elf_ex.e_machine))) {
|
||||
@@ -608,6 +605,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
|
||||
return -errno;
|
||||
}
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
elf_ppnt = elf_phdata;
|
||||
for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
|
||||
bswap_phdr(elf_ppnt);
|
||||
}
|
||||
#endif
|
||||
elf_ppnt = elf_phdata;
|
||||
|
||||
elf_bss = 0;
|
||||
@@ -909,7 +912,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
|
||||
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct pt_regs * regs, struct image_info *infop)
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
|
||||
+8
-1
@@ -1,7 +1,7 @@
|
||||
/* emulated ioctl list */
|
||||
|
||||
IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCGETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
|
||||
@@ -199,8 +199,12 @@
|
||||
IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
#if 0
|
||||
/* we invalidate these defines because they have a same number as
|
||||
termios ioctls */
|
||||
IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
|
||||
IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
|
||||
#endif
|
||||
IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
|
||||
@@ -280,3 +284,6 @@
|
||||
IOCTL(HDIO_SET_DMA, 0, TYPE_INT)
|
||||
IOCTL(HDIO_SET_32BIT, 0, TYPE_INT)
|
||||
IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT)
|
||||
|
||||
IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
|
||||
IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
|
||||
|
||||
+177
-220
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* emu main
|
||||
* qemu main
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
@@ -20,15 +20,23 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <elf.h>
|
||||
#include <endian.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gemu.h"
|
||||
#include "qemu.h"
|
||||
|
||||
#include "i386/hsw_interp.h"
|
||||
#include "cpu-i386.h"
|
||||
|
||||
unsigned long x86_stack_size;
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
|
||||
/* 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, ...)
|
||||
@@ -40,271 +48,220 @@ void gemu_log(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* virtual x86 CPU stuff */
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
extern int invoke_code16(Interp_ENV *, int, int);
|
||||
extern int invoke_code32(Interp_ENV *, int);
|
||||
extern char *e_print_cpuemu_regs(ENVPARAMS, int is32);
|
||||
extern char *e_emu_disasm(ENVPARAMS, unsigned char *org, int is32);
|
||||
extern void init_npu(void);
|
||||
|
||||
Interp_ENV env_global;
|
||||
Interp_ENV *envp_global;
|
||||
|
||||
QWORD EMUtime = 0;
|
||||
|
||||
int CEmuStat = 0;
|
||||
|
||||
long instr_count;
|
||||
|
||||
/* who will initialize this? */
|
||||
unsigned long io_bitmap[IO_BITMAP_SIZE+1];
|
||||
|
||||
/* debug flag, 0=disable 1..9=level */
|
||||
int d_emu = 0;
|
||||
|
||||
unsigned long CRs[5] =
|
||||
void cpu_x86_outb(int addr, int val)
|
||||
{
|
||||
0x00000013, /* valid bits: 0xe005003f */
|
||||
0x00000000, /* invalid */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000
|
||||
};
|
||||
|
||||
/*
|
||||
* DR0-3 = linear address of breakpoint 0-3
|
||||
* DR4=5 = reserved
|
||||
* DR6 b0-b3 = BP active
|
||||
* b13 = BD
|
||||
* b14 = BS
|
||||
* b15 = BT
|
||||
* DR7 b0-b1 = G:L bp#0
|
||||
* b2-b3 = G:L bp#1
|
||||
* b4-b5 = G:L bp#2
|
||||
* b6-b7 = G:L bp#3
|
||||
* b8-b9 = GE:LE
|
||||
* b13 = GD
|
||||
* b16-19= LLRW bp#0 LL=00(1),01(2),11(4)
|
||||
* b20-23= LLRW bp#1 RW=00(x),01(w),11(rw)
|
||||
* b24-27= LLRW bp#2
|
||||
* b28-31= LLRW bp#3
|
||||
*/
|
||||
unsigned long DRs[8] =
|
||||
{
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0xffff1ff0,
|
||||
0x00000400,
|
||||
0xffff1ff0,
|
||||
0x00000400
|
||||
};
|
||||
|
||||
unsigned long TRs[2] =
|
||||
{
|
||||
0x00000000,
|
||||
0x00000000
|
||||
};
|
||||
|
||||
void FatalAppExit(UINT wAction, LPCSTR lpText)
|
||||
{
|
||||
fprintf(stderr, "Fatal error '%s' in CPU\n", lpText);
|
||||
exit(1);
|
||||
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
||||
}
|
||||
|
||||
int e_debug_check(unsigned char *PC)
|
||||
void cpu_x86_outw(int addr, int val)
|
||||
{
|
||||
register unsigned long d7 = DRs[7];
|
||||
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
||||
}
|
||||
|
||||
if (d7&0x03) {
|
||||
if (d7&0x30000) return 0; /* only execute(00) bkp */
|
||||
if ((long)PC==DRs[0]) {
|
||||
e_printf("DBRK: DR0 hit at %p\n",PC);
|
||||
DRs[6] |= 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (d7&0x0c) {
|
||||
if (d7&0x300000) return 0;
|
||||
if ((long)PC==DRs[1]) {
|
||||
e_printf("DBRK: DR1 hit at %p\n",PC);
|
||||
DRs[6] |= 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (d7&0x30) {
|
||||
if (d7&0x3000000) return 0;
|
||||
if ((long)PC==DRs[2]) {
|
||||
e_printf("DBRK: DR2 hit at %p\n",PC);
|
||||
DRs[6] |= 4;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (d7&0xc0) {
|
||||
if (d7&0x30000000) return 0;
|
||||
if ((long)PC==DRs[3]) {
|
||||
e_printf("DBRK: DR3 hit at %p\n",PC);
|
||||
DRs[6] |= 8;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
void cpu_x86_outl(int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
||||
}
|
||||
|
||||
int cpu_x86_inb(int addr)
|
||||
{
|
||||
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Debug stuff */
|
||||
void logstr(unsigned long mask, const char *fmt,...)
|
||||
int cpu_x86_inw(int addr)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* unconditional message into debug log and stderr */
|
||||
#undef error
|
||||
void error(const char *fmt, ...)
|
||||
int cpu_x86_inl(int addr)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PortIO(DWORD port, DWORD value, UINT size, BOOL is_write)
|
||||
void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int seg32_bit)
|
||||
{
|
||||
fprintf(stderr, "IO: %s port=0x%lx value=0x%lx size=%d",
|
||||
is_write ? "write" : "read", port, value, size);
|
||||
return value;
|
||||
unsigned int e1, e2, limit_in_pages;
|
||||
limit_in_pages = 0;
|
||||
if (limit > 0xffff) {
|
||||
limit = limit >> 12;
|
||||
limit_in_pages = 1;
|
||||
}
|
||||
e1 = (addr << 16) | (limit & 0xffff);
|
||||
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
|
||||
e2 |= limit_in_pages << 23; /* byte granularity */
|
||||
e2 |= seg32_bit << 22; /* 32 bit segment */
|
||||
stl((uint8_t *)ptr, e1);
|
||||
stl((uint8_t *)ptr + 4, e2);
|
||||
}
|
||||
|
||||
void LogProcName(WORD wSel, WORD wOff, WORD wAction)
|
||||
uint64_t gdt_table[6];
|
||||
|
||||
void cpu_loop(struct CPUX86State *env)
|
||||
{
|
||||
|
||||
int err;
|
||||
uint8_t *pc;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
err = cpu_x86_exec(env);
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
switch(err) {
|
||||
case EXCP0D_GPF:
|
||||
if (pc[0] == 0xcd && pc[1] == 0x80) {
|
||||
/* syscall */
|
||||
env->eip += 2;
|
||||
env->regs[R_EAX] = do_syscall(env,
|
||||
env->regs[R_EAX],
|
||||
env->regs[R_EBX],
|
||||
env->regs[R_ECX],
|
||||
env->regs[R_EDX],
|
||||
env->regs[R_ESI],
|
||||
env->regs[R_EDI],
|
||||
env->regs[R_EBP]);
|
||||
} else {
|
||||
/* XXX: more precise info */
|
||||
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 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);
|
||||
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);
|
||||
break;
|
||||
case EXCP06_ILLOP:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n",
|
||||
(long)pc, err);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
|
||||
void INT_handler(int num, void *env)
|
||||
{
|
||||
fprintf(stderr, "EM86: int %d\n", num);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
/* XXX: currently we use LDT entries */
|
||||
#define __USER_CS (0x23|4)
|
||||
#define __USER_DS (0x2B|4)
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: gemu program [arguments...]\n"
|
||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu [-d] program [arguments...]\n"
|
||||
"Linux x86 emulator\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUX86State *global_env;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *filename;
|
||||
struct pt_regs regs1, *regs = ®s1;
|
||||
struct target_pt_regs regs1, *regs = ®s1;
|
||||
struct image_info info1, *info = &info1;
|
||||
Interp_ENV *env;
|
||||
CPUX86State *env;
|
||||
int optind;
|
||||
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
filename = argv[1];
|
||||
loglevel = 0;
|
||||
optind = 1;
|
||||
if (argv[optind] && !strcmp(argv[optind], "-d")) {
|
||||
loglevel = 1;
|
||||
optind++;
|
||||
}
|
||||
filename = argv[optind];
|
||||
|
||||
/* init debug */
|
||||
if (loglevel) {
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/* Zero out regs */
|
||||
memset(regs, 0, sizeof(struct pt_regs));
|
||||
memset(regs, 0, sizeof(struct target_pt_regs));
|
||||
|
||||
/* Zero out image_info */
|
||||
memset(info, 0, sizeof(struct image_info));
|
||||
|
||||
if(elf_exec(filename, argv+1, __environ, regs, info) != 0) {
|
||||
if(elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("start_brk 0x%08lx\n" , info->start_brk);
|
||||
printf("end_code 0x%08lx\n" , info->end_code);
|
||||
printf("start_code 0x%08lx\n" , info->start_code);
|
||||
printf("end_data 0x%08lx\n" , info->end_data);
|
||||
printf("start_stack 0x%08lx\n" , info->start_stack);
|
||||
printf("brk 0x%08lx\n" , info->brk);
|
||||
printf("esp 0x%08lx\n" , regs->esp);
|
||||
printf("eip 0x%08lx\n" , regs->eip);
|
||||
#endif
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
|
||||
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
|
||||
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
|
||||
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
|
||||
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
|
||||
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
|
||||
fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
|
||||
fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
|
||||
}
|
||||
|
||||
target_set_brk((char *)info->brk);
|
||||
syscall_init();
|
||||
signal_init();
|
||||
|
||||
env = &env_global;
|
||||
envp_global = env;
|
||||
memset(env, 0, sizeof(Interp_ENV));
|
||||
env = cpu_x86_init();
|
||||
global_env = env;
|
||||
|
||||
env->rax.e = regs->eax;
|
||||
env->rbx.e = regs->ebx;
|
||||
env->rcx.e = regs->ecx;
|
||||
env->rdx.e = regs->edx;
|
||||
env->rsi.esi = regs->esi;
|
||||
env->rdi.edi = regs->edi;
|
||||
env->rbp.ebp = regs->ebp;
|
||||
env->rsp.esp = regs->esp;
|
||||
env->cs.cs = __USER_CS;
|
||||
env->ds.ds = __USER_DS;
|
||||
env->es.es = __USER_DS;
|
||||
env->ss.ss = __USER_DS;
|
||||
env->fs.fs = __USER_DS;
|
||||
env->gs.gs = __USER_DS;
|
||||
env->trans_addr = regs->eip;
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
env->regs[R_ECX] = regs->ecx;
|
||||
env->regs[R_EDX] = regs->edx;
|
||||
env->regs[R_ESI] = regs->esi;
|
||||
env->regs[R_EDI] = regs->edi;
|
||||
env->regs[R_EBP] = regs->ebp;
|
||||
env->regs[R_ESP] = regs->esp;
|
||||
env->eip = regs->eip;
|
||||
|
||||
LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
|
||||
LDT[__USER_CS >> 3].dwSelLimit = 0xfffff;
|
||||
LDT[__USER_CS >> 3].lpSelBase = NULL;
|
||||
/* linux segment setup */
|
||||
env->gdt.base = (void *)gdt_table;
|
||||
env->gdt.limit = sizeof(gdt_table) - 1;
|
||||
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
|
||||
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
|
||||
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
||||
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_FS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_GS, __USER_DS);
|
||||
|
||||
LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
|
||||
LDT[__USER_DS >> 3].dwSelLimit = 0xfffff;
|
||||
LDT[__USER_DS >> 3].lpSelBase = NULL;
|
||||
init_npu();
|
||||
|
||||
for(;;) {
|
||||
int err;
|
||||
uint8_t *pc;
|
||||
|
||||
err = invoke_code32(env, -1);
|
||||
env->trans_addr = env->return_addr;
|
||||
pc = env->seg_regs[0] + env->trans_addr;
|
||||
switch(err) {
|
||||
case EXCP0D_GPF:
|
||||
if (pc[0] == 0xcd && pc[1] == 0x80) {
|
||||
/* syscall */
|
||||
env->trans_addr += 2;
|
||||
env->rax.e = do_syscall(env->rax.e,
|
||||
env->rbx.e,
|
||||
env->rcx.e,
|
||||
env->rdx.e,
|
||||
env->rsi.esi,
|
||||
env->rdi.edi,
|
||||
env->rbp.ebp);
|
||||
} else {
|
||||
goto trap_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
trap_error:
|
||||
fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err);
|
||||
d_emu = 9;
|
||||
fprintf(stderr, "%s\n%s\n",
|
||||
e_print_cpuemu_regs(env, 1),
|
||||
e_emu_disasm(env,pc,1));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
+14
-21
@@ -3,23 +3,13 @@
|
||||
|
||||
#include "thunk.h"
|
||||
|
||||
struct pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
@@ -44,14 +34,17 @@ struct image_info {
|
||||
};
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct pt_regs * regs, struct image_info *infop);
|
||||
struct target_pt_regs * regs, struct image_info *infop);
|
||||
|
||||
void target_set_brk(char *new_brk);
|
||||
void syscall_init(void);
|
||||
long do_syscall(int num, long arg1, long arg2, long arg3,
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6);
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
|
||||
|
||||
extern CPUX86State *global_env;
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
+836
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Emulation of Linux signal handling
|
||||
* Emulation of Linux signals
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
@@ -19,22 +19,40 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
/* Algorithm strongly inspired from em86 : we queue the signals so
|
||||
that we can handle them at precise points in the emulated code. */
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#define MAX_SIGQUEUE_SIZE 1024
|
||||
|
||||
struct sigqueue {
|
||||
struct sigqueue *next;
|
||||
target_siginfo_t info;
|
||||
};
|
||||
|
||||
struct emulated_sigaction {
|
||||
struct target_sigaction sa;
|
||||
int nb_pending;
|
||||
struct target_siginfo info;
|
||||
int pending; /* true if signal is pending */
|
||||
struct sigqueue *first;
|
||||
struct sigqueue info; /* in order to always have memory for the
|
||||
first signal, we put it here */
|
||||
};
|
||||
|
||||
struct emulated_sigaction sigact_table[NSIG];
|
||||
int signal_pending;
|
||||
static struct emulated_sigaction sigact_table[TARGET_NSIG];
|
||||
static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
|
||||
static struct sigqueue *first_free; /* first free siginfo queue entry */
|
||||
static int signal_pending; /* non zero if a signal may be pending */
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc);
|
||||
|
||||
/* XXX: do it properly */
|
||||
static inline int host_to_target_signal(int sig)
|
||||
{
|
||||
return sig;
|
||||
@@ -45,61 +63,848 @@ static inline int target_to_host_signal(int sig)
|
||||
return sig;
|
||||
}
|
||||
|
||||
void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
|
||||
d->sig[i] = tswapl(((unsigned long *)s)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
|
||||
((unsigned long *)d)[i] = tswapl(s->sig[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||
const sigset_t *sigset)
|
||||
{
|
||||
*old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
|
||||
}
|
||||
|
||||
void target_to_host_old_sigset(sigset_t *sigset,
|
||||
const target_ulong *old_sigset)
|
||||
{
|
||||
sigemptyset(sigset);
|
||||
*(unsigned long *)sigset = tswapl(*old_sigset);
|
||||
}
|
||||
|
||||
/* siginfo conversion */
|
||||
|
||||
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
||||
const siginfo_t *info)
|
||||
{
|
||||
int sig;
|
||||
sig = host_to_target_signal(info->si_signo);
|
||||
tinfo->si_signo = sig;
|
||||
tinfo->si_errno = 0;
|
||||
tinfo->si_code = 0;
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
/* should never come here, but who knows. The information for
|
||||
the target is irrelevant */
|
||||
tinfo->_sifields._sigfault._addr = 0;
|
||||
} else if (sig >= TARGET_SIGRTMIN) {
|
||||
tinfo->_sifields._rt._pid = info->si_pid;
|
||||
tinfo->_sifields._rt._uid = info->si_uid;
|
||||
/* XXX: potential problem if 64 bit */
|
||||
tinfo->_sifields._rt._sigval.sival_ptr =
|
||||
(target_ulong)info->si_value.sival_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void tswap_siginfo(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
int sig;
|
||||
sig = info->si_signo;
|
||||
tinfo->si_signo = tswap32(sig);
|
||||
tinfo->si_errno = tswap32(info->si_errno);
|
||||
tinfo->si_code = tswap32(info->si_code);
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
tinfo->_sifields._sigfault._addr =
|
||||
tswapl(info->_sifields._sigfault._addr);
|
||||
} else if (sig >= TARGET_SIGRTMIN) {
|
||||
tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
|
||||
tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
|
||||
tinfo->_sifields._rt._sigval.sival_ptr =
|
||||
tswapl(info->_sifields._rt._sigval.sival_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
|
||||
{
|
||||
host_to_target_siginfo_noswap(tinfo, info);
|
||||
tswap_siginfo(tinfo, tinfo);
|
||||
}
|
||||
|
||||
/* XXX: we support only POSIX RT signals are used. */
|
||||
/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
|
||||
{
|
||||
info->si_signo = tswap32(tinfo->si_signo);
|
||||
info->si_errno = tswap32(tinfo->si_errno);
|
||||
info->si_code = tswap32(tinfo->si_code);
|
||||
info->si_pid = tswap32(tinfo->_sifields._rt._pid);
|
||||
info->si_uid = tswap32(tinfo->_sifields._rt._uid);
|
||||
info->si_value.sival_ptr =
|
||||
(void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
|
||||
}
|
||||
|
||||
void signal_init(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
|
||||
/* set all host signal handlers */
|
||||
sigemptyset(&act.sa_mask);
|
||||
/* set all host signal handlers. ALL signals are blocked during
|
||||
the handlers to serialize them. */
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = host_signal_handler;
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
sigaction(i, &sa, NULL);
|
||||
sigaction(i, &act, NULL);
|
||||
}
|
||||
|
||||
memset(sigact_table, 0, sizeof(sigact_table));
|
||||
|
||||
first_free = &sigqueue_table[0];
|
||||
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
|
||||
sigqueue_table[i].next = &sigqueue_table[i + 1];
|
||||
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
|
||||
}
|
||||
|
||||
/* signal queue handling */
|
||||
|
||||
static inline struct sigqueue *alloc_sigqueue(void)
|
||||
{
|
||||
struct sigqueue *q = first_free;
|
||||
if (!q)
|
||||
return NULL;
|
||||
first_free = q->next;
|
||||
return q;
|
||||
}
|
||||
|
||||
static inline void free_sigqueue(struct sigqueue *q)
|
||||
{
|
||||
q->next = first_free;
|
||||
first_free = q;
|
||||
}
|
||||
|
||||
/* abort execution with signal */
|
||||
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",
|
||||
sig, strsignal(host_sig));
|
||||
#if 1
|
||||
_exit(-host_sig);
|
||||
#else
|
||||
{
|
||||
struct sigaction act;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = SIG_DFL;
|
||||
sigaction(SIGABRT, &act, NULL);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* queue a signal so that it will be send to the virtual CPU as soon
|
||||
as possible */
|
||||
int queue_signal(int sig, target_siginfo_t *info)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
struct sigqueue *q, **pq;
|
||||
target_ulong handler;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "queue_sigal: sig=%d\n",
|
||||
sig);
|
||||
#endif
|
||||
k = &sigact_table[sig - 1];
|
||||
handler = k->sa._sa_handler;
|
||||
if (handler == TARGET_SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are fatal */
|
||||
if (sig != TARGET_SIGCHLD &&
|
||||
sig != TARGET_SIGURG &&
|
||||
sig != TARGET_SIGWINCH) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
return 0; /* indicate ignored */
|
||||
}
|
||||
} else if (handler == TARGET_SIG_IGN) {
|
||||
/* ignore signal */
|
||||
return 0;
|
||||
} else if (handler == TARGET_SIG_ERR) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
pq = &k->first;
|
||||
if (sig < TARGET_SIGRTMIN) {
|
||||
/* if non real time signal, we queue exactly one signal */
|
||||
if (!k->pending)
|
||||
q = &k->info;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
if (!k->pending) {
|
||||
/* first signal */
|
||||
q = &k->info;
|
||||
} else {
|
||||
q = alloc_sigqueue();
|
||||
if (!q)
|
||||
return -EAGAIN;
|
||||
while (*pq != NULL)
|
||||
pq = &(*pq)->next;
|
||||
}
|
||||
}
|
||||
*pq = q;
|
||||
q->info = *info;
|
||||
q->next = NULL;
|
||||
k->pending = 1;
|
||||
/* signal that a new signal is pending */
|
||||
signal_pending = 1;
|
||||
return 1; /* indicates that the signal was queued */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
#ifdef __i386__
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x\n",
|
||||
uc->uc_mcontext.gregs[EAX],
|
||||
uc->uc_mcontext.gregs[EBX],
|
||||
uc->uc_mcontext.gregs[ECX],
|
||||
uc->uc_mcontext.gregs[EDX],
|
||||
uc->uc_mcontext.gregs[ESI],
|
||||
uc->uc_mcontext.gregs[EDI],
|
||||
uc->uc_mcontext.gregs[EBP],
|
||||
uc->uc_mcontext.gregs[ESP],
|
||||
uc->uc_mcontext.gregs[EFL],
|
||||
uc->uc_mcontext.gregs[EIP]);
|
||||
}
|
||||
#else
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
int signum;
|
||||
int sig;
|
||||
target_siginfo_t tinfo;
|
||||
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
||||
if (cpu_x86_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
}
|
||||
|
||||
/* get target signal number */
|
||||
signum = host_to_target(host_signum);
|
||||
if (signum >= TARGET_NSIG)
|
||||
sig = host_to_target_signal(host_signum);
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return;
|
||||
/* we save the old mask */
|
||||
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "gemu: got signal %d\n", sig);
|
||||
dump_regs(puc);
|
||||
#endif
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_x86_interrupt(global_env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_pending_signals(void)
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact)
|
||||
{
|
||||
int signum;
|
||||
target_ulong _sa_handler;
|
||||
struct emulated_sigaction *k;
|
||||
|
||||
struct emulated_sigaction *esig;
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return -EINVAL;
|
||||
k = &sigact_table[sig - 1];
|
||||
#if defined(DEBUG_SIGNAL) && 0
|
||||
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
|
||||
sig, (int)act, (int)oact);
|
||||
#endif
|
||||
if (oact) {
|
||||
oact->_sa_handler = tswapl(k->sa._sa_handler);
|
||||
oact->sa_flags = tswapl(k->sa.sa_flags);
|
||||
oact->sa_restorer = tswapl(k->sa.sa_restorer);
|
||||
oact->sa_mask = k->sa.sa_mask;
|
||||
}
|
||||
if (act) {
|
||||
k->sa._sa_handler = tswapl(act->_sa_handler);
|
||||
k->sa.sa_flags = tswapl(act->sa_flags);
|
||||
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
||||
k->sa.sa_mask = act->sa_mask;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
/* from the Linux kernel */
|
||||
|
||||
struct target_fpreg {
|
||||
uint16_t significand[4];
|
||||
uint16_t exponent;
|
||||
};
|
||||
|
||||
struct target_fpxreg {
|
||||
uint16_t significand[4];
|
||||
uint16_t exponent;
|
||||
uint16_t padding[3];
|
||||
};
|
||||
|
||||
struct target_xmmreg {
|
||||
target_ulong element[4];
|
||||
};
|
||||
|
||||
struct target_fpstate {
|
||||
/* Regular FPU environment */
|
||||
target_ulong cw;
|
||||
target_ulong sw;
|
||||
target_ulong tag;
|
||||
target_ulong ipoff;
|
||||
target_ulong cssel;
|
||||
target_ulong dataoff;
|
||||
target_ulong datasel;
|
||||
struct target_fpreg _st[8];
|
||||
uint16_t status;
|
||||
uint16_t magic; /* 0xffff = regular FPU data only */
|
||||
|
||||
/* FXSR FPU environment */
|
||||
target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
|
||||
target_ulong mxcsr;
|
||||
target_ulong reserved;
|
||||
struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
|
||||
struct target_xmmreg _xmm[8];
|
||||
target_ulong padding[56];
|
||||
};
|
||||
|
||||
#define X86_FXSR_MAGIC 0x0000
|
||||
|
||||
struct target_sigcontext {
|
||||
uint16_t gs, __gsh;
|
||||
uint16_t fs, __fsh;
|
||||
uint16_t es, __esh;
|
||||
uint16_t ds, __dsh;
|
||||
target_ulong edi;
|
||||
target_ulong esi;
|
||||
target_ulong ebp;
|
||||
target_ulong esp;
|
||||
target_ulong ebx;
|
||||
target_ulong edx;
|
||||
target_ulong ecx;
|
||||
target_ulong eax;
|
||||
target_ulong trapno;
|
||||
target_ulong err;
|
||||
target_ulong eip;
|
||||
uint16_t cs, __csh;
|
||||
target_ulong eflags;
|
||||
target_ulong esp_at_signal;
|
||||
uint16_t ss, __ssh;
|
||||
target_ulong fpstate; /* pointer */
|
||||
target_ulong oldmask;
|
||||
target_ulong cr2;
|
||||
};
|
||||
|
||||
typedef struct target_sigaltstack {
|
||||
target_ulong ss_sp;
|
||||
int ss_flags;
|
||||
target_ulong ss_size;
|
||||
} target_stack_t;
|
||||
|
||||
struct target_ucontext {
|
||||
target_ulong uc_flags;
|
||||
target_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
struct target_sigcontext uc_mcontext;
|
||||
target_sigset_t uc_sigmask; /* mask last for extensibility */
|
||||
};
|
||||
|
||||
struct sigframe
|
||||
{
|
||||
target_ulong pretcode;
|
||||
int sig;
|
||||
struct target_sigcontext sc;
|
||||
struct target_fpstate fpstate;
|
||||
target_ulong extramask[TARGET_NSIG_WORDS-1];
|
||||
char retcode[8];
|
||||
};
|
||||
|
||||
struct rt_sigframe
|
||||
{
|
||||
target_ulong pretcode;
|
||||
int sig;
|
||||
target_ulong pinfo;
|
||||
target_ulong puc;
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
struct target_fpstate fpstate;
|
||||
char retcode[8];
|
||||
};
|
||||
|
||||
/*
|
||||
* Set up a signal frame.
|
||||
*/
|
||||
|
||||
#define __put_user(x,ptr)\
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
stb(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 2:\
|
||||
stw(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 4:\
|
||||
stl(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 8:\
|
||||
stq(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define get_user(val, ptr) (typeof(*ptr))(*(ptr))
|
||||
|
||||
|
||||
#define __copy_to_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
tswap_siginfo(tinfo, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: save x87 state */
|
||||
static int
|
||||
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
CPUX86State *env, unsigned long mask)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs);
|
||||
err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs);
|
||||
err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es);
|
||||
err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds);
|
||||
err |= __put_user(env->regs[R_EDI], &sc->edi);
|
||||
err |= __put_user(env->regs[R_ESI], &sc->esi);
|
||||
err |= __put_user(env->regs[R_EBP], &sc->ebp);
|
||||
err |= __put_user(env->regs[R_ESP], &sc->esp);
|
||||
err |= __put_user(env->regs[R_EBX], &sc->ebx);
|
||||
err |= __put_user(env->regs[R_EDX], &sc->edx);
|
||||
err |= __put_user(env->regs[R_ECX], &sc->ecx);
|
||||
err |= __put_user(env->regs[R_EAX], &sc->eax);
|
||||
err |= __put_user(/*current->thread.trap_no*/ 0, &sc->trapno);
|
||||
err |= __put_user(/*current->thread.error_code*/ 0, &sc->err);
|
||||
err |= __put_user(env->eip, &sc->eip);
|
||||
err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs);
|
||||
err |= __put_user(env->eflags, &sc->eflags);
|
||||
err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
|
||||
err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss);
|
||||
#if 0
|
||||
tmp = save_i387(fpstate);
|
||||
if (tmp < 0)
|
||||
err = 1;
|
||||
else
|
||||
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
|
||||
#else
|
||||
err |= __put_user(0, &sc->fpstate);
|
||||
#endif
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which stack to use..
|
||||
*/
|
||||
|
||||
static inline void *
|
||||
get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
|
||||
{
|
||||
unsigned long esp;
|
||||
|
||||
/* Default to using normal stack */
|
||||
esp = env->regs[R_ESP];
|
||||
#if 0
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (ka->sa.sa_flags & SA_ONSTACK) {
|
||||
if (sas_ss_flags(esp) == 0)
|
||||
esp = current->sas_ss_sp + current->sas_ss_size;
|
||||
}
|
||||
|
||||
/* This is the legacy signal stack switching. */
|
||||
else if ((regs->xss & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
esp = (unsigned long) ka->sa.sa_restorer;
|
||||
}
|
||||
#endif
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
}
|
||||
|
||||
#define TF_MASK TRAP_FLAG
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
int err = 0;
|
||||
|
||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
goto give_sigsegv;
|
||||
#endif
|
||||
err |= __put_user((/*current->exec_domain
|
||||
&& current->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
? current->exec_domain->signal_invmap[sig]
|
||||
: */ sig),
|
||||
&frame->sig);
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]);
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
if (TARGET_NSIG_WORDS > 1) {
|
||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask));
|
||||
}
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
|
||||
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
|
||||
} else {
|
||||
err |= __put_user(frame->retcode, &frame->pretcode);
|
||||
/* This is popl %eax ; movl $,%eax ; int $0x80 */
|
||||
err |= __put_user(0xb858, (short *)(frame->retcode+0));
|
||||
err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
|
||||
err |= __put_user(0x80cd, (short *)(frame->retcode+6));
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
env->regs[R_ESP] = (unsigned long) frame;
|
||||
env->eip = (unsigned long) ka->sa._sa_handler;
|
||||
|
||||
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
||||
env->eflags &= ~TF_MASK;
|
||||
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == TARGET_SIGSEGV)
|
||||
ka->sa._sa_handler = TARGET_SIG_DFL;
|
||||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
int err = 0;
|
||||
|
||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
goto give_sigsegv;
|
||||
#endif
|
||||
|
||||
err |= __put_user((/*current->exec_domain
|
||||
&& current->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
? current->exec_domain->signal_invmap[sig]
|
||||
: */sig),
|
||||
&frame->sig);
|
||||
err |= __put_user((target_ulong)&frame->info, &frame->pinfo);
|
||||
err |= __put_user((target_ulong)&frame->uc, &frame->puc);
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
/* Create the ucontext. */
|
||||
err |= __put_user(0, &frame->uc.uc_flags);
|
||||
err |= __put_user(0, &frame->uc.uc_link);
|
||||
err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp);
|
||||
err |= __put_user(/* sas_ss_flags(regs->esp) */ 0,
|
||||
&frame->uc.uc_stack.ss_flags);
|
||||
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
|
||||
env, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
|
||||
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
|
||||
} else {
|
||||
err |= __put_user(frame->retcode, &frame->pretcode);
|
||||
/* This is movl $,%eax ; int $0x80 */
|
||||
err |= __put_user(0xb8, (char *)(frame->retcode+0));
|
||||
err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
|
||||
err |= __put_user(0x80cd, (short *)(frame->retcode+5));
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
env->regs[R_ESP] = (unsigned long) frame;
|
||||
env->eip = (unsigned long) ka->sa._sa_handler;
|
||||
|
||||
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
||||
env->eflags &= ~TF_MASK;
|
||||
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == TARGET_SIGSEGV)
|
||||
ka->sa._sa_handler = TARGET_SIG_DFL;
|
||||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
static int
|
||||
restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
|
||||
|
||||
|
||||
#define COPY(x) err |= __get_user(regs->x, &sc->x)
|
||||
|
||||
#define COPY_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp; }
|
||||
|
||||
#define COPY_SEG_STRICT(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp|3; }
|
||||
|
||||
#define GET_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
loadsegment(seg,tmp); }
|
||||
|
||||
cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
|
||||
cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
|
||||
cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
|
||||
cpu_x86_load_seg(env, R_DS, lduw(&sc->ds));
|
||||
|
||||
env->regs[R_EDI] = ldl(&sc->edi);
|
||||
env->regs[R_ESI] = ldl(&sc->esi);
|
||||
env->regs[R_EBP] = ldl(&sc->ebp);
|
||||
env->regs[R_ESP] = ldl(&sc->esp);
|
||||
env->regs[R_EBX] = ldl(&sc->ebx);
|
||||
env->regs[R_EDX] = ldl(&sc->edx);
|
||||
env->regs[R_ECX] = ldl(&sc->ecx);
|
||||
env->eip = ldl(&sc->eip);
|
||||
|
||||
cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
|
||||
cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
|
||||
|
||||
{
|
||||
unsigned int tmpflags;
|
||||
tmpflags = ldl(&sc->eflags);
|
||||
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
|
||||
// regs->orig_eax = -1; /* disable syscall checks */
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
struct _fpstate * buf;
|
||||
err |= __get_user(buf, &sc->fpstate);
|
||||
if (buf) {
|
||||
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
|
||||
goto badframe;
|
||||
err |= restore_i387(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*peax = ldl(&sc->eax);
|
||||
return err;
|
||||
#if 0
|
||||
badframe:
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUX86State *env)
|
||||
{
|
||||
struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8);
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
int eax, i;
|
||||
|
||||
/* set blocked signals */
|
||||
target_set.sig[0] = frame->sc.oldmask;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++)
|
||||
target_set.sig[i] = frame->extramask[i - 1];
|
||||
|
||||
target_to_host_sigset(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
if (restore_sigcontext(env, &frame->sc, &eax))
|
||||
goto badframe;
|
||||
return eax;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUX86State *env)
|
||||
{
|
||||
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
// stack_t st;
|
||||
int eax;
|
||||
|
||||
#if 0
|
||||
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
|
||||
|
||||
target_to_host_sigset(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
|
||||
goto badframe;
|
||||
|
||||
#if 0
|
||||
if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
|
||||
goto badframe;
|
||||
/* It is more difficult to avoid calling this function than to
|
||||
call it and ignore errors. */
|
||||
do_sigaltstack(&st, NULL, regs->esp);
|
||||
#endif
|
||||
return eax;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void process_pending_signals(void *cpu_env)
|
||||
{
|
||||
int sig;
|
||||
target_ulong handler;
|
||||
sigset_t set, old_set;
|
||||
target_sigset_t target_old_set;
|
||||
struct emulated_sigaction *k;
|
||||
struct sigqueue *q;
|
||||
|
||||
if (!signal_pending)
|
||||
return;
|
||||
|
||||
esig = sigact_table;
|
||||
for(signum = 1; signum < TARGET_NSIG; signum++) {
|
||||
if (esig->nb_pending != 0)
|
||||
k = sigact_table;
|
||||
for(sig = 1; sig <= TARGET_NSIG; sig++) {
|
||||
if (k->pending)
|
||||
goto handle_signal;
|
||||
esig++;
|
||||
k++;
|
||||
}
|
||||
/* if no signal is pending, just return */
|
||||
signal_pending = 0;
|
||||
return;
|
||||
|
||||
handle_signal:
|
||||
_sa_handler = esig->sa._sa_handler;
|
||||
if (_sa_handler == TARGET_SIG_DFL) {
|
||||
/* default handling
|
||||
#ifdef DEBUG_SIGNAL
|
||||
fprintf(stderr, "gemu: process signal %d\n", sig);
|
||||
#endif
|
||||
/* dequeue signal */
|
||||
q = k->first;
|
||||
k->first = q->next;
|
||||
if (!k->first)
|
||||
k->pending = 0;
|
||||
|
||||
handler = k->sa._sa_handler;
|
||||
if (handler == TARGET_SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are fatal */
|
||||
if (sig != TARGET_SIGCHLD &&
|
||||
sig != TARGET_SIGURG &&
|
||||
sig != TARGET_SIGWINCH) {
|
||||
force_sig(sig);
|
||||
}
|
||||
} else if (handler == TARGET_SIG_IGN) {
|
||||
/* ignore sig */
|
||||
} else if (handler == TARGET_SIG_ERR) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
/* compute the blocked signals during the handler execution */
|
||||
target_to_host_sigset(&set, &k->sa.sa_mask);
|
||||
/* SA_NODEFER indicates that the current signal should not be
|
||||
blocked during the handler */
|
||||
if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
|
||||
sigaddset(&set, target_to_host_signal(sig));
|
||||
|
||||
/* block signals in the handler using Linux */
|
||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
/* save the previous blocked signal state to restore it at the
|
||||
end of the signal execution (see do_sigreturn) */
|
||||
host_to_target_sigset(&target_old_set, &old_set);
|
||||
|
||||
/* 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);
|
||||
else
|
||||
setup_frame(sig, k, &target_old_set, cpu_env);
|
||||
if (k->sa.sa_flags & TARGET_SA_RESETHAND)
|
||||
k->sa._sa_handler = TARGET_SIG_DFL;
|
||||
}
|
||||
|
||||
|
||||
if (q != &k->info)
|
||||
free_sigqueue(q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+724
-129
File diff suppressed because it is too large
Load Diff
@@ -24,11 +24,31 @@ struct target_timeval {
|
||||
target_long tv_usec;
|
||||
};
|
||||
|
||||
struct target_timespec {
|
||||
target_long tv_sec;
|
||||
target_long tv_nsec;
|
||||
};
|
||||
|
||||
struct target_itimerval {
|
||||
struct target_timeval it_interval;
|
||||
struct target_timeval it_value;
|
||||
};
|
||||
|
||||
struct target_iovec {
|
||||
target_long iov_base; /* Starting address */
|
||||
target_long iov_len; /* Number of bytes */
|
||||
};
|
||||
|
||||
struct target_msghdr {
|
||||
target_long msg_name; /* Socket name */
|
||||
int msg_namelen; /* Length of name */
|
||||
target_long msg_iov; /* Data blocks */
|
||||
target_long msg_iovlen; /* Number of blocks */
|
||||
target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
|
||||
target_long msg_controllen; /* Length of cmsg list */
|
||||
unsigned int msg_flags;
|
||||
};
|
||||
|
||||
struct target_rusage {
|
||||
struct target_timeval ru_utime; /* user time used */
|
||||
struct target_timeval ru_stime; /* system time used */
|
||||
@@ -52,7 +72,7 @@ typedef struct {
|
||||
int val[2];
|
||||
} kernel_fsid_t;
|
||||
|
||||
struct statfs {
|
||||
struct kernel_statfs {
|
||||
int f_type;
|
||||
int f_bsize;
|
||||
int f_blocks;
|
||||
@@ -65,6 +85,22 @@ struct statfs {
|
||||
int f_spare[6];
|
||||
};
|
||||
|
||||
struct target_dirent {
|
||||
target_long d_ino;
|
||||
target_long d_off;
|
||||
unsigned short d_reclen;
|
||||
char d_name[256]; /* We must not include limits.h! */
|
||||
};
|
||||
|
||||
struct target_dirent64 {
|
||||
uint64_t d_ino;
|
||||
int64_t d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_type;
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
|
||||
/* mostly generic signal stuff */
|
||||
#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */
|
||||
#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */
|
||||
@@ -82,6 +118,49 @@ typedef struct {
|
||||
target_ulong sig[TARGET_NSIG_WORDS];
|
||||
} target_sigset_t;
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++)
|
||||
d->sig[i] = tswapl(s->sig[i]);
|
||||
}
|
||||
#else
|
||||
static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void target_siginitset(target_sigset_t *d, target_ulong set)
|
||||
{
|
||||
int i;
|
||||
d->sig[0] = set;
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++)
|
||||
d->sig[i] = 0;
|
||||
}
|
||||
|
||||
void host_to_target_sigset(target_sigset_t *d, sigset_t *s);
|
||||
void target_to_host_sigset(sigset_t *d, target_sigset_t *s);
|
||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||
const sigset_t *sigset);
|
||||
void target_to_host_old_sigset(sigset_t *sigset,
|
||||
const target_ulong *old_sigset);
|
||||
struct target_sigaction;
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
|
||||
struct target_rlimit {
|
||||
target_ulong rlim_cur;
|
||||
target_ulong rlim_max;
|
||||
};
|
||||
|
||||
struct target_pollfd {
|
||||
int fd; /* file descriptor */
|
||||
short events; /* requested events */
|
||||
short revents; /* returned events */
|
||||
};
|
||||
|
||||
/* Networking ioctls */
|
||||
#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
|
||||
#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
|
||||
|
||||
@@ -62,3 +62,5 @@ STRUCT(cdrom_read_audio,
|
||||
STRUCT(hd_geometry,
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
|
||||
|
||||
STRUCT(dirent,
|
||||
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
|
||||
|
||||
+534
@@ -0,0 +1,534 @@
|
||||
DEF(end)
|
||||
DEF(movl_A0_EAX)
|
||||
DEF(addl_A0_EAX)
|
||||
DEF(addl_A0_EAX_s1)
|
||||
DEF(addl_A0_EAX_s2)
|
||||
DEF(addl_A0_EAX_s3)
|
||||
DEF(movl_T0_EAX)
|
||||
DEF(movl_T1_EAX)
|
||||
DEF(movh_T0_EAX)
|
||||
DEF(movh_T1_EAX)
|
||||
DEF(movl_EAX_T0)
|
||||
DEF(movl_EAX_T1)
|
||||
DEF(movl_EAX_A0)
|
||||
DEF(cmovw_EAX_T1_T0)
|
||||
DEF(cmovl_EAX_T1_T0)
|
||||
DEF(movw_EAX_T0)
|
||||
DEF(movw_EAX_T1)
|
||||
DEF(movw_EAX_A0)
|
||||
DEF(movb_EAX_T0)
|
||||
DEF(movh_EAX_T0)
|
||||
DEF(movb_EAX_T1)
|
||||
DEF(movh_EAX_T1)
|
||||
DEF(movl_A0_ECX)
|
||||
DEF(addl_A0_ECX)
|
||||
DEF(addl_A0_ECX_s1)
|
||||
DEF(addl_A0_ECX_s2)
|
||||
DEF(addl_A0_ECX_s3)
|
||||
DEF(movl_T0_ECX)
|
||||
DEF(movl_T1_ECX)
|
||||
DEF(movh_T0_ECX)
|
||||
DEF(movh_T1_ECX)
|
||||
DEF(movl_ECX_T0)
|
||||
DEF(movl_ECX_T1)
|
||||
DEF(movl_ECX_A0)
|
||||
DEF(cmovw_ECX_T1_T0)
|
||||
DEF(cmovl_ECX_T1_T0)
|
||||
DEF(movw_ECX_T0)
|
||||
DEF(movw_ECX_T1)
|
||||
DEF(movw_ECX_A0)
|
||||
DEF(movb_ECX_T0)
|
||||
DEF(movh_ECX_T0)
|
||||
DEF(movb_ECX_T1)
|
||||
DEF(movh_ECX_T1)
|
||||
DEF(movl_A0_EDX)
|
||||
DEF(addl_A0_EDX)
|
||||
DEF(addl_A0_EDX_s1)
|
||||
DEF(addl_A0_EDX_s2)
|
||||
DEF(addl_A0_EDX_s3)
|
||||
DEF(movl_T0_EDX)
|
||||
DEF(movl_T1_EDX)
|
||||
DEF(movh_T0_EDX)
|
||||
DEF(movh_T1_EDX)
|
||||
DEF(movl_EDX_T0)
|
||||
DEF(movl_EDX_T1)
|
||||
DEF(movl_EDX_A0)
|
||||
DEF(cmovw_EDX_T1_T0)
|
||||
DEF(cmovl_EDX_T1_T0)
|
||||
DEF(movw_EDX_T0)
|
||||
DEF(movw_EDX_T1)
|
||||
DEF(movw_EDX_A0)
|
||||
DEF(movb_EDX_T0)
|
||||
DEF(movh_EDX_T0)
|
||||
DEF(movb_EDX_T1)
|
||||
DEF(movh_EDX_T1)
|
||||
DEF(movl_A0_EBX)
|
||||
DEF(addl_A0_EBX)
|
||||
DEF(addl_A0_EBX_s1)
|
||||
DEF(addl_A0_EBX_s2)
|
||||
DEF(addl_A0_EBX_s3)
|
||||
DEF(movl_T0_EBX)
|
||||
DEF(movl_T1_EBX)
|
||||
DEF(movh_T0_EBX)
|
||||
DEF(movh_T1_EBX)
|
||||
DEF(movl_EBX_T0)
|
||||
DEF(movl_EBX_T1)
|
||||
DEF(movl_EBX_A0)
|
||||
DEF(cmovw_EBX_T1_T0)
|
||||
DEF(cmovl_EBX_T1_T0)
|
||||
DEF(movw_EBX_T0)
|
||||
DEF(movw_EBX_T1)
|
||||
DEF(movw_EBX_A0)
|
||||
DEF(movb_EBX_T0)
|
||||
DEF(movh_EBX_T0)
|
||||
DEF(movb_EBX_T1)
|
||||
DEF(movh_EBX_T1)
|
||||
DEF(movl_A0_ESP)
|
||||
DEF(addl_A0_ESP)
|
||||
DEF(addl_A0_ESP_s1)
|
||||
DEF(addl_A0_ESP_s2)
|
||||
DEF(addl_A0_ESP_s3)
|
||||
DEF(movl_T0_ESP)
|
||||
DEF(movl_T1_ESP)
|
||||
DEF(movh_T0_ESP)
|
||||
DEF(movh_T1_ESP)
|
||||
DEF(movl_ESP_T0)
|
||||
DEF(movl_ESP_T1)
|
||||
DEF(movl_ESP_A0)
|
||||
DEF(cmovw_ESP_T1_T0)
|
||||
DEF(cmovl_ESP_T1_T0)
|
||||
DEF(movw_ESP_T0)
|
||||
DEF(movw_ESP_T1)
|
||||
DEF(movw_ESP_A0)
|
||||
DEF(movb_ESP_T0)
|
||||
DEF(movh_ESP_T0)
|
||||
DEF(movb_ESP_T1)
|
||||
DEF(movh_ESP_T1)
|
||||
DEF(movl_A0_EBP)
|
||||
DEF(addl_A0_EBP)
|
||||
DEF(addl_A0_EBP_s1)
|
||||
DEF(addl_A0_EBP_s2)
|
||||
DEF(addl_A0_EBP_s3)
|
||||
DEF(movl_T0_EBP)
|
||||
DEF(movl_T1_EBP)
|
||||
DEF(movh_T0_EBP)
|
||||
DEF(movh_T1_EBP)
|
||||
DEF(movl_EBP_T0)
|
||||
DEF(movl_EBP_T1)
|
||||
DEF(movl_EBP_A0)
|
||||
DEF(cmovw_EBP_T1_T0)
|
||||
DEF(cmovl_EBP_T1_T0)
|
||||
DEF(movw_EBP_T0)
|
||||
DEF(movw_EBP_T1)
|
||||
DEF(movw_EBP_A0)
|
||||
DEF(movb_EBP_T0)
|
||||
DEF(movh_EBP_T0)
|
||||
DEF(movb_EBP_T1)
|
||||
DEF(movh_EBP_T1)
|
||||
DEF(movl_A0_ESI)
|
||||
DEF(addl_A0_ESI)
|
||||
DEF(addl_A0_ESI_s1)
|
||||
DEF(addl_A0_ESI_s2)
|
||||
DEF(addl_A0_ESI_s3)
|
||||
DEF(movl_T0_ESI)
|
||||
DEF(movl_T1_ESI)
|
||||
DEF(movh_T0_ESI)
|
||||
DEF(movh_T1_ESI)
|
||||
DEF(movl_ESI_T0)
|
||||
DEF(movl_ESI_T1)
|
||||
DEF(movl_ESI_A0)
|
||||
DEF(cmovw_ESI_T1_T0)
|
||||
DEF(cmovl_ESI_T1_T0)
|
||||
DEF(movw_ESI_T0)
|
||||
DEF(movw_ESI_T1)
|
||||
DEF(movw_ESI_A0)
|
||||
DEF(movb_ESI_T0)
|
||||
DEF(movh_ESI_T0)
|
||||
DEF(movb_ESI_T1)
|
||||
DEF(movh_ESI_T1)
|
||||
DEF(movl_A0_EDI)
|
||||
DEF(addl_A0_EDI)
|
||||
DEF(addl_A0_EDI_s1)
|
||||
DEF(addl_A0_EDI_s2)
|
||||
DEF(addl_A0_EDI_s3)
|
||||
DEF(movl_T0_EDI)
|
||||
DEF(movl_T1_EDI)
|
||||
DEF(movh_T0_EDI)
|
||||
DEF(movh_T1_EDI)
|
||||
DEF(movl_EDI_T0)
|
||||
DEF(movl_EDI_T1)
|
||||
DEF(movl_EDI_A0)
|
||||
DEF(cmovw_EDI_T1_T0)
|
||||
DEF(cmovl_EDI_T1_T0)
|
||||
DEF(movw_EDI_T0)
|
||||
DEF(movw_EDI_T1)
|
||||
DEF(movw_EDI_A0)
|
||||
DEF(movb_EDI_T0)
|
||||
DEF(movh_EDI_T0)
|
||||
DEF(movb_EDI_T1)
|
||||
DEF(movh_EDI_T1)
|
||||
DEF(addl_T0_T1_cc)
|
||||
DEF(orl_T0_T1_cc)
|
||||
DEF(andl_T0_T1_cc)
|
||||
DEF(subl_T0_T1_cc)
|
||||
DEF(xorl_T0_T1_cc)
|
||||
DEF(cmpl_T0_T1_cc)
|
||||
DEF(negl_T0_cc)
|
||||
DEF(incl_T0_cc)
|
||||
DEF(decl_T0_cc)
|
||||
DEF(testl_T0_T1_cc)
|
||||
DEF(addl_T0_T1)
|
||||
DEF(orl_T0_T1)
|
||||
DEF(andl_T0_T1)
|
||||
DEF(subl_T0_T1)
|
||||
DEF(xorl_T0_T1)
|
||||
DEF(negl_T0)
|
||||
DEF(incl_T0)
|
||||
DEF(decl_T0)
|
||||
DEF(notl_T0)
|
||||
DEF(bswapl_T0)
|
||||
DEF(mulb_AL_T0)
|
||||
DEF(imulb_AL_T0)
|
||||
DEF(mulw_AX_T0)
|
||||
DEF(imulw_AX_T0)
|
||||
DEF(mull_EAX_T0)
|
||||
DEF(imull_EAX_T0)
|
||||
DEF(imulw_T0_T1)
|
||||
DEF(imull_T0_T1)
|
||||
DEF(divb_AL_T0)
|
||||
DEF(idivb_AL_T0)
|
||||
DEF(divw_AX_T0)
|
||||
DEF(idivw_AX_T0)
|
||||
DEF(divl_EAX_T0)
|
||||
DEF(idivl_EAX_T0)
|
||||
DEF(movl_T0_im)
|
||||
DEF(addl_T0_im)
|
||||
DEF(andl_T0_ffff)
|
||||
DEF(movl_T0_T1)
|
||||
DEF(movl_T1_im)
|
||||
DEF(addl_T1_im)
|
||||
DEF(movl_T1_A0)
|
||||
DEF(movl_A0_im)
|
||||
DEF(addl_A0_im)
|
||||
DEF(andl_A0_ffff)
|
||||
DEF(ldub_T0_A0)
|
||||
DEF(ldsb_T0_A0)
|
||||
DEF(lduw_T0_A0)
|
||||
DEF(ldsw_T0_A0)
|
||||
DEF(ldl_T0_A0)
|
||||
DEF(ldub_T1_A0)
|
||||
DEF(ldsb_T1_A0)
|
||||
DEF(lduw_T1_A0)
|
||||
DEF(ldsw_T1_A0)
|
||||
DEF(ldl_T1_A0)
|
||||
DEF(stb_T0_A0)
|
||||
DEF(stw_T0_A0)
|
||||
DEF(stl_T0_A0)
|
||||
DEF(add_bitw_A0_T1)
|
||||
DEF(add_bitl_A0_T1)
|
||||
DEF(jmp_T0)
|
||||
DEF(jmp_im)
|
||||
DEF(int_im)
|
||||
DEF(int3)
|
||||
DEF(into)
|
||||
DEF(jb_subb)
|
||||
DEF(jz_subb)
|
||||
DEF(jbe_subb)
|
||||
DEF(js_subb)
|
||||
DEF(jl_subb)
|
||||
DEF(jle_subb)
|
||||
DEF(setb_T0_subb)
|
||||
DEF(setz_T0_subb)
|
||||
DEF(setbe_T0_subb)
|
||||
DEF(sets_T0_subb)
|
||||
DEF(setl_T0_subb)
|
||||
DEF(setle_T0_subb)
|
||||
DEF(rolb_T0_T1_cc)
|
||||
DEF(rolb_T0_T1)
|
||||
DEF(rorb_T0_T1_cc)
|
||||
DEF(rorb_T0_T1)
|
||||
DEF(rclb_T0_T1_cc)
|
||||
DEF(rcrb_T0_T1_cc)
|
||||
DEF(shlb_T0_T1_cc)
|
||||
DEF(shlb_T0_T1)
|
||||
DEF(shrb_T0_T1_cc)
|
||||
DEF(shrb_T0_T1)
|
||||
DEF(sarb_T0_T1_cc)
|
||||
DEF(sarb_T0_T1)
|
||||
DEF(adcb_T0_T1_cc)
|
||||
DEF(sbbb_T0_T1_cc)
|
||||
DEF(cmpxchgb_T0_T1_EAX_cc)
|
||||
DEF(movsb)
|
||||
DEF(rep_movsb)
|
||||
DEF(stosb)
|
||||
DEF(rep_stosb)
|
||||
DEF(lodsb)
|
||||
DEF(rep_lodsb)
|
||||
DEF(scasb)
|
||||
DEF(repz_scasb)
|
||||
DEF(repnz_scasb)
|
||||
DEF(cmpsb)
|
||||
DEF(repz_cmpsb)
|
||||
DEF(repnz_cmpsb)
|
||||
DEF(outsb)
|
||||
DEF(rep_outsb)
|
||||
DEF(insb)
|
||||
DEF(rep_insb)
|
||||
DEF(outb_T0_T1)
|
||||
DEF(inb_T0_T1)
|
||||
DEF(jb_subw)
|
||||
DEF(jz_subw)
|
||||
DEF(jbe_subw)
|
||||
DEF(js_subw)
|
||||
DEF(jl_subw)
|
||||
DEF(jle_subw)
|
||||
DEF(loopnzw)
|
||||
DEF(loopzw)
|
||||
DEF(loopw)
|
||||
DEF(jecxzw)
|
||||
DEF(setb_T0_subw)
|
||||
DEF(setz_T0_subw)
|
||||
DEF(setbe_T0_subw)
|
||||
DEF(sets_T0_subw)
|
||||
DEF(setl_T0_subw)
|
||||
DEF(setle_T0_subw)
|
||||
DEF(rolw_T0_T1_cc)
|
||||
DEF(rolw_T0_T1)
|
||||
DEF(rorw_T0_T1_cc)
|
||||
DEF(rorw_T0_T1)
|
||||
DEF(rclw_T0_T1_cc)
|
||||
DEF(rcrw_T0_T1_cc)
|
||||
DEF(shlw_T0_T1_cc)
|
||||
DEF(shlw_T0_T1)
|
||||
DEF(shrw_T0_T1_cc)
|
||||
DEF(shrw_T0_T1)
|
||||
DEF(sarw_T0_T1_cc)
|
||||
DEF(sarw_T0_T1)
|
||||
DEF(shldw_T0_T1_im_cc)
|
||||
DEF(shldw_T0_T1_ECX_cc)
|
||||
DEF(shrdw_T0_T1_im_cc)
|
||||
DEF(shrdw_T0_T1_ECX_cc)
|
||||
DEF(adcw_T0_T1_cc)
|
||||
DEF(sbbw_T0_T1_cc)
|
||||
DEF(cmpxchgw_T0_T1_EAX_cc)
|
||||
DEF(btw_T0_T1_cc)
|
||||
DEF(btsw_T0_T1_cc)
|
||||
DEF(btrw_T0_T1_cc)
|
||||
DEF(btcw_T0_T1_cc)
|
||||
DEF(bsfw_T0_cc)
|
||||
DEF(bsrw_T0_cc)
|
||||
DEF(movsw)
|
||||
DEF(rep_movsw)
|
||||
DEF(stosw)
|
||||
DEF(rep_stosw)
|
||||
DEF(lodsw)
|
||||
DEF(rep_lodsw)
|
||||
DEF(scasw)
|
||||
DEF(repz_scasw)
|
||||
DEF(repnz_scasw)
|
||||
DEF(cmpsw)
|
||||
DEF(repz_cmpsw)
|
||||
DEF(repnz_cmpsw)
|
||||
DEF(outsw)
|
||||
DEF(rep_outsw)
|
||||
DEF(insw)
|
||||
DEF(rep_insw)
|
||||
DEF(outw_T0_T1)
|
||||
DEF(inw_T0_T1)
|
||||
DEF(jb_subl)
|
||||
DEF(jz_subl)
|
||||
DEF(jbe_subl)
|
||||
DEF(js_subl)
|
||||
DEF(jl_subl)
|
||||
DEF(jle_subl)
|
||||
DEF(loopnzl)
|
||||
DEF(loopzl)
|
||||
DEF(loopl)
|
||||
DEF(jecxzl)
|
||||
DEF(setb_T0_subl)
|
||||
DEF(setz_T0_subl)
|
||||
DEF(setbe_T0_subl)
|
||||
DEF(sets_T0_subl)
|
||||
DEF(setl_T0_subl)
|
||||
DEF(setle_T0_subl)
|
||||
DEF(roll_T0_T1_cc)
|
||||
DEF(roll_T0_T1)
|
||||
DEF(rorl_T0_T1_cc)
|
||||
DEF(rorl_T0_T1)
|
||||
DEF(rcll_T0_T1_cc)
|
||||
DEF(rcrl_T0_T1_cc)
|
||||
DEF(shll_T0_T1_cc)
|
||||
DEF(shll_T0_T1)
|
||||
DEF(shrl_T0_T1_cc)
|
||||
DEF(shrl_T0_T1)
|
||||
DEF(sarl_T0_T1_cc)
|
||||
DEF(sarl_T0_T1)
|
||||
DEF(shldl_T0_T1_im_cc)
|
||||
DEF(shldl_T0_T1_ECX_cc)
|
||||
DEF(shrdl_T0_T1_im_cc)
|
||||
DEF(shrdl_T0_T1_ECX_cc)
|
||||
DEF(adcl_T0_T1_cc)
|
||||
DEF(sbbl_T0_T1_cc)
|
||||
DEF(cmpxchgl_T0_T1_EAX_cc)
|
||||
DEF(btl_T0_T1_cc)
|
||||
DEF(btsl_T0_T1_cc)
|
||||
DEF(btrl_T0_T1_cc)
|
||||
DEF(btcl_T0_T1_cc)
|
||||
DEF(bsfl_T0_cc)
|
||||
DEF(bsrl_T0_cc)
|
||||
DEF(movsl)
|
||||
DEF(rep_movsl)
|
||||
DEF(stosl)
|
||||
DEF(rep_stosl)
|
||||
DEF(lodsl)
|
||||
DEF(rep_lodsl)
|
||||
DEF(scasl)
|
||||
DEF(repz_scasl)
|
||||
DEF(repnz_scasl)
|
||||
DEF(cmpsl)
|
||||
DEF(repz_cmpsl)
|
||||
DEF(repnz_cmpsl)
|
||||
DEF(outsl)
|
||||
DEF(rep_outsl)
|
||||
DEF(insl)
|
||||
DEF(rep_insl)
|
||||
DEF(outl_T0_T1)
|
||||
DEF(inl_T0_T1)
|
||||
DEF(movsbl_T0_T0)
|
||||
DEF(movzbl_T0_T0)
|
||||
DEF(movswl_T0_T0)
|
||||
DEF(movzwl_T0_T0)
|
||||
DEF(movswl_EAX_AX)
|
||||
DEF(movsbw_AX_AL)
|
||||
DEF(movslq_EDX_EAX)
|
||||
DEF(movswl_DX_AX)
|
||||
DEF(pushl_T0)
|
||||
DEF(pushw_T0)
|
||||
DEF(pushl_ss32_T0)
|
||||
DEF(pushw_ss32_T0)
|
||||
DEF(pushl_ss16_T0)
|
||||
DEF(pushw_ss16_T0)
|
||||
DEF(popl_T0)
|
||||
DEF(popw_T0)
|
||||
DEF(popl_ss32_T0)
|
||||
DEF(popw_ss32_T0)
|
||||
DEF(popl_ss16_T0)
|
||||
DEF(popw_ss16_T0)
|
||||
DEF(addl_ESP_4)
|
||||
DEF(addl_ESP_2)
|
||||
DEF(addw_ESP_4)
|
||||
DEF(addw_ESP_2)
|
||||
DEF(addl_ESP_im)
|
||||
DEF(addw_ESP_im)
|
||||
DEF(rdtsc)
|
||||
DEF(aam)
|
||||
DEF(aad)
|
||||
DEF(aaa)
|
||||
DEF(aas)
|
||||
DEF(daa)
|
||||
DEF(das)
|
||||
DEF(movl_seg_T0)
|
||||
DEF(movl_T0_seg)
|
||||
DEF(addl_A0_seg)
|
||||
DEF(jo_cc)
|
||||
DEF(jb_cc)
|
||||
DEF(jz_cc)
|
||||
DEF(jbe_cc)
|
||||
DEF(js_cc)
|
||||
DEF(jp_cc)
|
||||
DEF(jl_cc)
|
||||
DEF(jle_cc)
|
||||
DEF(seto_T0_cc)
|
||||
DEF(setb_T0_cc)
|
||||
DEF(setz_T0_cc)
|
||||
DEF(setbe_T0_cc)
|
||||
DEF(sets_T0_cc)
|
||||
DEF(setp_T0_cc)
|
||||
DEF(setl_T0_cc)
|
||||
DEF(setle_T0_cc)
|
||||
DEF(xor_T0_1)
|
||||
DEF(set_cc_op)
|
||||
DEF(movl_eflags_T0)
|
||||
DEF(movb_eflags_T0)
|
||||
DEF(movl_T0_eflags)
|
||||
DEF(cld)
|
||||
DEF(std)
|
||||
DEF(clc)
|
||||
DEF(stc)
|
||||
DEF(cmc)
|
||||
DEF(salc)
|
||||
DEF(flds_FT0_A0)
|
||||
DEF(fldl_FT0_A0)
|
||||
DEF(fild_FT0_A0)
|
||||
DEF(fildl_FT0_A0)
|
||||
DEF(fildll_FT0_A0)
|
||||
DEF(flds_ST0_A0)
|
||||
DEF(fldl_ST0_A0)
|
||||
DEF(fldt_ST0_A0)
|
||||
DEF(fild_ST0_A0)
|
||||
DEF(fildl_ST0_A0)
|
||||
DEF(fildll_ST0_A0)
|
||||
DEF(fsts_ST0_A0)
|
||||
DEF(fstl_ST0_A0)
|
||||
DEF(fstt_ST0_A0)
|
||||
DEF(fist_ST0_A0)
|
||||
DEF(fistl_ST0_A0)
|
||||
DEF(fistll_ST0_A0)
|
||||
DEF(fbld_ST0_A0)
|
||||
DEF(fbst_ST0_A0)
|
||||
DEF(fpush)
|
||||
DEF(fpop)
|
||||
DEF(fdecstp)
|
||||
DEF(fincstp)
|
||||
DEF(fmov_ST0_FT0)
|
||||
DEF(fmov_FT0_STN)
|
||||
DEF(fmov_ST0_STN)
|
||||
DEF(fmov_STN_ST0)
|
||||
DEF(fxchg_ST0_STN)
|
||||
DEF(fcom_ST0_FT0)
|
||||
DEF(fucom_ST0_FT0)
|
||||
DEF(fadd_ST0_FT0)
|
||||
DEF(fmul_ST0_FT0)
|
||||
DEF(fsub_ST0_FT0)
|
||||
DEF(fsubr_ST0_FT0)
|
||||
DEF(fdiv_ST0_FT0)
|
||||
DEF(fdivr_ST0_FT0)
|
||||
DEF(fadd_STN_ST0)
|
||||
DEF(fmul_STN_ST0)
|
||||
DEF(fsub_STN_ST0)
|
||||
DEF(fsubr_STN_ST0)
|
||||
DEF(fdiv_STN_ST0)
|
||||
DEF(fdivr_STN_ST0)
|
||||
DEF(fchs_ST0)
|
||||
DEF(fabs_ST0)
|
||||
DEF(fxam_ST0)
|
||||
DEF(fld1_ST0)
|
||||
DEF(fldl2t_ST0)
|
||||
DEF(fldl2e_ST0)
|
||||
DEF(fldpi_ST0)
|
||||
DEF(fldlg2_ST0)
|
||||
DEF(fldln2_ST0)
|
||||
DEF(fldz_ST0)
|
||||
DEF(fldz_FT0)
|
||||
DEF(f2xm1)
|
||||
DEF(fyl2x)
|
||||
DEF(fptan)
|
||||
DEF(fpatan)
|
||||
DEF(fxtract)
|
||||
DEF(fprem1)
|
||||
DEF(fprem)
|
||||
DEF(fyl2xp1)
|
||||
DEF(fsqrt)
|
||||
DEF(fsincos)
|
||||
DEF(frndint)
|
||||
DEF(fscale)
|
||||
DEF(fsin)
|
||||
DEF(fcos)
|
||||
DEF(fnstsw_A0)
|
||||
DEF(fnstsw_EAX)
|
||||
DEF(fnstcw_A0)
|
||||
DEF(fldcw_A0)
|
||||
DEF(fclex)
|
||||
DEF(fninit)
|
||||
DEF(lock)
|
||||
DEF(unlock)
|
||||
@@ -0,0 +1,116 @@
|
||||
/* templates for various register related operations */
|
||||
|
||||
void OPPROTO glue(op_movl_A0,REGNAME)(void)
|
||||
{
|
||||
A0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_addl_A0,REGNAME)(void)
|
||||
{
|
||||
A0 += REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void)
|
||||
{
|
||||
A0 += REG << 1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void)
|
||||
{
|
||||
A0 += REG << 2;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void)
|
||||
{
|
||||
A0 += REG << 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T0,REGNAME)(void)
|
||||
{
|
||||
T0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T1,REGNAME)(void)
|
||||
{
|
||||
T1 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movh_T0,REGNAME)(void)
|
||||
{
|
||||
T0 = REG >> 8;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movh_T1,REGNAME)(void)
|
||||
{
|
||||
T1 = REG >> 8;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void)
|
||||
{
|
||||
REG = A0;
|
||||
}
|
||||
|
||||
/* mov T1 to REG if T0 is true */
|
||||
void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
if (T0)
|
||||
REG = (REG & 0xffff0000) | (T1 & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
if (T0)
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & 0xffff0000) | (T0 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & 0xffff0000) | (T1 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: A0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void)
|
||||
{
|
||||
REG = (REG & 0xffff0000) | (A0 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & 0xffffff00) | (T0 & 0xff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8);
|
||||
}
|
||||
|
||||
/* NOTE: T1 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & 0xffffff00) | (T1 & 0xff);
|
||||
}
|
||||
|
||||
/* NOTE: T1 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8);
|
||||
}
|
||||
+1058
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
/* ld script to make i386 Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
|
||||
OUTPUT_ARCH(powerpc)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
+122
-30
@@ -245,24 +245,24 @@
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
unsigned short __pad1;
|
||||
unsigned long st_ino;
|
||||
target_ulong st_ino;
|
||||
unsigned short st_mode;
|
||||
unsigned short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
unsigned short st_rdev;
|
||||
unsigned short __pad2;
|
||||
unsigned long st_size;
|
||||
unsigned long st_blksize;
|
||||
unsigned long st_blocks;
|
||||
unsigned long st_atime;
|
||||
unsigned long __unused1;
|
||||
unsigned long st_mtime;
|
||||
unsigned long __unused2;
|
||||
unsigned long st_ctime;
|
||||
unsigned long __unused3;
|
||||
unsigned long __unused4;
|
||||
unsigned long __unused5;
|
||||
target_ulong st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong st_blocks;
|
||||
target_ulong st_atime;
|
||||
target_ulong __unused1;
|
||||
target_ulong st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_ulong st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
/* This matches struct stat64 in glibc2.1, hence the absolutely
|
||||
@@ -273,54 +273,93 @@ struct target_stat64 {
|
||||
unsigned char __pad0[10];
|
||||
|
||||
#define STAT64_HAS_BROKEN_ST_INO 1
|
||||
unsigned long __st_ino;
|
||||
target_ulong __st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
|
||||
unsigned long st_uid;
|
||||
unsigned long st_gid;
|
||||
target_ulong st_uid;
|
||||
target_ulong st_gid;
|
||||
|
||||
unsigned short st_rdev;
|
||||
unsigned char __pad3[10];
|
||||
|
||||
long long st_size;
|
||||
unsigned long st_blksize;
|
||||
target_ulong st_blksize;
|
||||
|
||||
unsigned long st_blocks; /* Number 512-byte blocks allocated. */
|
||||
unsigned long __pad4; /* future possible st_blocks high bits */
|
||||
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
|
||||
target_ulong __pad4; /* future possible st_blocks high bits */
|
||||
|
||||
unsigned long st_atime;
|
||||
unsigned long __pad5;
|
||||
target_ulong st_atime;
|
||||
target_ulong __pad5;
|
||||
|
||||
unsigned long st_mtime;
|
||||
unsigned long __pad6;
|
||||
target_ulong st_mtime;
|
||||
target_ulong __pad6;
|
||||
|
||||
unsigned long st_ctime;
|
||||
unsigned long __pad7; /* will be high 32 bits of ctime someday */
|
||||
target_ulong st_ctime;
|
||||
target_ulong __pad7; /* will be high 32 bits of ctime someday */
|
||||
|
||||
unsigned long long st_ino;
|
||||
};
|
||||
|
||||
typedef unsigned long old_sigset_t; /* at least 32 bits */
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
#define TARGET_SA_SIGINFO 0x00000004
|
||||
#define TARGET_SA_ONSTACK 0x08000000
|
||||
#define TARGET_SA_RESTART 0x10000000
|
||||
#define TARGET_SA_NODEFER 0x40000000
|
||||
#define TARGET_SA_RESETHAND 0x80000000
|
||||
#define TARGET_SA_RESTORER 0x04000000
|
||||
|
||||
#define TARGET_SIGHUP 1
|
||||
#define TARGET_SIGINT 2
|
||||
#define TARGET_SIGQUIT 3
|
||||
#define TARGET_SIGILL 4
|
||||
#define TARGET_SIGTRAP 5
|
||||
#define TARGET_SIGABRT 6
|
||||
#define TARGET_SIGIOT 6
|
||||
#define TARGET_SIGBUS 7
|
||||
#define TARGET_SIGFPE 8
|
||||
#define TARGET_SIGKILL 9
|
||||
#define TARGET_SIGUSR1 10
|
||||
#define TARGET_SIGSEGV 11
|
||||
#define TARGET_SIGUSR2 12
|
||||
#define TARGET_SIGPIPE 13
|
||||
#define TARGET_SIGALRM 14
|
||||
#define TARGET_SIGTERM 15
|
||||
#define TARGET_SIGSTKFLT 16
|
||||
#define TARGET_SIGCHLD 17
|
||||
#define TARGET_SIGCONT 18
|
||||
#define TARGET_SIGSTOP 19
|
||||
#define TARGET_SIGTSTP 20
|
||||
#define TARGET_SIGTTIN 21
|
||||
#define TARGET_SIGTTOU 22
|
||||
#define TARGET_SIGURG 23
|
||||
#define TARGET_SIGXCPU 24
|
||||
#define TARGET_SIGXFSZ 25
|
||||
#define TARGET_SIGVTALRM 26
|
||||
#define TARGET_SIGPROF 27
|
||||
#define TARGET_SIGWINCH 28
|
||||
#define TARGET_SIGIO 29
|
||||
#define TARGET_SIGRTMIN 32
|
||||
|
||||
struct target_old_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_ulong sa_mask;
|
||||
target_ulong sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
target_ulong sa_restorer;
|
||||
};
|
||||
|
||||
struct target_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_sigset_t sa_mask;
|
||||
target_ulong sa_flags;
|
||||
target_ulong sa_restorer;
|
||||
target_sigset_t sa_mask;
|
||||
};
|
||||
|
||||
typedef union target_sigval {
|
||||
int sival_int;
|
||||
void *sival_ptr;
|
||||
target_ulong sival_ptr;
|
||||
} target_sigval_t;
|
||||
|
||||
#define TARGET_SI_MAX_SIZE 128
|
||||
@@ -350,7 +389,7 @@ typedef struct target_siginfo {
|
||||
struct {
|
||||
pid_t _pid; /* sender's pid */
|
||||
uid_t _uid; /* sender's uid */
|
||||
sigval_t _sigval;
|
||||
target_sigval_t _sigval;
|
||||
} _rt;
|
||||
|
||||
/* SIGCHLD */
|
||||
@@ -364,7 +403,7 @@ typedef struct target_siginfo {
|
||||
|
||||
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
|
||||
struct {
|
||||
void *_addr; /* faulting insn/memory ref. */
|
||||
target_ulong _addr; /* faulting insn/memory ref. */
|
||||
} _sigfault;
|
||||
|
||||
/* SIGPOLL */
|
||||
@@ -375,6 +414,46 @@ typedef struct target_siginfo {
|
||||
} _sifields;
|
||||
} target_siginfo_t;
|
||||
|
||||
/*
|
||||
* SIGILL si_codes
|
||||
*/
|
||||
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
||||
|
||||
/*
|
||||
* SIGFPE si_codes
|
||||
*/
|
||||
#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
|
||||
#define TARGET_FPE_INTOVF (2) /* integer overflow */
|
||||
#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
|
||||
#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
|
||||
#define TARGET_FPE_FLTUND (5) /* floating point underflow */
|
||||
#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
|
||||
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
|
||||
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
|
||||
#define TARGET_NSIGFPE 8
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
|
||||
struct target_pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
|
||||
/* ioctls */
|
||||
|
||||
/*
|
||||
@@ -632,6 +711,16 @@ struct target_termios {
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
#define TARGET_LDT_ENTRIES 8192
|
||||
#define TARGET_LDT_ENTRY_SIZE 8
|
||||
|
||||
struct target_modify_ldt_ldt_s {
|
||||
unsigned int entry_number;
|
||||
target_ulong base_addr;
|
||||
unsigned int limit;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
|
||||
|
||||
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
|
||||
@@ -758,3 +847,6 @@ struct target_termios {
|
||||
#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff
|
||||
|
||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
|
||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
include ../config.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS=testclone testsig testthread sha1-i386 test-i386
|
||||
endif
|
||||
TESTS+=sha1
|
||||
|
||||
QEMU=../qemu
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
hello: hello.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
strip hello
|
||||
|
||||
testclone: testclone.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testsig: testsig.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testthread: testthread.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||
|
||||
# i386 emulation test (test various opcodes) */
|
||||
test-i386: test-i386.c test-i386-code16.S \
|
||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm
|
||||
|
||||
test: test-i386
|
||||
ifeq ($(ARCH),i386)
|
||||
./test-i386 > test-i386.ref
|
||||
endif
|
||||
$(QEMU) test-i386 > test-i386.out
|
||||
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
|
||||
|
||||
# speed test
|
||||
sha1-i386: sha1.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
sha1: sha1.c
|
||||
$(HOST_CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
speed: sha1 sha1-i386
|
||||
time ./sha1
|
||||
time $(QEMU) ./sha1-i386
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o $(TESTS)
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <asm/unistd.h>
|
||||
|
||||
extern inline volatile void exit(int status)
|
||||
{
|
||||
int __res;
|
||||
__asm__ volatile ("movl %%ecx,%%ebx\n"\
|
||||
"int $0x80" \
|
||||
: "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
|
||||
}
|
||||
|
||||
extern inline int write(int fd, const char * buf, int len)
|
||||
{
|
||||
int status;
|
||||
__asm__ volatile ("pushl %%ebx\n"\
|
||||
"movl %%esi,%%ebx\n"\
|
||||
"int $0x80\n" \
|
||||
"popl %%ebx\n"\
|
||||
: "=a" (status) \
|
||||
: "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
|
||||
}
|
||||
|
||||
void _startup(void)
|
||||
{
|
||||
write(1, "Hello World\n", 12);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
.code16
|
||||
.globl code16_start
|
||||
.globl code16_end
|
||||
|
||||
CS_SEG = 0xf
|
||||
|
||||
code16_start:
|
||||
|
||||
.globl code16_func1
|
||||
|
||||
/* basic test */
|
||||
code16_func1 = . - code16_start
|
||||
mov $1, %eax
|
||||
data32 lret
|
||||
|
||||
/* test push/pop in 16 bit mode */
|
||||
.globl code16_func2
|
||||
code16_func2 = . - code16_start
|
||||
xor %eax, %eax
|
||||
mov $0x12345678, %ebx
|
||||
movl %esp, %ecx
|
||||
push %bx
|
||||
subl %esp, %ecx
|
||||
pop %ax
|
||||
data32 lret
|
||||
|
||||
/* test various jmp opcodes */
|
||||
.globl code16_func3
|
||||
code16_func3 = . - code16_start
|
||||
jmp 1f
|
||||
nop
|
||||
1:
|
||||
mov $4, %eax
|
||||
mov $0x12345678, %ebx
|
||||
xor %bx, %bx
|
||||
jz 2f
|
||||
add $2, %ax
|
||||
2:
|
||||
|
||||
call myfunc
|
||||
|
||||
lcall $CS_SEG, $(myfunc2 - code16_start)
|
||||
|
||||
ljmp $CS_SEG, $(myjmp1 - code16_start)
|
||||
myjmp1_next:
|
||||
|
||||
cs lcall myfunc2_addr - code16_start
|
||||
|
||||
cs ljmp myjmp2_addr - code16_start
|
||||
myjmp2_next:
|
||||
|
||||
data32 lret
|
||||
|
||||
myfunc2_addr:
|
||||
.short myfunc2 - code16_start
|
||||
.short CS_SEG
|
||||
|
||||
myjmp2_addr:
|
||||
.short myjmp2 - code16_start
|
||||
.short CS_SEG
|
||||
|
||||
myjmp1:
|
||||
add $8, %ax
|
||||
jmp myjmp1_next
|
||||
|
||||
myjmp2:
|
||||
add $16, %ax
|
||||
jmp myjmp2_next
|
||||
|
||||
myfunc:
|
||||
add $1, %ax
|
||||
ret
|
||||
|
||||
myfunc2:
|
||||
add $4, %ax
|
||||
lret
|
||||
|
||||
|
||||
code16_end:
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
void glue(glue(test_, OP), b)(int op0, int op1)
|
||||
{
|
||||
int res, s1, s0, flags;
|
||||
s0 = op0;
|
||||
s1 = op1;
|
||||
res = s0;
|
||||
flags = 0;
|
||||
asm ("push %4\n\t"
|
||||
"popf\n\t"
|
||||
stringify(OP)"b %b2\n\t"
|
||||
"pushf\n\t"
|
||||
"popl %1\n\t"
|
||||
: "=a" (res), "=g" (flags)
|
||||
: "q" (s1), "0" (res), "1" (flags));
|
||||
printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
|
||||
stringify(OP) "b", s0, s1, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void glue(glue(test_, OP), w)(int op0h, int op0, int op1)
|
||||
{
|
||||
int res, s1, flags, resh;
|
||||
s1 = op1;
|
||||
resh = op0h;
|
||||
res = op0;
|
||||
flags = 0;
|
||||
asm ("push %5\n\t"
|
||||
"popf\n\t"
|
||||
stringify(OP) "w %w3\n\t"
|
||||
"pushf\n\t"
|
||||
"popl %1\n\t"
|
||||
: "=a" (res), "=g" (flags), "=d" (resh)
|
||||
: "q" (s1), "0" (res), "1" (flags), "2" (resh));
|
||||
printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n",
|
||||
stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void glue(glue(test_, OP), l)(int op0h, int op0, int op1)
|
||||
{
|
||||
int res, s1, flags, resh;
|
||||
s1 = op1;
|
||||
resh = op0h;
|
||||
res = op0;
|
||||
flags = 0;
|
||||
asm ("push %5\n\t"
|
||||
"popf\n\t"
|
||||
stringify(OP) "l %3\n\t"
|
||||
"pushf\n\t"
|
||||
"popl %1\n\t"
|
||||
: "=a" (res), "=g" (flags), "=d" (resh)
|
||||
: "q" (s1), "0" (res), "1" (flags), "2" (resh));
|
||||
printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n",
|
||||
stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
#undef OP
|
||||
@@ -0,0 +1,138 @@
|
||||
|
||||
#define exec_op glue(exec_, OP)
|
||||
#define exec_opl glue(glue(exec_, OP), l)
|
||||
#define exec_opw glue(glue(exec_, OP), w)
|
||||
#define exec_opb glue(glue(exec_, OP), b)
|
||||
|
||||
#ifndef OP_SHIFTD
|
||||
|
||||
#ifdef OP_NOBYTE
|
||||
#define EXECSHIFT(size, res, s1, s2, flags) \
|
||||
asm ("push %4\n\t"\
|
||||
"popf\n\t"\
|
||||
stringify(OP) size " %" size "2, %" size "0\n\t" \
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=g" (res), "=g" (flags)\
|
||||
: "r" (s1), "0" (res), "1" (flags));
|
||||
#else
|
||||
#define EXECSHIFT(size, res, s1, s2, flags) \
|
||||
asm ("push %4\n\t"\
|
||||
"popf\n\t"\
|
||||
stringify(OP) size " %%cl, %" size "0\n\t" \
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=q" (res), "=g" (flags)\
|
||||
: "c" (s1), "0" (res), "1" (flags));
|
||||
#endif
|
||||
|
||||
void exec_opl(int s2, int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECSHIFT("", res, s1, s2, flags);
|
||||
/* overflow is undefined if count != 1 */
|
||||
if (s1 != 1)
|
||||
flags &= ~CC_O;
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opw(int s2, int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECSHIFT("w", res, s1, s2, flags);
|
||||
/* overflow is undefined if count != 1 */
|
||||
if (s1 != 1)
|
||||
flags &= ~CC_O;
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
#else
|
||||
#define EXECSHIFT(size, res, s1, s2, flags) \
|
||||
asm ("push %4\n\t"\
|
||||
"popf\n\t"\
|
||||
stringify(OP) size " %%cl, %" size "5, %" size "0\n\t" \
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=g" (res), "=g" (flags)\
|
||||
: "c" (s1), "0" (res), "1" (flags), "r" (s2));
|
||||
|
||||
void exec_opl(int s2, int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECSHIFT("", res, s1, s2, flags);
|
||||
/* overflow is undefined if count != 1 */
|
||||
if (s1 != 1)
|
||||
flags &= ~CC_O;
|
||||
printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opw(int s2, int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECSHIFT("w", res, s1, s2, flags);
|
||||
/* overflow is undefined if count != 1 */
|
||||
if (s1 != 1)
|
||||
flags &= ~CC_O;
|
||||
printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef OP_NOBYTE
|
||||
void exec_opb(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECSHIFT("b", res, s1, 0, flags);
|
||||
/* overflow is undefined if count != 1 */
|
||||
if (s1 != 1)
|
||||
flags &= ~CC_O;
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
void exec_op(int s2, int s0, int s1)
|
||||
{
|
||||
exec_opl(s2, s0, s1, 0);
|
||||
exec_opw(s2, s0, s1, 0);
|
||||
#ifndef OP_NOBYTE
|
||||
exec_opb(s0, s1, 0);
|
||||
#endif
|
||||
#ifdef OP_CC
|
||||
exec_opl(s2, s0, s1, CC_C);
|
||||
exec_opw(s2, s0, s1, CC_C);
|
||||
exec_opb(s0, s1, CC_C);
|
||||
#endif
|
||||
}
|
||||
|
||||
void glue(test_, OP)(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 32; i++)
|
||||
exec_op(0x21ad3d34, 0x12345678, i);
|
||||
for(i = 0; i < 32; i++)
|
||||
exec_op(0x813f3421, 0x82345678, i);
|
||||
}
|
||||
|
||||
void *glue(_test_, OP) __init_call = glue(test_, OP);
|
||||
|
||||
#undef OP
|
||||
#undef OP_CC
|
||||
#undef OP_SHIFTD
|
||||
#undef OP_NOBYTE
|
||||
#undef EXECSHIFT
|
||||
|
||||
@@ -0,0 +1,838 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
|
||||
#define TEST_CMOV 0
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#define CC_C 0x0001
|
||||
#define CC_P 0x0004
|
||||
#define CC_A 0x0010
|
||||
#define CC_Z 0x0040
|
||||
#define CC_S 0x0080
|
||||
#define CC_O 0x0800
|
||||
|
||||
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
|
||||
|
||||
static void *call_start __init_call = NULL;
|
||||
|
||||
#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
|
||||
|
||||
#define OP add
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP sub
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP xor
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP and
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP or
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP cmp
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP adc
|
||||
#define OP_CC
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP sbb
|
||||
#define OP_CC
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP inc
|
||||
#define OP_CC
|
||||
#define OP1
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP dec
|
||||
#define OP_CC
|
||||
#define OP1
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP neg
|
||||
#define OP_CC
|
||||
#define OP1
|
||||
#include "test-i386.h"
|
||||
|
||||
#define OP not
|
||||
#define OP_CC
|
||||
#define OP1
|
||||
#include "test-i386.h"
|
||||
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
|
||||
|
||||
#define OP shl
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP shr
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP sar
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP rol
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP ror
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP rcr
|
||||
#define OP_CC
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP rcl
|
||||
#define OP_CC
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP shld
|
||||
#define OP_SHIFTD
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP shrd
|
||||
#define OP_SHIFTD
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
/* XXX: should be more precise ? */
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (CC_C)
|
||||
|
||||
#define OP bt
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP bts
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP btr
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
#define OP btc
|
||||
#define OP_NOBYTE
|
||||
#include "test-i386-shift.h"
|
||||
|
||||
/* lea test (modrm support) */
|
||||
#define TEST_LEA(STR)\
|
||||
{\
|
||||
asm("leal " STR ", %0"\
|
||||
: "=r" (res)\
|
||||
: "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
|
||||
printf("lea %s = %08x\n", STR, res);\
|
||||
}
|
||||
|
||||
#define TEST_LEA16(STR)\
|
||||
{\
|
||||
asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
|
||||
: "=wq" (res)\
|
||||
: "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
|
||||
printf("lea %s = %08x\n", STR, res);\
|
||||
}
|
||||
|
||||
|
||||
void test_lea(void)
|
||||
{
|
||||
int eax, ebx, ecx, edx, esi, edi, res;
|
||||
eax = 0x0001;
|
||||
ebx = 0x0002;
|
||||
ecx = 0x0004;
|
||||
edx = 0x0008;
|
||||
esi = 0x0010;
|
||||
edi = 0x0020;
|
||||
|
||||
TEST_LEA("0x4000");
|
||||
|
||||
TEST_LEA("(%%eax)");
|
||||
TEST_LEA("(%%ebx)");
|
||||
TEST_LEA("(%%ecx)");
|
||||
TEST_LEA("(%%edx)");
|
||||
TEST_LEA("(%%esi)");
|
||||
TEST_LEA("(%%edi)");
|
||||
|
||||
TEST_LEA("0x40(%%eax)");
|
||||
TEST_LEA("0x40(%%ebx)");
|
||||
TEST_LEA("0x40(%%ecx)");
|
||||
TEST_LEA("0x40(%%edx)");
|
||||
TEST_LEA("0x40(%%esi)");
|
||||
TEST_LEA("0x40(%%edi)");
|
||||
|
||||
TEST_LEA("0x4000(%%eax)");
|
||||
TEST_LEA("0x4000(%%ebx)");
|
||||
TEST_LEA("0x4000(%%ecx)");
|
||||
TEST_LEA("0x4000(%%edx)");
|
||||
TEST_LEA("0x4000(%%esi)");
|
||||
TEST_LEA("0x4000(%%edi)");
|
||||
|
||||
TEST_LEA("(%%eax, %%ecx)");
|
||||
TEST_LEA("(%%ebx, %%edx)");
|
||||
TEST_LEA("(%%ecx, %%ecx)");
|
||||
TEST_LEA("(%%edx, %%ecx)");
|
||||
TEST_LEA("(%%esi, %%ecx)");
|
||||
TEST_LEA("(%%edi, %%ecx)");
|
||||
|
||||
TEST_LEA("0x40(%%eax, %%ecx)");
|
||||
TEST_LEA("0x4000(%%ebx, %%edx)");
|
||||
|
||||
TEST_LEA("(%%ecx, %%ecx, 2)");
|
||||
TEST_LEA("(%%edx, %%ecx, 4)");
|
||||
TEST_LEA("(%%esi, %%ecx, 8)");
|
||||
|
||||
TEST_LEA("(,%%eax, 2)");
|
||||
TEST_LEA("(,%%ebx, 4)");
|
||||
TEST_LEA("(,%%ecx, 8)");
|
||||
|
||||
TEST_LEA("0x40(,%%eax, 2)");
|
||||
TEST_LEA("0x40(,%%ebx, 4)");
|
||||
TEST_LEA("0x40(,%%ecx, 8)");
|
||||
|
||||
|
||||
TEST_LEA("-10(%%ecx, %%ecx, 2)");
|
||||
TEST_LEA("-10(%%edx, %%ecx, 4)");
|
||||
TEST_LEA("-10(%%esi, %%ecx, 8)");
|
||||
|
||||
TEST_LEA("0x4000(%%ecx, %%ecx, 2)");
|
||||
TEST_LEA("0x4000(%%edx, %%ecx, 4)");
|
||||
TEST_LEA("0x4000(%%esi, %%ecx, 8)");
|
||||
|
||||
/* limited 16 bit addressing test */
|
||||
TEST_LEA16("0x4000");
|
||||
TEST_LEA16("(%%bx)");
|
||||
TEST_LEA16("(%%si)");
|
||||
TEST_LEA16("(%%di)");
|
||||
TEST_LEA16("0x40(%%bx)");
|
||||
TEST_LEA16("0x40(%%si)");
|
||||
TEST_LEA16("0x40(%%di)");
|
||||
TEST_LEA16("0x4000(%%bx)");
|
||||
TEST_LEA16("0x4000(%%si)");
|
||||
TEST_LEA16("(%%bx,%%si)");
|
||||
TEST_LEA16("(%%bx,%%di)");
|
||||
TEST_LEA16("0x40(%%bx,%%si)");
|
||||
TEST_LEA16("0x40(%%bx,%%di)");
|
||||
TEST_LEA16("0x4000(%%bx,%%si)");
|
||||
TEST_LEA16("0x4000(%%bx,%%di)");
|
||||
}
|
||||
|
||||
#define TEST_JCC(JCC, v1, v2)\
|
||||
{\
|
||||
int res;\
|
||||
asm("movl $1, %0\n\t"\
|
||||
"cmpl %2, %1\n\t"\
|
||||
"j" JCC " 1f\n\t"\
|
||||
"movl $0, %0\n\t"\
|
||||
"1:\n\t"\
|
||||
: "=r" (res)\
|
||||
: "r" (v1), "r" (v2));\
|
||||
printf("%-10s %d\n", "j" JCC, res);\
|
||||
\
|
||||
asm("movl $0, %0\n\t"\
|
||||
"cmpl %2, %1\n\t"\
|
||||
"set" JCC " %b0\n\t"\
|
||||
: "=r" (res)\
|
||||
: "r" (v1), "r" (v2));\
|
||||
printf("%-10s %d\n", "set" JCC, res);\
|
||||
if (TEST_CMOV) {\
|
||||
asm("movl $0x12345678, %0\n\t"\
|
||||
"cmpl %2, %1\n\t"\
|
||||
"cmov" JCC "l %3, %0\n\t"\
|
||||
: "=r" (res)\
|
||||
: "r" (v1), "r" (v2), "m" (1));\
|
||||
printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\
|
||||
asm("movl $0x12345678, %0\n\t"\
|
||||
"cmpl %2, %1\n\t"\
|
||||
"cmov" JCC "w %w3, %w0\n\t"\
|
||||
: "=r" (res)\
|
||||
: "r" (v1), "r" (v2), "r" (1));\
|
||||
printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\
|
||||
} \
|
||||
}
|
||||
|
||||
/* various jump tests */
|
||||
void test_jcc(void)
|
||||
{
|
||||
TEST_JCC("ne", 1, 1);
|
||||
TEST_JCC("ne", 1, 0);
|
||||
|
||||
TEST_JCC("e", 1, 1);
|
||||
TEST_JCC("e", 1, 0);
|
||||
|
||||
TEST_JCC("l", 1, 1);
|
||||
TEST_JCC("l", 1, 0);
|
||||
TEST_JCC("l", 1, -1);
|
||||
|
||||
TEST_JCC("le", 1, 1);
|
||||
TEST_JCC("le", 1, 0);
|
||||
TEST_JCC("le", 1, -1);
|
||||
|
||||
TEST_JCC("ge", 1, 1);
|
||||
TEST_JCC("ge", 1, 0);
|
||||
TEST_JCC("ge", -1, 1);
|
||||
|
||||
TEST_JCC("g", 1, 1);
|
||||
TEST_JCC("g", 1, 0);
|
||||
TEST_JCC("g", 1, -1);
|
||||
|
||||
TEST_JCC("b", 1, 1);
|
||||
TEST_JCC("b", 1, 0);
|
||||
TEST_JCC("b", 1, -1);
|
||||
|
||||
TEST_JCC("be", 1, 1);
|
||||
TEST_JCC("be", 1, 0);
|
||||
TEST_JCC("be", 1, -1);
|
||||
|
||||
TEST_JCC("ae", 1, 1);
|
||||
TEST_JCC("ae", 1, 0);
|
||||
TEST_JCC("ae", 1, -1);
|
||||
|
||||
TEST_JCC("a", 1, 1);
|
||||
TEST_JCC("a", 1, 0);
|
||||
TEST_JCC("a", 1, -1);
|
||||
|
||||
|
||||
TEST_JCC("p", 1, 1);
|
||||
TEST_JCC("p", 1, 0);
|
||||
|
||||
TEST_JCC("np", 1, 1);
|
||||
TEST_JCC("np", 1, 0);
|
||||
|
||||
TEST_JCC("o", 0x7fffffff, 0);
|
||||
TEST_JCC("o", 0x7fffffff, -1);
|
||||
|
||||
TEST_JCC("no", 0x7fffffff, 0);
|
||||
TEST_JCC("no", 0x7fffffff, -1);
|
||||
|
||||
TEST_JCC("s", 0, 1);
|
||||
TEST_JCC("s", 0, -1);
|
||||
TEST_JCC("s", 0, 0);
|
||||
|
||||
TEST_JCC("ns", 0, 1);
|
||||
TEST_JCC("ns", 0, -1);
|
||||
TEST_JCC("ns", 0, 0);
|
||||
}
|
||||
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (CC_O | CC_C)
|
||||
|
||||
#define OP mul
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#define OP imul
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (0)
|
||||
|
||||
#define OP div
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#define OP idiv
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
void test_imulw2(int op0, int op1)
|
||||
{
|
||||
int res, s1, s0, flags;
|
||||
s0 = op0;
|
||||
s1 = op1;
|
||||
res = s0;
|
||||
flags = 0;
|
||||
asm ("push %4\n\t"
|
||||
"popf\n\t"
|
||||
"imulw %w2, %w0\n\t"
|
||||
"pushf\n\t"
|
||||
"popl %1\n\t"
|
||||
: "=q" (res), "=g" (flags)
|
||||
: "q" (s1), "0" (res), "1" (flags));
|
||||
printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
|
||||
"imulw", s0, s1, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void test_imull2(int op0, int op1)
|
||||
{
|
||||
int res, s1, s0, flags;
|
||||
s0 = op0;
|
||||
s1 = op1;
|
||||
res = s0;
|
||||
flags = 0;
|
||||
asm ("push %4\n\t"
|
||||
"popf\n\t"
|
||||
"imull %2, %0\n\t"
|
||||
"pushf\n\t"
|
||||
"popl %1\n\t"
|
||||
: "=q" (res), "=g" (flags)
|
||||
: "q" (s1), "0" (res), "1" (flags));
|
||||
printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
|
||||
"imull", s0, s1, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void test_mul(void)
|
||||
{
|
||||
test_imulb(0x1234561d, 4);
|
||||
test_imulb(3, -4);
|
||||
test_imulb(0x80, 0x80);
|
||||
test_imulb(0x10, 0x10);
|
||||
|
||||
test_imulw(0, 0x1234001d, 45);
|
||||
test_imulw(0, 23, -45);
|
||||
test_imulw(0, 0x8000, 0x8000);
|
||||
test_imulw(0, 0x100, 0x100);
|
||||
|
||||
test_imull(0, 0x1234001d, 45);
|
||||
test_imull(0, 23, -45);
|
||||
test_imull(0, 0x80000000, 0x80000000);
|
||||
test_imull(0, 0x10000, 0x10000);
|
||||
|
||||
test_mulb(0x1234561d, 4);
|
||||
test_mulb(3, -4);
|
||||
test_mulb(0x80, 0x80);
|
||||
test_mulb(0x10, 0x10);
|
||||
|
||||
test_mulw(0, 0x1234001d, 45);
|
||||
test_mulw(0, 23, -45);
|
||||
test_mulw(0, 0x8000, 0x8000);
|
||||
test_mulw(0, 0x100, 0x100);
|
||||
|
||||
test_mull(0, 0x1234001d, 45);
|
||||
test_mull(0, 23, -45);
|
||||
test_mull(0, 0x80000000, 0x80000000);
|
||||
test_mull(0, 0x10000, 0x10000);
|
||||
|
||||
test_imulw2(0x1234001d, 45);
|
||||
test_imulw2(23, -45);
|
||||
test_imulw2(0x8000, 0x8000);
|
||||
test_imulw2(0x100, 0x100);
|
||||
|
||||
test_imull2(0x1234001d, 45);
|
||||
test_imull2(23, -45);
|
||||
test_imull2(0x80000000, 0x80000000);
|
||||
test_imull2(0x10000, 0x10000);
|
||||
|
||||
test_idivb(0x12341678, 0x127e);
|
||||
test_idivb(0x43210123, -5);
|
||||
test_idivb(0x12340004, -1);
|
||||
|
||||
test_idivw(0, 0x12345678, 12347);
|
||||
test_idivw(0, -23223, -45);
|
||||
test_idivw(0, 0x12348000, -1);
|
||||
test_idivw(0x12343, 0x12345678, 0x81238567);
|
||||
|
||||
test_idivl(0, 0x12345678, 12347);
|
||||
test_idivl(0, -233223, -45);
|
||||
test_idivl(0, 0x80000000, -1);
|
||||
test_idivl(0x12343, 0x12345678, 0x81234567);
|
||||
|
||||
test_divb(0x12341678, 0x127e);
|
||||
test_divb(0x43210123, -5);
|
||||
test_divb(0x12340004, -1);
|
||||
|
||||
test_divw(0, 0x12345678, 12347);
|
||||
test_divw(0, -23223, -45);
|
||||
test_divw(0, 0x12348000, -1);
|
||||
test_divw(0x12343, 0x12345678, 0x81238567);
|
||||
|
||||
test_divl(0, 0x12345678, 12347);
|
||||
test_divl(0, -233223, -45);
|
||||
test_divl(0, 0x80000000, -1);
|
||||
test_divl(0x12343, 0x12345678, 0x81234567);
|
||||
}
|
||||
|
||||
#define TEST_BSX(op, size, op0)\
|
||||
{\
|
||||
int res, val, resz;\
|
||||
val = op0;\
|
||||
asm("xorl %1, %1 ; " #op " %" size "2, %" size "0 ; setz %b1" \
|
||||
: "=r" (res), "=q" (resz)\
|
||||
: "g" (val));\
|
||||
printf("%-10s A=%08x R=%08x %d\n", #op, val, resz ? 0 : res, resz);\
|
||||
}
|
||||
|
||||
void test_bsx(void)
|
||||
{
|
||||
TEST_BSX(bsrw, "w", 0);
|
||||
TEST_BSX(bsrw, "w", 0x12340128);
|
||||
TEST_BSX(bsrl, "", 0);
|
||||
TEST_BSX(bsrl, "", 0x00340128);
|
||||
TEST_BSX(bsfw, "w", 0);
|
||||
TEST_BSX(bsfw, "w", 0x12340128);
|
||||
TEST_BSX(bsfl, "", 0);
|
||||
TEST_BSX(bsfl, "", 0x00340128);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
|
||||
void test_fops(double a, double b)
|
||||
{
|
||||
printf("a=%f b=%f a+b=%f\n", a, b, a + b);
|
||||
printf("a=%f b=%f a-b=%f\n", a, b, a - b);
|
||||
printf("a=%f b=%f a*b=%f\n", a, b, a * b);
|
||||
printf("a=%f b=%f a/b=%f\n", a, b, a / b);
|
||||
printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
|
||||
printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
|
||||
printf("a=%f sin(a)=%f\n", a, sin(a));
|
||||
printf("a=%f cos(a)=%f\n", a, cos(a));
|
||||
printf("a=%f tan(a)=%f\n", a, tan(a));
|
||||
printf("a=%f log(a)=%f\n", a, log(a));
|
||||
printf("a=%f exp(a)=%f\n", a, exp(a));
|
||||
printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
|
||||
/* just to test some op combining */
|
||||
printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
|
||||
printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
|
||||
printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
|
||||
|
||||
}
|
||||
|
||||
void test_fcmp(double a, double b)
|
||||
{
|
||||
printf("(%f<%f)=%d\n",
|
||||
a, b, a < b);
|
||||
printf("(%f<=%f)=%d\n",
|
||||
a, b, a <= b);
|
||||
printf("(%f==%f)=%d\n",
|
||||
a, b, a == b);
|
||||
printf("(%f>%f)=%d\n",
|
||||
a, b, a > b);
|
||||
printf("(%f<=%f)=%d\n",
|
||||
a, b, a >= b);
|
||||
}
|
||||
|
||||
void test_fcvt(double a)
|
||||
{
|
||||
float fa;
|
||||
long double la;
|
||||
|
||||
fa = a;
|
||||
la = a;
|
||||
printf("(float)%f = %f\n", a, fa);
|
||||
printf("(long double)%f = %Lf\n", a, la);
|
||||
printf("a=%016Lx\n", *(long long *)&a);
|
||||
printf("la=%016Lx %04x\n", *(long long *)&la,
|
||||
*(unsigned short *)((char *)(&la) + 8));
|
||||
printf("a=%f floor(a)=%f\n", a, floor(a));
|
||||
printf("a=%f ceil(a)=%f\n", a, ceil(a));
|
||||
printf("a=%f rint(a)=%f\n", a, rint(a));
|
||||
}
|
||||
|
||||
#define TEST(N) \
|
||||
asm("fld" #N : "=t" (a)); \
|
||||
printf("fld" #N "= %f\n", a);
|
||||
|
||||
void test_fconst(void)
|
||||
{
|
||||
double a;
|
||||
TEST(1);
|
||||
TEST(l2t);
|
||||
TEST(l2e);
|
||||
TEST(pi);
|
||||
TEST(lg2);
|
||||
TEST(ln2);
|
||||
TEST(z);
|
||||
}
|
||||
|
||||
void test_fbcd(double a)
|
||||
{
|
||||
unsigned short bcd[5];
|
||||
double b;
|
||||
|
||||
asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
|
||||
asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
|
||||
printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
|
||||
a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
|
||||
}
|
||||
|
||||
void test_floats(void)
|
||||
{
|
||||
test_fops(2, 3);
|
||||
test_fops(1.4, -5);
|
||||
test_fcmp(2, -1);
|
||||
test_fcmp(2, 2);
|
||||
test_fcmp(2, 3);
|
||||
test_fcvt(1.0/7.0);
|
||||
test_fcvt(-1.0/9.0);
|
||||
test_fcvt(1e30);
|
||||
test_fconst();
|
||||
test_fbcd(1234567890123456);
|
||||
test_fbcd(-123451234567890);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
|
||||
#define TEST_BCD(op, op0, cc_in, cc_mask)\
|
||||
{\
|
||||
int res, flags;\
|
||||
res = op0;\
|
||||
flags = cc_in;\
|
||||
asm ("push %3\n\t"\
|
||||
"popf\n\t"\
|
||||
#op "\n\t"\
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=a" (res), "=g" (flags)\
|
||||
: "0" (res), "1" (flags));\
|
||||
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\
|
||||
#op, op0, res, cc_in, flags & cc_mask);\
|
||||
}
|
||||
|
||||
void test_bcd(void)
|
||||
{
|
||||
TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
|
||||
TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
|
||||
|
||||
TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A));
|
||||
|
||||
TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A));
|
||||
TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A));
|
||||
|
||||
TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
|
||||
TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
|
||||
}
|
||||
|
||||
#define TEST_XCHG(op, size, opconst)\
|
||||
{\
|
||||
int op0, op1;\
|
||||
op0 = 0x12345678;\
|
||||
op1 = 0xfbca7654;\
|
||||
asm(#op " %" size "0, %" size "1" \
|
||||
: "=q" (op0), opconst (op1) \
|
||||
: "0" (op0), "1" (op1));\
|
||||
printf("%-10s A=%08x B=%08x\n",\
|
||||
#op, op0, op1);\
|
||||
}
|
||||
|
||||
#define TEST_CMPXCHG(op, size, opconst, eax)\
|
||||
{\
|
||||
int op0, op1;\
|
||||
op0 = 0x12345678;\
|
||||
op1 = 0xfbca7654;\
|
||||
asm(#op " %" size "0, %" size "1" \
|
||||
: "=q" (op0), opconst (op1) \
|
||||
: "0" (op0), "1" (op1), "a" (eax));\
|
||||
printf("%-10s EAX=%08x A=%08x C=%08x\n",\
|
||||
#op, eax, op0, op1);\
|
||||
}
|
||||
|
||||
void test_xchg(void)
|
||||
{
|
||||
TEST_XCHG(xchgl, "", "=q");
|
||||
TEST_XCHG(xchgw, "w", "=q");
|
||||
TEST_XCHG(xchgb, "b", "=q");
|
||||
|
||||
TEST_XCHG(xchgl, "", "=m");
|
||||
TEST_XCHG(xchgw, "w", "=m");
|
||||
TEST_XCHG(xchgb, "b", "=m");
|
||||
|
||||
TEST_XCHG(xaddl, "", "=q");
|
||||
TEST_XCHG(xaddw, "w", "=q");
|
||||
TEST_XCHG(xaddb, "b", "=q");
|
||||
|
||||
TEST_XCHG(xaddl, "", "=m");
|
||||
TEST_XCHG(xaddw, "w", "=m");
|
||||
TEST_XCHG(xaddb, "b", "=m");
|
||||
|
||||
TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654);
|
||||
TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654);
|
||||
TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654);
|
||||
|
||||
TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc);
|
||||
TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc);
|
||||
TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc);
|
||||
|
||||
TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654);
|
||||
TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654);
|
||||
TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654);
|
||||
|
||||
TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc);
|
||||
TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc);
|
||||
TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
/* segmentation tests */
|
||||
|
||||
#include <asm/ldt.h>
|
||||
#include <linux/unistd.h>
|
||||
|
||||
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
|
||||
|
||||
uint8_t seg_data1[4096];
|
||||
uint8_t seg_data2[4096];
|
||||
|
||||
#define MK_SEL(n) (((n) << 3) | 7)
|
||||
|
||||
/* NOTE: we use Linux modify_ldt syscall */
|
||||
void test_segs(void)
|
||||
{
|
||||
struct modify_ldt_ldt_s ldt;
|
||||
long long ldt_table[3];
|
||||
int res, res2;
|
||||
char tmp;
|
||||
|
||||
ldt.entry_number = 1;
|
||||
ldt.base_addr = (unsigned long)&seg_data1;
|
||||
ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
|
||||
ldt.seg_32bit = 1;
|
||||
ldt.contents = MODIFY_LDT_CONTENTS_DATA;
|
||||
ldt.read_exec_only = 0;
|
||||
ldt.limit_in_pages = 1;
|
||||
ldt.seg_not_present = 0;
|
||||
ldt.useable = 1;
|
||||
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
|
||||
|
||||
ldt.entry_number = 2;
|
||||
ldt.base_addr = (unsigned long)&seg_data2;
|
||||
ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12;
|
||||
ldt.seg_32bit = 1;
|
||||
ldt.contents = MODIFY_LDT_CONTENTS_DATA;
|
||||
ldt.read_exec_only = 0;
|
||||
ldt.limit_in_pages = 1;
|
||||
ldt.seg_not_present = 0;
|
||||
ldt.useable = 1;
|
||||
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
|
||||
|
||||
modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<3;i++)
|
||||
printf("%d: %016Lx\n", i, ldt_table[i]);
|
||||
}
|
||||
#endif
|
||||
/* do some tests with fs or gs */
|
||||
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
|
||||
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
|
||||
|
||||
seg_data1[1] = 0xaa;
|
||||
seg_data2[1] = 0x55;
|
||||
|
||||
asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
|
||||
printf("FS[1] = %02x\n", res);
|
||||
|
||||
asm volatile ("gs movzbl 0x1, %0" : "=r" (res));
|
||||
printf("GS[1] = %02x\n", res);
|
||||
|
||||
/* tests with ds/ss (implicit segment case) */
|
||||
tmp = 0xa5;
|
||||
asm volatile ("pushl %%ebp\n\t"
|
||||
"pushl %%ds\n\t"
|
||||
"movl %2, %%ds\n\t"
|
||||
"movl %3, %%ebp\n\t"
|
||||
"movzbl 0x1, %0\n\t"
|
||||
"movzbl (%%ebp), %1\n\t"
|
||||
"popl %%ds\n\t"
|
||||
"popl %%ebp\n\t"
|
||||
: "=r" (res), "=r" (res2)
|
||||
: "r" (MK_SEL(1)), "r" (&tmp));
|
||||
printf("DS[1] = %02x\n", res);
|
||||
printf("SS[tmp] = %02x\n", res2);
|
||||
}
|
||||
|
||||
/* 16 bit code test */
|
||||
extern char code16_start, code16_end;
|
||||
extern char code16_func1;
|
||||
extern char code16_func2;
|
||||
extern char code16_func3;
|
||||
|
||||
void test_code16(void)
|
||||
{
|
||||
struct modify_ldt_ldt_s ldt;
|
||||
int res, res2;
|
||||
|
||||
/* build a code segment */
|
||||
ldt.entry_number = 1;
|
||||
ldt.base_addr = (unsigned long)&code16_start;
|
||||
ldt.limit = &code16_end - &code16_start;
|
||||
ldt.seg_32bit = 0;
|
||||
ldt.contents = MODIFY_LDT_CONTENTS_CODE;
|
||||
ldt.read_exec_only = 0;
|
||||
ldt.limit_in_pages = 0;
|
||||
ldt.seg_not_present = 0;
|
||||
ldt.useable = 1;
|
||||
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
|
||||
|
||||
/* call the first function */
|
||||
asm volatile ("lcall %1, %2"
|
||||
: "=a" (res)
|
||||
: "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc");
|
||||
printf("func1() = 0x%08x\n", res);
|
||||
asm volatile ("lcall %2, %3"
|
||||
: "=a" (res), "=c" (res2)
|
||||
: "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc");
|
||||
printf("func2() = 0x%08x spdec=%d\n", res, res2);
|
||||
asm volatile ("lcall %1, %2"
|
||||
: "=a" (res)
|
||||
: "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc");
|
||||
printf("func3() = 0x%08x\n", res);
|
||||
}
|
||||
|
||||
|
||||
static void *call_end __init_call = NULL;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void **ptr;
|
||||
void (*func)(void);
|
||||
|
||||
ptr = &call_start + 1;
|
||||
while (*ptr != NULL) {
|
||||
func = *ptr++;
|
||||
func();
|
||||
}
|
||||
test_bsx();
|
||||
test_mul();
|
||||
test_jcc();
|
||||
test_floats();
|
||||
test_bcd();
|
||||
test_xchg();
|
||||
test_lea();
|
||||
test_segs();
|
||||
test_code16();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
#define exec_op glue(exec_, OP)
|
||||
#define exec_opl glue(glue(exec_, OP), l)
|
||||
#define exec_opw glue(glue(exec_, OP), w)
|
||||
#define exec_opb glue(glue(exec_, OP), b)
|
||||
|
||||
#define EXECOP2(size, res, s1, flags) \
|
||||
asm ("push %4\n\t"\
|
||||
"popf\n\t"\
|
||||
stringify(OP) size " %" size "2, %" size "0\n\t" \
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=q" (res), "=g" (flags)\
|
||||
: "q" (s1), "0" (res), "1" (flags));
|
||||
|
||||
#define EXECOP1(size, res, flags) \
|
||||
asm ("push %3\n\t"\
|
||||
"popf\n\t"\
|
||||
stringify(OP) size " %" size "0\n\t" \
|
||||
"pushf\n\t"\
|
||||
"popl %1\n\t"\
|
||||
: "=q" (res), "=g" (flags)\
|
||||
: "0" (res), "1" (flags));
|
||||
|
||||
#ifdef OP1
|
||||
void exec_opl(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP1("", res, flags);
|
||||
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "l", s0, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opw(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP1("w", res, flags);
|
||||
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "w", s0, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opb(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP1("b", res, flags);
|
||||
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "b", s0, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
#else
|
||||
void exec_opl(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP2("", res, s1, flags);
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opw(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP2("w", res, s1, flags);
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
|
||||
void exec_opb(int s0, int s1, int iflags)
|
||||
{
|
||||
int res, flags;
|
||||
res = s0;
|
||||
flags = iflags;
|
||||
EXECOP2("b", res, s1, flags);
|
||||
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
|
||||
stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
void exec_op(int s0, int s1)
|
||||
{
|
||||
exec_opl(s0, s1, 0);
|
||||
exec_opw(s0, s1, 0);
|
||||
exec_opb(s0, s1, 0);
|
||||
#ifdef OP_CC
|
||||
exec_opl(s0, s1, CC_C);
|
||||
exec_opw(s0, s1, CC_C);
|
||||
exec_opb(s0, s1, CC_C);
|
||||
#endif
|
||||
}
|
||||
|
||||
void glue(test_, OP)(void)
|
||||
{
|
||||
exec_op(0x12345678, 0x812FADA);
|
||||
exec_op(0x12341, 0x12341);
|
||||
exec_op(0x12341, -0x12341);
|
||||
exec_op(0xffffffff, 0);
|
||||
exec_op(0xffffffff, -1);
|
||||
exec_op(0xffffffff, 1);
|
||||
exec_op(0xffffffff, 2);
|
||||
exec_op(0x7fffffff, 0);
|
||||
exec_op(0x7fffffff, 1);
|
||||
exec_op(0x7fffffff, -1);
|
||||
exec_op(0x80000000, -1);
|
||||
exec_op(0x80000000, 1);
|
||||
exec_op(0x80000000, -2);
|
||||
exec_op(0x12347fff, 0);
|
||||
exec_op(0x12347fff, 1);
|
||||
exec_op(0x12347fff, -1);
|
||||
exec_op(0x12348000, -1);
|
||||
exec_op(0x12348000, 1);
|
||||
exec_op(0x12348000, -2);
|
||||
exec_op(0x12347f7f, 0);
|
||||
exec_op(0x12347f7f, 1);
|
||||
exec_op(0x12347f7f, -1);
|
||||
exec_op(0x12348080, -1);
|
||||
exec_op(0x12348080, 1);
|
||||
exec_op(0x12348080, -2);
|
||||
}
|
||||
|
||||
void *glue(_test_, OP) __init_call = glue(test_, OP);
|
||||
|
||||
#undef OP
|
||||
#undef OP_CC
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
|
||||
int thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
|
||||
for(i=0;i<10;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
for(i=0;i<20;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(120 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STACK_SIZE 16384
|
||||
|
||||
void test_clone(void)
|
||||
{
|
||||
uint8_t *stack1, *stack2;
|
||||
int pid1, pid2, status1, status2;
|
||||
|
||||
stack1 = malloc(STACK_SIZE);
|
||||
pid1 = clone(thread1_func, stack1 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
|
||||
|
||||
stack2 = malloc(STACK_SIZE);
|
||||
pid2 = clone(thread2_func, stack2 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
|
||||
|
||||
while (waitpid(pid1, &status1, 0) != pid1);
|
||||
while (waitpid(pid2, &status2, 0) != pid2);
|
||||
printf("status1=0x%x\n", status1);
|
||||
printf("status2=0x%x\n", status2);
|
||||
printf("End of clone test.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_clone();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void alarm_handler(int sig)
|
||||
{
|
||||
printf("alarm signal=%d\n", sig);
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x\n",
|
||||
uc->uc_mcontext.gregs[EAX],
|
||||
uc->uc_mcontext.gregs[EBX],
|
||||
uc->uc_mcontext.gregs[ECX],
|
||||
uc->uc_mcontext.gregs[EDX],
|
||||
uc->uc_mcontext.gregs[ESI],
|
||||
uc->uc_mcontext.gregs[EDI],
|
||||
uc->uc_mcontext.gregs[EBP],
|
||||
uc->uc_mcontext.gregs[ESP],
|
||||
uc->uc_mcontext.gregs[EFL],
|
||||
uc->uc_mcontext.gregs[EIP]);
|
||||
}
|
||||
|
||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
|
||||
printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
|
||||
strsignal(info->si_signo),
|
||||
info->si_signo, info->si_errno, info->si_code,
|
||||
(unsigned long)info->si_addr);
|
||||
dump_regs(uc);
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
int v1;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
|
||||
/* test division by zero reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
|
||||
/* now divide by zero */
|
||||
v1 = 0;
|
||||
v1 = 2 / v1;
|
||||
}
|
||||
|
||||
/* test illegal instruction reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
|
||||
/* now execute an invalid instruction */
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
|
||||
act.sa_handler = alarm_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
alarm(1);
|
||||
for(i = 0;i < 2; i++) {
|
||||
sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
|
||||
void *thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
|
||||
for(i=0;i<10;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
for(i=0;i<20;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(150 * 1000);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void test_pthread(void)
|
||||
{
|
||||
pthread_t tid1, tid2;
|
||||
|
||||
pthread_create(&tid1, NULL, thread1_func, "hello1");
|
||||
pthread_create(&tid2, NULL, thread2_func, "hello2");
|
||||
pthread_join(tid1, NULL);
|
||||
pthread_join(tid2, NULL);
|
||||
printf("End of pthread test.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_pthread();
|
||||
return 0;
|
||||
}
|
||||
@@ -3,25 +3,25 @@
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gemu.h"
|
||||
#include "qemu.h"
|
||||
#include "thunk.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
@@ -1,19 +1,71 @@
|
||||
/*
|
||||
* Generic thunking code to convert data between host and target CPU
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef THUNK_H
|
||||
#define THUNK_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
||||
#define bswap_16(x) \
|
||||
({ \
|
||||
uint16_t __x = (x); \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
|
||||
})
|
||||
|
||||
#define bswap_32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
#define bswap_64(x) \
|
||||
({ \
|
||||
uint64_t __x = (x); \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
|
||||
})
|
||||
|
||||
#undef WORDS_BIGENDIAN
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define WORDS_BIGENDIAN
|
||||
#endif
|
||||
|
||||
#ifdef WORD_BIGENDIAN
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define BSWAP_NEEDED
|
||||
#endif
|
||||
|
||||
/* XXX: auto autoconf */
|
||||
/* XXX: autoconf */
|
||||
#define TARGET_I386
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
|
||||
+3662
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user