summaryrefslogtreecommitdiffstats
path: root/libcpu
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-01-02 17:44:39 +0000
committerUlrich Drepper <drepper@redhat.com>2008-01-02 17:44:39 +0000
commit3cbdd387c752999255aea91600b5cfdefbeac7d0 (patch)
tree50c18bd26f8cd31f4c1aa3ce1d78bb98548659ba /libcpu
parentad024afc93dcd0f4797b3e80bfb6b80c34da5c12 (diff)
downloadandroid_external_elfutils-3cbdd387c752999255aea91600b5cfdefbeac7d0.tar.gz
android_external_elfutils-3cbdd387c752999255aea91600b5cfdefbeac7d0.tar.bz2
android_external_elfutils-3cbdd387c752999255aea91600b5cfdefbeac7d0.zip
propagate from branch 'com.redhat.elfutils.disasm' (head d15b4eb794e81e477f9896fe82a74cb5ecf4514c)
to branch 'com.redhat.elfutils' (head eaacbf01f8cc89d043ec6eca9b5e35cb5c4cde06)
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/ChangeLog181
-rw-r--r--libcpu/Makefile.am57
-rw-r--r--libcpu/defs/i386634
-rw-r--r--libcpu/defs/i386.doc74
-rw-r--r--libcpu/defs/x86_64341
-rw-r--r--libcpu/i386_data.h1406
-rw-r--r--libcpu/i386_disasm.c914
-rw-r--r--libcpu/i386_gendis.c39
-rw-r--r--libcpu/i386_lex.l115
-rw-r--r--libcpu/i386_parse.y1641
-rw-r--r--libcpu/memory-access.h168
-rw-r--r--libcpu/x86_64_disasm.c5
12 files changed, 5570 insertions, 5 deletions
diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog
index 5c2a4ac7..c5be1d7b 100644
--- a/libcpu/ChangeLog
+++ b/libcpu/ChangeLog
@@ -1,3 +1,184 @@
+2008-01-01 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: More 0f prefix support.
+ * i386_data.h (FCT_mmxreg): Implement.
+ (FCT_mmxreg2): Implement.
+ (FCT_mmreg): Remove.
+ * i386_disasm.c (i386_disasm): More special instructions.
+ Fix tttn suffix for cmov.
+ * i386_parse.y: Simplify test for mod/r_m mode.
+
+2007-12-31 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Fix order or arguments for mov of control/debug registers.
+ * i386_data.h (FCT_ccc): Implement
+ (FCT_ddd): Implement
+
+2007-12-30 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Fix 0f groups 6 and 7.
+ * i386_data.c (FCT_mod$16r_m): Implement.
+ * i386_disasm.c (i386_disasm): Third parameter can also have string.
+
+2007-12-29 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Add lots of floating point ops.
+ * i386_data.h (FCT_fmod$fr_m): Removed.
+ (FCT_freg): Implement.
+ * i386_disasm.c (i386_disasm): Implement suffix_D.
+ * i386_parse.y: Emit suffix_D.
+
+ * defs/i386: Use rel instead of dispA.
+ Fix lcall, dec, div, idiv, imul, inc, jmp, ljmp, mul, neg, not, push,
+ test.
+
+ * i386_data.h (FCT_dispA): Removed.
+ (FCT_ds_xx): Add test for end of input buffer.
+ * i386_disasm.c (ABORT_ENTRY): Removed.
+ (i386_disasm): Fix handling of SIB. Pass correct address value to
+ operand callbacks.
+
+ * Makefile.am (*.mnemonics): Filter out INVALID entry.
+ * defs/i386: Define imms8 and use in appropriate places.
+ Add INVALID entries for special opcodes with special mnemonics.
+ Fix int3. Fix typo in shl. Correct xlat.
+ * i386_data.h (FCT_ds_xx): New function.
+ (FCT_ds_si): Use it.
+ (FCT_ds_bx): New function.
+ (FCT_imms8): New function.
+ * i386_disasm.c (MNE_INVALID): Define.
+ (i386_disasm): Handle invalid opcodes in mnemonics printing, not
+ separately. Fix address value passed to operand handlers.
+ * i386_parse.y (bx_reg): Define.
+ (instrtable_out): Handle INVALID entries differently, just use
+ MNE_INVALID value for .mnemonic.
+
+2007-12-28 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Fix shift and mov immediate instructions.
+ * i386_data.h (FCT_imm16): Implement.
+
+ * defs/i386: Use absval instead of abs of lcall and ljmp.
+ Add parameters for cmps. Fix test and mov immediate.
+ * i386_data.h: Implement FCT_absval.
+ * i386_disasm.c: Handle data16 for suffix_w and FCT_imm.
+
+ * defs/i386: Move entries with 0x9b prefix together.
+ * i386_disasm.c (i386_disasm): Fix recognizing insufficient bytes in
+ input. Handle data16 with suffix_W.
+
+ * i386_data.h (FCT_*): Add end parameter to all functions. Check
+ before using more bytes.
+ (FCT_sel): Implement.
+ * i386_disasm.c (i386_disasm): Better handle end of input buffer.
+ Specal opcode 0x99.
+
+ * Makefile.am: Use m4 to preprocess defs/* files.
+ * defs/i386: Adjust appropriately.
+ * i386_data.c (FCT_ax): Implement.
+ (FCT_ax$w): Use FCT_ax.
+ * i386_disasm.c (ADD_STRING): Use _len instead of len.
+ (i386_disasm): If no instruction can be matched because of lack of
+ input and prefixes have been matched, print prefixes.
+ Recognize abort entries.
+ Handle special cases.
+ * i386_gendis.c: Recognize - input file name.
+ * i386_lex.c: Recognize INVALID token.
+ * i386_parse.y: Handle INVALID token input.
+
+ * defs/i386: Fix mov, pop.
+ * i386_data.h (FCT_sreg3): Implement.
+
+2007-12-27 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Fix adc, add, cmp, or, sbb, sub, xchg, xor.
+ * i386_data.h (FCT_imms): New function.
+ (FCT_imm$s): Use FCT_imms for handling of signed values.
+ (FCT_imm8): Sign extend values.
+ * i386_disasm.c (i386_disasm): Implement suffix_w0.
+ * i386_parse.y: Emit suffix w0.
+
+ * i386_data.h (FCT_disp8): Add 0x prefix.
+ (FCT_ds_si): Implement.
+ * i386_disasm.c (i386_disasm): Increment addr for invalid prefixes.
+ Implement tttn suffix.
+ * i386_parse.y: Emit tttn suffix definition.
+
+2007-12-26 Ulrich Drepper <drepper@redhat.com>
+
+ * i386_data.h (struct instr_enc): Use suffix field.
+ (FCT_dx): Fill in body.
+ (FCT_es_di): Likewise.
+ (FCT_imm$s): Sign-extended byte values.
+ * i386_disasm.c: Protect ADD_CHAR and ADD_STRING macros. Adjust uses.
+ (i386_disasm): Handle suffix.
+ * i386_parse.y: Emit suffix information.
+ * defs/i386: Remove unnecessary suffixes.
+
+ * Makefile.am: Disable building x86-64 version for now.
+
+ * defs/i386: Fix and, bound, cmp, or, pop, sbb, sub, xor.
+ * i386_data.h: Pass pointer to prefix to functions. If not prefixes
+ are consumed this means invalid input.
+ * i386_disasm.c: Fix prefix printing. Adjust function calls for
+ parameter change.
+ * i386_parse.y: Recognize moda prefix.
+
+2007-12-21 Ulrich Drepper <drepper@redhat.com>
+
+ * i386_data.h: Fix SIB handling.
+ * i386_disasm.c: Likewise.
+
+2007-12-19 Ulrich Drepper <drepper@redhat.com>
+
+ * defs/i386: Fix up 'and' opcode.
+
+2007-10-31 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile.am: Add dependencies of the generated files on the source
+ files.
+ (i386_lex_CFLAGS): Add -Wno-sign-compare.
+
+ * defs/i386: A lot more data.
+ * defs/x86_64: Likewise.
+ * i386_data.h (struct instr_enc): Add off1_3, off2_3, and off3_3
+ fields.
+ (opfct_t): Add parameter for third operand.
+ (FCT_*): Likewise.
+ (data_prefix): New function.
+ (FCT_abs): Implement.
+ (FCT_ax): Renamed to FCT_ax$w amd implement.
+ (FCT_disp8): Implement.
+ (FCT_dispA): Implement.
+ (FCT_imm): Implement.
+ (FCT_imm$w): Implement.
+ (FCT_imm$s): Don't zero-pad numbers.
+ (FCT_imm8): Likewise.
+ (FCT_rel): Likewise.
+ (general_mod$r_m): New function.
+ (FCT_mod$r_m): Use it.
+ (FCT_mod$r_m$w): New function.
+ (FCT_mod$8r_m): New function.
+ (FCT_reg): Correctly handle 16-bit registers.
+ (FCT_reg$w): New function.
+ * i386_disasm.c (i386_disasm): Handle prefixes better.
+ Pass third parameter to operand functions.
+ * i386_parse.y (struct instruction): Add off3 field.
+ Handle third operand throughout.
+
+2007-02-05 Ulrich Drepper <drepper@redhat.com>
+
+ * i386_disasm.c: New file.
+ * i386_data.h: New file.
+ * i386_gendis.c: New file.
+ * i386_lex.l: New file.
+ * i386_parse.y: New file.
+ * memory-access.h: New file.
+ * x86_64_disasm.c: New file.
+ * defs/i386: New file.
+ * defs/i386.doc: New file.
+ * defs/x86_64: New file.
+
2005-02-15 Ulrich Drepper <drepper@redhat.com>
* Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2.
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 23222bec..c511408d 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to create Makefile.in
##
-## Copyright (C) 2002, 2005 Red Hat, Inc.
+## Copyright (C) 2002, 2004, 2005, 2007 Red Hat, Inc.
## This file is part of Red Hat elfutils.
##
## Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -25,9 +25,56 @@
## <http://www.openinventionnetwork.com>.
##
DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H
-AM_CFLAGS = -Wall -Wshadow -Werror -Wextra -Wformat=2 -Wunused
-INCLUDES = -I$(srcdir)
+if MUDFLAP
+AM_CFLAGS = -fmudflap
+else
+AM_CFLAGS =
+endif
+AM_CFLAGS += -Wall -Wshadow -Werror -Wunused -Wextra -std=gnu99 -fpic \
+ $($(*F)_CFLAGS)
+INCLUDES = -I$(srcdir) -I$(srcdir)/../lib -I$(srcdir)/../libelf \
+ -I$(srcdir)/../libebl -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
+LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
+AM_YFLAGS = -p$(<F:parse.y=)
-noinst_LIBRARIES = libcpu_i386.a
+if MUDFLAP
+libmudflap = -lmudflap
+endif
-libcpu_i386_a_SOURCES = i386_dis.c
+# XXX x86-64 uncommented for now.
+noinst_LIBRARIES = libcpu_i386.a# libcpu_x86_64.a
+noinst_PROGRAMS = i386_gendis
+
+libcpu_i386_a_SOURCES = i386_disasm.c
+# XXX Unused for now.
+#libcpu_x86_64_a_SOURCES = x86_64_disasm.c
+
+i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y
+
+i386_disasm.o: i386.mnemonics i386_dis.h
+x86_64_disasm.o: x86_64.mnemonics x86_64_dis.h i386_disasm.c
+
+i386_dis.h: i386_gendis $(srcdir)/defs/i386
+ m4 -Di386 -DDISASSEMBLER $(srcdir)/defs/i386 | ./i386_gendis - > $@
+x86_64_dis.h: i386_gendis $(srcdir)/defs/x86_64
+ m4 -Dx86_64 -DDISASSEMBLER $(srcdir)/defs/x86_64 | ./i386_gendis - > $@
+
+i386.mnemonics x86_64.mnemonics: %.mnemonics: $(srcdir)/defs/%
+ m4 -D$(<F) -DDISASSEMBLER $^ \
+ | sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:]]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \
+ | sort -u > $@
+
+libeu = ../lib/libeu.a
+
+i386_lex_CFLAGS = -Wno-unused-label -Wno-unused-function -Wno-sign-compare
+i386_gendis.o: i386_parse.c i386.mnemonics
+i386_parse_CFLAGS = -DNMNES=$$(wc -l < i386.mnemonics)
+i386_lex.o: i386_parse.c
+i386_gendis_LDADD = $(libeu) -lm $(libmudflap)
+
+noinst_HEADERS = memory-access.h i386_parse.h i386_data.h
+
+EXTRA_DIST = defs/i386 defs/x86_64
+
+CLEANFILES = i386.mnemonics i386_dis.h x86_64.mnemonics x86_64_dis.h
diff --git a/libcpu/defs/i386 b/libcpu/defs/i386
new file mode 100644
index 00000000..b0cdfb4b
--- /dev/null
+++ b/libcpu/defs/i386
@@ -0,0 +1,634 @@
+%mask {s} 1
+%mask {w} 1
+%mask {w1} 1
+dnl floating point reg suffix
+%mask {D} 1
+%mask {imm8} 8
+%mask {imms8} 8
+%mask {imm16} 16
+%mask {reg} 3
+%mask {reg16} 3
+%mask {tttn} 4
+%mask {gg} 2
+%mask {mod} 2
+%mask {moda} 2
+%mask {MOD} 2
+%mask {r_m} 3
+dnl like {r_m} but referencing byte register
+%mask {8r_m} 3
+dnl like {r_m} but referencing 16-bit register
+%mask {16r_m} 3
+%mask {disp8} 8
+dnl imm really is 8/16/32 bit depending on the situation.
+%mask {imm} 8
+%mask {imms} 8
+%mask {rel} 32
+%mask {abs} 32
+%mask {absval} 32
+%mask {sel} 16
+%mask {imm32} 32
+%mask {ccc} 3
+%mask {ddd} 3
+%mask {sreg3} 3
+%mask {sreg2} 2
+%mask {mmxreg} 3
+%mask {mmxreg2} 3
+%mask {R_M} 3
+%mask {0g} 2
+%mask {GG} 2
+%mask {gG} 2
+%mask {Mod} 2
+%mask {xmmreg} 3
+%mask {R_m} 3
+%mask {mmreg} 3
+%mask {xmmreg1} 3
+%mask {xmmreg2} 3
+%mask {predpd} 8
+%mask {predps} 8
+%mask {predsd} 8
+%mask {predss} 8
+%mask {freg} 3
+%mask {fmod} 2
+%mask {fr_m} 3
+%prefix {R}
+%prefix {RE}
+%suffix {W}
+%suffix {w0}
+%synonym {xmmreg1} {xmmreg}
+%synonym {xmmreg2} {xmmreg}
+
+%%
+ifdef(`i386',
+`00110111:aaa
+11010101,00001010:aad
+11010100,00001010:aam
+00111111:aas
+')dnl
+0001010{w},{imm}:adc {imm}{w},{ax}{w}
+1000000{w},{mod}010{r_m},{imm}:adc{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}010{r_m},{imms8}:adc{w} {imms8},{mod}{r_m}
+0001000{w},{mod}{reg}{r_m}:adc {reg}{w},{mod}{r_m}
+0001001{w},{mod}{reg}{r_m}:adc {mod}{r_m},{reg}{w}
+0000010{w},{imm}:add {imm}{w},{ax}{w}
+1000000{w},{mod}000{r_m},{imm}:add{w} {imm}{w},{mod}{r_m}{w}
+10000011,{mod}000{r_m},{imms8}:add{w0} {imms8},{mod}{r_m}
+0000000{w},{mod}{reg}{r_m}:add {reg}{w},{mod}{r_m}
+0000001{w},{mod}{reg}{r_m}:add {mod}{r_m},{reg}{w}
+11110010,00001111,01011000,{Mod}{xmmreg}{R_m}:addsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+01100110,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubpd {Mod}{R_m},{xmmreg}
+11110010,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubps {Mod}{R_m},{xmmreg}
+0010010{w},{imm}:and {imm}{w},{ax}{w}
+1000000{w},{mod}100{r_m},{imm}:and{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}100{r_m},{imms}:and{w} {imms},{mod}{r_m}
+0010000{w},{mod}{reg}{r_m}:and {reg}{w},{mod}{r_m}{w}
+0010001{w},{mod}{reg}{r_m}:and {mod}{r_m}{w},{reg}{w}
+01100110,00001111,01010100,{Mod}{xmmreg}{R_m}:andpd {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+01100110,00001111,01010101,{Mod}{xmmreg}{R_m}:andnpd {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+ifdef(`i386',
+`01100011,{mod}{reg16}{r_m}:arpl {reg16},{mod}{r_m}
+01100010,{moda}{reg}{r_m}:bound {reg},{moda}{r_m}
+')dnl
+00001111,10111100,{mod}{reg}{r_m}:bsf {reg},{mod}{r_m}
+00001111,10111101,{mod}{reg}{r_m}:bsr {reg},{mod}{r_m}
+00001111,11001{reg}:bswap {reg}
+00001111,10100011,{mod}{reg}{r_m}:bt {reg},{mod}{r_m}
+00001111,10111010,{mod}100{r_m},{imm8}:bt {imm8},{mod}{r_m}
+00001111,10111011,{mod}{reg}{r_m}:btc {reg},{mod}{r_m}
+00001111,10111010,{mod}111{r_m},{imm8}:btc {imm8},{mod}{r_m}
+00001111,10110011,{mod}{reg}{r_m}:btr {reg},{mod}{r_m}
+00001111,10111010,{mod}110{r_m},{imm8}:btr {imm8},{mod}{r_m}
+00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m}
+00001111,10111010,{mod}101{r_m},{imm8}:bts {imm8},{mod}{r_m}
+11101000,{rel}:call {rel}
+11111111,{mod}010{r_m}:call *{mod}{r_m}
+ifdef(`i386',
+`10011010,{absval},{sel}:lcall {sel},{absval}
+')dnl
+11111111,{mod}011{r_m}:lcall *{mod}{r_m}
+# SPECIAL 10011000:[{rex.w}?cltq:{dpfx}?cbtw:cwtl]
+10011000:INVALID
+# SPECIAL 10011001:[{rew.w}?cqto:{dpfx}?cltd:cwtd]
+10011001:INVALID
+11111000:clc
+11111100:cld
+00001111,10101110,{mod}111{r_m}:clflush {mod}{r_m}
+11111010:cli
+00001111,00000101:syscall
+00001111,00000110:clts
+00001111,00000111:sysret
+00001111,00110100:sysenter
+00001111,00110101:sysexit
+11110101:cmc
+00001111,0100{tttn},{mod}{reg}{r_m}:cmov{tttn} {mod}{r_m},{reg}
+0011110{w},{imm}:cmp {imm}{w},{ax}{w}
+1000000{w},{mod}111{r_m},{imm}:cmp{w} {imm}{w},{mod}{r_m}{w}
+10000011,{mod}111{r_m},{imms8}:cmp{w0} {imms8},{mod}{r_m}
+0011100{w},{mod}{reg}{r_m}:cmp {reg}{w},{mod}{r_m}{w}
+0011101{w},{mod}{reg}{r_m}:cmp {mod}{r_m}{w},{reg}{w}
+01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{predpd}:cmpl{predpd} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmppd {imm8},{Mod}{R_m},{xmmreg
+}')dnl
+00001111,11000010,{Mod}{xmmreg}{R_m},{predps}:cmpl{predps} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpps {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+1010011{w}:{RE}cmps{w} {es_di},{ds_si}
+11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{predsd}:cmpl{predsd} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpsd {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{predss}:cmpl{predss} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpss {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+00001111,1011000{w},{mod}{reg}{r_m}:cmpxchg{w} {reg},{mod}{r_m}
+# SPECIAL 00001111,11000111,{mod}001{r_m}:[{rex.w}?cmpxchg16b:cmpxchg8b] {reg},{mod}{r_m}
+00001111,10100010:cpuid
+11110011,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtdq2pd {Mod}{R_m},{xmmreg}
+00001111,01011011,{Mod}{xmmreg}{R_m}:cvtdq2ps {Mod}{R_m},{xmmreg}
+11110010,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtpd2dq {Mod}{R_m},{xmmreg}
+01100110,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtpd2ps {Mod}{R_m},{xmmreg}
+01100110,00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2pd {MOD}{R_M},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:{R}INVALID {MOD}{R_M},{xmmreg}
+01100110,00001111,01011011,{Mod}{xmmreg}{R_m}:cvtps2dq {Mod}{R_m},{xmmreg}
+00001111,01011010,{Mod}{xmmreg}{R_m}:cvtps2pd {Mod}{R_m},{xmmreg}
+11110010,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtsd2ss {Mod}{R_m},{xmmreg}
+11110010,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2sd {mod}{r_m},{xmmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+11110011,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtss2sd {Mod}{R_m},{xmmreg}
+01100110,00001111,11100110,{Mod}{xmmreg}{R_m}:cvttpd2dq {Mod}{R_m},{xmmreg}
+11110011,00001111,01011011,{Mod}{mmxreg}{R_m}:cvttps2dq {Mod}{R_m},{mmxreg}
+ifdef(`i386',
+`00100111:daa
+00101111:das
+')dnl
+1111111{w},{mod}001{r_m}:dec{w} {mod}{r_m}{w}
+ifdef(`i386',
+`01001{reg}:dec {reg}
+')dnl
+1111011{w},{mod}110{r_m}:div{w} {mod}{r_m}{w}
+01100110,00001111,01011110,{Mod}{xmmreg}{R_m}:divpd {Mod}{R_m},{xmmreg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110010,00001111,01011110,{Mod}{xmmreg}{R_m}:divsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,01110111:emms
+11001000,{imm16},{imm8}:enter {imm16},{imm8}
+11011001,11010000:fnop
+11011001,11100000:fchs
+11011001,11100001:fabs
+11011001,11100100:ftst
+11011001,11100101:fxam
+11011001,11101000:fld1
+11011001,11101001:fldl2t
+11011001,11101010:fldl2e
+11011001,11101011:fldpi
+11011001,11101100:fldlg2
+11011001,11101101:fldln2
+11011001,11101110:fldz
+11011001,11110000:f2xm1
+11011001,11110001:fyl2x
+11011001,11110010:fptan
+11011001,11110011:fpatan
+11011001,11110100:fxtract
+11011001,11110101:fprem1
+11011001,11110110:fdecstp
+11011001,11110111:fincstp
+11011001,11111000:fprem
+11011001,11111001:fyl2xp1
+11011001,11111010:fsqrt
+11011001,11111011:fsincos
+11011001,11111100:frndint
+11011001,11111101:fscale
+11011001,11111110:fsin
+11011001,11111111:fcos
+# ORDER
+11011000,11000{freg}:fadd {freg},%st
+11011100,11000{freg}:fadd %st,{freg}
+11011{D}00,{mod}000{r_m}:fadd{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11001{freg}:fmul {freg},%st
+11011100,11001{freg}:fmul %st,{freg}
+11011{D}00,{mod}001{r_m}:fmul{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11100{freg}:fsub {freg},%st
+11011100,11100{freg}:fsub %st,{freg}
+11011{D}00,{mod}100{r_m}:fsub{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11101{freg}:fsubr {freg},%st
+11011100,11101{freg}:fsubr %st,{freg}
+11011{D}00,{mod}101{r_m}:fsubr{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11010{freg}:fst {freg}
+11011{D}01,{mod}010{r_m}:fst{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11011{freg}:fstp {freg}
+11011{D}01,{mod}011{r_m}:fstp{D} {mod}{r_m}
+# ORDER END
+11011001,{mod}100{r_m}:fldenv {mod}{r_m}
+11011001,{mod}101{r_m}:fldcw {mod}{r_m}
+11011001,{mod}110{r_m}:fnstenv {mod}{r_m}
+11011001,{mod}111{r_m}:fnstcw {mod}{r_m}
+11011001,11001{freg}:fxch {freg}
+# ORDER
+11011110,11000{freg}:faddp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11000001:faddp
+')dnl
+# ORDER
+11011010,11000{freg}:fcmovb {freg},%st
+11011{w1}10,{mod}000{r_m}:fiadd{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011010,11001{freg}:fcmove {freg},%st
+11011110,11001{freg}:fmulp %st,{freg}
+11011{w1}10,{mod}001{r_m}:fimul{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011110,11100{freg}:fsubp %st,{freg}
+11011{w1}10,{mod}100{r_m}:fisub{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011110,11101{freg}:fsubrp %st,{freg}
+11011{w1}10,{mod}101{r_m}:fisubr{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011111,11100000:fnstsw %ax
+11011111,{mod}100{r_m}:fbld {mod}{r_m}
+# ORDER END
+# ORDER
+11011111,11110{freg}:fcomip {freg},%st
+11011111,{mod}110{r_m}:fbstp {mod}{r_m}
+# ORDER END
+11011001,11100000:fchs
+# ORDER
+10011011,11011011,11100010:fclex
+10011011,11011011,11100011:finit
+10011011:fwait
+# END ORDER
+11011011,11100010:fnclex
+11011010,11000{freg}:fcmovb {freg},%st
+11011010,11001{freg}:fcmove {freg},%st
+11011010,11010{freg}:fcmovbe {freg},%st
+11011010,11011{freg}:fcmovu {freg},%st
+11011011,11000{freg}:fcmovnb {freg},%st
+11011011,11001{freg}:fcmovne {freg},%st
+11011011,11010{freg}:fcmovnbe {freg},%st
+11011011,11011{freg}:fcmovnu {freg},%st
+# ORDER
+11011000,11010{freg}:fcom {freg}
+ifdef(`ASSEMBLER',
+`11011000,11010001:fcom
+')dnl
+11011{D}00,{mod}010{r_m}:fcom{D} {mod}{r_m}
+# END ORDER
+# ORDER
+11011000,11011{freg}:fcomp {freg}
+ifdef(`ASSEMBLER',
+`11011000,11011001:fcomp
+')dnl
+11011{D}00,{mod}011{r_m}:fcomp{D} {mod}{r_m}
+# END ORDER
+11011110,11011001:fcompp
+11011011,11110{freg}:fcomi {freg},%st
+11011111,11110{freg}:fcomip {freg},%st
+11011011,11101{freg}:fucomi {freg},%st
+11011111,11101{freg}:fucomip {freg},%st
+11011001,11111111:fcos
+11011001,11110110:fdecstp
+# ORDER
+11011000,11110{freg}:fdiv {freg},%st
+11011100,11110{freg}:fdiv %st,{freg}
+11011{D}00,{mod}110{r_m}:fdiv{D} {mod}{r_m}
+# END ORDER
+11011010,{mod}110{r_m}:fidivl {mod}{r_m}
+# ORDER
+11011110,11110{freg}:fdivp %st,{freg}
+11011110,{mod}110{r_m}:fidiv {mod}{r_m}
+# END ORDER
+11011110,11111{freg}:fdivrp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11111001:fdivp
+')dnl
+# ORDER
+11011000,11111{freg}:fdivr {freg},%st
+11011100,11111{freg}:fdivr %st,{freg}
+11011{D}00,{mod}111{r_m}:fdivr{D} {mod}{r_m}
+# END ORDER
+11011010,{mod}111{r_m}:fidivrl {mod}{r_m}
+11011110,{mod}111{r_m}:fidivr {mod}{r_m}
+11011110,11110{freg}:fdivrp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11110001:fdivrp
+')dnl
+11011101,11000{freg}:ffree {freg}
+11011010,11010{freg}:fcmovbe {freg}
+11011{w1}10,{mod}010{r_m}:ficom{w1} {mod}{r_m}
+11011010,11011{freg}:fcmovu {freg}
+11011{w1}10,{mod}011{r_m}:ficomp{w1} {mod}{r_m}
+11011111,{mod}000{r_m}:fild {mod}{r_m}
+11011011,{mod}000{r_m}:fildl {mod}{r_m}
+11011111,{mod}101{r_m}:fildll {mod}{r_m}
+11011001,11110111:fincstp
+11011011,11100011:fninit
+11011{w1}11,{mod}010{r_m}:fist{w1} {mod}{r_m}
+11011{w1}11,{mod}011{r_m}:fistp{w1} {mod}{r_m}
+11011111,{mod}111{r_m}:fistpll {mod}{r_m}
+11011{w1}11,{mod}001{r_m}:fisttp{w1} {mod}{r_m}
+11011101,{mod}001{r_m}:fisttpll {mod}{r_m}
+11011011,{mod}101{r_m}:fldt {mod}{r_m}
+11011011,{mod}111{r_m}:fstpt {mod}{r_m}
+# ORDER
+11011001,11000{freg}:fld {freg}
+11011{D}01,{mod}000{r_m}:fld{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11100{freg}:fucom {freg}
+11011101,{mod}100{r_m}:frstor {mod}{r_m}
+# ORDER END
+11011101,11101{freg}:fucomp {freg}
+11011101,{mod}110{r_m}:fnsave {mod}{r_m}
+11011101,{mod}111{r_m}:fnstsw {mod}{r_m}
+#
+#
+#
+11110100:hlt
+1111011{w},{mod}111{r_m}:idiv{w} {mod}{r_m}{w}
+1111011{w},{mod}101{r_m}:imul{w} {mod}{r_m}{w}
+00001111,10101111,{mod}{reg}{r_m}:imul {reg},{mod}{r_m}
+011010{s}1,{mod}{reg}{r_m},{imm}:imul {imm}{s},{mod}{r_m},{reg}
+1110010{w},{imm8}:in {imm8},{ax}{w}
+1110110{w}:in {dx},{ax}{w}
+1111111{w},{mod}000{r_m}:inc{w} {mod}{r_m}{w}
+01000{reg}:inc {reg}
+0110110{w}:{R}ins{w} {dx},{es_di}
+11001101,{imm8}:int {imm8}
+11001100:int3
+11001110:into
+00001111,00001000:invd
+# ORDER
+00001111,00000001,11111000:swapgs
+00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m}
+# ORDER END
+11001111:iret{W}
+0111{tttn},{disp8}:j{tttn} {disp8}
+00001111,1000{tttn},{rel}:j{tttn} {rel}
+00001111,1001{tttn},{mod}000{8r_m}:set{tttn} {mod}{8r_m}
+# SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8}
+11100011,{disp8}:INVALID {disp8}
+11101011,{disp8}:jmp {disp8}
+11101001,{rel}:jmp {rel}
+11111111,{mod}100{r_m}:jmp *{mod}{r_m}
+11101010,{absval},{sel}:ljmp {sel},{absval}
+11111111,{mod}101{r_m}:ljmp *{mod}{r_m}
+10011111:lahf
+00001111,00000010,{mod}{reg}{16r_m}:lar {mod}{16r_m},{reg}
+11000101,{mod}{reg}{r_m}:lds {mod}{r_m},{reg}
+10001101,{mod}{reg}{r_m}:lea {mod}{r_m},{reg}
+11001001:leave
+11000100,{mod}{reg}{r_m}:les {mod}{r_m},{reg}
+00001111,10110100,{mod}{reg}{r_m}:lfs {mod}{r_m},{reg}
+00001111,00000001,{mod}010{r_m}:lgdt{w0} {mod}{r_m}
+00001111,10110101,{mod}{reg}{r_m}:lgs {mod}{r_m},{reg}
+00001111,00000001,{mod}011{r_m}:lidt{w0} {mod}{r_m}
+00001111,00000000,{mod}010{16r_m}:lldt {mod}{16r_m}
+00001111,00000001,{mod}110{16r_m}:lmsw {mod}{16r_m}
+11110000:lock
+1010110{w}:{R}lods {ds_si},{ax}{w}
+11100010,{disp8}:loop {disp8}
+11100001,{disp8}:loope {disp8}
+11100000,{disp8}:loopne {disp8}
+00001111,00000011,{mod}{reg}{16r_m}:lsl {mod}{16r_m},{reg}
+00001111,10110010,{mod}{reg}{r_m}:lss {mod}{r_m},{reg}
+00001111,00000000,{mod}011{16r_m}:ltr {mod}{16r_m}
+1000100{w},{mod}{reg}{r_m}:mov {reg}{w},{mod}{r_m}{w}
+1000101{w},{mod}{reg}{r_m}:mov {mod}{r_m}{w},{reg}{w}
+1100011{w},{mod}000{r_m},{imm}:mov{w} {imm}{w},{mod}{r_m}{w}
+1011{w}{reg},{imm}:mov {imm}{w},{reg}{w}
+1010000{w},{abs}:mov {abs},{ax}{w}
+1010001{w},{abs}:mov {ax}{w},{abs}
+00001111,00100000,11{ccc}{reg}:mov {ccc},{reg}
+00001111,00100010,11{ccc}{reg}:mov {reg},{ccc}
+00001111,00100001,11{ddd}{reg}:mov {ddd},{reg}
+00001111,00100011,11{ddd}{reg}:mov {reg},{ddd}
+10001100,{mod}{sreg3}{r_m}:mov {sreg3},{mod}{r_m}
+10001110,{mod}{sreg3}{r_m}:mov {mod}{r_m},{sreg3}
+1010010{w}:{R}movs{w} {ds_si},{es_di}
+00001111,1011111{w},{mod}{reg}{r_m}:movsx{w} {mod}{r_m},{reg}
+00001111,1011011{w},{mod}{reg}{r_m}:movzx{w} {mod}{r_m},{reg}
+1111011{w},{mod}100{r_m}:mul{w} {mod}{r_m}{w}
+1111011{w},{mod}011{r_m}:neg{w} {mod}{r_m}{w}
+ifdef(`ASSEMBLER',
+`10010000:nop
+11110011,10010000:pause
+',
+`10010000:{R}INVALID
+')dnl
+1111011{w},{mod}010{r_m}:not{w} {mod}{r_m}{w}
+0000100{w},{mod}{reg}{r_m}:or {reg}{w},{mod}{r_m}{w}
+0000101{w},{mod}{reg}{r_m}:or {mod}{r_m}{w},{reg}{w}
+1000000{w},{mod}001{r_m},{imm}:or{w} {imm}{w},{mod}{r_m}{w}
+100000{s}{w},{mod}001{r_m},{imm}:or{w} {imm}{s},{mod}{r_m}{w}
+0000110{w},{imm}:or {imm}{w},{ax}{w}
+1110011{w},{imm8}:out {ax}{w},{imm8}
+1110111{w}:out {ax}{w},{dx}
+0110111{w}:{R}outs{w} {ds_si},{dx}
+10001111,{mod}000{r_m}:pop{w} {mod}{r_m}
+01011{reg}:pop {reg}
+00001111,10{sreg3}001:pop {sreg3}
+01100001:popa{W}
+10011101:popf{W}
+11111111,{mod}110{r_m}:push{w} {mod}{r_m}
+01010{reg}:push {reg}
+011010{s}0,{imm}:push {imm}{s}
+000{sreg2}110:push {sreg2}
+00001111,10{sreg3}000:push {sreg3}
+01100000:pusha{W}
+10011100:pushf{W}
+1101000{w},{mod}010{r_m}:rcl{w} {mod}{r_m}{w}
+1101001{w},{mod}010{r_m}:rcl{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}010{r_m},{imm8}:rcl{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}011{r_m}:rcr{w} {mod}{r_m}{w}
+1101001{w},{mod}011{r_m}:rcr{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}011{r_m},{imm8}:rcr{w} {imm8},{mod}{r_m}{w}
+00001111,00110010:rdmsr
+00001111,00110011:rdpmc
+00001111,00110001:rdtsc
+11000011:ret
+11000010,{imm16}:ret {imm16}
+11001011:lret
+11001010,{imm16}:lret {imm16}
+1101000{w},{mod}000{r_m}:rol{w} {mod}{r_m}{w}
+1101001{w},{mod}000{r_m}:rol{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}000{r_m},{imm8}:rol{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}001{r_m}:ror{w} {mod}{r_m}{w}
+1101001{w},{mod}001{r_m}:ror{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}001{r_m},{imm8}:ror{w} {imm8},{mod}{r_m}{w}
+00001111,10101010:rsm
+10011110:sahf
+1101000{w},{mod}111{r_m}:sar{w} {mod}{r_m}{w}
+1101001{w},{mod}111{r_m}:sar{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}111{r_m},{imm8}:sar{w} {imm8},{mod}{r_m}{w}
+0001100{w},{mod}{reg}{r_m}:sbb {reg}{w},{mod}{r_m}{w}
+0001101{w},{mod}{reg}{r_m}:sbb {mod}{r_m}{w},{reg}{w}
+0001110{w},{imm}:sbb {imm}{w},{ax}{w}
+1000000{w},{mod}011{r_m},{imm}:sbb{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}011{r_m},{imms}:sbb{w} {imms},{mod}{r_m}
+1010111{w}:{RE}scas {es_di},{ax}{w}
+00001111,1001{tttn},{mod}000{r_m}:set{tttn} {mod}{r_m}
+1101000{w},{mod}100{r_m}:shl{w} {mod}{r_m}{w}
+1101001{w},{mod}100{r_m}:shl{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}100{r_m},{imm8}:shl{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}101{r_m}:shr{w} {mod}{r_m}{w}
+00001111,10100100,{mod}{reg}{r_m},{imm8}:shld {imm8},{reg},{mod}{r_m}
+00001111,10100101,{mod}{reg}{r_m}:shld %cl,{reg},{mod}{r_m}
+1101001{w},{mod}101{r_m}:shr{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}101{r_m},{imm8}:shr{w} {imm8},{mod}{r_m}{w}
+00001111,10101100,{mod}{reg}{r_m},{imm8}:shrd {imm8},{reg},{mod}{r_m}
+00001111,10101101,{mod}{reg}{r_m}:shrd %cl,{reg},{mod}{r_m}
+# ORDER
+00001111,00000001,11000001:vmcall
+00001111,00000001,11000010:vmlaunch
+00001111,00000001,11000011:vmresume
+00001111,00000001,11000100:vmxoff
+00001111,00000001,{mod}000{r_m}:sgdtl {mod}{r_m}
+# ORDER END
+# ORDER
+00001111,00000001,11001000:monitor %eax,%ecx,%edx
+00001111,00000001,11001001:mwait %eax,%ecx
+00001111,00000001,{mod}001{r_m}:sidtl {mod}{r_m}
+# ORDER END
+00001111,00000000,{mod}000{r_m}:sldt {mod}{r_m}
+00001111,00000001,{mod}100{r_m}:smsw {mod}{r_m}
+11111001:stc
+11111101:std
+11111011:sti
+1010101{w}:{R}stos {ax}{w},{es_di}
+00001111,00000000,{mod}001{r_m}:str {mod}{r_m}
+0010100{w},{mod}{reg}{r_m}:sub {reg}{w},{mod}{r_m}{w}
+0010101{w},{mod}{reg}{r_m}:sub {mod}{r_m}{w},{reg}{w}
+0010110{w},{imm}:sub {imm}{w},{ax}{w}
+1000000{w},{mod}101{r_m},{imm}:sub{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}101{r_m},{imms}:sub{w} {imms},{mod}{r_m}
+1000010{w},{mod}{reg}{r_m}:test {reg}{w},{mod}{r_m}{w}
+1010100{w},{imm}:test {imm}{w},{ax}{w}
+1111011{w},{mod}000{r_m},{imm}:test{w} {imm}{w},{mod}{r_m}{w}
+00001111,00001011:ud2a
+00001111,00000000,{mod}100{16r_m}:verr {mod}{16r_m}
+00001111,00000000,{mod}101{16r_m}:verw {mod}{16r_m}
+00001111,00001001:wbinvd
+00001111,00001101,{mod}000{8r_m}:prefetch {mod}{8r_m}
+00001111,00001101,{mod}001{8r_m}:prefetchw {mod}{8r_m}
+00001111,00011000,{mod}000{r_m}:prefetchnta {mod}{r_m}
+00001111,00011000,{mod}001{r_m}:prefetcht0 {mod}{r_m}
+00001111,00011000,{mod}010{r_m}:prefetcht1 {mod}{r_m}
+00001111,00011000,{mod}011{r_m}:prefetcht2 {mod}{r_m}
+00001111,00011111,{mod}{reg}{r_m}:nop{w} {mod}{r_m}
+dnl without prefix: movups
+dnl with 0xf3: movss
+dnl with 0x66: movupd
+dnl with 0xf2: movsd
+00001111,00010000,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010001,{Mod}{xmmreg}{R_m}:{R}INVALID {xmmreg},{Mod}{R_m}
+00001111,00110000:wrmsr
+00001111,1100000{w},{mod}{reg}{r_m}:xadd{w} {reg},{mod}{r_m}
+1000011{w},{mod}{reg}{r_m}:xchg {reg}{w},{mod}{r_m}{w}
+10010{reg}:xchg {ax},{reg}
+11010111:xlat {ds_bx}
+0011000{w},{mod}{reg}{r_m}:xor {reg}{w},{mod}{r_m}{w}
+0011001{w},{mod}{reg}{r_m}:xor {mod}{r_m}{w},{reg}{w}
+0011010{w},{imm}:xor {imm}{w},{ax}{w}
+1000000{w},{mod}110{r_m},{imm}:xor{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}110{r_m},{imms}:xor{w} {imms},{mod}{r_m}
+00001111,01110111:emms
+00001111,01101110,{mod}{mmxreg}{r_m}:movd {mod}{r_m},{mmxreg}
+00001111,01111110,{mod}{mmxreg}{r_m}:movd {mmxreg},{mod}{r_m}
+00001111,01101111,{MOD}{mmxreg}{R_M}:movq {MOD}{R_M},{mmxreg}
+00001111,01111111,{MOD}{mmxreg}{R_M}:movq {mmxreg},{MOD}{R_M}
+00001111,01101011,{MOD}{mmxreg}{R_M}:packssdw {MOD}{R_M},{mmxreg}
+00001111,01100011,{MOD}{mmxreg}{R_M}:packsswb {MOD}{R_M},{mmxreg}
+00001111,01100111,{MOD}{mmxreg}{R_M}:packuswb {MOD}{R_M},{mmxreg}
+00001111,111111{gg},{MOD}{mmxreg}{R_M}:padd{gg} {MOD}{R_M},{mmxreg}
+00001111,111111{0g},{MOD}{mmxreg}{R_M}:padds{0g} {MOD}{R_M},{mmxreg}
+00001111,110111{0g},{MOD}{mmxreg}{R_M}:paddus{0g} {MOD}{R_M},{mmxreg}
+00001111,11011011,{MOD}{mmxreg}{R_M}:pand {MOD}{R_M},{mmxreg}
+00001111,11011111,{MOD}{mmxreg}{R_M}:pandn {MOD}{R_M},{mmxreg}
+00001111,011101{gg},{MOD}{mmxreg}{R_M}:pcmpeq{gg} {MOD}{R_M},{mmxreg}
+00001111,011001{gg},{MOD}{mmxreg}{R_M}:pcmpgt{gg} {MOD}{R_M},{mmxreg}
+00001111,11110101,{MOD}{mmxreg}{R_M}:pmaddwd {MOD}{R_M},{mmxreg}
+00001111,11100101,{MOD}{mmxreg}{R_M}:pmulhw {MOD}{R_M},{mmxreg}
+00001111,11010101,{MOD}{mmxreg}{R_M}:pmullw {MOD}{R_M},{mmxreg}
+00001111,11101011,{MOD}{mmxreg}{R_M}:por {MOD}{R_M},{mmxreg}
+00001111,111100{GG},{MOD}{mmxreg}{R_M}:psll{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11110{mmxreg},{imm8}:psll{GG} {imm8},{mmxreg}
+00001111,111000{gG},{MOD}{mmxreg}{R_M}:psra{gG} {MOD}{R_M},{mmxreg}
+00001111,011100{gG},11100{mmxreg},{imm8}:psra{gG} {imm8},{mmxreg}
+00001111,110100{GG},{MOD}{mmxreg}{R_M}:psrl{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11010{mmxreg},{imm8}:psrl{GG} {imm8},{mmxreg}
+00001111,111110{gg},{MOD}{mmxreg}{R_M}:psub{gg} {MOD}{R_M},{mmxreg}
+00001111,111010{0g},{MOD}{mmxreg}{R_M}:psubs{0g} {MOD}{R_M},{mmxreg}
+00001111,110110{0g},{MOD}{mmxreg}{R_M}:psubus{0g} {MOD}{R_M},{mmxreg}
+00001111,011010{gg},{MOD}{mmxreg}{R_M}:punpckh{gg} {MOD}{R_M},{mmxreg}
+00001111,011000{gg},{MOD}{mmxreg}{R_M}:punpckl{gg} {MOD}{R_M},{mmxreg}
+00001111,11101111,{MOD}{mmxreg}{R_M}:pxor {MOD}{R_M},{mmxreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordps {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordss {Mod}{R_m},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2ps {MOD}{R_M},{xmmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,10101110,{mod}001{r_m}:fxrstor {mod}{r_m}
+00001111,10101110,{mod}000{r_m}:fxsave {mod}{r_m}
+00001111,10101110,{mod}010{r_m}:ldmxcsr {mod}{r_m}
+00001111,01011111,{Mod}{xmmreg}{R_m}:maxps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011111,{Mod}{xmmreg}{R_m}:maxss {Mod}{R_m},{xmmreg}
+00001111,01011101,{Mod}{xmmreg}{R_m}:minps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011101,{Mod}{xmmreg}{R_m}:minss {Mod}{R_m},{xmmreg}
+00001111,00101000,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00101001,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00010010,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010011,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00010100,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00010101,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00010110,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010111,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00101011,{mod}{xmmreg}{r_m}:INVALID {xmmreg},{mod}{r_m}
+00001111,00101100,{Mod}{mmxreg2}{R_m}:{R}INVALID {Mod}{R_m},{mmxreg2}
+00001111,00101101,{Mod}{mmxreg2}{R_m}:{R}INVALID {Mod}{R_m},{mmxreg2}
+00001111,00101110,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00101111,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00110111:getsec
+00001111,01010000,11{reg}{xmmreg}:INVALID {xmmreg},{reg}
+00001111,01010001,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,01010010,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,01010011,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+# ORDER:
+dnl Many previous entries depend on this being last.
+000{sreg2}111:pop {sreg2}
+# ORDER END:
diff --git a/libcpu/defs/i386.doc b/libcpu/defs/i386.doc
new file mode 100644
index 00000000..732cd238
--- /dev/null
+++ b/libcpu/defs/i386.doc
@@ -0,0 +1,74 @@
+{imm} only parameter:
+ - is {s} in opcode: {s} == 0, unsigned (8/)16/32 bit immediate
+ {s} == 1, signed 8 bit immediate
+
+{es:di}: segment register normally %es, can be overwritten
+ edi/di depending on apfx
+
+{ds:si}: segment register normally %ds, can be overwritten
+ esi/si depending on apfx
+
+{ax} al/ax/eax depending of dpfx and w
+
+{dx} (%edx) or (%dx) depending on apfx
+
+
+{w} 0 = b, 1 = { no dpfx = l, dpfx = w }
+
+{W} no dpfx = <empty>, dpfx = w
+{WW} no dpfx = l, dpfx = w
+
+{R} rep prefix possible
+{RE} repe or repne prefix possible
+
+{ccc} CRx registers
+{ddd} DRx registers
+
+{gg} 00 = b, 01 = w, 10 = d, 11 = <illegal>
+{0g} 00 = b, 01 = w, 10 = <illegal>, 11 = <illegal>
+{GG} 00 = <illegal>, 01 = w, 10 = d, 11 = q
+{gG} 00 = <illegal>, 01 = w, 10 = d, 11 = <illegal>
+
+{modr/m} normal registers
+{MODR/M} MMX registers
+{ModR/m} XMM registers
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Special opcodes (prefixes):
+
+
+01100111:{apfx}
+01100110:{dpfx}
+
+00101110:{cs}
+00111110:{ds}
+00100110:{es}
+01100100:{fs}
+01100101:{gs}
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+table format
+
+1bit RE flag
+1bit R flag
+16bit mnemonic
+3bit suffix
+
+5bit fct
+2bit string
+6bit offset1
+5bit offset2
+
+4bit fct
+1bit string
+6bit offset1
+4bit offset2
+
+2bit fct
+1bit string
+3bit offset1
+1bit offset2
+
+61bit
diff --git a/libcpu/defs/x86_64 b/libcpu/defs/x86_64
new file mode 100644
index 00000000..090c4751
--- /dev/null
+++ b/libcpu/defs/x86_64
@@ -0,0 +1,341 @@
+%mask {s} 1
+%mask {w} 1
+%mask {D} 1
+%mask {imm8} 8
+%mask {imm16} 16
+%mask {reg} 3
+%mask {tttn} 4
+%mask {gg} 2
+%mask {mod} 2
+%mask {MOD} 2
+%mask {r_m} 3
+%mask {disp8} 8
+# imm really is 8/16/32 bit depending on the situation.
+%mask {imm} 8
+%mask {abs} 32
+%mask {sel} 16
+%mask {imm32} 32
+%mask {dispA} 32
+%mask {ccc} 3
+%mask {ddd} 3
+%mask {sreg3} 3
+%mask {sreg2} 2
+%mask {mmxreg} 3
+%mask {R_M} 3
+%mask {0g} 2
+%mask {GG} 2
+%mask {gG} 2
+%mask {Mod} 2
+%mask {xmmreg} 3
+%mask {R_m} 3
+%mask {xmmreg1} 3
+%mask {xmmreg2} 3
+%mask {mmreg} 3
+%prefix {R}
+%prefix {RE}
+%suffix {W}
+%suffix {WW}
+%synonym {xmmreg1} {xmmreg}
+%synonym {xmmreg2} {xmmreg}
+
+%%
+0001010{w},{imm}:adc {imm}{w},{ax}{w}
+1000000{w},{mod}010{r_m},{imm}:adc{w} {imm},{mod}{r_m}
+1000001{w},{mod}010{r_m},{imm8}:adc{w} {imm8},{mod}{r_m}
+0001000{w},{mod}{reg}{r_m}:adc{w} {reg},{mod}{r_m}
+0001001{w},{mod}{reg}{r_m}:adc{w} {mod}{r_m},{reg}
+0000010{w},{imm}:add {imm}{w},{ax}{w}
+1000000{w},{mod}000{r_m},{imm}:add{w} {imm},{mod}{r_m}
+1000001{w},{mod}000{r_m},{imm8}:add{w} {imm8},{mod}{r_m}
+0000000{w},{mod}{reg}{r_m}:add {reg}{w},{mod}{r_m}
+0000001{w},{mod}{reg}{r_m}:add {mod}{r_m},{reg}{w}
+01100110,00001111,01011000,{Mod}{xmmreg}{R_m}:addpd {Mod}{R_m},{xmmreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110010,00001111,01011000,{Mod}{xmmreg}{R_m}:addsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+01100110,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubpd {Mod}{R_m},{xmmreg}
+11110010,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubps {Mod}{R_m},{xmmreg}
+#
+#
+#
+0010000{w},{mod}{reg}{r_m}:and{w} {reg},{mod}{r_m}
+0010001{w},{mod}{reg}{r_m}:and{w} {mod}{r_m},{reg}
+0010010{w},{imm}:and {imm}{w},{ax}{w}
+100000{s}{w},{mod}100{r_m},{imm}:and{w} {imm}{s},{mod}{r_m}
+01100011,{mod}{reg}{r_m}:arpl {reg},{mod}{r_m}
+01100010,{mod}{reg}{r_m}:bound {reg},{mod}{r_m}
+00001111,10111100,{mod}{reg}{r_m}:bsf {reg},{mod}{r_m}
+00001111,10111101,{mod}{reg}{r_m}:bsr {reg},{mod}{r_m}
+00001111,11001{reg}:bswap {reg}
+00001111,10111010,{mod}100{r_m},{imm8}:bt {imm8},{mod}{r_m}
+00001111,10100011,{mod}{reg}{r_m}:bt {reg},{mod}{r_m}
+00001111,10111010,{mod}111{r_m},{imm8}:btc {imm8},{mod}{r_m}
+00001111,10111011,{mod}{reg}{r_m}:btc {reg},{mod}{r_m}
+00001111,10111010,{mod}110{r_m},{imm8}:btr {imm8},{mod}{r_m}
+00001111,10110011,{mod}{reg}{r_m}:btr {reg},{mod}{r_m}
+00001111,10111010,{mod}101{r_m},{imm8}:bts {imm8},{mod}{r_m}
+00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m}
+11101000,{abs}:call {abs}
+11111111,{mod}010{r_m}:call *{mod}{r_m}
+10011010,{abs},{sel}:lcall {sel},{abs}
+11111111,{mod}011{r_m}:lcall {mod}{r_m}
+10011000:cbt{WW}
+#SPECIAL 10011001:[{dpfx}?cltd:cwtd]
+11111000:clc
+11111100:cld
+11111010:cli
+00001111,00000110:clts
+11110101:cmc
+00001111,0100{tttn},{mod}{reg}{r_m}:cmov{tttn} {mod}{r_m},{reg}
+0011100{w},{mod}{reg}{r_m}:cmp{w} {reg},{mod}{r_m}
+0011101{w},{mod}{reg}{r_m}:cmp{w} {mod}{r_m},{reg}
+0011110{w},{imm}:cmp {imm}{w},{ax}{w}
+100000{s}{w},{mod}111{r_m},{imm}:cmp{w} {imm}{s},{mod}{r_m}
+1010011{w}:{RE}cmps{w}
+00001111,1011000{w},{mod}{reg}{r_m}:cmpxchg{w} {reg},{mod}{r_m}
+00001111,11000111,{mod}{reg}{r_m}:cmpxchg8b {reg},{mod}{r_m}
+00001111,10100010:cpuid
+00100111:daa
+00101111:das
+1111111{w},{mod}001{r_m}:dec{w} {mod}{r_m}
+01001{reg}:dec {reg}
+1111011{w},{mod}110{r_m}:div{w} {mod}{r_m}
+11001000,{imm16},{imm8}:enter {imm16},{imm8}
+11110100:hlt
+1111011{w},{mod}111{r_m}:idiv{w} {mod}{r_m}
+1111011{w},{mod}101{r_m}:imul{w} {mod}{r_m}
+00001111,10101111,{mod}{reg}{r_m}:imul {reg},{mod}{r_m}
+011010{s}1,{mod}{reg}{r_m},{imm}:imul {imm}{s},{mod}{r_m},{reg}
+1110010{w},{imm8}:in {imm8},{ax}{w}
+1110110{w}:in {dx},{ax}{w}
+1111111{w},{mod}000{r_m}:inc{w} {mod}{r_m}
+01000{reg}:inc {reg}
+0110110{w}:{R}ins{w} {dx},{es_di}
+11001101,{imm8}:int {imm8}
+11001100:int 3
+11001110:into
+00001111,00001000:invd
+00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m}
+11001111:iret{W}
+0111{tttn},{disp8}:j{tttn} {disp8}
+00001111,1000{tttn},{dispA}:j{tttn} {dispA}
+#SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8}
+11101011,{disp8}:jmp {disp8}
+11101001,{dispA}:jmp {dispA}
+11111111,{mod}100{r_m}:jmp *{mod}{r_m}
+11101010,{abs},{sel}:ljmp {sel},{abs}
+11111111,{mod}101{r_m}:ljmp {mod}{r_m}
+10011111:lahf
+00001111,00000010,{mod}{reg}{r_m}:lar {mod}{r_m},{reg}
+11000101,{mod}{reg}{r_m}:lds {mod}{r_m},{reg}
+10001101,{mod}{reg}{r_m}:lea {mod}{r_m},{reg}
+11001001:leave
+11000100,{mod}{reg}{r_m}:les {mod}{r_m},{reg}
+00001111,10110100,{mod}{reg}{r_m}:lfs {mod}{r_m},{reg}
+00001111,00000001,{mod}010{r_m}:lgdt{WW} {mod}{r_m}
+00001111,10110101,{mod}{reg}{r_m}:lgs {mod}{r_m},{reg}
+00001111,00000001,{mod}011{r_m}:lidt{WW} {mod}{r_m}
+00001111,00000000,{mod}010{r_m}:lldt{WW} {mod}{r_m}
+00001111,00000001,{mod}110{r_m}:lmsw {mod}{r_m}
+11110000:lock
+1010110{w}:{R}lods {ds_si},{ax}{w}
+11100010,{disp8}:loop {disp8}
+11100001,{disp8}:loope {disp8}
+11100000,{disp8}:loopne {disp8}
+00001111,00000011,{mod}{reg}{r_m}:lsl {mod}{r_m},{reg}
+00001111,10110010,{mod}{reg}{r_m}:lss {mod}{r_m},{reg}
+00001111,00000000,{mod}011{r_m}:ltr {mod}{r_m}
+1000100{w},{mod}{reg}{r_m}:mov{w} {reg},{mod}{r_m}
+1000101{w},{mod}{reg}{r_m}:mov{w} {mod}{r_m},{reg}
+1100011{w},{mod}000{r_m},{imm}:mov{w} {imm},{mod}{r_m}
+1011{w}{reg},{imm}:mov{w} {imm},{reg}
+1010000{w},{abs}:mov {ax}{w},{abs}
+1010001{w},{abs}:mov {abs},{ax}{w}
+00001111,00100000,11{ccc}{reg}:mov {reg},{ccc}
+00001111,00100010,11{ccc}{reg}:mov {ccc},{reg}
+00001111,00100001,11{ddd}{reg}:mov {reg},{ddd}
+00001111,00100011,11{ddd}{reg}:mov {ddd},{reg}
+10001100,{mod}{sreg3}{r_m}:mov {sreg3},{mod}{r_m}
+10001110,{mod}{sreg3}{r_m}:mov {mod}{r_m},{sreg3}
+1010010{w}:{R}movs{w} {ds_si},{es_di}
+00001111,1011111{w},{mod}{reg}{r_m}:movsx{w} {mod}{r_m},{reg}
+00001111,1011011{w},{mod}{reg}{r_m}:movzx{w} {mod}{r_m},{reg}
+1111011{w},{mod}100{r_m}:mul{w} {mod}{r_m}
+1111011{w},{mod}011{r_m}:neg{w} {mod}{r_m}
+10010000:nop
+11110011,10010000:pause
+1111011{w},{mod}010{r_m}:not{w} {mod}{r_m}
+0000100{w},{mod}{reg}{r_m}:or{w} {reg},{mod}{r_m}
+0000101{w},{mod}{reg}{r_m}:or{w} {mod}{r_m},{reg}
+100000{s}{w},{mod}001{r_m},{imm}:or{w} {imm}{s},{mod}{r_m}
+0000110{w},{imm}:mov {imm}{w},{ax}{w}
+1110011{w},{imm8}:out {ax}{w},{imm8}
+1110111{w}:out {ax}{w},{dx}
+0110111{w}:{R}outs{w} {ds_si},{dx}
+10001111,{mod}000{r_m}:pop {mod}{r_m}
+01011{reg}:pop {reg}
+000{sreg2}111:pop {sreg2}
+00001111,10{sreg3}001:pop {sreg3}
+01100001:popa{W}
+10011101:popf{W}
+11111111,{mod}110{r_m}:push {mod}{r_m}
+01010{reg}:push {reg}
+011010{s}0,{imm}:push {imm}{s}
+000{sreg2}110:push {sreg2}
+00001111,10{sreg3}000:push {sreg3}
+01100000:pusha{W}
+10011100:pushf{W}
+1101000{w},{mod}010{r_m}:rcl{w} {mod}{r_m}
+1101001{w},{mod}010{r_m}:rcl{w} %cl,{mod}{r_m}
+1100000{w},{mod}010{r_m},{imm8}:rcl{w} {imm8},{mod}{r_m}
+1101000{w},{mod}011{r_m}:rcr{w} {mod}{r_m}
+1101001{w},{mod}011{r_m}:rcr{w} %cl,{mod}{r_m}
+1100000{w},{mod}011{r_m},{imm8}:rcr{w} {imm8},{mod}{r_m}
+00001111,00110010:rdmsr
+00001111,00110011:rdpmc
+00001111,00110001:rdtsc
+11000011:ret
+11000010,{imm16}:ret {imm16}
+11001011:lret
+11001010,{imm16}:lret {imm16}
+1101000{w},{mod}000{r_m}:rol{w} {mod}{r_m}
+1101001{w},{mod}000{r_m}:rol{w} %cl,{mod}{r_m}
+1100000{w},{mod}000{r_m},{imm8}:rol{w} {imm8},{mod}{r_m}
+1101000{w},{mod}001{r_m}:ror{w} {mod}{r_m}
+1101001{w},{mod}001{r_m}:ror{w} %cl,{mod}{r_m}
+1100000{w},{mod}001{r_m},{imm8}:ror{w} {imm8},{mod}{r_m}
+00001111,10101010:rsm
+10011110:sahf
+1101000{w},{mod}111{r_m}:sar{w} {mod}{r_m}
+1101001{w},{mod}111{r_m}:sar{w} %cl,{mod}{r_m}
+1100000{w},{mod}111{r_m},{imm8}:sar{w} {imm8},{mod}{r_m}
+0001100{w},{mod}{reg}{r_m}:sbb{w} {reg},{mod}{r_m}
+0001101{w},{mod}{reg}{r_m}:sbb{w} {mod}{r_m},{reg}
+0001110{w},{imm}:sbb {imm}{w},{ax}{w}
+100000{s}{w},{mod}011{r_m},{imm}:sbb{w} {imm}{s},{mod}{r_m}
+1010111{w}:{RE}scas {es_di},{ax}{w}
+00001111,1001{tttn},{mod}000{r_m}:set{tttn} {mod}{r_m}
+00001111,00000001,{mod}000{r_m}:sgdt {mod}{r_m}
+1101000{w},{mod}100{r_m}:shl{w} {mod}{r_m}
+1101001{w},{mod}100{r_m}:shl{w} %cl,{mod}{r_m}
+1100000{w},{mod}100{r_m},{imm8}:shl{w} {imm8},{mod}{r_m}
+1101000{w},{mod}101{r_m}:shr{w} {mod}{r_m}
+00001111,10100100,{mod}{reg}{r_m},{imm8}:shld {imm8},{reg},{mod}{r_m}
+00001111,10100101,{mod}{reg}{r_m}:shld %cl,{reg},{mod}{r_m}
+1101001{w},{mod}101{r_m}:shr{w} %cl,{mod}{r_m}
+1100000{w},{mod}101{r_m},{imm8}:shr{w} {imm8},{mod}{r_m}
+00001111,10101100,{mod}{reg}{r_m},{imm8}:shrd {imm8},{reg},{mod}{r_m}
+00001111,10101101,{mod}{reg}{r_m}:shrd %cl,{reg},{mod}{r_m}
+00001111,00000001,{mod}001{r_m}:sidt {mod}{r_m}
+00001111,00000000,{mod}000{r_m}:sldt {mod}{r_m}
+00001111,00000001,{mod}100{r_m}:smsw {mod}{r_m}
+11111001:stc
+11111101:std
+11111011:sti
+1010101{w}:{R}stos {ax}{w},{es_di}
+00001111,00000000,{mod}001{r_m}:str {mod}{r_m}
+0010100{w},{mod}{reg}{r_m}:sub{w} {reg},{mod}{r_m}
+0010101{w},{mod}{reg}{r_m}:sub{w} {mod}{r_m},{reg}
+0010110{w},{imm}:sub {imm}{w},{ax}{w}
+100000{s}{w},{mod}101{r_m},{imm}:sub{w} {imm}{s},{mod}{r_m}
+1000010{w},{mod}{reg}{r_m}:test{w} {reg},{mod}{r_m}{w}
+1000011{w},{mod}{reg}{r_m}:test{w} {mod}{r_m}{w},{reg}
+0010100{w},{imm}:test {imm}{w},{ax}{w}
+1111011{w},{mod}000{r_m},{imm}:test{w} {imm},{mod}{r_m}
+00001111,00001011:ud2a
+00001111,00000000,{mod}100{r_m}:verr {mod}{r_m}
+00001111,00000000,{mod}101{r_m}:verw {mod}{r_m}
+10011011:wait
+00001111,00001001:wbinvd
+00001111,00110000:wrmsr
+00001111,1100000{w},{mod}{reg}{r_m}:xadd{w} {reg},{mod}{r_m}
+1000011{w},{mod}{reg}{r_m}:xchg{w} {reg},{mod}{r_m}
+11010111:xlat
+0011000{w},{mod}{reg}{r_m}:xor{w} {reg},{mod}{r_m}
+0011001{w},{mod}{reg}{r_m}:xor{w} {mod}{r_m},{reg}
+0011010{w},{imm}:xor {imm}{w},{ax}{w}
+100000{s}{w},{mod}110{r_m},{imm}:xor{w} {imm}{s},{mod}{r_m}
+00001111,01110111:emms
+00001111,01101110,{mod}{mmxreg}{r_m}:movd {mod}{r_m},{mmxreg}
+00001111,01111110,{mod}{mmxreg}{r_m}:movd {mmxreg},{mod}{r_m}
+00001111,01101111,{MOD}{mmxreg}{R_M}:movq {MOD}{R_M},{mmxreg}
+00001111,01111111,{MOD}{mmxreg}{R_M}:movq {mmxreg},{MOD}{R_M}
+00001111,01101011,{MOD}{mmxreg}{R_M}:packssdw {MOD}{R_M},{mmxreg}
+00001111,01100011,{MOD}{mmxreg}{R_M}:packsswb {MOD}{R_M},{mmxreg}
+00001111,01100111,{MOD}{mmxreg}{R_M}:packuswb {MOD}{R_M},{mmxreg}
+00001111,111111{gg},{MOD}{mmxreg}{R_M}:padd{gg} {MOD}{R_M},{mmxreg}
+00001111,111111{0g},{MOD}{mmxreg}{R_M}:padds{0g} {MOD}{R_M},{mmxreg}
+00001111,110111{0g},{MOD}{mmxreg}{R_M}:paddus{0g} {MOD}{R_M},{mmxreg}
+00001111,11011011,{MOD}{mmxreg}{R_M}:pand {MOD}{R_M},{mmxreg}
+00001111,11011111,{MOD}{mmxreg}{R_M}:pandn {MOD}{R_M},{mmxreg}
+00001111,011101{gg},{MOD}{mmxreg}{R_M}:pcmpeq{gg} {MOD}{R_M},{mmxreg}
+00001111,011001{gg},{MOD}{mmxreg}{R_M}:pcmpgt{gg} {MOD}{R_M},{mmxreg}
+00001111,11110101,{MOD}{mmxreg}{R_M}:pmaddwd {MOD}{R_M},{mmxreg}
+00001111,11100101,{MOD}{mmxreg}{R_M}:pmulhw {MOD}{R_M},{mmxreg}
+00001111,11010101,{MOD}{mmxreg}{R_M}:pmullw {MOD}{R_M},{mmxreg}
+00001111,11101011,{MOD}{mmxreg}{R_M}:por {MOD}{R_M},{mmxreg}
+00001111,111100{GG},{MOD}{mmxreg}{R_M}:psll{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11110{mmxreg},{imm8}:psll{GG} {imm8},{mmxreg}
+00001111,111000{gG},{MOD}{mmxreg}{R_M}:psra{gG} {MOD}{R_M},{mmxreg}
+00001111,011100{gG},11100{mmxreg},{imm8}:psra{gG} {imm8},{mmxreg}
+00001111,110100{GG},{MOD}{mmxreg}{R_M}:psrl{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11010{mmxreg},{imm8}:psrl{GG} {imm8},{mmxreg}
+00001111,111110{gg},{MOD}{mmxreg}{R_M}:psub{gg} {MOD}{R_M},{mmxreg}
+00001111,111010{0g},{MOD}{mmxreg}{R_M}:psubs{0g} {MOD}{R_M},{mmxreg}
+00001111,110110{0g},{MOD}{mmxreg}{R_M}:psubus{0g} {MOD}{R_M},{mmxreg}
+00001111,011010{gg},{MOD}{mmxreg}{R_M}:punpckh{gg} {MOD}{R_M},{mmxreg}
+00001111,011000{gg},{MOD}{mmxreg}{R_M}:punpckl{gg} {MOD}{R_M},{mmxreg}
+00001111,11101111,{MOD}{mmxreg}{R_M}:pxor {MOD}{R_M},{mmxreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordps {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordss {Mod}{R_m},{xmmreg}
+00001111,00101111,{Mod}{xmmreg}{R_m}:comiss {Mod}{R_m},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2ps {MOD}{R_M},{xmmreg}
+00001111,00101101,{MOD}{mmreg}{R_M}:cvtps2pi {MOD}{R_M},{mmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+11110011,00001111,00101101,{Mod}{reg}{R_m}:cvtss2si {Mod}{R_m},{reg}
+00001111,00101100,{Mod}{mmreg}{R_m}:cvttps2pi {Mod}{R_m},{mmreg}
+11110011,00001111,00101100,{Mod}{reg}{R_m}:cvttss2si {Mod}{R_m},{reg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,10101110,{mod}001{r_m}:fxrstor {mod}{r_m}
+00001111,10101110,{mod}000{r_m}:fxsave {mod}{r_m}
+00001111,10101110,{mod}010{r_m}:ldmxcsr {mod}{r_m}
+00001111,01011111,{Mod}{xmmreg}{R_m}:maxps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011111,{Mod}{xmmreg}{R_m}:maxss {Mod}{R_m},{xmmreg}
+00001111,01011101,{Mod}{xmmreg}{R_m}:minps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011101,{Mod}{xmmreg}{R_m}:minss {Mod}{R_m},{xmmreg}
+00001111,00101000,{Mod}{xmmreg}{R_m}:movaps {Mod}{R_m},{xmmreg}
+00001111,00101001,{Mod}{xmmreg}{R_m}:movaps {xmmreg},{Mod}{R_m}
+# ORDER:
+00001111,00010010,11{xmmreg1}{xmmreg2}:movhlps {xmmreg1},{xmmreg2}
+00001111,00010011,11{xmmreg1}{xmmreg2}:movhlps {xmmreg2},{xmmreg1}
+00001111,00010010,{Mod}{xmmreg}{R_m}:movlps {Mod}{R_m},{xmmreg}
+00001111,00010011,{Mod}{xmmreg}{R_m}:movlps {xmmreg},{Mod}{R_m}
+# ORDER END:
+# ORDER:
+00001111,00010110,11{xmmreg1}{xmmreg2}:movlhps {xmmreg1},{xmmreg2}
+00001111,00010111,11{xmmreg1}{xmmreg2}:movlhps {xmmreg2},{xmmreg1}
+00001111,00010110,{Mod}{xmmreg}{R_m}:movhps {Mod}{R_m},{xmmreg}
+00001111,00010111,{Mod}{xmmreg}{R_m}:movhps {xmmreg},{Mod}{R_m}
+# ORDER END:
+# BOGUS
+00000000,11{reg}111:fadd {reg}
+00001111,00000001,11000001:vmcall
diff --git a/libcpu/i386_data.h b/libcpu/i386_data.h
new file mode 100644
index 00000000..38e99354
--- /dev/null
+++ b/libcpu/i386_data.h
@@ -0,0 +1,1406 @@
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libasm.h>
+
+struct instr_enc
+{
+ /* The mnemonic. Especially encoded for the optimized table. */
+ unsigned int mnemonic : MNEMONIC_BITS;
+
+ /* The rep/repe prefixes. */
+ unsigned int rep : 1;
+ unsigned int repe : 1;
+
+ /* Mnemonic suffix. */
+ unsigned int suffix : SUFFIX_BITS;
+
+ /* Nonzero if the instruction uses modr/m. */
+ unsigned int modrm : 1;
+
+ /* 1st parameter. */
+ unsigned int fct1 : FCT1_BITS;
+#ifdef STR1_BITS
+ unsigned int str1 : STR1_BITS;
+#endif
+ unsigned int off1_1 : OFF1_1_BITS;
+ unsigned int off1_2 : OFF1_2_BITS;
+ unsigned int off1_3 : OFF1_3_BITS;
+
+ /* 2nd parameter. */
+ unsigned int fct2 : FCT2_BITS;
+#ifdef STR2_BITS
+ unsigned int str2 : STR2_BITS;
+#endif
+ unsigned int off2_1 : OFF2_1_BITS;
+ unsigned int off2_2 : OFF2_2_BITS;
+ unsigned int off2_3 : OFF2_3_BITS;
+
+ /* 3rd parameter. */
+ unsigned int fct3 : FCT3_BITS;
+#ifdef STR3_BITS
+ unsigned int str3 : STR3_BITS;
+#endif
+ unsigned int off3_1 : OFF3_1_BITS;
+#ifdef OFF3_2_BITS
+ unsigned int off3_2 : OFF3_2_BITS;
+#endif
+#ifdef OFF3_3_BITS
+ unsigned int off3_3 : OFF3_3_BITS;
+#endif
+};
+
+
+typedef int (*opfct_t) (GElf_Addr, int *, const char *, size_t, size_t, size_t,
+ char *, size_t *, size_t, const uint8_t *data,
+ const uint8_t **param_start, const uint8_t *end,
+ DisasmGetSymCB_t, void *);
+
+
+static int
+data_prefix (int *prefixes, char *bufp, size_t *bufcntp, size_t bufsize)
+{
+ char ch = '\0';
+ if (*prefixes & has_cs)
+ {
+ ch = 'c';
+ *prefixes &= ~has_cs;
+ }
+ else if (*prefixes & has_ds)
+ {
+ ch = 'd';
+ *prefixes &= ~has_ds;
+ }
+ else if (*prefixes & has_es)
+ {
+ ch = 'e';
+ *prefixes &= has_es;
+ }
+ else if (*prefixes & has_fs)
+ {
+ ch = 'f';
+ *prefixes &= ~has_fs;
+ }
+ else if (*prefixes & has_gs)
+ {
+ ch = 'g';
+ *prefixes &= ~has_gs;
+ }
+ else if (*prefixes & has_ss)
+ {
+ ch = 's';
+ *prefixes &= ~has_ss;
+ }
+ else
+ return 0;
+
+ if (*bufcntp + 4 > bufsize)
+ return *bufcntp + 4 - bufsize;
+
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = ch;
+ bufp[(*bufcntp)++] = 's';
+ bufp[(*bufcntp)++] = ':';
+
+ return 0;
+}
+
+static const char regs[8][4] =
+ {
+ "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
+ };
+
+static int
+general_mod$r_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+ if (r != 0)
+ return r;
+
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((*prefixes & has_addr16) == 0)
+ {
+ if ((modrm & 7) != 4)
+ {
+ int32_t disp = 0;
+ bool nodisp = false;
+
+ if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80)
+ /* 32 bit displacement. */
+ disp = read_4sbyte_unaligned (&data[opoff1 / 8 + 1]);
+ else if ((modrm & 0xc0) == 0x40)
+ /* 8 bit displacement. */
+ disp = *(const int8_t *) &data[opoff1 / 8 + 1];
+ else if ((modrm & 0xc0) == 0)
+ nodisp = true;
+
+ char tmpbuf[sizeof ("-0x12345678(%rrr)")];
+ int n;
+ if (nodisp)
+ n = snprintf (tmpbuf, sizeof (tmpbuf), "(%%%s)", regs[modrm & 7]);
+ else if ((modrm & 0xc7) != 5)
+ n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%%s)",
+ disp < 0 ? "-" : "", disp < 0 ? -disp : disp,
+ regs[modrm & 7]);
+ else
+ n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx32, disp);
+
+ if (*bufcntp + n + 1 > bufsize)
+ return *bufcntp + n + 1 - bufsize;
+
+ memcpy (&bufp[*bufcntp], tmpbuf, n + 1);
+ *bufcntp += n;
+ }
+ else
+ {
+ /* SIB */
+ uint_fast8_t sib = data[opoff1 / 8 + 1];
+ int32_t disp = 0;
+ bool nodisp = false;
+
+ if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
+ || ((modrm & 0xc7) == 0x4 && (sib & 0x7) == 0x5))
+ /* 32 bit displacement. */
+ disp = read_4sbyte_unaligned (&data[opoff1 / 8 + 2]);
+ else if ((modrm & 0xc0) == 0x40)
+ /* 8 bit displacement. */
+ disp = *(const int8_t *) &data[opoff1 / 8 + 2];
+ else
+ nodisp = true;
+
+ char tmpbuf[sizeof ("-0x12345678(%rrr,%rrr,N)")];
+ char *cp = tmpbuf;
+ int n;
+ if ((modrm & 0xc0) != 0 || (sib & 0x3f) != 0x25)
+ {
+ if (!nodisp)
+ {
+ n = snprintf (cp, sizeof (tmpbuf), "%s0x%" PRIx32,
+ disp < 0 ? "-" : "", disp < 0 ? -disp : disp);
+ cp += n;
+ }
+
+ *cp++ = '(';
+
+ if ((modrm & 0xc7) != 0x4 || (sib & 0x7) != 0x5)
+ {
+ *cp++ = '%';
+ cp = mempcpy (cp, regs[sib & 7], 3);
+ }
+
+ if ((sib & 0x38) != 0x20)
+ {
+ *cp++ = ',';
+ *cp++ = '%';
+ cp = mempcpy (cp, regs[(sib >> 3) & 7], 3);
+
+ *cp++ = ',';
+ *cp++ = '0' + (1 << (sib >> 6));
+ }
+
+ *cp++ = ')';
+ }
+ else
+ {
+ assert (! nodisp);
+ n = snprintf (cp, sizeof (tmpbuf), "0x%" PRIx32, disp);
+ cp += n;
+ }
+
+ if (*bufcntp + (cp - tmpbuf) > bufsize)
+ return *bufcntp + (cp - tmpbuf) - bufsize;
+
+ memcpy (&bufp[*bufcntp], tmpbuf, cp - tmpbuf);
+ *bufcntp += cp - tmpbuf;
+ }
+ }
+ return 0;
+}
+
+
+static int
+FCT_MOD$R_M (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ uint_fast8_t byte = data[opoff2 / 8] & 7;
+ assert (opoff2 % 8 == 5);
+ size_t avail = bufsize - *bufcntp;
+ int needed;
+ if (*prefixes & (has_rep | has_repne))
+ needed = snprintf (&bufp[*bufcntp], avail, "%%%s", regs[byte]);
+ else
+ needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+
+
+static int
+FCT_Mod$R_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ uint_fast8_t byte = data[opoff2 / 8] & 7;
+ assert (opoff2 % 8 == 5);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, byte);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+
+static int
+generic_abs (int *prefixes __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)),
+ const char *absstring)
+{
+ int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+ if (r != 0)
+ return r;
+
+ assert (opoff1 % 8 == 0);
+ assert (opoff1 / 8 == 1);
+ if (*param_start + 4 > end)
+ return -1;
+ *param_start += 4;
+ uint32_t absval = read_4ubyte_unaligned (&data[1]);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%s0x%" PRIx32,
+ absstring, absval);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_absval (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ return generic_abs (prefixes, opoff1, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb,
+ symcbarg, "$");
+}
+
+static int
+FCT_abs (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ return generic_abs (prefixes, opoff1, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb,
+ symcbarg, "");
+}
+
+static int
+FCT_ax (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ int is_16bit = (*prefixes & has_data16) != 0;
+
+ if (*bufcntp + 4 - is_16bit > bufsize)
+ return *bufcntp + 4 - is_16bit - bufsize;
+
+ bufp[(*bufcntp)++] = '%';
+ if (! is_16bit)
+ bufp[(*bufcntp)++] = 'e';
+ bufp[(*bufcntp)++] = 'a';
+ bufp[(*bufcntp)++] = 'x';
+
+ return 0;
+}
+
+static int
+FCT_ax$w (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if ((data[opoff2 / 8] & (1 << (7 - (opoff2 & 7)))) != 0)
+ return FCT_ax (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = 'a';
+ bufp[(*bufcntp)++] = 'l';
+
+ return 0;
+}
+
+static int
+FCT_ccc (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (*prefixes & has_data16)
+ return -1;
+
+ assert (opoff1 % 8 == 2);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%cr%" PRIx32,
+ (uint32_t) (data[opoff1 / 8] >> 3) & 7);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_ddd (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (*prefixes & has_data16)
+ return -1;
+
+ assert (opoff1 % 8 == 2);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%db%" PRIx32,
+ (uint32_t) (data[opoff1 / 8] >> 3) & 7);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_disp8 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ int32_t offset = *(const int8_t *) (*param_start)++;
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "0x%" PRIx32,
+ (uint32_t) (addr + (*param_start - data) + offset));
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+__attribute__ ((noinline))
+FCT_ds_xx (const char *reg,
+ int *prefixes __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)))
+{
+ int prefix = *prefixes & SEGMENT_PREFIXES;
+
+ if (prefix == 0)
+ prefix = has_ds;
+ /* Make sure only one bit is set. */
+ else if ((prefix - 1) & prefix)
+ return -1;
+ else
+ *prefixes ^= prefix;
+
+ int r = data_prefix (&prefix, bufp, bufcntp, bufsize);
+ if (r != 0)
+ return r;
+
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "(%%%s%s)",
+ *prefixes & idx_addr16 ? "" : "e", reg);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+
+ return 0;
+}
+
+static int
+FCT_ds_bx (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ return FCT_ds_xx ("bx", prefixes, bufp, bufcntp, bufsize);
+}
+
+static int
+FCT_ds_si (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ return FCT_ds_xx ("si", prefixes, bufp, bufcntp, bufsize);
+}
+
+static int
+FCT_dx (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (*bufcntp + 7 > bufsize)
+ return *bufcntp + 7 - bufsize;
+
+ memcpy (&bufp[*bufcntp], "(%dx)", 5);
+ *bufcntp += 5;
+
+ return 0;
+}
+
+static int
+FCT_es_di (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%es:(%%%sdi)",
+ *prefixes & idx_addr16 ? "" : "e");
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+
+ return 0;
+}
+
+static int
+FCT_imm (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ int needed;
+ if (*prefixes & has_data16)
+ {
+ if (*param_start + 2 > end)
+ return -1;
+ uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+ needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+ }
+ else
+ {
+ if (*param_start + 4 > end)
+ return -1;
+ uint32_t word = read_4ubyte_unaligned_inc (*param_start);
+ needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32, word);
+ }
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_imm$w (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if ((data[opoff2 / 8] & (1 << (7 - (opoff2 & 7)))) != 0)
+ return FCT_imm (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+
+ size_t avail = bufsize - *bufcntp;
+ uint_fast8_t word = *(*param_start)++;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIxFAST8, word);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_imms (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ int_fast8_t byte = *(*param_start)++;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+ (int32_t) byte);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_imm$s (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t opcode = data[opoff2 / 8];
+ size_t avail = bufsize - *bufcntp;
+ if ((opcode & 2) != 0)
+ return FCT_imms (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb,
+ symcbarg);
+
+ if ((*prefixes & has_data16) == 0)
+ {
+ if (*param_start + 4 > end)
+ return -1;
+ uint32_t word = read_4ubyte_unaligned_inc (*param_start);
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32, word);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ }
+ else
+ {
+ if (*param_start + 2 > end)
+ return -1;
+ uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ }
+ return 0;
+}
+
+static int
+FCT_imm16 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (*param_start + 2 > end)
+ return -1;
+ uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_imms8 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ int_fast8_t byte = *(*param_start)++;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+ (int32_t) byte);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_imm8 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ uint_fast8_t byte = *(*param_start)++;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+ (uint32_t) byte);
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+#ifndef X86_64
+static int
+FCT_rel (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ size_t avail = bufsize - *bufcntp;
+ if (*param_start + 4 > end)
+ return -1;
+ uint32_t rel = read_4ubyte_unaligned_inc (*param_start);
+ int needed = snprintf (&bufp[*bufcntp], avail, "0x%" PRIx32,
+ (uint32_t) (addr + rel + (*param_start - data)));
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+#endif
+
+static int
+FCT_mmxreg (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+ byte = (byte >> (5 - opoff1 % 8)) & 7;
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_mmxreg2 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+ byte = (byte >> (5 - opoff1 % 8)) & 7;
+ size_t avail = bufsize - *bufcntp;
+ int needed;
+ if (*prefixes & (has_rep | has_repne))
+ needed = snprintf (&bufp[*bufcntp], avail, "%%%s", regs[byte]);
+ else
+ needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+
+static int
+FCT_mod$r_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ int is_16bit = (*prefixes & has_data16) != 0;
+
+ if (*bufcntp + 5 - is_16bit > bufsize)
+ return *bufcntp + 5 - is_16bit - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ memcpy (&bufp[*bufcntp], regs[modrm & 7] + is_16bit,
+ sizeof (regs[0]) - is_16bit);
+ *bufcntp += 3 - is_16bit;
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+
+
+#ifndef X86_64
+static int
+FCT_moda$r_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+ if (r != 0)
+ return r;
+
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+
+ memcpy (&bufp[*bufcntp], "???", 3);
+ *bufcntp += 3;
+
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+#endif
+
+
+static int
+FCT_mod$r_m$w (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+ if (r != 0)
+ return r;
+
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ if ((data[opoff3 / 8] & (1 << (7 - (opoff3 & 7)))) == 0)
+ {
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = "acdb"[modrm & 3];
+ bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2];
+ }
+ else
+ {
+ int is_16bit = (*prefixes & has_data16) != 0;
+
+ if (*bufcntp + 5 - is_16bit > bufsize)
+ return *bufcntp + 5 - is_16bit - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ memcpy (&bufp[*bufcntp], regs[modrm & 7] + is_16bit,
+ sizeof (regs[0]) - is_16bit);
+ *bufcntp += 3 - is_16bit;
+ }
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+
+
+#ifndef X86_64
+static int
+FCT_mod$8r_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = "acdb"[modrm & 3];
+ bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2];
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+#endif
+
+static int
+FCT_mod$16r_m (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ uint_fast8_t modrm = data[opoff1 / 8];
+ if ((modrm & 0xc0) == 0xc0)
+ {
+ uint_fast8_t byte = data[opoff1 / 8] & 7;
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ memcpy (&bufp[*bufcntp], regs[byte] + 1, sizeof (regs[0]) - 1);
+ *bufcntp += 2;
+ return 0;
+ }
+
+ return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end,
+ symcb, symcbarg);
+}
+
+static int
+FCT_reg (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 + 3 <= 8);
+ byte >>= 8 - (opoff1 % 8 + 3);
+ byte &= 7;
+ int is_16bit = (*prefixes & has_data16) != 0;
+ if (*bufcntp + 4 > bufsize)
+ return *bufcntp + 4 - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ memcpy (&bufp[*bufcntp], regs[byte] + is_16bit, sizeof (regs[0]) - is_16bit);
+ *bufcntp += 3 - is_16bit;
+ return 0;
+}
+
+static int
+FCT_reg$w (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (data[opoff2 / 8] & (1 << (7 - (opoff2 & 7))))
+ return FCT_reg (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 + 3 <= 8);
+ byte >>= 8 - (opoff1 % 8 + 3);
+ byte &= 7;
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = "acdb"[byte & 3];
+ bufp[(*bufcntp)++] = "lh"[byte >> 2];
+ return 0;
+}
+
+#ifndef X86_64
+static int
+FCT_freg (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 / 8 == 1);
+ assert (opoff1 % 8 == 5);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%st(%" PRIx32 ")",
+ (uint32_t) (data[1] & 7));
+ if ((size_t) needed > avail)
+ return (size_t) needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_reg16 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ if (*prefixes & has_data16)
+ return -1;
+
+ *prefixes |= has_data16;
+ return FCT_reg (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+ bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+}
+#endif
+
+static int
+FCT_sel (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ assert (opoff1 % 8 == 0);
+ assert (opoff1 / 8 == 5);
+ if (*param_start + 2 > end)
+ return -1;
+ *param_start += 2;
+ uint16_t absval = read_2ubyte_unaligned (&data[5]);
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, absval);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
+
+static int
+FCT_sreg2 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 + 3 <= 8);
+ byte >>= 8 - (opoff1 % 8 + 2);
+
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = "ecsd"[byte & 3];
+ bufp[(*bufcntp)++] = 's';
+
+ return 0;
+}
+
+static int
+FCT_sreg3 (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 + 4 <= 8);
+ byte >>= 8 - (opoff1 % 8 + 3);
+
+ if ((byte & 7) >= 6)
+ return -1;
+
+ if (*bufcntp + 3 > bufsize)
+ return *bufcntp + 3 - bufsize;
+
+ bufp[(*bufcntp)++] = '%';
+ bufp[(*bufcntp)++] = "ecsdfg"[byte & 7];
+ bufp[(*bufcntp)++] = 's';
+
+ return 0;
+}
+
+static int
+FCT_string (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ return 0;
+}
+
+static int
+FCT_xmmreg (GElf_Addr addr __attribute__ ((unused)),
+ int *prefixes __attribute__ ((unused)),
+ const char *op1str __attribute__ ((unused)),
+ size_t opoff1 __attribute__ ((unused)),
+ size_t opoff2 __attribute__ ((unused)),
+ size_t opoff3 __attribute__ ((unused)),
+ char *bufp __attribute__ ((unused)),
+ size_t *bufcntp __attribute__ ((unused)),
+ size_t bufsize __attribute__ ((unused)),
+ const uint8_t *data __attribute__ ((unused)),
+ const uint8_t **param_start __attribute__ ((unused)),
+ const uint8_t *end __attribute__ ((unused)),
+ DisasmGetSymCB_t symcb __attribute__ ((unused)),
+ void *symcbarg __attribute__ ((unused)))
+{
+ uint_fast8_t byte = data[opoff1 / 8];
+ assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+ byte = (byte >> (5 - opoff1 % 8)) & 7;
+ size_t avail = bufsize - *bufcntp;
+ int needed = snprintf (&bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, byte);
+ if ((size_t) needed > avail)
+ return needed - avail;
+ *bufcntp += needed;
+ return 0;
+}
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
new file mode 100644
index 00000000..ca173cc6
--- /dev/null
+++ b/libcpu/i386_disasm.c
@@ -0,0 +1,914 @@
+#include <assert.h>
+#include <config.h>
+#include <ctype.h>
+#include <endian.h>
+#include <errno.h>
+#include <gelf.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include "../libebl/libeblP.h"
+
+#define MACHINE_ENCODING __LITTLE_ENDIAN
+#include "memory-access.h"
+
+
+#ifndef MNEFILE
+# define MNEFILE "i386.mnemonics"
+#endif
+
+#define MNESTRFIELD(line) MNESTRFIELD1 (line)
+#define MNESTRFIELD1(line) str##line
+static const union mnestr_t
+{
+ struct
+ {
+#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
+#include MNEFILE
+#undef MNE
+ };
+ char str[0];
+} mnestr =
+ {
+ {
+#define MNE(name) #name,
+#include MNEFILE
+#undef MNE
+ }
+ };
+
+/* The index can be stored in the instrtab. */
+enum
+ {
+#define MNE(name) MNE_##name,
+#include MNEFILE
+#undef MNE
+ MNE_INVALID
+ };
+
+static const unsigned short int mneidx[] =
+ {
+#define MNE(name) \
+ [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
+#include MNEFILE
+#undef MNE
+ };
+
+
+enum
+ {
+ idx_cs = 0,
+ idx_ds,
+ idx_es,
+ idx_fs,
+ idx_gs,
+ idx_ss,
+ idx_data16,
+ idx_addr16,
+ idx_rep,
+ idx_repne,
+ idx_lock
+ };
+
+enum
+ {
+#define prefbit(pref) has_##pref = 1 << idx_##pref
+ prefbit (cs),
+ prefbit (ds),
+ prefbit (es),
+ prefbit (fs),
+ prefbit (gs),
+ prefbit (ss),
+ prefbit (data16),
+ prefbit (addr16),
+ prefbit (rep),
+ prefbit (repne),
+ prefbit (lock)
+#undef prefbit
+ };
+#define SEGMENT_PREFIXES \
+ (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
+
+#define prefix_cs 0x2e
+#define prefix_ds 0x3e
+#define prefix_es 0x26
+#define prefix_fs 0x64
+#define prefix_gs 0x65
+#define prefix_ss 0x36
+#define prefix_data16 0x66
+#define prefix_addr16 0x67
+#define prefix_rep 0xf3
+#define prefix_repne 0xf2
+#define prefix_lock 0xf0
+
+
+static const uint8_t known_prefixes[] =
+ {
+#define newpref(pref) [idx_##pref] = prefix_##pref
+ newpref (cs),
+ newpref (ds),
+ newpref (es),
+ newpref (fs),
+ newpref (gs),
+ newpref (ss),
+ newpref (data16),
+ newpref (addr16),
+ newpref (rep),
+ newpref (repne),
+ newpref (lock)
+#undef newpref
+ };
+#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
+
+
+#if 0
+static const char *prefix_str[] =
+ {
+#define newpref(pref) [idx_##pref] = #pref
+ newpref (cs),
+ newpref (ds),
+ newpref (es),
+ newpref (fs),
+ newpref (gs),
+ newpref (ss),
+ newpref (data16),
+ newpref (addr16),
+ newpref (rep),
+ newpref (repne),
+ newpref (lock)
+#undef newpref
+ };
+#endif
+
+
+#ifndef DISFILE
+# define DISFILE "i386_dis.h"
+#endif
+#include DISFILE
+
+
+#define ADD_CHAR(ch) \
+ do { \
+ if (unlikely (bufcnt == bufsize)) \
+ goto enomem; \
+ buf[bufcnt++] = (ch); \
+ } while (0)
+
+#define ADD_STRING(str) \
+ do { \
+ const char *_str = (str); \
+ size_t _len = strlen (_str); \
+ if (unlikely (bufcnt + _len > bufsize)) \
+ goto enomem; \
+ memcpy (buf + bufcnt, str, _len); \
+ bufcnt += _len; \
+ } while (0)
+
+
+#include <stdio.h>
+int
+i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
+ const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
+ void *outcbarg, void *symcbarg)
+{
+ const char *save_fmt = fmt;
+
+ while (1)
+ {
+#define BUFSIZE 512
+ const size_t bufsize = BUFSIZE;
+ char initbuf[BUFSIZE];
+ char *buf = initbuf;
+ size_t bufcnt = 0;
+
+ int prefixes = 0;
+
+ const uint8_t *data = *startp;
+ const uint8_t *begin = data;
+
+ fmt = save_fmt;
+
+ /* Recognize all prefixes. */
+ while (data < end)
+ {
+ unsigned int i;
+ for (i = 0; i < nknown_prefixes; ++i)
+ if (known_prefixes[i] == *data)
+ break;
+ if (i == nknown_prefixes)
+ break;
+
+ prefixes |= 1 << i;
+
+ ++data;
+ }
+
+ assert (data <= end);
+ if (data == end)
+ {
+ if (prefixes != 0)
+ goto print_prefix;
+
+ return -1;
+ }
+
+ const uint8_t *curr = match_data;
+ const uint8_t *const match_end = match_data + sizeof (match_data);
+
+ enomem:
+ ;
+
+ size_t cnt = 0;
+ while (curr < match_end)
+ {
+ const uint8_t *const start = curr;
+
+ uint_fast8_t len = *curr++;
+
+ assert (len > 0);
+ assert (curr + 2 * len + 2 <= match_end);
+
+ const uint8_t *codep = data;
+ size_t avail = len;
+
+ do
+ {
+ uint_fast8_t masked = *codep++ & *curr++;
+ if (masked != *curr++)
+ break;
+
+ --avail;
+ if (codep == end && avail > 0)
+ return 0;
+ }
+ while (avail > 0);
+
+ if (avail != 0)
+ {
+ not:
+ curr = start + 1 + 2 * len + 2;
+ ++cnt;
+ continue;
+ }
+
+ if (len > end - data)
+ /* There is not enough data for the entire instruction. The
+ caller can figure this out by looking at the pointer into
+ the input data. */
+ return 0;
+
+ size_t prefix_size = 0;
+
+ // XXXonly print as prefix if valid?
+ if ((prefixes & has_lock) != 0)
+ {
+ ADD_STRING ("lock ");
+ prefix_size += 5;
+ }
+
+ if (instrtab[cnt].rep)
+ {
+ if ((prefixes & has_rep) != 0)
+ {
+ ADD_STRING ("rep ");
+ prefix_size += 4;
+ }
+ }
+ else if (instrtab[cnt].repe
+ && (prefixes & (has_rep | has_repne)) != 0)
+ {
+ if ((prefixes & has_repne) != 0)
+ {
+ ADD_STRING ("repne ");
+ prefix_size += 6;
+ }
+ else if ((prefixes & has_rep) != 0)
+ {
+ ADD_STRING ("repe ");
+ prefix_size += 5;
+ }
+ }
+ else if ((prefixes & (has_rep | has_repne)) != 0)
+ {
+ uint_fast8_t byte;
+ print_prefix:
+ bufcnt = 0;
+ byte = *begin;
+ /* This is a prefix byte. Print it. */
+ switch (byte)
+ {
+ case prefix_rep:
+ ADD_STRING ("rep");
+ break;
+ case prefix_repne:
+ ADD_STRING ("repne");
+ break;
+ case prefix_cs:
+ ADD_STRING ("cs");
+ break;
+ case prefix_ds:
+ ADD_STRING ("ds");
+ break;
+ case prefix_es:
+ ADD_STRING ("es");
+ break;
+ case prefix_fs:
+ ADD_STRING ("fs");
+ break;
+ case prefix_gs:
+ ADD_STRING ("gs");
+ break;
+ case prefix_ss:
+ ADD_STRING ("ss");
+ break;
+ case prefix_data16:
+ ADD_STRING ("data16");
+ break;
+ case prefix_addr16:
+ ADD_STRING ("addr16");
+ break;
+ case prefix_lock:
+ ADD_STRING ("lock");
+ break;
+ default:
+ /* Cannot happen. */
+ abort ();
+ }
+ data = begin + 1;
+ ++addr;
+
+ /* The string definitely fits. */
+ buf[bufcnt++] = '\0';
+
+ goto out;
+ }
+
+ /* We have a match. First determine how many bytes are
+ needed for the adressing mode. */
+ const uint8_t *param_start = codep;
+ if (instrtab[cnt].modrm)
+ {
+ uint_fast8_t modrm = codep[-1];
+
+ if ((prefixes & has_addr16) == 0)
+ {
+ /* Account for SIB. */
+ if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
+ param_start += 1;
+ }
+
+ /* Account for displacement. */
+ if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
+ || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
+ param_start += 4;
+ else if ((modrm & 0xc0) == 0x40)
+ param_start += 1;
+ }
+
+ unsigned long string_end_idx = 0;
+ while (*fmt != '\0')
+ {
+ if (*fmt != '%')
+ {
+ char ch = *fmt++;
+ if (ch == '\\')
+ {
+ switch ((ch = *fmt++))
+ {
+ case '0' ... '7':
+ {
+ int val = ch - '0';
+ ch = *fmt;
+ if (ch >= '0' && ch <= '7')
+ {
+ val *= 8;
+ val += ch - '0';
+ ch = *++fmt;
+ if (ch >= '0' && ch <= '7' && val < 32)
+ {
+ val *= 8;
+ val += ch - '0';
+ ++fmt;
+ }
+ }
+ ch = val;
+ }
+ break;
+
+ case 'n':
+ ch = '\n';
+ break;
+
+ case 't':
+ ch = '\t';
+ break;
+
+ default:
+ return EINVAL;
+ }
+ }
+ ADD_CHAR (ch);
+ continue;
+ }
+ ++fmt;
+
+ int width = 0;
+ while (isdigit (*fmt))
+ width = width * 10 + (*fmt++ - '0');
+
+ int prec = 0;
+ if (*fmt == '.')
+ while (isdigit (*++fmt))
+ prec = prec * 10 + (*fmt - '0');
+
+ size_t start_idx = bufcnt;
+ switch (*fmt++)
+ {
+ const char *str;
+
+ case 'm':
+ /* Mnemonic. */
+
+ if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
+ {
+ switch (*data)
+ {
+ case 0x90:
+ if (prefixes & ~has_rep)
+ goto print_prefix;
+ /* Discard the 'rep' prefix string possibly
+ already in the buffer. */
+ bufcnt = 0;
+ str = prefixes & has_rep ? "pause" : "nop";
+ break;
+
+ case 0x98:
+ if (prefixes & ~has_data16)
+ goto print_prefix;
+ str = prefixes & has_data16 ? "cbtw" : "cwtl";
+ break;
+
+ case 0x99:
+ if (prefixes & ~has_data16)
+ goto print_prefix;
+ str = prefixes & has_data16 ? "cwtd" : "cltd";
+ break;
+
+ case 0xe3:
+ if (prefixes & ~has_addr16)
+ goto print_prefix;
+ str = prefixes & has_addr16 ? "jcxz" : "jecxz";
+ break;
+
+ case 0x0f:
+ if (data[1] == 0x10 || data[1] == 0x11)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "movupd"
+ : mod & has_rep
+ ? "movss"
+ : mod & has_repne
+ ? "movsd"
+ : "movups");
+ break;
+ }
+ if (data[1] == 0x12)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "movlpd"
+ : mod & has_rep
+ ? "movsldup"
+ : mod & has_repne
+ ? "movddup"
+ : (data[2] & 0xc0) == 0xc0
+ ? "movhlps"
+ : "movlps");
+ break;
+ }
+ if (data[1] == 0x13)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? ((data[2] & 0xc0) == 0xc0
+ ? "movhlpd"
+ : "movlpd")
+ : (data[2] & 0xc0) == 0xc0
+ ? "movhlps"
+ : "movlps");
+ break;
+ }
+ if (data[1] == 0x14)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "unpcklpd" : "unpcklps");
+ break;
+ }
+ if (data[1] == 0x15)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "unpckhpd" : "unpckhps");
+ break;
+ }
+ if (data[1] == 0x16)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "movhpd"
+ : mod & has_rep
+ ? "movshdup"
+ : (data[2] & 0xc0) == 0xc0
+ ? "movlhps"
+ : "movhps");
+ break;
+ }
+ if (data[1] == 0x17)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? ((data[2] & 0xc0) == 0xc0
+ ? "movlhpd" : "movhpd")
+ : (data[2] & 0xc0) == 0xc0
+ ? "movlhps"
+ : "movhps");
+ break;
+ }
+ if (data[1] == 0x28 || data[1] == 0x29)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16) ? "movapd" : "movaps";
+ break;
+ }
+ if (data[1] == 0x2a)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "cvtpi2pd"
+ : mod & has_rep
+ ? "cvtsi2ss"
+ : mod & has_repne
+ ? "cvtsi2sd"
+ : "cvtpi2ps");
+ break;
+ }
+ if (data[1] == 0x2b)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ prefixes ^= mod;
+ str = (mod & has_data16) ? "movntpd" : "movntps";
+ break;
+ }
+ if (data[1] == 0x2c)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "cvttpd2pi"
+ : mod & has_rep
+ ? "cvttss2si"
+ : mod & has_repne
+ ? "cvttsd2si"
+ : "cvttps2pi");
+ break;
+ }
+ if (data[1] == 0x2d)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "cvtpd2pi"
+ : mod & has_rep
+ ? "cvtss2si"
+ : mod & has_repne
+ ? "cvtsd2si"
+ : "cvtps2pi");
+ break;
+ }
+ if (data[1] == 0x2e)
+ {
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "ucomisd" : "ucomiss");
+ break;
+ }
+ if (data[1] == 0x2f)
+ {
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "comisd" : "comiss");
+ break;
+ }
+ if (data[1] == 0x50)
+ {
+ int mod = prefixes & has_data16;
+ if (mod & (mod - 1))
+ return -1;
+ prefixes ^= mod;
+ str = (mod & has_data16
+ ? "movmskpd" : "movmskps");
+ break;
+ }
+ if (data[1] == 0x51)
+ {
+ bufcnt = 0;
+ int mod = prefixes & (has_data16 | has_rep
+ | has_repne);
+ if (mod & (mod - 1))
+ return -1;
+ str = (mod & has_data16
+ ? "sqrtpd"
+ : mod & has_rep
+ ? "sqrtss"
+ : mod & has_repne
+ ? "sqrtsd"
+ : "sqrtps");
+ break;
+ }
+ if (data[1] == 0x52)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_rep;
+ if (mod & (mod - 1))
+ return -1;
+ str = mod & has_rep ? "rsqrtss" : "rsqrtps";
+ break;
+ }
+ if (data[1] == 0x53)
+ {
+ bufcnt = 0;
+ int mod = prefixes & has_rep;
+ if (mod & (mod - 1))
+ return -1;
+ str = mod & has_rep ? "rcpss" : "rcpps";
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ abort ();
+ }
+ }
+ else
+ str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
+
+ ADD_STRING (str);
+
+ switch (instrtab[cnt].suffix)
+ {
+ case suffix_none:
+ break;
+ case suffix_w:
+ if ((codep[-1] & 0xc0) != 0xc0)
+ {
+ char ch;
+
+ if (data[0] & 1)
+ {
+ if (prefixes & has_data16)
+ ch = 'w';
+ else
+ ch = 'l';
+ }
+ else
+ ch = 'b';
+
+ ADD_CHAR (ch);
+ }
+ break;
+ case suffix_w0:
+ if ((codep[-1] & 0xc0) != 0xc0)
+ ADD_CHAR ('l');
+ break;
+ case suffix_w1:
+ if ((data[0] & 0x4) == 0)
+ ADD_CHAR ('l');
+ break;
+ case suffix_W:
+ if (prefixes & has_data16)
+ {
+ ADD_CHAR ('w');
+ prefixes &= ~has_data16;
+ }
+#ifdef x86_64
+ else
+ abort ();
+#endif
+ break;
+ case suffix_tttn:;
+ static const char tttn[16][3] =
+ {
+ "o", "no", "b", "ae", "e", "ne", "be", "a",
+ "s", "ns", "p", "np", "l", "ge", "le", "g"
+ };
+ ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
+ break;
+ case suffix_D:
+ if ((codep[-1] & 0xc0) != 0xc0)
+ ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
+ break;
+ default:
+ printf("unknown suffix %d\n", instrtab[cnt].suffix);
+ abort ();
+ }
+
+ string_end_idx = bufcnt;
+ break;
+
+ case 'o':
+ if (prec == 1 && instrtab[cnt].fct1 != 0)
+ {
+ /* First parameter. */
+ if (instrtab[cnt].str1 != 0)
+ ADD_STRING (op1_str[instrtab[cnt].str1]);
+
+ int r = op1_fct[instrtab[cnt].fct1] (addr
+ + (data - begin),
+ &prefixes,
+#ifdef STR1_BITS
+ op1_str[instrtab[cnt].str1],
+#else
+ NULL,
+#endif
+ instrtab[cnt].off1_1 + OFF1_1_BIAS,
+ instrtab[cnt].off1_2 + OFF1_2_BIAS,
+ instrtab[cnt].off1_3 + OFF1_3_BIAS,
+ buf, &bufcnt, bufsize,
+ data, &param_start,
+ end,
+ symcb, symcbarg);
+ if (r < 0)
+ goto not;
+ if (r > 0)
+ goto enomem;
+
+ string_end_idx = ~0ul;
+ }
+ else if (prec == 2 && instrtab[cnt].fct2 != 0)
+ {
+ /* Second parameter. */
+#ifdef STR2_BITS
+ // XXX Probably not needed once the instruction
+ // XXX tables are complete
+ if (instrtab[cnt].str2 != 0)
+ ADD_STRING (op2_str[instrtab[cnt].str2]);
+#endif
+
+ int r = op2_fct[instrtab[cnt].fct2] (addr
+ + (data - begin),
+ &prefixes,
+#ifdef STR2_BITS
+ op2_str[instrtab[cnt].str2],
+#else
+ NULL,
+#endif
+ instrtab[cnt].off2_1 + OFF2_1_BIAS,
+ instrtab[cnt].off2_2 + OFF2_2_BIAS,
+ instrtab[cnt].off2_3 + OFF2_3_BIAS,
+ buf, &bufcnt, bufsize,
+ data, &param_start,
+ end,
+ symcb, symcbarg);
+ if (r < 0)
+ goto not;
+ if (r > 0)
+ goto enomem;
+
+ string_end_idx = ~0ul;
+ }
+ else if (prec == 3 && instrtab[cnt].fct3 != 0)
+ {
+ /* Third parameter. */
+#ifdef STR3_BITS
+ // XXX Probably not needed once the instruction
+ // XXX tables are complete
+ if (instrtab[cnt].str3 != 0)
+ ADD_STRING (op3_str[instrtab[cnt].str3]);
+#endif
+
+ int r = op3_fct[instrtab[cnt].fct3] (addr
+ + (data - begin),
+ &prefixes,
+#ifdef STR3_BITS
+ op3_str[instrtab[cnt].str3],
+#else
+ NULL,
+#endif
+ instrtab[cnt].off3_1 + OFF3_1_BIAS,
+#ifdef OFF3_2_BITS
+ instrtab[cnt].off3_2 + OFF3_2_BIAS,
+#else
+ 0,
+#endif
+#ifdef OFF3_3_BITS
+ instrtab[cnt].off3_3 + OFF3_3_BIAS,
+#else
+ 0,
+#endif
+ buf, &bufcnt, bufsize,
+ data, &param_start,
+ end,
+ symcb, symcbarg);
+ if (r < 0)
+ goto not;
+ if (r > 0)
+ goto enomem;
+
+ string_end_idx = ~0ul;
+ }
+ break;
+
+ case 'e':
+ /* String end marker. */
+ if (string_end_idx == ~0ul)
+ string_end_idx = bufcnt;
+ /* No padding. */
+ width = 0;
+ break;
+ }
+
+ /* Pad according to the specified width. */
+ while (bufcnt + prefix_size < start_idx + width)
+ ADD_CHAR (' ');
+ prefix_size = 0;
+ }
+
+ if ((prefixes & SEGMENT_PREFIXES) != 0)
+ goto print_prefix;
+
+ if (string_end_idx != ~0ul)
+ buf[string_end_idx] = '\0';
+
+ addr += param_start - begin;
+ data = param_start;
+
+ goto out;
+ }
+
+ /* Invalid (or at least unhandled) opcode. */
+ if (prefixes != 0)
+ goto print_prefix;
+ assert (*startp == data);
+ ++data;
+ ADD_STRING ("(bad)");
+ addr += data - begin;
+
+ buf[bufcnt++] = '\0';
+
+ out:
+ *startp = data;
+ int res = outcb (buf, strlen (buf), outcbarg);
+ if (res != 0)
+ return res;
+ }
+
+ return 0;
+}
diff --git a/libcpu/i386_gendis.c b/libcpu/i386_gendis.c
new file mode 100644
index 00000000..ca01db8c
--- /dev/null
+++ b/libcpu/i386_gendis.c
@@ -0,0 +1,39 @@
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+extern int i386_parse (void);
+
+
+extern FILE *i386_in;
+extern int i386_debug;
+char *infname;
+
+FILE *outfile;
+
+int
+main (int argc, char *argv[argc])
+{
+ outfile = stdout;
+
+ if (argc == 1)
+ error (EXIT_FAILURE, 0, "usage: %s <MNEDEFFILE>", argv[0]);
+
+ //i386_debug = 1;
+ infname = argv[1];
+ if (strcmp (infname, "-") == 0)
+ i386_in = stdin;
+ else
+ {
+ i386_in = fopen (infname, "r");
+ if (i386_in == NULL)
+ error (EXIT_FAILURE, errno, "cannot open %s", argv[1]);
+ }
+
+ i386_parse ();
+
+ return error_message_count != 0;
+}
diff --git a/libcpu/i386_lex.l b/libcpu/i386_lex.l
new file mode 100644
index 00000000..ea121909
--- /dev/null
+++ b/libcpu/i386_lex.l
@@ -0,0 +1,115 @@
+%{
+/* Copyright (C) 2004, 2005, 2007 Red Hat, Inc.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <error.h>
+#include <libintl.h>
+
+#include <system.h>
+#include "i386_parse.h"
+
+
+static void eat_to_eol (void);
+static void invalid_char (int ch);
+%}
+
+ID [a-zA-Z_][a-zA-Z0-9_/]*
+ID2 [a-zA-Z0-9_:/]*
+NUMBER [0-9]+
+WHITE [[:space:]]+
+
+%option yylineno
+%option never-interactive
+%option noyywrap
+
+
+%x MAIN
+
+%%
+
+"%mask" { return kMASK; }
+
+"%prefix" { return kPREFIX; }
+"%suffix" { return kSUFFIX; }
+
+"%synonym" { return kSYNONYM; }
+
+{NUMBER} { i386_lval.num = strtoul (yytext, NULL, 10);
+ return kNUMBER; }
+
+"%%" { BEGIN (MAIN); return kPERCPERC; }
+
+
+<MAIN>"0" { return '0'; }
+<MAIN>"1" { return '1'; }
+
+<INITIAL,MAIN>"{"{ID2}"}" { i386_lval.str = xstrndup (yytext + 1,
+ yyleng - 2);
+ return kBITFIELD; }
+
+<MAIN>"INVALID" { i386_lval.str = (void *) -1l;
+ return kID; }
+
+<MAIN>{ID} { i386_lval.str = xstrndup (yytext, yyleng);
+ return kID; }
+
+<MAIN>"," { return ','; }
+
+<MAIN>":" { return ':'; }
+
+<INITIAL,MAIN>^"\n" { /* IGNORE */ }
+
+<INITIAL,MAIN>"\n" { return '\n'; }
+
+<INITIAL,MAIN>^"#" { eat_to_eol (); }
+
+{WHITE} { /* IGNORE */ }
+
+<MAIN>{WHITE} { return kSPACE; }
+
+<MAIN>. { i386_lval.ch = *yytext; return kCHAR; }
+
+. { invalid_char (*yytext); }
+
+
+%%
+
+static void
+eat_to_eol (void)
+{
+ while (1)
+ {
+ int c = input ();
+
+ if (c == EOF || c == '\n')
+ break;
+ }
+}
+
+static void
+invalid_char (int ch)
+{
+ error (0, 0, (isascii (ch)
+ ? gettext ("invalid character '%c' at line %d; ignored")
+ : gettext ("invalid character '\\%o' at line %d; ignored")),
+ ch, yylineno);
+}
+
+// Local Variables:
+// mode: C
+// End:
diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y
new file mode 100644
index 00000000..9ad11622
--- /dev/null
+++ b/libcpu/i386_parse.y
@@ -0,0 +1,1641 @@
+%{
+/* Parser for i386 CPU description.
+ Copyright (C) 2004, 2005, 2007 Red Hat, Inc.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <error.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <math.h>
+#include <obstack.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include <system.h>
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* The error handler. */
+static void yyerror (const char *s);
+
+extern int yylex (void);
+extern int i386_lineno;
+extern char *infname;
+
+
+struct known_bitfield
+{
+ char *name;
+ unsigned long int bits;
+ int tmp;
+};
+
+
+struct bitvalue
+{
+ enum bittype { zeroone, field, failure } type;
+ union
+ {
+ unsigned int value;
+ struct known_bitfield *field;
+ };
+ struct bitvalue *next;
+};
+
+
+struct argname
+{
+ enum nametype { string, nfield } type;
+ union
+ {
+ char *str;
+ struct known_bitfield *field;
+ };
+ struct argname *next;
+};
+
+
+struct argument
+{
+ struct argname *name;
+ struct argument *next;
+};
+
+
+struct instruction
+{
+ /* The byte encoding. */
+ struct bitvalue *bytes;
+
+ /* Prefix possible. */
+ int repe;
+ int rep;
+
+ /* Mnemonic. */
+ char *mnemonic;
+
+ /* Suffix. */
+ enum { suffix_none = 0, suffix_w, suffix_w0, suffix_W, suffix_tttn,
+ suffix_w1, suffix_gg, suffix_GG, suffix_0g, suffix_gG,
+ suffix_predpd, suffix_predps, suffix_predsd, suffix_predss,
+ suffix_D } suffix;
+
+ /* Flag set if modr/m is used. */
+ int modrm;
+
+ /* Operands. */
+ struct operand
+ {
+ char *fct;
+ char *str;
+ int off1;
+ int off2;
+ int off3;
+ } operands[3];
+
+ struct instruction *next;
+};
+
+
+struct synonym
+{
+ char *from;
+ char *to;
+};
+
+
+struct suffix
+{
+ char *name;
+ int idx;
+};
+
+
+struct argstring
+{
+ char *str;
+ int idx;
+};
+
+
+static struct known_bitfield ax_reg =
+ {
+ .name = "ax", .bits = 0, .tmp = 0
+ };
+
+static struct known_bitfield dx_reg =
+ {
+ .name = "dx", .bits = 0, .tmp = 0
+ };
+
+static struct known_bitfield di_reg =
+ {
+ .name = "es_di", .bits = 0, .tmp = 0
+ };
+
+static struct known_bitfield si_reg =
+ {
+ .name = "ds_si", .bits = 0, .tmp = 0
+ };
+
+static struct known_bitfield bx_reg =
+ {
+ .name = "ds_bx", .bits = 0, .tmp = 0
+ };
+
+
+static int bitfield_compare (const void *p1, const void *p2);
+static void new_bitfield (char *name, unsigned long int num);
+static void check_bits (struct bitvalue *value);
+static int check_duplicates (struct bitvalue *val);
+static int check_argsdef (struct bitvalue *bitval, struct argument *args);
+static int check_bitsused (struct bitvalue *bitval,
+ struct known_bitfield *suffix,
+ struct argument *args);
+static struct argname *combine (struct argname *name);
+static void fillin_arg (struct bitvalue *bytes, struct argname *name,
+ struct instruction *instr, int n);
+static void find_numbers (void);
+static int compare_syn (const void *p1, const void *p2);
+static int compare_suf (const void *p1, const void *p2);
+static void instrtable_out (void);
+#if 0
+static void create_mnemonic_table (void);
+#endif
+
+static void *bitfields;
+static struct instruction *instructions;
+static size_t ninstructions;
+static void *synonyms;
+static void *suffixes;
+static int nsuffixes;
+static void *mnemonics;
+size_t nmnemonics;
+extern FILE *outfile;
+
+/* Number of bits used mnemonics. */
+#if 0
+static size_t best_mnemonic_bits;
+#endif
+%}
+
+%union {
+ unsigned long int num;
+ char *str;
+ char ch;
+ struct known_bitfield *field;
+ struct bitvalue *bit;
+ struct argname *name;
+ struct argument *arg;
+}
+
+%token kMASK
+%token kPREFIX
+%token kSUFFIX
+%token kSYNONYM
+%token <str> kID
+%token <num> kNUMBER
+%token kPERCPERC
+%token <str> kBITFIELD
+%token <ch> kCHAR
+%token kSPACE
+
+%type <bit> bit byte bytes
+%type <field> bitfieldopt
+%type <name> argcomp arg
+%type <arg> args optargs
+
+%defines
+
+%%
+
+spec: masks kPERCPERC '\n' instrs
+ {
+ if (error_message_count != 0)
+ error (EXIT_FAILURE, 0,
+ "terminated due to previous error");
+
+ instrtable_out ();
+ }
+ ;
+
+masks: masks '\n' mask
+ | mask
+ ;
+
+mask: kMASK kBITFIELD kNUMBER
+ { new_bitfield ($2, $3); }
+ | kPREFIX kBITFIELD
+ { new_bitfield ($2, -1); }
+ | kSUFFIX kBITFIELD
+ { new_bitfield ($2, -2); }
+ | kSYNONYM kBITFIELD kBITFIELD
+ {
+ struct synonym *newp = xmalloc (sizeof (*newp));
+ newp->from = $2;
+ newp->to = $3;
+ if (tfind (newp, &synonyms, compare_syn) != NULL)
+ error (0, 0,
+ "%d: duplicate definition for synonym '%s'",
+ i386_lineno, $2);
+ else if (tsearch ( newp, &synonyms, compare_syn) == NULL)
+ error (EXIT_FAILURE, 0, "tsearch");
+ }
+ |
+ ;
+
+instrs: instrs '\n' instr
+ | instr
+ ;
+
+instr: bytes ':' bitfieldopt kID bitfieldopt optargs
+ {
+ if ($3 != NULL && strcmp ($3->name, "RE") != 0
+ && strcmp ($3->name, "R") != 0)
+ {
+ error (0, 0, "%d: only 'R' and 'RE' prefix allowed",
+ i386_lineno - 1);
+ }
+ if (check_duplicates ($1) == 0
+ && check_argsdef ($1, $6) == 0
+ && check_bitsused ($1, $5, $6) == 0)
+ {
+ struct instruction *newp = xcalloc (sizeof (*newp),
+ 1);
+ if ($3 != NULL)
+ {
+ if (strcmp ($3->name, "RE") == 0)
+ newp->repe = 1;
+ else if (strcmp ($3->name, "R") == 0)
+ newp->rep = 1;
+ }
+
+ newp->bytes = $1;
+ newp->mnemonic = $4;
+ if (newp->mnemonic != (void *) -1l
+ && tfind ($4, &mnemonics,
+ (comparison_fn_t) strcmp) == NULL)
+ {
+ if (tsearch ($4, &mnemonics,
+ (comparison_fn_t) strcmp) == NULL)
+ error (EXIT_FAILURE, errno, "tsearch");
+ ++nmnemonics;
+ }
+
+ if ($5 != NULL)
+ {
+ if (strcmp ($5->name, "w") == 0)
+ newp->suffix = suffix_w;
+ else if (strcmp ($5->name, "w0") == 0)
+ newp->suffix = suffix_w0;
+ else if (strcmp ($5->name, "tttn") == 0)
+ newp->suffix = suffix_tttn;
+ else if (strcmp ($5->name, "w1") == 0)
+ newp->suffix = suffix_w1;
+ else if (strcmp ($5->name, "W") == 0)
+ newp->suffix = suffix_W;
+ else if (strcmp ($5->name, "gg") == 0)
+ newp->suffix = suffix_gg;
+ else if (strcmp ($5->name, "GG") == 0)
+ newp->suffix = suffix_GG;
+ else if (strcmp ($5->name, "0g") == 0)
+ newp->suffix = suffix_0g;
+ else if (strcmp ($5->name, "gG") == 0)
+ newp->suffix = suffix_gG;
+ else if (strcmp ($5->name, "predpd") == 0)
+ newp->suffix = suffix_predpd;
+ else if (strcmp ($5->name, "predps") == 0)
+ newp->suffix = suffix_predps;
+ else if (strcmp ($5->name, "predsd") == 0)
+ newp->suffix = suffix_predsd;
+ else if (strcmp ($5->name, "predss") == 0)
+ newp->suffix = suffix_predss;
+ else if (strcmp ($5->name, "D") == 0)
+ newp->suffix = suffix_D;
+ else
+ error (EXIT_FAILURE, 0,
+ "%s: %d: unknown suffix '%s'",
+ infname, i386_lineno - 1, $5->name);
+
+ struct suffix search = { .name = $5->name };
+ if (tfind (&search, &suffixes, compare_suf)
+ == NULL)
+ {
+ struct suffix *ns = xmalloc (sizeof (*ns));
+ ns->name = $5->name;
+ ns->idx = ++nsuffixes;
+ if (tsearch (ns, &suffixes, compare_suf)
+ == NULL)
+ error (EXIT_FAILURE, errno, "tsearch");
+ }
+ }
+
+ struct argument *args = $6;
+ int n = 0;
+ while (args != NULL)
+ {
+ fillin_arg ($1, args->name, newp, n);
+
+ args = args->next;
+ ++n;
+ }
+
+ newp->next = instructions;
+ instructions = newp;
+ ++ninstructions;
+ }
+ }
+ |
+ ;
+
+bitfieldopt: kBITFIELD
+ {
+ struct known_bitfield search;
+ search.name = $1;
+ struct known_bitfield **res;
+ res = tfind (&search, &bitfields, bitfield_compare);
+ if (res == NULL)
+ {
+ error (0, 0, "%d: unknown bitfield '%s'",
+ i386_lineno, search.name);
+ $$ = NULL;
+ }
+ else
+ $$ = *res;
+ }
+ |
+ { $$ = NULL; }
+ ;
+
+bytes: bytes ',' byte
+ {
+ check_bits ($3);
+
+ struct bitvalue *runp = $1;
+ while (runp->next != NULL)
+ runp = runp->next;
+ runp->next = $3;
+ $$ = $1;
+ }
+ | byte
+ {
+ check_bits ($1);
+ $$ = $1;
+ }
+ ;
+
+byte: byte bit
+ {
+ struct bitvalue *runp = $1;
+ while (runp->next != NULL)
+ runp = runp->next;
+ runp->next = $2;
+ $$ = $1;
+ }
+ | bit
+ { $$ = $1; }
+ ;
+
+bit: '0'
+ {
+ $$ = xmalloc (sizeof (struct bitvalue));
+ $$->type = zeroone;
+ $$->value = 0;
+ $$->next = NULL;
+ }
+ | '1'
+ {
+ $$ = xmalloc (sizeof (struct bitvalue));
+ $$->type = zeroone;
+ $$->value = 1;
+ $$->next = NULL;
+ }
+ | kBITFIELD
+ {
+ $$ = xmalloc (sizeof (struct bitvalue));
+ struct known_bitfield search;
+ search.name = $1;
+ struct known_bitfield **res;
+ res = tfind (&search, &bitfields, bitfield_compare);
+ if (res == NULL)
+ {
+ error (0, 0, "%d: unknown bitfield '%s'",
+ i386_lineno, search.name);
+ $$->type = failure;
+ }
+ else
+ {
+ $$->type = field;
+ $$->field = *res;
+ }
+ $$->next = NULL;
+ }
+ ;
+
+optargs: kSPACE args
+ { $$ = $2; }
+ |
+ { $$ = NULL; }
+ ;
+
+args: args ',' arg
+ {
+ struct argument *runp = $1;
+ while (runp->next != NULL)
+ runp = runp->next;
+ runp->next = xmalloc (sizeof (struct argument));
+ runp->next->name = combine ($3);
+ runp->next->next = NULL;
+ $$ = $1;
+ }
+ | arg
+ {
+ $$ = xmalloc (sizeof (struct argument));
+ $$->name = combine ($1);
+ $$->next = NULL;
+ }
+ ;
+
+arg: arg argcomp
+ {
+ struct argname *runp = $1;
+ while (runp->next != NULL)
+ runp = runp->next;
+ runp->next = $2;
+ $$ = $1;
+ }
+ | argcomp
+ { $$ = $1; }
+ ;
+argcomp: kBITFIELD
+ {
+ $$ = xmalloc (sizeof (struct argname));
+ $$->type = nfield;
+ $$->next = NULL;
+
+ struct known_bitfield search;
+ search.name = $1;
+ struct known_bitfield **res;
+ res = tfind (&search, &bitfields, bitfield_compare);
+ if (res == NULL)
+ {
+ if (strcmp ($1, "ax") == 0)
+ $$->field = &ax_reg;
+ else if (strcmp ($1, "dx") == 0)
+ $$->field = &dx_reg;
+ else if (strcmp ($1, "es_di") == 0)
+ $$->field = &di_reg;
+ else if (strcmp ($1, "ds_si") == 0)
+ $$->field = &si_reg;
+ else if (strcmp ($1, "ds_bx") == 0)
+ $$->field = &bx_reg;
+ else
+ {
+ error (0, 0, "%d: unknown bitfield '%s'",
+ i386_lineno, search.name);
+ $$->field = NULL;
+ }
+ }
+ else
+ $$->field = *res;
+ }
+ | kCHAR
+ {
+ $$ = xmalloc (sizeof (struct argname));
+ $$->type = string;
+ $$->next = NULL;
+ $$->str = xmalloc (2);
+ $$->str[0] = $1;
+ $$->str[1] = '\0';
+ }
+ | kID
+ {
+ $$ = xmalloc (sizeof (struct argname));
+ $$->type = string;
+ $$->next = NULL;
+ $$->str = $1;
+ }
+ | ':'
+ {
+ $$ = xmalloc (sizeof (struct argname));
+ $$->type = string;
+ $$->next = NULL;
+ $$->str = xmalloc (2);
+ $$->str[0] = ':';
+ $$->str[1] = '\0';
+ }
+ ;
+
+%%
+
+static void
+yyerror (const char *s)
+{
+ error (0, 0, gettext ("while reading i386 CPU description: %s at line %d"),
+ gettext (s), i386_lineno);
+}
+
+
+static int
+bitfield_compare (const void *p1, const void *p2)
+{
+ struct known_bitfield *f1 = (struct known_bitfield *) p1;
+ struct known_bitfield *f2 = (struct known_bitfield *) p2;
+
+ return strcmp (f1->name, f2->name);
+}
+
+
+static void
+new_bitfield (char *name, unsigned long int num)
+{
+ struct known_bitfield *newp = xmalloc (sizeof (struct known_bitfield));
+ newp->name = name;
+ newp->bits = num;
+ newp->tmp = 0;
+
+ if (tfind (newp, &bitfields, bitfield_compare) != NULL)
+ {
+ error (0, 0, "%d: duplicated definition of bitfield '%s'",
+ i386_lineno, name);
+ free (name);
+ return;
+ }
+
+ if (tsearch (newp, &bitfields, bitfield_compare) == NULL)
+ error (EXIT_FAILURE, errno, "%d: cannot insert new bitfield '%s'",
+ i386_lineno, name);
+}
+
+
+/* Check that the number of bits is a multiple of 8. */
+static void
+check_bits (struct bitvalue *val)
+{
+ struct bitvalue *runp = val;
+ unsigned int total = 0;
+
+ while (runp != NULL)
+ {
+ if (runp->type == zeroone)
+ ++total;
+ else if (runp->field == NULL)
+ /* No sense doing anything, the field is not known. */
+ return;
+ else
+ total += runp->field->bits;
+
+ runp = runp->next;
+ }
+
+ if (total % 8 != 0)
+ {
+ struct obstack os;
+ obstack_init (&os);
+
+ while (val != NULL)
+ {
+ if (val->type == zeroone)
+ obstack_printf (&os, "%u", val->value);
+ else
+ obstack_printf (&os, "{%s}", val->field->name);
+ val = val->next;
+ }
+ obstack_1grow (&os, '\0');
+
+ error (0, 0, "%d: field '%s' not a multiple of 8 bits in size",
+ i386_lineno, (char *) obstack_finish (&os));
+
+ obstack_free (&os, NULL);
+ }
+}
+
+
+static int
+check_duplicates (struct bitvalue *val)
+{
+ static int testcnt;
+ ++testcnt;
+
+ int result = 0;
+ while (val != NULL)
+ {
+ if (val->type == field && val->field != NULL)
+ {
+ if (val->field->tmp == testcnt)
+ {
+ error (0, 0, "%d: bitfield '%s' used more than once",
+ i386_lineno - 1, val->field->name);
+ result = 1;
+ }
+ val->field->tmp = testcnt;
+ }
+
+ val = val->next;
+ }
+
+ return result;
+}
+
+
+static int
+check_argsdef (struct bitvalue *bitval, struct argument *args)
+{
+ int result = 0;
+
+ while (args != NULL)
+ {
+ for (struct argname *name = args->name; name != NULL; name = name->next)
+ if (name->type == nfield && name->field != NULL
+ && name->field != &ax_reg && name->field != &dx_reg
+ && name->field != &di_reg && name->field != &si_reg
+ && name->field != &bx_reg)
+ {
+ struct bitvalue *runp = bitval;
+
+ while (runp != NULL)
+ if (runp->type == field && runp->field == name->field)
+ break;
+ else
+ runp = runp->next;
+
+ if (runp == NULL)
+ {
+ error (0, 0, "%d: unknown bitfield '%s' used in output format",
+ i386_lineno - 1, name->field->name);
+ result = 1;
+ }
+ }
+
+ args = args->next;
+ }
+
+ return result;
+}
+
+
+static int
+check_bitsused (struct bitvalue *bitval, struct known_bitfield *suffix,
+ struct argument *args)
+{
+ int result = 0;
+
+ while (bitval != NULL)
+ {
+ if (bitval->type == field && bitval->field != NULL
+ && bitval->field != suffix
+ /* {w} is handled special. */
+ && strcmp (bitval->field->name, "w") != 0)
+ {
+ struct argument *runp;
+ for (runp = args; runp != NULL; runp = runp->next)
+ {
+ struct argname *name = runp->name;
+
+ while (name != NULL)
+ if (name->type == nfield && name->field == bitval->field)
+ break;
+ else
+ name = name->next;
+
+ if (name != NULL)
+ break;
+ }
+
+#if 0
+ if (runp == NULL)
+ {
+ error (0, 0, "%d: bitfield '%s' not used",
+ i386_lineno - 1, bitval->field->name);
+ result = 1;
+ }
+#endif
+ }
+
+ bitval = bitval->next;
+ }
+
+ return result;
+}
+
+
+static struct argname *
+combine (struct argname *name)
+{
+ struct argname *last_str = NULL;
+ for (struct argname *runp = name; runp != NULL; runp = runp->next)
+ {
+ if (runp->type == string)
+ {
+ if (last_str == NULL)
+ last_str = runp;
+ else
+ {
+ last_str->str = xrealloc (last_str->str,
+ strlen (last_str->str)
+ + strlen (runp->str) + 1);
+ strcat (last_str->str, runp->str);
+ last_str->next = runp->next;
+ }
+ }
+ else
+ last_str = NULL;
+ }
+ return name;
+}
+
+
+#define obstack_grow_str(ob, str) obstack_grow (ob, str, strlen (str))
+
+
+static void
+fillin_arg (struct bitvalue *bytes, struct argname *name,
+ struct instruction *instr, int n)
+{
+ static struct obstack ob;
+ static int initialized;
+ if (! initialized)
+ {
+ initialized = 1;
+ obstack_init (&ob);
+ }
+
+ struct argname *runp = name;
+ int cnt = 0;
+ while (runp != NULL)
+ {
+ /* We ignore strings in the function name. */
+ if (runp->type == string)
+ {
+ if (instr->operands[n].str != NULL)
+ error (EXIT_FAILURE, 0,
+ "%d: cannot have more than one string parameter",
+ i386_lineno - 1);
+
+ instr->operands[n].str = runp->str;
+ }
+ else
+ {
+ assert (runp->type == nfield);
+
+ /* Construct the function name. */
+ if (cnt++ > 0)
+ obstack_1grow (&ob, '$');
+
+ if (runp->field == NULL)
+ /* Add some string which contains invalid characters. */
+ obstack_grow_str (&ob, "!!!INVALID!!!");
+ else
+ obstack_grow_str (&ob, runp->field->name);
+
+ /* Now compute the bit offset of the field. */
+ struct bitvalue *b = bytes;
+ int bitoff = 0;
+ if (runp->field != NULL)
+ while (b != NULL)
+ {
+ if (b->type == field && b->field != NULL)
+ {
+ if (strcmp (b->field->name, runp->field->name) == 0)
+ break;
+ bitoff += b->field->bits;
+ }
+ else
+ ++bitoff;
+
+ b = b->next;
+ }
+ if (instr->operands[n].off1 == 0)
+ instr->operands[n].off1 = bitoff;
+ else if (instr->operands[n].off2 == 0)
+ instr->operands[n].off2 = bitoff;
+ else if (instr->operands[n].off3 == 0)
+ instr->operands[n].off3 = bitoff;
+ else
+ error (EXIT_FAILURE, 0,
+ "%d: cannot have more than three fields in parameter",
+ i386_lineno - 1);
+
+ if (runp->field != NULL
+ && strncasecmp (runp->field->name, "mod", 3) == 0)
+ instr->modrm = 1;
+ }
+
+ runp = runp->next;
+ }
+ if (obstack_object_size (&ob) == 0)
+ obstack_grow_str (&ob, "string");
+ obstack_1grow (&ob, '\0');
+ char *fct = obstack_finish (&ob);
+
+ struct synonym search = { .from = fct };
+ struct synonym **res = tfind (&search, &synonyms, compare_syn);
+ if (res != NULL)
+ fct = (*res)->to;
+
+ instr->operands[n].fct = fct;
+}
+
+
+#if 0
+static void
+nameout (const void *nodep, VISIT value, int level)
+{
+ if (value == leaf || value == postorder)
+ printf (" %s\n", *(const char **) nodep);
+}
+#endif
+
+
+static int
+compare_argstring (const void *p1, const void *p2)
+{
+ const struct argstring *a1 = (const struct argstring *) p1;
+ const struct argstring *a2 = (const struct argstring *) p2;
+
+ return strcmp (a1->str, a2->str);
+}
+
+
+static int maxoff[3][3];
+static int minoff[3][3] = { { 1000, 1000, 1000 },
+ { 1000, 1000, 1000 },
+ { 1000, 1000, 1000 } };
+static int nbitoff[3][3];
+static void *fct_names[3];
+static int nbitfct[3];
+static int nbitsuf;
+static void *strs[3];
+static int nbitstr[3];
+static int total_bits = 2; // Already counted the rep/repe bits.
+
+static void
+find_numbers (void)
+{
+ int nfct_names[3] = { 0, 0, 0 };
+ int nstrs[3] = { 0, 0, 0 };
+
+ /* We reverse the order of the instruction list while processing it.
+ Later phases need it in the order in which the input file has
+ them. */
+ struct instruction *reversed = NULL;
+
+ struct instruction *runp = instructions;
+ while (runp != NULL)
+ {
+ for (int i = 0; i < 3; ++i)
+ if (runp->operands[i].fct != NULL)
+ {
+ struct argstring search = { .str = runp->operands[i].fct };
+ if (tfind (&search, &fct_names[i], compare_argstring) == NULL)
+ {
+ struct argstring *newp = xmalloc (sizeof (*newp));
+ newp->str = runp->operands[i].fct;
+ newp->idx = 0;
+ if (tsearch (newp, &fct_names[i], compare_argstring) == NULL)
+ error (EXIT_FAILURE, errno, "tsearch");
+ ++nfct_names[i];
+ }
+
+ if (runp->operands[i].str != NULL)
+ {
+ search.str = runp->operands[i].str;
+ if (tfind (&search, &strs[i], compare_argstring) == NULL)
+ {
+ struct argstring *newp = xmalloc (sizeof (*newp));
+ newp->str = runp->operands[i].str;
+ newp->idx = 0;
+ if (tsearch (newp, &strs[i], compare_argstring) == NULL)
+ error (EXIT_FAILURE, errno, "tsearch");
+ ++nstrs[i];
+ }
+ }
+
+ maxoff[i][0] = MAX (maxoff[i][0], runp->operands[i].off1);
+ maxoff[i][1] = MAX (maxoff[i][1], runp->operands[i].off2);
+ maxoff[i][2] = MAX (maxoff[i][2], runp->operands[i].off3);
+
+ if (runp->operands[i].off1 > 0)
+ minoff[i][0] = MIN (minoff[i][0], runp->operands[i].off1);
+ if (runp->operands[i].off2 > 0)
+ minoff[i][1] = MIN (minoff[i][1], runp->operands[i].off2);
+ if (runp->operands[i].off3 > 0)
+ minoff[i][2] = MIN (minoff[i][2], runp->operands[i].off3);
+ }
+
+ struct instruction *old = runp;
+ runp = runp->next;
+
+ old->next = reversed;
+ reversed = old;
+ }
+ instructions = reversed;
+
+ int d;
+ int c;
+ for (int i = 0; i < 3; ++i)
+ {
+ // printf ("min1 = %d, min2 = %d, min3 = %d\n", minoff[i][0], minoff[i][1], minoff[i][2]);
+ // printf ("max1 = %d, max2 = %d, max3 = %d\n", maxoff[i][0], maxoff[i][1], maxoff[i][2]);
+
+ if (minoff[i][0] == 1000)
+ nbitoff[i][0] = 0;
+ else
+ {
+ nbitoff[i][0] = 1;
+ d = maxoff[i][0] - minoff[i][0];
+ c = 1;
+ while (c < d)
+ {
+ ++nbitoff[i][0];
+ c *= 2;
+ }
+ total_bits += nbitoff[i][0];
+ }
+
+ if (minoff[i][1] == 1000)
+ nbitoff[i][1] = 0;
+ else
+ {
+ nbitoff[i][1] = 1;
+ d = maxoff[i][1] - minoff[i][1];
+ c = 1;
+ while (c < d)
+ {
+ ++nbitoff[i][1];
+ c *= 2;
+ }
+ total_bits += nbitoff[i][1];
+ }
+
+ if (minoff[i][2] == 1000)
+ nbitoff[i][2] = 0;
+ else
+ {
+ nbitoff[i][2] = 1;
+ d = maxoff[i][2] - minoff[i][2];
+ c = 1;
+ while (c < d)
+ {
+ ++nbitoff[i][2];
+ c *= 2;
+ }
+ total_bits += nbitoff[i][2];
+ }
+ // printf ("off1 = %d, off2 = %d, off3 = %d\n", nbitoff[i][0], nbitoff[i][1], nbitoff[i][2]);
+
+ nbitfct[i] = 1;
+ d = nfct_names[i];
+ c = 1;
+ while (c < d)
+ {
+ ++nbitfct[i];
+ c *= 2;
+ }
+ total_bits += nbitfct[i];
+ // printf ("%d fct[%d], %d bits\n", nfct_names[i], i, nbitfct[i]);
+
+ if (nstrs[i] != 0)
+ {
+ nbitstr[i] = 1;
+ d = nstrs[i];
+ c = 1;
+ while (c < d)
+ {
+ ++nbitstr[i];
+ c *= 2;
+ }
+ total_bits += nbitstr[i];
+ }
+
+ // twalk (fct_names[i], nameout);
+ }
+
+ nbitsuf = 0;
+ d = nsuffixes;
+ c = 1;
+ while (c < d)
+ {
+ ++nbitsuf;
+ c *= 2;
+ }
+ total_bits += nbitsuf;
+ // printf ("%d suffixes, %d bits\n", nsuffixes, nbitsuf);
+}
+
+
+static int
+compare_syn (const void *p1, const void *p2)
+{
+ const struct synonym *s1 = (const struct synonym *) p1;
+ const struct synonym *s2 = (const struct synonym *) p2;
+
+ return strcmp (s1->from, s2->from);
+}
+
+
+static int
+compare_suf (const void *p1, const void *p2)
+{
+ const struct suffix *s1 = (const struct suffix *) p1;
+ const struct suffix *s2 = (const struct suffix *) p2;
+
+ return strcmp (s1->name, s2->name);
+}
+
+
+static int count_op_str;
+static void
+print_op_str (const void *nodep, VISIT value,
+ int level __attribute__ ((unused)))
+{
+ if (value == leaf || value == postorder)
+ {
+ fprintf (outfile, " \"%s\",\n", (*(struct argstring **) nodep)->str);
+ (*(struct argstring **) nodep)->idx = ++count_op_str;
+ }
+}
+
+
+static void
+print_op_fct (const void *nodep, VISIT value,
+ int level __attribute__ ((unused)))
+{
+ if (value == leaf || value == postorder)
+ {
+ fprintf (outfile, " FCT_%s,\n", (*(struct argstring **) nodep)->str);
+ (*(struct argstring **) nodep)->idx = ++count_op_str;
+ }
+}
+
+
+static void
+instrtable_out (void)
+{
+ find_numbers ();
+
+#if 0
+ create_mnemonic_table ();
+
+ fprintf (outfile, "#define MNEMONIC_BITS %zu\n", best_mnemonic_bits);
+#else
+ fprintf (outfile, "#define MNEMONIC_BITS %ld\n",
+ lrint (ceil (log2 (NMNES))));
+#endif
+ fprintf (outfile, "#define SUFFIX_BITS %d\n", nbitsuf);
+ for (int i = 0; i < 3; ++i)
+ {
+ fprintf (outfile, "#define FCT%d_BITS %d\n", i + 1, nbitfct[i]);
+ if (nbitstr[i] != 0)
+ fprintf (outfile, "#define STR%d_BITS %d\n", i + 1, nbitstr[i]);
+ fprintf (outfile, "#define OFF%d_1_BITS %d\n", i + 1, nbitoff[i][0]);
+ fprintf (outfile, "#define OFF%d_1_BIAS %d\n", i + 1, minoff[i][0]);
+ if (nbitoff[i][1] != 0)
+ {
+ fprintf (outfile, "#define OFF%d_2_BITS %d\n", i + 1, nbitoff[i][1]);
+ fprintf (outfile, "#define OFF%d_2_BIAS %d\n", i + 1, minoff[i][1]);
+ }
+ if (nbitoff[i][2] != 0)
+ {
+ fprintf (outfile, "#define OFF%d_3_BITS %d\n", i + 1, nbitoff[i][2]);
+ fprintf (outfile, "#define OFF%d_3_BIAS %d\n", i + 1, minoff[i][2]);
+ }
+ }
+
+ fputs ("\n#include <i386_data.h>\n\n", outfile);
+
+
+#define APPEND(a, b) APPEND_ (a, b)
+#define APPEND_(a, b) a##b
+#define EMIT_SUFFIX(suf) \
+ fprintf (outfile, "#define suffix_%s %d\n", #suf, APPEND (suffix_, suf))
+ EMIT_SUFFIX (none);
+ EMIT_SUFFIX (w);
+ EMIT_SUFFIX (w0);
+ EMIT_SUFFIX (W);
+ EMIT_SUFFIX (tttn);
+ EMIT_SUFFIX (D);
+ EMIT_SUFFIX (w1);
+
+ fputc_unlocked ('\n', outfile);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ /* Functions. */
+ count_op_str = 0;
+ fprintf (outfile, "static opfct_t op%d_fct[] =\n{\n NULL,\n", i + 1);
+ twalk (fct_names[i], print_op_fct);
+ fputs ("};\n", outfile);
+
+ /* The operand strings. */
+ if (nbitstr[i] != 0)
+ {
+ count_op_str = 0;
+ fprintf (outfile, "static const char *op%d_str[] =\n{\n NULL,\n",
+ i + 1);
+ twalk (strs[i], print_op_str);
+ fputs ("};\n", outfile);
+ }
+ }
+
+
+ fputs ("static const struct instr_enc instrtab[] =\n{\n", outfile);
+ struct instruction *instr;
+ for (instr = instructions; instr != NULL; instr = instr->next)
+ {
+ fputs (" {", outfile);
+ if (instr->mnemonic == (void *) -1l)
+ fputs (" .mnemonic = MNE_INVALID,", outfile);
+ else
+ fprintf (outfile, " .mnemonic = MNE_%s,", instr->mnemonic);
+ fprintf (outfile, " .rep = %d,", instr->rep);
+ fprintf (outfile, " .repe = %d,", instr->repe);
+ fprintf (outfile, " .suffix = %d,", instr->suffix);
+ fprintf (outfile, " .modrm = %d,", instr->modrm);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ int idx = 0;
+ if (instr->operands[i].fct != NULL)
+ {
+ struct argstring search = { .str = instr->operands[i].fct };
+ struct argstring **res = tfind (&search, &fct_names[i],
+ compare_argstring);
+ assert (res != NULL);
+ idx = (*res)->idx;
+ }
+ fprintf (outfile, " .fct%d = %d,", i + 1, idx);
+
+ idx = 0;
+ if (instr->operands[i].str != NULL)
+ {
+ struct argstring search = { .str = instr->operands[i].str };
+ struct argstring **res = tfind (&search, &strs[i],
+ compare_argstring);
+ assert (res != NULL);
+ idx = (*res)->idx;
+ }
+ if (nbitstr[i] != 0)
+ fprintf (outfile, " .str%d = %d,", i + 1, idx);
+
+ fprintf (outfile, " .off%d_1 = %d,", i + 1,
+ MAX (0, instr->operands[i].off1 - minoff[i][0]));
+
+ if (nbitoff[i][1] != 0)
+ fprintf (outfile, " .off%d_2 = %d,", i + 1,
+ MAX (0, instr->operands[i].off2 - minoff[i][1]));
+
+ if (nbitoff[i][2] != 0)
+ fprintf (outfile, " .off%d_3 = %d,", i + 1,
+ MAX (0, instr->operands[i].off3 - minoff[i][2]));
+ }
+
+ fputs (" },\n", outfile);
+ }
+ fputs ("};\n", outfile);
+
+ fputs ("static const uint8_t match_data[] =\n{\n", outfile);
+ size_t cnt = 0;
+ for (instr = instructions; instr != NULL; instr = instr->next, ++cnt)
+ {
+ /* First count the number of bytes. */
+ size_t totalbits = 0;
+ size_t zerobits = 0;
+ struct bitvalue *b = instr->bytes;
+ while (b != NULL)
+ {
+ if (b->type == zeroone)
+ {
+ ++totalbits;
+ zerobits = 0;
+ }
+ else
+ {
+ totalbits += b->field->bits;
+ /* We must always count the mod/rm byte. */
+ if (strncasecmp (b->field->name, "mod", 3) == 0)
+ zerobits = 0;
+ else
+ zerobits += b->field->bits;
+ }
+ b = b->next;
+ }
+ size_t nbytes = (totalbits - zerobits + 7) / 8;
+ assert (nbytes > 0);
+
+ fprintf (outfile, " %#zx,", nbytes);
+
+ /* Now create the mask and byte values. */
+ uint8_t byte = 0;
+ uint8_t mask = 0;
+ int nbits = 0;
+ b = instr->bytes;
+ while (b != NULL)
+ {
+ if (b->type == zeroone)
+ {
+ byte = (byte << 1) | b->value;
+ mask = (mask << 1) | 1;
+ if (++nbits == 8)
+ {
+ fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", mask, byte);
+ byte = mask = nbits = 0;
+ if (--nbytes == 0)
+ break;
+ }
+ }
+ else
+ {
+ unsigned long int remaining = b->field->bits;
+ while (nbits + remaining > 8)
+ {
+ fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",",
+ mask << (8 - nbits), byte << (8 - nbits));
+ remaining = nbits + remaining - 8;
+ byte = mask = nbits = 0;
+ if (--nbytes == 0)
+ break;
+ }
+ byte <<= remaining;
+ mask <<= remaining;
+ nbits += remaining;
+ if (nbits == 8)
+ {
+ fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", mask, byte);
+ byte = mask = nbits = 0;
+ if (--nbytes == 0)
+ break;
+ }
+ }
+ b = b->next;
+ }
+
+ fprintf (outfile, " %#zx, %#zx,\n", cnt & 0xff, cnt >> 8);
+ }
+ fputs ("};\n", outfile);
+}
+
+
+#if 0
+static size_t mnemonic_maxlen;
+static size_t mnemonic_minlen;
+static size_t
+which_chars (const char *str[], size_t nstr)
+{
+ char used_char[256];
+ memset (used_char, '\0', sizeof (used_char));
+ mnemonic_maxlen = 0;
+ mnemonic_minlen = 10000;
+ for (size_t cnt = 0; cnt < nstr; ++cnt)
+ {
+ const unsigned char *cp = (const unsigned char *) str[cnt];
+ mnemonic_maxlen = MAX (mnemonic_maxlen, strlen ((char *) cp));
+ mnemonic_minlen = MIN (mnemonic_minlen, strlen ((char *) cp));
+ do
+ used_char[*cp++] = 1;
+ while (*cp != '\0');
+ }
+ size_t nused_char = 0;
+ for (size_t cnt = 0; cnt < 256; ++cnt)
+ if (used_char[cnt] != 0)
+ ++nused_char;
+ return nused_char;
+}
+
+
+static const char **mnemonic_strs;
+static size_t nmnemonic_strs;
+static void
+add_mnemonics (const void *nodep, VISIT value,
+ int level __attribute__ ((unused)))
+{
+ if (value == leaf || value == postorder)
+ mnemonic_strs[nmnemonic_strs++] = *(const char **) nodep;
+}
+
+
+struct charfreq
+{
+ char ch;
+ int freq;
+};
+static struct charfreq pfxfreq[256];
+static struct charfreq sfxfreq[256];
+
+
+static int
+compare_freq (const void *p1, const void *p2)
+{
+ const struct charfreq *c1 = (const struct charfreq *) p1;
+ const struct charfreq *c2 = (const struct charfreq *) p2;
+
+ if (c1->freq > c2->freq)
+ return -1;
+ if (c1->freq < c2->freq)
+ return 1;
+ return 0;
+}
+
+
+static size_t
+compute_pfxfreq (const char *str[], size_t nstr)
+{
+ memset (pfxfreq, '\0', sizeof (pfxfreq));
+
+ for (size_t i = 0; i < nstr; ++i)
+ pfxfreq[i].ch = i;
+
+ for (size_t i = 0; i < nstr; ++i)
+ ++pfxfreq[*((const unsigned char *) str[i])].freq;
+
+ qsort (pfxfreq, 256, sizeof (struct charfreq), compare_freq);
+
+ size_t n = 0;
+ while (n < 256 && pfxfreq[n].freq != 0)
+ ++n;
+ return n;
+}
+
+
+struct strsnlen
+{
+ const char *str;
+ size_t len;
+};
+
+static size_t
+compute_sfxfreq (size_t nstr, struct strsnlen *strsnlen)
+{
+ memset (sfxfreq, '\0', sizeof (sfxfreq));
+
+ for (size_t i = 0; i < nstr; ++i)
+ sfxfreq[i].ch = i;
+
+ for (size_t i = 0; i < nstr; ++i)
+ ++sfxfreq[((const unsigned char *) strchrnul (strsnlen[i].str, '\0'))[-1]].freq;
+
+ qsort (sfxfreq, 256, sizeof (struct charfreq), compare_freq);
+
+ size_t n = 0;
+ while (n < 256 && sfxfreq[n].freq != 0)
+ ++n;
+ return n;
+}
+
+
+static void
+create_mnemonic_table (void)
+{
+ mnemonic_strs = xmalloc (nmnemonics * sizeof (char *));
+
+ twalk (mnemonics, add_mnemonics);
+
+ (void) which_chars (mnemonic_strs, nmnemonic_strs);
+
+ size_t best_so_far = 100000000;
+ char *best_prefix = NULL;
+ char *best_suffix = NULL;
+ char *best_table = NULL;
+ size_t best_table_size = 0;
+ size_t best_table_bits = 0;
+ size_t best_prefix_bits = 0;
+
+ /* We can precompute the prefix characters. */
+ size_t npfx_char = compute_pfxfreq (mnemonic_strs, nmnemonic_strs);
+
+ /* Compute best size for string representation including explicit NUL. */
+ for (size_t pfxbits = 0; (1u << pfxbits) < 2 * npfx_char; ++pfxbits)
+ {
+ char prefix[1 << pfxbits];
+ size_t i;
+ for (i = 0; i < (1u << pfxbits) - 1; ++i)
+ prefix[i] = pfxfreq[i].ch;
+ prefix[i] = '\0';
+
+ struct strsnlen strsnlen[nmnemonic_strs];
+
+ for (i = 0; i < nmnemonic_strs; ++i)
+ {
+ if (strchr (prefix, *mnemonic_strs[i]) != NULL)
+ strsnlen[i].str = mnemonic_strs[i] + 1;
+ else
+ strsnlen[i].str = mnemonic_strs[i];
+ strsnlen[i].len = strlen (strsnlen[i].str);
+ }
+
+ /* With the prefixes gone, try to combine strings. */
+ size_t nstrsnlen = 1;
+ for (i = 1; i < nmnemonic_strs; ++i)
+ {
+ size_t j;
+ for (j = 0; j < nstrsnlen; ++j)
+ if (strsnlen[i].len > strsnlen[j].len
+ && strcmp (strsnlen[j].str,
+ strsnlen[i].str + (strsnlen[i].len
+ - strsnlen[j].len)) == 0)
+ {
+ strsnlen[j] = strsnlen[i];
+ break;
+ }
+ else if (strsnlen[i].len < strsnlen[j].len
+ && strcmp (strsnlen[i].str,
+ strsnlen[j].str + (strsnlen[j].len
+ - strsnlen[i].len)) == 0)
+ break;
+;
+ if (j == nstrsnlen)
+ strsnlen[nstrsnlen++] = strsnlen[i];
+ }
+
+ size_t nsfx_char = compute_sfxfreq (nstrsnlen, strsnlen);
+
+ for (size_t sfxbits = 0; (1u << sfxbits) < 2 * nsfx_char; ++sfxbits)
+ {
+ char suffix[1 << sfxbits];
+
+ for (i = 0; i < (1u << sfxbits) - 1; ++i)
+ suffix[i] = sfxfreq[i].ch;
+ suffix[i] = '\0';
+
+ size_t newlen[nstrsnlen];
+
+ for (i = 0; i < nstrsnlen; ++i)
+ if (strchr (suffix, strsnlen[i].str[strsnlen[i].len - 1]) != NULL)
+ newlen[i] = strsnlen[i].len - 1;
+ else
+ newlen[i] = strsnlen[i].len;
+
+ char charused[256];
+ memset (charused, '\0', sizeof (charused));
+ size_t ncharused = 0;
+
+ const char *tablestr[nstrsnlen];
+ size_t ntablestr = 1;
+ tablestr[0] = strsnlen[0].str;
+ size_t table = newlen[0] + 1;
+ for (i = 1; i < nstrsnlen; ++i)
+ {
+ size_t j;
+ for (j = 0; j < ntablestr; ++j)
+ if (newlen[i] > newlen[j]
+ && memcmp (tablestr[j],
+ strsnlen[i].str + (newlen[i] - newlen[j]),
+ newlen[j]) == 0)
+ {
+ table += newlen[i] - newlen[j];
+ tablestr[j] = strsnlen[i].str;
+ newlen[j] = newlen[i];
+ break;
+ }
+ else if (newlen[i] < newlen[j]
+ && memcmp (strsnlen[i].str,
+ tablestr[j] + (newlen[j] - newlen[i]),
+ newlen[i]) == 0)
+ break;
+
+ if (j == ntablestr)
+ {
+ table += newlen[i] + 1;
+ tablestr[ntablestr] = strsnlen[i].str;
+ newlen[ntablestr] = newlen[i];
+
+ ++ntablestr;
+ }
+
+ for (size_t x = 0; x < newlen[j]; ++x)
+ if (charused[((const unsigned char *) tablestr[j])[x]]++ == 0)
+ ++ncharused;
+ }
+
+ size_t ncharused_bits = 0;
+ i = 1;
+ while (i < ncharused)
+ {
+ i *= 2;
+ ++ncharused_bits;
+ }
+
+ size_t table_bits = 0;
+ i = 1;
+ while (i < table)
+ {
+ i *= 2;
+ ++table_bits;
+ }
+
+ size_t mnemonic_bits = table_bits + pfxbits + sfxbits;
+ size_t new_total = (((table + 7) / 8) * ncharused_bits + ncharused
+ + (pfxbits == 0 ? 0 : (1 << pfxbits) - 1)
+ + (sfxbits == 0 ? 0 : (1 << sfxbits) - 1)
+ + (((total_bits + mnemonic_bits + 7) / 8)
+ * ninstructions));
+
+ if (new_total < best_so_far)
+ {
+ best_so_far = new_total;
+ best_mnemonic_bits = mnemonic_bits;
+
+ free (best_suffix);
+ best_suffix = xstrdup (suffix);
+
+ free (best_prefix);
+ best_prefix = xstrdup (prefix);
+ best_prefix_bits = pfxbits;
+
+ best_table_size = table;
+ best_table_bits = table_bits;
+ char *cp = best_table = xrealloc (best_table, table);
+ for (i = 0; i < ntablestr; ++i)
+ {
+ assert (cp + newlen[i] + 1 <= best_table + table);
+ cp = mempcpy (cp, tablestr[i], newlen[i]);
+ *cp++ = '\0';
+ }
+ assert (cp == best_table + table);
+ }
+ }
+ }
+
+ fputs ("static const char mnemonic_table[] =\n\"", outfile);
+ for (size_t i = 0; i < best_table_size; ++i)
+ {
+ if (((i + 1) % 60) == 0)
+ fputs ("\"\n\"", outfile);
+ if (!isascii (best_table[i]) || !isprint (best_table[i]))
+ fprintf (outfile, "\\%03o", best_table[i]);
+ else
+ fputc (best_table[i], outfile);
+ }
+ fputs ("\";\n", outfile);
+
+ if (best_prefix[0] != '\0')
+ fprintf (outfile,
+ "static const char prefix[%zu] = \"%s\";\n"
+ "#define PREFIXCHAR_BITS %zu\n",
+ strlen (best_prefix), best_prefix, best_prefix_bits);
+ else
+ fputs ("#define NO_PREFIX\n", outfile);
+
+ if (best_suffix[0] != '\0')
+ fprintf (outfile, "static const char suffix[%zu] = \"%s\";\n",
+ strlen (best_suffix), best_suffix);
+ else
+ fputs ("#define NO_SUFFIX\n", outfile);
+
+ for (size_t i = 0; i < nmnemonic_strs; ++i)
+ {
+ const char *mne = mnemonic_strs[i];
+
+ size_t pfxval = 0;
+ char *cp = strchr (best_prefix, *mne);
+ if (cp != NULL)
+ {
+ pfxval = 1 + (cp - best_prefix);
+ ++mne;
+ }
+
+ size_t l = strlen (mne);
+
+ size_t sfxval = 0;
+ cp = strchr (best_suffix, mne[l - 1]);
+ if (cp != NULL)
+ {
+ sfxval = 1 + (cp - best_suffix);
+ --l;
+ }
+
+ char *off = memmem (best_table, best_table_size, mne, l);
+ while (off[l] != '\0')
+ {
+ off = memmem (off + 1, best_table_size, mne, l);
+ assert (off != NULL);
+ }
+
+ fprintf (outfile, "#define MNE_%s %#zx\n",
+ mnemonic_strs[i],
+ (off - best_table)
+ + ((pfxval + (sfxval << best_prefix_bits)) << best_table_bits));
+ }
+}
+#endif
diff --git a/libcpu/memory-access.h b/libcpu/memory-access.h
new file mode 100644
index 00000000..0d61f485
--- /dev/null
+++ b/libcpu/memory-access.h
@@ -0,0 +1,168 @@
+/* Unaligned memory access functionality.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifndef _MEMORY_ACCESS_H
+#define _MEMORY_ACCESS_H 1
+
+#include <byteswap.h>
+#include <endian.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+/* When loading this file we require the macro MACHINE_ENCODING to be
+ defined to signal the endianness of the architecture which is
+ defined. */
+#ifndef MACHINE_ENCODING
+# error "MACHINE_ENCODING needs to be defined"
+#endif
+#if MACHINE_ENCODING != __BIG_ENDIAN && MACHINE_ENCODING != __LITTLE_ENDIAN
+# error "MACHINE_ENCODING must signal either big or little endian"
+#endif
+
+
+/* We use simple memory access functions in case the hardware allows it.
+ The caller has to make sure we don't have alias problems. */
+#if ALLOW_UNALIGNED
+
+# define read_2ubyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? bswap_16 (*((const uint16_t *) (Addr))) \
+ : *((const uint16_t *) (Addr)))
+# define read_2sbyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
+ : *((const int16_t *) (Addr)))
+
+# define read_4ubyte_unaligned_noncvt(Addr) \
+ *((const uint32_t *) (Addr))
+# define read_4ubyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? bswap_32 (*((const uint32_t *) (Addr))) \
+ : *((const uint32_t *) (Addr)))
+# define read_4sbyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
+ : *((const int32_t *) (Addr)))
+
+# define read_8ubyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? bswap_64 (*((const uint64_t *) (Addr))) \
+ : *((const uint64_t *) (Addr)))
+# define read_8sbyte_unaligned(Addr) \
+ (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \
+ ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
+ : *((const int64_t *) (Addr)))
+
+#else
+
+union unaligned
+ {
+ void *p;
+ uint16_t u2;
+ uint32_t u4;
+ uint64_t u8;
+ int16_t s2;
+ int32_t s4;
+ int64_t s8;
+ } __attribute__ ((packed));
+
+static inline uint16_t
+read_2ubyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return bswap_16 (up->u2);
+ return up->u2;
+}
+static inline int16_t
+read_2sbyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return (int16_t) bswap_16 (up->u2);
+ return up->s2;
+}
+
+static inline uint32_t
+read_4ubyte_unaligned_noncvt (const void *p)
+{
+ const union unaligned *up = p;
+ return up->u4;
+}
+static inline uint32_t
+read_4ubyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return bswap_32 (up->u4);
+ return up->u4;
+}
+static inline int32_t
+read_4sbyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return (int32_t) bswap_32 (up->u4);
+ return up->s4;
+}
+
+static inline uint64_t
+read_8ubyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return bswap_64 (up->u8);
+ return up->u8;
+}
+static inline int64_t
+read_8sbyte_unaligned (const void *p)
+{
+ const union unaligned *up = p;
+ if (MACHINE_ENCODING != __BYTE_ORDER)
+ return (int64_t) bswap_64 (up->u8);
+ return up->s8;
+}
+
+#endif /* allow unaligned */
+
+
+#define read_2ubyte_unaligned_inc(Addr) \
+ ({ uint16_t t_ = read_2ubyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
+ t_; })
+#define read_2sbyte_unaligned_inc(Addr) \
+ ({ int16_t t_ = read_2sbyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
+ t_; })
+
+#define read_4ubyte_unaligned_inc(Addr) \
+ ({ uint32_t t_ = read_4ubyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
+ t_; })
+#define read_4sbyte_unaligned_inc(Addr) \
+ ({ int32_t t_ = read_4sbyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
+ t_; })
+
+#define read_8ubyte_unaligned_inc(Addr) \
+ ({ uint64_t t_ = read_8ubyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
+ t_; })
+#define read_8sbyte_unaligned_inc(Addr) \
+ ({ int64_t t_ = read_8sbyte_unaligned (Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
+ t_; })
+
+#endif /* memory-access.h */
diff --git a/libcpu/x86_64_disasm.c b/libcpu/x86_64_disasm.c
new file mode 100644
index 00000000..f6ae7957
--- /dev/null
+++ b/libcpu/x86_64_disasm.c
@@ -0,0 +1,5 @@
+#define i386_disasm x86_64_disasm
+#define DISFILE "x86_64_dis.h"
+#define MNEFILE "x86_64.mnemonics"
+#define X86_64
+#include "i386_disasm.c"