From 3cbdd387c752999255aea91600b5cfdefbeac7d0 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 2 Jan 2008 17:44:39 +0000 Subject: propagate from branch 'com.redhat.elfutils.disasm' (head d15b4eb794e81e477f9896fe82a74cb5ecf4514c) to branch 'com.redhat.elfutils' (head eaacbf01f8cc89d043ec6eca9b5e35cb5c4cde06) --- libcpu/ChangeLog | 181 ++++++ libcpu/Makefile.am | 57 +- libcpu/defs/i386 | 634 +++++++++++++++++++ libcpu/defs/i386.doc | 74 +++ libcpu/defs/x86_64 | 341 ++++++++++ libcpu/i386_data.h | 1406 +++++++++++++++++++++++++++++++++++++++++ libcpu/i386_disasm.c | 914 +++++++++++++++++++++++++++ libcpu/i386_gendis.c | 39 ++ libcpu/i386_lex.l | 115 ++++ libcpu/i386_parse.y | 1641 ++++++++++++++++++++++++++++++++++++++++++++++++ libcpu/memory-access.h | 168 +++++ libcpu/x86_64_disasm.c | 5 + 12 files changed, 5570 insertions(+), 5 deletions(-) create mode 100644 libcpu/defs/i386 create mode 100644 libcpu/defs/i386.doc create mode 100644 libcpu/defs/x86_64 create mode 100644 libcpu/i386_data.h create mode 100644 libcpu/i386_disasm.c create mode 100644 libcpu/i386_gendis.c create mode 100644 libcpu/i386_lex.l create mode 100644 libcpu/i386_parse.y create mode 100644 libcpu/memory-access.h create mode 100644 libcpu/x86_64_disasm.c (limited to 'libcpu') 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * i386_data.h: Fix SIB handling. + * i386_disasm.c: Likewise. + +2007-12-19 Ulrich Drepper + + * defs/i386: Fix up 'and' opcode. + +2007-10-31 Ulrich Drepper + + * 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 + + * 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 * 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 @@ ## . ## 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$( $@ +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$( $@ + +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 = , 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 = +{0g} 00 = b, 01 = w, 10 = , 11 = +{GG} 00 = , 01 = w, 10 = d, 11 = q +{gG} 00 = , 01 = w, 10 = d, 11 = + +{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 +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +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, ¶m_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, ¶m_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, ¶m_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 +#include +#include +#include +#include + + +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 ", 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 , 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 +#endif + +#include +#include +#include + +#include +#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; } + + +
"0" { return '0'; } +
"1" { return '1'; } + +"{"{ID2}"}" { i386_lval.str = xstrndup (yytext + 1, + yyleng - 2); + return kBITFIELD; } + +
"INVALID" { i386_lval.str = (void *) -1l; + return kID; } + +
{ID} { i386_lval.str = xstrndup (yytext, yyleng); + return kID; } + +
"," { return ','; } + +
":" { return ':'; } + +^"\n" { /* IGNORE */ } + +"\n" { return '\n'; } + +^"#" { eat_to_eol (); } + +{WHITE} { /* IGNORE */ } + +
{WHITE} { return kSPACE; } + +
. { 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 , 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 kID +%token kNUMBER +%token kPERCPERC +%token kBITFIELD +%token kCHAR +%token kSPACE + +%type bit byte bytes +%type bitfieldopt +%type argcomp arg +%type 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 \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 , 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 +#include +#include +#include + + +/* 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" -- cgit v1.2.3