diff options
Diffstat (limited to 'libcpu')
-rw-r--r-- | libcpu/ChangeLog | 357 | ||||
-rw-r--r-- | libcpu/Makefile.am | 72 | ||||
-rw-r--r-- | libcpu/Makefile.in | 547 | ||||
-rw-r--r-- | libcpu/defs/i386 | 970 | ||||
-rw-r--r-- | libcpu/i386_data.h | 1415 | ||||
-rw-r--r-- | libcpu/i386_disasm.c | 1054 | ||||
-rw-r--r-- | libcpu/i386_gendis.c | 69 | ||||
-rw-r--r-- | libcpu/i386_lex.c | 2011 | ||||
-rw-r--r-- | libcpu/i386_lex.l | 126 | ||||
-rw-r--r-- | libcpu/i386_parse.c | 3356 | ||||
-rw-r--r-- | libcpu/i386_parse.h | 95 | ||||
-rw-r--r-- | libcpu/i386_parse.y | 1684 | ||||
-rw-r--r-- | libcpu/memory-access.h | 179 | ||||
-rw-r--r-- | libcpu/x86_64_disasm.c | 31 |
14 files changed, 11966 insertions, 0 deletions
diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog new file mode 100644 index 0000000..c49f8b9 --- /dev/null +++ b/libcpu/ChangeLog @@ -0,0 +1,357 @@ +2010-08-16 Roland McGrath <roland@redhat.com> + + * Makefile.am (%_defs): New pattern rule. + (%_dis.h, %.mnemonics): Define as pattern rules using %_defs input. + (CLEANFILES): Include all those files. + +2010-02-15 Roland McGrath <roland@redhat.com> + + * Makefile.am: Use config/eu.am for common stuff. + +2009-04-14 Roland McGrath <roland@redhat.com> + + * Makefile.am (AM_CFLAGS): Add -fdollars-in-identifiers; it is not the + default on every machine. + +2009-01-23 Roland McGrath <roland@redhat.com> + + * Makefile.am (i386_parse_CFLAGS): Use quotes around command + substitution that can produce leading whitespace. + +2009-01-01 Ulrich Drepper <drepper@redhat.com> + + * i386_parse.y (instrtable_out): Optimize match_data table by not + emitting 0xff masks for leading bytes. + * i386_disasm.c (i386_disasm): Adjust reader of match_data. + + * i386_disasm.c (i386_disasm): Reset bufcnt when not matched. We + don't expect snprintf to fail. + +2008-12-31 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add dppd, dpps, insertps, movntdqa, mpsadbw, packusdw, + pblendvb, pblendw, pcmpeqq, pcmpestri, pcmpestrm, pcmpistri, pcmpistrm, + pcmpgtq, phminposuw, pinsrb, pinsrd, pmaxsb, pmaxsd, pmaxud, pmaxuw, + pminsb, pminsd, pminud, pminuw, pmovsxbw, pmovsxbd, pmovsxbq, pmovsxwd, + pmovsxwq, pmovsxdq, pmovzxbw, pmovzxbd, pmovzxbq, pmovzxwd, pmovzxwq, + pmovzxdq, pmuldq, pmulld, popcnt, ptest, roundss, roundps, roundpd, + and roundsd opcodes. + + * i386_disasm.c (i386_disasm): Correct resizing of buffer. + + * i386_parse.y (struct argstring): Add off element. + (off_op_str): New global variable. + (print_op_str): Print strings as concatenated strings. Keep track + of index and length. Update ->off element. + (print_op_str_idx): New function. + (instrtable_out): Mark op%d_fct as const. + Emit two tables for the strings: the string itself (op%d_str) and the + index table (op%d_str_idx). + * i386_disasm.c (i386_disasm): Adjust for new op%d_str definition. + + * i386_disasm.c [X86_64] (i386_disasm): Handle rex prefix when + printing only prefix. + + * i386_disasm.c (i386_disasm): Minor optimizations. + + * i386_parse.y (instrtable_out): No need to emit index, the reader can + keep track. + * i386_disasm.c (i386_disasm): The index is not emitted anymore, no + need to skip it. + + * i386_disasm.c (amd3dnow): Mark as const. + + * defs/i386: Add blendvpd and blendvps opcodes. + +2008-12-30 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add blendpd and blendps opcodes. + +2008-12-19 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add entry for AMD 3DNOW. + * i386_disasm.c: Implement AMD 3DNOW disassembly. + +2008-12-17 Ulrich Drepper <drepper@redhat.com> + + * i386_disasm.c (i386_disasm): If instruction matches prefix, + undoing the prefix match finishes the instruction. + +2008-01-21 Roland McGrath <roland@redhat.com> + + * defs/i386: Fix typo in comment. + * i386_disasm.c (i386_disasm): Handle cltq, cqto. + + * i386_parse.y: Add sanity check for NMNES macro value. + * Makefile.am (i386_parse.o): Fix target in dependency rule. + (i386_parse.h): New target with empty commands. + (i386_lex.o): Depend on it in place of i386_parse.c. + +2008-01-21 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am (EXTRA_DIST): Remove defs/x86_64. + +2008-01-14 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add fixes for opcodes with register number in opcode, + 64-bit immediate forms, nop with rex.B. + * i386_data.h [X86_64] (FCT_imm64$w): New function. + (FCT_oreg): New function. + (FCT_oreg$w): New function. + * i386_disasm.c (i386_disasm): Reinitialize fmt always before + starting the loop to process the string. Handle 0x90 special for + x86-64. + * i386_parse.y (fillin_arg): Expand synonyms before concatening to + form the function name. + +2008-01-11 Ulrich Drepper <drepper@redhat.com> + + * i386_disasm.c (struct output_buffer): Remove symcb and symcbarg. + (i386_disasm): Remove appropriate initializers. + Use symcb to lookup symbol strings. + + * i386_disasm.c (struct output_buffer): Add labelbuf, labelbufsize, + symaddr_use, and symaddr fields. + (i386_disasm): Remove labelbuf and labelbufsize variables. + Add back %e format. Implement %a and %l formats. + + * i386_data.h (general_mod$r_m): Set symaddr_use and symaddr for %rip + base addressing. + + * i386_disasm.c (i386_disasm): Resize output buffer if necessary. + Optimize output_data initialization. Free buffers before return. + (struct output_data): Remove op1str field. Adjust code. + (i386_disasm): Store final NUL btye at end of functions. + +2008-01-10 Ulrich Drepper <drepper@redhat.com> + + * i386_data.h (FCT_crdb): New function. + (FCT_ccc): Use FCT_crdb. + (FCT_ddd): Likewise. + + * defs/i386: Fix a few instructions with immediate arguments. + + * i386_disasm.c: Rewrite interface to callback functions for operands + to take a single pointer to a structure. + * i386_data.h: Adjust all functions. + +2008-01-08 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Enable x86-64 again. + * defs/i386: Lots of changes for x86-64. + * i386_data.h: Add support for use in x86-64 disassembler. + * i386_disasm.c: Likewise. + * i386_parse.y: Likewise. + * defs/x86_64: Removed. + +2008-01-04 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Cleanups, remove masks which are not needed. + Add remaining Intel opcodes. + * i386_data.h (FCT_imm8): Check for input buffer overrun. + * i386_disasm.c (i386_disasm): Likewise. + * i386_parse.y: Remove suffixes which are not needed anymore. + +2008-01-03 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add yet more SSE instructions. + +2008-01-02 Ulrich Drepper <drepper@redhat.com> + + * i386_disasm.c (i386_disasm): Extend matcher to allow tables to + contain instructions with prefixes. + * defs/i386: Use for many SSE operations. + * i386_data.h (FCT_mmxreg2): Removed. + +2008-01-01 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: More 0f prefix support. + * i386_data.h (FCT_mmxreg): Implement. + (FCT_mmxreg2): Implement. + (FCT_mmreg): Remove. + * i386_disasm.c (i386_disasm): More special instructions. + Fix tttn suffix for cmov. + * i386_parse.y: Simplify test for mod/r_m mode. + +2007-12-31 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Fix order or arguments for mov of control/debug registers. + * i386_data.h (FCT_ccc): Implement + (FCT_ddd): Implement + +2007-12-30 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Fix 0f groups 6 and 7. + * i386_data.c (FCT_mod$16r_m): Implement. + * i386_disasm.c (i386_disasm): Third parameter can also have string. + +2007-12-29 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Add lots of floating point ops. + * i386_data.h (FCT_fmod$fr_m): Removed. + (FCT_freg): Implement. + * i386_disasm.c (i386_disasm): Implement suffix_D. + * i386_parse.y: Emit suffix_D. + + * defs/i386: Use rel instead of dispA. + Fix lcall, dec, div, idiv, imul, inc, jmp, ljmp, mul, neg, not, push, + test. + + * i386_data.h (FCT_dispA): Removed. + (FCT_ds_xx): Add test for end of input buffer. + * i386_disasm.c (ABORT_ENTRY): Removed. + (i386_disasm): Fix handling of SIB. Pass correct address value to + operand callbacks. + + * Makefile.am (*.mnemonics): Filter out INVALID entry. + * defs/i386: Define imms8 and use in appropriate places. + Add INVALID entries for special opcodes with special mnemonics. + Fix int3. Fix typo in shl. Correct xlat. + * i386_data.h (FCT_ds_xx): New function. + (FCT_ds_si): Use it. + (FCT_ds_bx): New function. + (FCT_imms8): New function. + * i386_disasm.c (MNE_INVALID): Define. + (i386_disasm): Handle invalid opcodes in mnemonics printing, not + separately. Fix address value passed to operand handlers. + * i386_parse.y (bx_reg): Define. + (instrtable_out): Handle INVALID entries differently, just use + MNE_INVALID value for .mnemonic. + +2007-12-28 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Fix shift and mov immediate instructions. + * i386_data.h (FCT_imm16): Implement. + + * defs/i386: Use absval instead of abs of lcall and ljmp. + Add parameters for cmps. Fix test and mov immediate. + * i386_data.h: Implement FCT_absval. + * i386_disasm.c: Handle data16 for suffix_w and FCT_imm. + + * defs/i386: Move entries with 0x9b prefix together. + * i386_disasm.c (i386_disasm): Fix recognizing insufficient bytes in + input. Handle data16 with suffix_W. + + * i386_data.h (FCT_*): Add end parameter to all functions. Check + before using more bytes. + (FCT_sel): Implement. + * i386_disasm.c (i386_disasm): Better handle end of input buffer. + Specal opcode 0x99. + + * Makefile.am: Use m4 to preprocess defs/* files. + * defs/i386: Adjust appropriately. + * i386_data.c (FCT_ax): Implement. + (FCT_ax$w): Use FCT_ax. + * i386_disasm.c (ADD_STRING): Use _len instead of len. + (i386_disasm): If no instruction can be matched because of lack of + input and prefixes have been matched, print prefixes. + Recognize abort entries. + Handle special cases. + * i386_gendis.c: Recognize - input file name. + * i386_lex.c: Recognize INVALID token. + * i386_parse.y: Handle INVALID token input. + + * defs/i386: Fix mov, pop. + * i386_data.h (FCT_sreg3): Implement. + +2007-12-27 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Fix adc, add, cmp, or, sbb, sub, xchg, xor. + * i386_data.h (FCT_imms): New function. + (FCT_imm$s): Use FCT_imms for handling of signed values. + (FCT_imm8): Sign extend values. + * i386_disasm.c (i386_disasm): Implement suffix_w0. + * i386_parse.y: Emit suffix w0. + + * i386_data.h (FCT_disp8): Add 0x prefix. + (FCT_ds_si): Implement. + * i386_disasm.c (i386_disasm): Increment addr for invalid prefixes. + Implement tttn suffix. + * i386_parse.y: Emit tttn suffix definition. + +2007-12-26 Ulrich Drepper <drepper@redhat.com> + + * i386_data.h (struct instr_enc): Use suffix field. + (FCT_dx): Fill in body. + (FCT_es_di): Likewise. + (FCT_imm$s): Sign-extended byte values. + * i386_disasm.c: Protect ADD_CHAR and ADD_STRING macros. Adjust uses. + (i386_disasm): Handle suffix. + * i386_parse.y: Emit suffix information. + * defs/i386: Remove unnecessary suffixes. + + * Makefile.am: Disable building x86-64 version for now. + + * defs/i386: Fix and, bound, cmp, or, pop, sbb, sub, xor. + * i386_data.h: Pass pointer to prefix to functions. If not prefixes + are consumed this means invalid input. + * i386_disasm.c: Fix prefix printing. Adjust function calls for + parameter change. + * i386_parse.y: Recognize moda prefix. + +2007-12-21 Ulrich Drepper <drepper@redhat.com> + + * i386_data.h: Fix SIB handling. + * i386_disasm.c: Likewise. + +2007-12-19 Ulrich Drepper <drepper@redhat.com> + + * defs/i386: Fix up 'and' opcode. + +2007-10-31 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Add dependencies of the generated files on the source + files. + (i386_lex_CFLAGS): Add -Wno-sign-compare. + + * defs/i386: A lot more data. + * defs/x86_64: Likewise. + * i386_data.h (struct instr_enc): Add off1_3, off2_3, and off3_3 + fields. + (opfct_t): Add parameter for third operand. + (FCT_*): Likewise. + (data_prefix): New function. + (FCT_abs): Implement. + (FCT_ax): Renamed to FCT_ax$w amd implement. + (FCT_disp8): Implement. + (FCT_dispA): Implement. + (FCT_imm): Implement. + (FCT_imm$w): Implement. + (FCT_imm$s): Don't zero-pad numbers. + (FCT_imm8): Likewise. + (FCT_rel): Likewise. + (general_mod$r_m): New function. + (FCT_mod$r_m): Use it. + (FCT_mod$r_m$w): New function. + (FCT_mod$8r_m): New function. + (FCT_reg): Correctly handle 16-bit registers. + (FCT_reg$w): New function. + * i386_disasm.c (i386_disasm): Handle prefixes better. + Pass third parameter to operand functions. + * i386_parse.y (struct instruction): Add off3 field. + Handle third operand throughout. + +2007-02-05 Ulrich Drepper <drepper@redhat.com> + + * i386_disasm.c: New file. + * i386_data.h: New file. + * i386_gendis.c: New file. + * i386_lex.l: New file. + * i386_parse.y: New file. + * memory-access.h: New file. + * x86_64_disasm.c: New file. + * defs/i386: New file. + * defs/i386.doc: New file. + * defs/x86_64: New file. + +2005-02-15 Ulrich Drepper <drepper@redhat.com> + + * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2. + +2005-02-05 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am (AM_CFLAGS): Define, instead of adding things to DEFS. + +2003-08-11 Ulrich Drepper <drepper@redhat.com> + + * Moved to CVS archive. diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am new file mode 100644 index 0000000..c62db6d --- /dev/null +++ b/libcpu/Makefile.am @@ -0,0 +1,72 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2002-2010 Red Hat, Inc. +## This file is part of Red Hat elfutils. +## +## Red Hat elfutils is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by the +## Free Software Foundation; version 2 of the License. +## +## Red Hat elfutils is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with Red Hat elfutils; if not, write to the Free Software Foundation, +## Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. +## +## Red Hat elfutils is an included package of the Open Invention Network. +## An included package of the Open Invention Network is a package for which +## Open Invention Network licensees cross-license their patents. No patent +## license is granted, either expressly or impliedly, by designation as an +## included package. Should you wish to participate in the Open Invention +## Network licensing program, please visit www.openinventionnetwork.com +## <http://www.openinventionnetwork.com>. +## +include $(top_srcdir)/config/eu.am +INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ + -I$(srcdir)/../libdw -I$(srcdir)/../libasm +AM_CFLAGS += -fpic -fdollars-in-identifiers +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=) +LEX_OUTPUT_ROOT = lex.$(<F:lex.l=) +AM_YFLAGS = -p$(<F:parse.y=) + +noinst_LIBRARIES = libcpu_i386.a libcpu_x86_64.a +noinst_PROGRAMS = i386_gendis + +libcpu_i386_a_SOURCES = i386_disasm.c +libcpu_x86_64_a_SOURCES = x86_64_disasm.c + +i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y + +i386_disasm.o: i386.mnemonics i386_dis.h +x86_64_disasm.o: x86_64.mnemonics x86_64_dis.h i386_disasm.c + +%_defs: $(srcdir)/defs/i386 + m4 -D$* -DDISASSEMBLER $< > $@ + +%_dis.h: %_defs i386_gendis + ./i386_gendis $< > $@ + +%.mnemonics: %_defs + sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:]]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \ + $< | sort -u > $@ + +i386_lex_no_Werror = yes + +libeu = ../lib/libeu.a + +i386_lex_CFLAGS = -Wno-unused-label -Wno-unused-function -Wno-sign-compare +i386_parse.o: i386_parse.c i386.mnemonics +i386_parse_CFLAGS = -DNMNES="`wc -l < i386.mnemonics`" +i386_lex.o: i386_parse.h +i386_gendis_LDADD = $(libeu) -lm $(libmudflap) + +i386_parse.h: i386_parse.c ; + +noinst_HEADERS = memory-access.h i386_parse.h i386_data.h + +EXTRA_DIST = defs/i386 + +CLEANFILES += $(foreach P,i386 x86_64,$P_defs $P.mnemonics $P_dis.h) diff --git a/libcpu/Makefile.in b/libcpu/Makefile.in new file mode 100644 index 0000000..8da9935 --- /dev/null +++ b/libcpu/Makefile.in @@ -0,0 +1,547 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/config/eu.am ChangeLog \ + i386_lex.c i386_parse.c +@MUDFLAP_TRUE@am__append_1 = -fmudflap +noinst_PROGRAMS = i386_gendis$(EXEEXT) +subdir = libcpu +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/zip.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libcpu_i386_a_AR = $(AR) $(ARFLAGS) +libcpu_i386_a_LIBADD = +am_libcpu_i386_a_OBJECTS = i386_disasm.$(OBJEXT) +libcpu_i386_a_OBJECTS = $(am_libcpu_i386_a_OBJECTS) +libcpu_x86_64_a_AR = $(AR) $(ARFLAGS) +libcpu_x86_64_a_LIBADD = +am_libcpu_x86_64_a_OBJECTS = x86_64_disasm.$(OBJEXT) +libcpu_x86_64_a_OBJECTS = $(am_libcpu_x86_64_a_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am_i386_gendis_OBJECTS = i386_gendis.$(OBJEXT) i386_lex.$(OBJEXT) \ + i386_parse.$(OBJEXT) +i386_gendis_OBJECTS = $(am_i386_gendis_OBJECTS) +am__DEPENDENCIES_1 = +i386_gendis_DEPENDENCIES = $(libeu) $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || +YLWRAP = $(top_srcdir)/config/ylwrap +@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(libcpu_i386_a_SOURCES) $(libcpu_x86_64_a_SOURCES) \ + $(i386_gendis_SOURCES) +DIST_SOURCES = $(libcpu_i386_a_SOURCES) $(libcpu_x86_64_a_SOURCES) \ + $(i386_gendis_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUGPRED = @DEBUGPRED@ +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR='"${localedir}"' +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = lex.$(<F:lex.l=) +LIBEBL_SUBDIR = @LIBEBL_SUBDIR@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MODVERSION = @MODVERSION@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +base_cpu = @base_cpu@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +eu_version = @eu_version@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +zip_LIBS = @zip_LIBS@ +INCLUDES = -I. -I$(srcdir) -I$(top_srcdir)/lib -I.. \ + -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ + -I$(srcdir)/../libdw -I$(srcdir)/../libasm +AM_CFLAGS = -std=gnu99 -Wall -Wshadow $(if \ + $($(*F)_no_Werror),,-Werror) $(if \ + $($(*F)_no_Wunused),,-Wunused -Wextra) $(if \ + $($(*F)_no_Wformat),-Wno-format,-Wformat=2) $($(*F)_CFLAGS) \ + $(am__append_1) -fpic -fdollars-in-identifiers +@MUDFLAP_FALSE@libmudflap = +@MUDFLAP_TRUE@libmudflap = -lmudflap +COMPILE.os = $(filter-out -fprofile-arcs -ftest-coverage $(no_mudflap.os),\ + $(COMPILE)) + +CLEANFILES = *.gcno *.gcda $(foreach P,i386 x86_64,$P_defs \ + $P.mnemonics $P_dis.h) +textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=) +AM_YFLAGS = -p$(<F:parse.y=) +noinst_LIBRARIES = libcpu_i386.a libcpu_x86_64.a +libcpu_i386_a_SOURCES = i386_disasm.c +libcpu_x86_64_a_SOURCES = x86_64_disasm.c +i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y +i386_lex_no_Werror = yes +libeu = ../lib/libeu.a +i386_lex_CFLAGS = -Wno-unused-label -Wno-unused-function -Wno-sign-compare +i386_parse_CFLAGS = -DNMNES="`wc -l < i386.mnemonics`" +i386_gendis_LDADD = $(libeu) -lm $(libmudflap) +noinst_HEADERS = memory-access.h i386_parse.h i386_data.h +EXTRA_DIST = defs/i386 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .l .o .obj .y +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/eu.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits libcpu/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnits libcpu/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libcpu_i386.a: $(libcpu_i386_a_OBJECTS) $(libcpu_i386_a_DEPENDENCIES) + -rm -f libcpu_i386.a + $(libcpu_i386_a_AR) libcpu_i386.a $(libcpu_i386_a_OBJECTS) $(libcpu_i386_a_LIBADD) + $(RANLIB) libcpu_i386.a +libcpu_x86_64.a: $(libcpu_x86_64_a_OBJECTS) $(libcpu_x86_64_a_DEPENDENCIES) + -rm -f libcpu_x86_64.a + $(libcpu_x86_64_a_AR) libcpu_x86_64.a $(libcpu_x86_64_a_OBJECTS) $(libcpu_x86_64_a_LIBADD) + $(RANLIB) libcpu_x86_64.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +i386_gendis$(EXEEXT): $(i386_gendis_OBJECTS) $(i386_gendis_DEPENDENCIES) + @rm -f i386_gendis$(EXEEXT) + $(LINK) $(i386_gendis_OBJECTS) $(i386_gendis_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386_disasm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386_gendis.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386_lex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386_parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_64_disasm.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.l.c: + $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f i386_lex.c + -rm -f i386_parse.c +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + + +%.os: %.c %.o +@AMDEP_TRUE@ if $(COMPILE.os) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ +@AMDEP_TRUE@ -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ +@AMDEP_TRUE@ then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ +@AMDEP_TRUE@ rm -f "$(DEPDIR)/$*.Tpo"; \ +@AMDEP_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@AMDEP_TRUE@ fi +@AMDEP_FALSE@ $(COMPILE.os) -c -o $@ -fpic -DPIC -DSHARED $< + +i386_disasm.o: i386.mnemonics i386_dis.h +x86_64_disasm.o: x86_64.mnemonics x86_64_dis.h i386_disasm.c + +%_defs: $(srcdir)/defs/i386 + m4 -D$* -DDISASSEMBLER $< > $@ + +%_dis.h: %_defs i386_gendis + ./i386_gendis $< > $@ + +%.mnemonics: %_defs + sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:]]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \ + $< | sort -u > $@ +i386_parse.o: i386_parse.c i386.mnemonics +i386_lex.o: i386_parse.h + +i386_parse.h: i386_parse.c ; + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libcpu/defs/i386 b/libcpu/defs/i386 new file mode 100644 index 0000000..e0db28d --- /dev/null +++ b/libcpu/defs/i386 @@ -0,0 +1,970 @@ +%mask {s} 1 +%mask {w} 1 +%mask {w1} 1 +%mask {W1} 1 +%mask {W2} 1 +dnl floating point reg suffix +%mask {D} 1 +%mask {imm8} 8 +%mask {imms8} 8 +%mask {imm16} 16 +%mask {reg} 3 +%mask {oreg} 3 +%mask {reg16} 3 +%mask {reg64} 3 +%mask {tttn} 4 +%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 +dnl like {r_m} but referencing 32- or 64-bit register +%mask {64r_m} 3 +%mask {disp8} 8 +dnl imm really is 8/16/32 bit depending on the situation. +%mask {imm} 8 +%mask {imm64} 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 {R_M} 3 +%mask {Mod} 2 +%mask {xmmreg} 3 +%mask {R_m} 3 +%mask {xmmreg1} 3 +%mask {xmmreg2} 3 +%mask {mmxreg1} 3 +%mask {mmxreg2} 3 +%mask {predps} 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} +%synonym {mmxreg1} {mmxreg} +%synonym {mmxreg2} {mmxreg} +ifdef(`i386', +`%synonym {oreg} {reg} +%synonym {imm64} {imm} +')dnl + +%% +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}{w} +0001001{w},{mod}{reg}{r_m}:adc {mod}{r_m}{w},{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{w} {imms8},{mod}{r_m} +0000000{w},{mod}{reg}{r_m}:add {reg}{w},{mod}{r_m}{w} +0000001{w},{mod}{reg}{r_m}:add {mod}{r_m}{w},{reg}{w} +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},{imms8}:and{w} {imms8},{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} +', +`01100011,{mod}{reg64}{r_m}:movslq {mod}{r_m},{reg64} +')dnl +00001111,10111100,{mod}{reg}{r_m}:bsf {mod}{r_m},{reg} +00001111,10111101,{mod}{reg}{r_m}:bsr {mod}{r_m},{reg} +00001111,11001{reg}:bswap {reg} +00001111,10100011,{mod}{reg}{r_m}:bt {reg},{mod}{r_m} +00001111,10111010,{mod}100{r_m},{imm8}:bt{w} {imm8},{mod}{r_m} +00001111,10111011,{mod}{reg}{r_m}:btc {reg},{mod}{r_m} +00001111,10111010,{mod}111{r_m},{imm8}:btc{w} {imm8},{mod}{r_m} +00001111,10110011,{mod}{reg}{r_m}:btr {reg},{mod}{r_m} +00001111,10111010,{mod}110{r_m},{imm8}:btr{w} {imm8},{mod}{r_m} +00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m} +00001111,10111010,{mod}101{r_m},{imm8}:bts{w} {imm8},{mod}{r_m} +11101000,{rel}:call{W} {rel} +11111111,{mod}010{64r_m}:call{W} *{mod}{64r_m} +ifdef(`i386', +`10011010,{absval},{sel}:lcall {sel},{absval} +')dnl +11111111,{mod}011{64r_m}:lcall{W} *{mod}{64r_m} +# SPECIAL 10011000:[{rex.w}?cltq:{dpfx}?cbtw:cwtl] +10011000:INVALID +# SPECIAL 10011001:[{rex.w}?cqto:{dpfx}?cltd:cwtd] +10011001:INVALID +11111000:clc +11111100:cld +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{w} {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} +ifdef(`ASSEMBLER', +`11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpsd {imm8},{Mod}{R_m},{xmmreg} +11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpss {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmppd {imm8},{Mod}{R_m},{xmmreg} +00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpps {imm8},{Mod}{R_m},{xmmreg} +', +`11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:INVALID {Mod}{R_m},{xmmreg} +11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:INVALID {Mod}{R_m},{xmmreg} +01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:INVALID {Mod}{R_m},{xmmreg} +00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:INVALID {Mod}{R_m},{xmmreg} +')dnl +1010011{w}:{RE}cmps{w} {es_di},{ds_si} +00001111,1011000{w},{mod}{reg}{r_m}:cmpxchg {reg}{w},{mod}{r_m}{w} +ifdef(`i386', +`00001111,11000111,{mod}001{r_m}:cmpxchg8b {mod}{r_m} +', +`# SPECIAL 00001111,11000111,{mod}001{r_m}:[{rex.w}?cmpxchg16b:cmpxchg8b] {reg},{mod}{r_m} +00001111,11000111,{mod}001{r_m}:INVALID {mod}{r_m} +')dnl +00001111,10100010:cpuid +11110011,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtdq2pd {Mod}{R_m},{xmmreg} +11110010,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtpd2dq {Mod}{R_m},{xmmreg} +01100110,00001111,11100110,{Mod}{xmmreg}{R_m}:cvttpd2dq {Mod}{R_m},{xmmreg} +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} +00001111,01110111:emms +11001000,{imm16},{imm8}:enter{W} {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 {mod}{r_m},{reg} +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} +ifdef(`i386', +`01000{reg}:inc {reg} +')dnl +0110110{w}:{R}ins{w} {dx},{es_di} +11001101,{imm8}:int {imm8} +11001100:int3 +ifdef(`i386', +`11001110:into +')dnl +00001111,00001000:invd +# ORDER +00001111,00000001,11111000:swapgs +00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m} +# ORDER END +11001111:iret{W1} +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{W} {rel} +11111111,{mod}100{64r_m}:jmp{W} *{mod}{64r_m} +11101010,{absval},{sel}:ljmp {sel},{absval} +11111111,{mod}101{64r_m}:ljmp{W} *{mod}{64r_m} +10011111:lahf +00001111,00000010,{mod}{reg}{16r_m}:lar {mod}{16r_m},{reg} +ifdef(`i386', +`11000101,{mod}{reg}{r_m}:lds {mod}{r_m},{reg} +')dnl +10001101,{mod}{reg}{r_m}:lea {mod}{r_m},{reg} +11001001:leave{W} +ifdef(`i386', +`11000100,{mod}{reg}{r_m}:les {mod}{r_m},{reg} +')dnl +00001111,10110100,{mod}{reg}{r_m}:lfs {mod}{r_m},{reg} +00001111,10110101,{mod}{reg}{r_m}:lgs {mod}{r_m},{reg} +ifdef(`i386', +`00001111,00000001,{mod}010{r_m}:lgdt{w0} {mod}{r_m} +00001111,00000001,{mod}011{r_m}:lidt{w0} {mod}{r_m} +', +`00001111,00000001,{mod}010{r_m}:lgdt {mod}{r_m} +00001111,00000001,{mod}011{r_m}:lidt {mod}{r_m} +')dnl +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}{oreg},{imm64}:mov {imm64}{w},{oreg}{w} +1010000{w},{abs}:mov {abs},{ax}{w} +1010001{w},{abs}:mov {ax}{w},{abs} +00001111,00100000,11{ccc}{reg64}:mov {ccc},{reg64} +00001111,00100010,11{ccc}{reg64}:mov {reg64},{ccc} +00001111,00100001,11{ddd}{reg64}:mov {ddd},{reg64} +00001111,00100011,11{ddd}{reg64}:mov {reg64},{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,10111110,{mod}{reg}{8r_m}:movsbl {mod}{8r_m},{reg} +00001111,10111111,{mod}{reg}{16r_m}:movswl {mod}{16r_m},{reg} +00001111,10110110,{mod}{reg}{8r_m}:movzbl {mod}{8r_m},{reg} +00001111,10110111,{mod}{reg}{16r_m}:movzwl {mod}{16r_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} +11110011,10010000:pause +ifdef(`i386', +`10010000:nop +', +`10010000:INVALID +')dnl +# ORDER before out +11110011,00001111,10111000,{mod}{reg}{r_m}:popcnt {mod}{r_m},{reg} +# END ORDER +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} +1000001{w},{mod}001{r_m},{imms8}:or{w} {imms8},{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} +ifdef(`i386', +`10001111,{mod}000{r_m}:pop{w} {mod}{r_m} +', +# XXX This is not the cleanest way... +`10001111,11000{reg64}:pop {reg64} +10001111,{mod}000{r_m}:pop{W} {mod}{r_m} +')dnl +00001111,10{sreg3}001:pop{W} {sreg3} +10011101:popf{W} +# XXX This is not the cleanest way... +ifdef(`i386', +`11111111,{mod}110{r_m}:push{w} {mod}{r_m} +', +`11111111,11110{reg64}:push {reg64} +11111111,{mod}110{r_m}:pushq {mod}{r_m} +')dnl +ifdef(`i386', +`01010{reg}:push {reg} +01011{reg}:pop {reg} +', +`01010{reg64}:push {reg64} +01011{reg64}:pop {reg64} +')dnl +011010{s}0,{imm}:push{W} {imm}{s} +000{sreg2}110:push {sreg2} +00001111,10{sreg3}000:push{W} {sreg3} +ifdef(`i386', +`01100000:pusha{W} +01100001:popa{W} +')dnl +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{W} +11000010,{imm16}:ret{W} {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},{imms8}:sbb{w} {imms8},{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,01111000,{mod}{reg64}{64r_m}:vmread {reg64},{mod}{64r_m} +00001111,01111001,{mod}{reg64}{64r_m}:vmwrite {mod}{64r_m},{reg64} +ifdef(`i386', +`00001111,00000001,{mod}000{r_m}:sgdtl {mod}{r_m} +', +`00001111,00000001,{mod}000{r_m}:sgdt {mod}{r_m} +')dnl +# ORDER END +# ORDER +ifdef(`i386', +`00001111,00000001,11001000:monitor %eax,%ecx,%edx +00001111,00000001,11001001:mwait %eax,%ecx +', +`00001111,00000001,11001000:monitor %rax,%rcx,%rdx +00001111,00000001,11001001:mwait %rax,%rcx +')dnl +ifdef(`i386', +`00001111,00000001,{mod}001{r_m}:sidtl {mod}{r_m} +', +`00001111,00000001,{mod}001{r_m}:sidt {mod}{r_m} +')dnl +# 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},{imms8}:sub{w} {imms8},{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} +00001111,00110000:wrmsr +00001111,1100000{w},{mod}{reg}{r_m}:xadd {reg}{w},{mod}{r_m}{w} +1000011{w},{mod}{reg}{r_m}:xchg {reg}{w},{mod}{r_m}{w} +10010{oreg}:xchg {ax},{oreg} +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},{imms8}:xor{w} {imms8},{mod}{r_m} +00001111,01110111:emms +01100110,00001111,11011011,{Mod}{xmmreg}{R_m}:pand {Mod}{R_m},{xmmreg} +00001111,11011011,{MOD}{mmxreg}{R_M}:pand {MOD}{R_M},{mmxreg} +01100110,00001111,11011111,{Mod}{xmmreg}{R_m}:pandn {Mod}{R_m},{xmmreg} +00001111,11011111,{MOD}{mmxreg}{R_M}:pandn {MOD}{R_M},{mmxreg} +01100110,00001111,11110101,{Mod}{xmmreg}{R_m}:pmaddwd {Mod}{R_m},{xmmreg} +00001111,11110101,{MOD}{mmxreg}{R_M}:pmaddwd {MOD}{R_M},{mmxreg} +01100110,00001111,11101011,{Mod}{xmmreg}{R_m}:por {Mod}{R_m},{xmmreg} +00001111,11101011,{MOD}{mmxreg}{R_M}:por {MOD}{R_M},{mmxreg} +01100110,00001111,11101111,{Mod}{xmmreg}{R_m}:pxor {Mod}{R_m},{xmmreg} +00001111,11101111,{MOD}{mmxreg}{R_M}:pxor {MOD}{R_M},{mmxreg} +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,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,10101110,{mod}011{r_m}:stmxcsr {mod}{r_m} +11110010,00001111,00010000,{Mod}{xmmreg}{R_m}:movsd {Mod}{R_m},{xmmreg} +11110011,00001111,00010000,{Mod}{xmmreg}{R_m}:movss {Mod}{R_m},{xmmreg} +01100110,00001111,00010000,{Mod}{xmmreg}{R_m}:movupd {Mod}{R_m},{xmmreg} +00001111,00010000,{Mod}{xmmreg}{R_m}:movups {Mod}{R_m},{xmmreg} +11110010,00001111,00010001,{Mod}{xmmreg}{R_m}:movsd {xmmreg},{Mod}{R_m} +11110011,00001111,00010001,{Mod}{xmmreg}{R_m}:movss {xmmreg},{Mod}{R_m} +01100110,00001111,00010001,{Mod}{xmmreg}{R_m}:movupd {xmmreg},{Mod}{R_m} +00001111,00010001,{Mod}{xmmreg}{R_m}:movups {xmmreg},{Mod}{R_m} +11110010,00001111,00010010,{Mod}{xmmreg}{R_m}:movddup {Mod}{R_m},{xmmreg} +11110011,00001111,00010010,{Mod}{xmmreg}{R_m}:movsldup {Mod}{R_m},{xmmreg} +01100110,00001111,00010010,{Mod}{xmmreg}{R_m}:movlpd {Mod}{R_m},{xmmreg} +00001111,00010010,11{xmmreg1}{xmmreg2}:movhlps {xmmreg2},{xmmreg1} +00001111,00010010,{Mod}{xmmreg}{R_m}:movlps {Mod}{R_m},{xmmreg} +01100110,00001111,00010011,11{xmmreg1}{xmmreg2}:movhlpd {xmmreg1},{xmmreg2} +00001111,00010011,11{xmmreg1}{xmmreg2}:movhlps {xmmreg1},{xmmreg2} +01100110,00001111,00010011,{Mod}{xmmreg}{R_m}:movlpd {xmmreg},{Mod}{R_m} +00001111,00010011,{Mod}{xmmreg}{R_m}:movlps {xmmreg},{Mod}{R_m} +01100110,00001111,00010100,{Mod}{xmmreg}{R_m}:unpcklpd {Mod}{R_m},{xmmreg} +00001111,00010100,{Mod}{xmmreg}{R_m}:unpcklps {Mod}{R_m},{xmmreg} +01100110,00001111,00010101,{Mod}{xmmreg}{R_m}:unpckhpd {Mod}{R_m},{xmmreg} +00001111,00010101,{Mod}{xmmreg}{R_m}:unpckhps {Mod}{R_m},{xmmreg} +11110011,00001111,00010110,{Mod}{xmmreg}{R_m}:movshdup {Mod}{R_m},{xmmreg} +01100110,00001111,00010110,{Mod}{xmmreg}{R_m}:movhpd {Mod}{R_m},{xmmreg} +00001111,00010110,11{xmmreg1}{xmmreg2}:movlhps {xmmreg2},{xmmreg1} +00001111,00010110,{Mod}{xmmreg}{R_m}:movhps {Mod}{R_m},{xmmreg} +01100110,00001111,00010111,11{xmmreg1}{xmmreg2}:movlhpd {xmmreg1},{xmmreg2} +00001111,00010111,11{xmmreg1}{xmmreg2}:movlhps {xmmreg1},{xmmreg2} +01100110,00001111,00010111,{Mod}{xmmreg}{R_m}:movhpd {xmmreg},{Mod}{R_m} +00001111,00010111,{Mod}{xmmreg}{R_m}:movhps {xmmreg},{Mod}{R_m} +01100110,00001111,00101000,{Mod}{xmmreg}{R_m}:movapd {Mod}{R_m},{xmmreg} +00001111,00101000,{Mod}{xmmreg}{R_m}:movaps {Mod}{R_m},{xmmreg} +01100110,00001111,00101001,{Mod}{xmmreg}{R_m}:movapd {xmmreg},{Mod}{R_m} +00001111,00101001,{Mod}{xmmreg}{R_m}:movaps {xmmreg},{Mod}{R_m} +11110010,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2sd {mod}{r_m},{xmmreg} +11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg} +01100110,00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2pd {MOD}{R_M},{xmmreg} +00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2ps {MOD}{R_M},{xmmreg} +01100110,00001111,00101011,{mod}{xmmreg}{r_m}:movntpd {xmmreg},{mod}{r_m} +00001111,00101011,{mod}{xmmreg}{r_m}:movntps {xmmreg},{mod}{r_m} +11110010,00001111,00101100,{Mod}{reg}{R_m}:cvttsd2si {Mod}{R_m},{reg} +11110011,00001111,00101100,{Mod}{reg}{R_m}:cvttss2si {Mod}{R_m},{reg} +01100110,00001111,00101100,{Mod}{mmxreg}{R_m}:cvttpd2pi {Mod}{R_m},{mmxreg} +00001111,00101100,{Mod}{mmxreg}{R_m}:cvttps2pi {Mod}{R_m},{mmxreg} +01100110,00001111,00101101,{Mod}{mmxreg}{R_m}:cvtpd2pi {Mod}{R_m},{mmxreg} +11110010,00001111,00101101,{Mod}{reg}{R_m}:cvtsd2si {Mod}{R_m},{reg} +11110011,00001111,00101101,{Mod}{reg}{R_m}:cvtss2si {Mod}{R_m},{reg} +00001111,00101101,{Mod}{mmxreg}{R_m}:cvtps2pi {Mod}{R_m},{mmxreg} +01100110,00001111,00101110,{Mod}{xmmreg}{R_m}:ucomisd {Mod}{R_m},{xmmreg} +00001111,00101110,{Mod}{xmmreg}{R_m}:ucomiss {Mod}{R_m},{xmmreg} +01100110,00001111,00101111,{Mod}{xmmreg}{R_m}:comisd {Mod}{R_m},{xmmreg} +00001111,00101111,{Mod}{xmmreg}{R_m}:comiss {Mod}{R_m},{xmmreg} +00001111,00110111:getsec +01100110,00001111,01010000,11{reg}{xmmreg}:movmskpd {xmmreg},{reg} +00001111,01010000,11{reg}{xmmreg}:movmskps {xmmreg},{reg} +01100110,00001111,01010001,{Mod}{xmmreg}{R_m}:sqrtpd {Mod}{R_m},{xmmreg} +11110010,00001111,01010001,{Mod}{xmmreg}{R_m}:sqrtsd {Mod}{R_m},{xmmreg} +11110011,00001111,01010001,{Mod}{xmmreg}{R_m}:sqrtss {Mod}{R_m},{xmmreg} +00001111,01010001,{Mod}{xmmreg}{R_m}:sqrtps {Mod}{R_m},{xmmreg} +11110011,00001111,01010010,{Mod}{xmmreg}{R_m}:rsqrtss {Mod}{R_m},{xmmreg} +00001111,01010010,{Mod}{xmmreg}{R_m}:rsqrtps {Mod}{R_m},{xmmreg} +11110011,00001111,01010011,{Mod}{xmmreg}{R_m}:rcpss {Mod}{R_m},{xmmreg} +00001111,01010011,{Mod}{xmmreg}{R_m}:rcpps {Mod}{R_m},{xmmreg} +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} +01100110,00001111,01010110,{Mod}{xmmreg}{R_m}:orpd {Mod}{R_m},{xmmreg} +00001111,01010110,{Mod}{xmmreg}{R_m}:orps {Mod}{R_m},{xmmreg} +01100110,00001111,01010111,{Mod}{xmmreg}{R_m}:xorpd {Mod}{R_m},{xmmreg} +00001111,01010111,{Mod}{xmmreg}{R_m}:xorps {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,01011000,{Mod}{xmmreg}{R_m}:addpd {Mod}{R_m},{xmmreg} +00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg} +11110010,00001111,01011001,{Mod}{xmmreg}{R_m}:mulsd {Mod}{R_m},{xmmreg} +11110011,00001111,01011001,{Mod}{xmmreg}{R_m}:mulss {Mod}{R_m},{xmmreg} +01100110,00001111,01011001,{Mod}{xmmreg}{R_m}:mulpd {Mod}{R_m},{xmmreg} +00001111,01011001,{Mod}{xmmreg}{R_m}:mulps {Mod}{R_m},{xmmreg} +11110010,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtsd2ss {Mod}{R_m},{xmmreg} +11110011,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtss2sd {Mod}{R_m},{xmmreg} +01100110,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtpd2ps {Mod}{R_m},{xmmreg} +00001111,01011010,{Mod}{xmmreg}{R_m}:cvtps2pd {Mod}{R_m},{xmmreg} +01100110,00001111,01011011,{Mod}{xmmreg}{R_m}:cvtps2dq {Mod}{R_m},{xmmreg} +11110011,00001111,01011011,{Mod}{xmmreg}{R_m}:cvttps2dq {Mod}{R_m},{xmmreg} +00001111,01011011,{Mod}{xmmreg}{R_m}:cvtdq2ps {Mod}{R_m},{xmmreg} +11110010,00001111,01011100,{Mod}{xmmreg}{R_m}:subsd {Mod}{R_m},{xmmreg} +11110011,00001111,01011100,{Mod}{xmmreg}{R_m}:subss {Mod}{R_m},{xmmreg} +01100110,00001111,01011100,{Mod}{xmmreg}{R_m}:subpd {Mod}{R_m},{xmmreg} +00001111,01011100,{Mod}{xmmreg}{R_m}:subps {Mod}{R_m},{xmmreg} +11110010,00001111,01011101,{Mod}{xmmreg}{R_m}:minsd {Mod}{R_m},{xmmreg} +11110011,00001111,01011101,{Mod}{xmmreg}{R_m}:minss {Mod}{R_m},{xmmreg} +01100110,00001111,01011101,{Mod}{xmmreg}{R_m}:minpd {Mod}{R_m},{xmmreg} +00001111,01011101,{Mod}{xmmreg}{R_m}:minps {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} +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,01011111,{Mod}{xmmreg}{R_m}:maxsd {Mod}{R_m},{xmmreg} +11110011,00001111,01011111,{Mod}{xmmreg}{R_m}:maxss {Mod}{R_m},{xmmreg} +01100110,00001111,01011111,{Mod}{xmmreg}{R_m}:maxpd {Mod}{R_m},{xmmreg} +00001111,01011111,{Mod}{xmmreg}{R_m}:maxps {Mod}{R_m},{xmmreg} +01100110,00001111,01100000,{Mod}{xmmreg}{R_m}:punpcklbw {Mod}{R_m},{xmmreg} +00001111,01100000,{MOD}{mmxreg}{R_M}:punpcklbw {MOD}{R_M},{mmxreg} +01100110,00001111,01100001,{Mod}{xmmreg}{R_m}:punpcklwd {Mod}{R_m},{xmmreg} +00001111,01100001,{MOD}{mmxreg}{R_M}:punpcklwd {MOD}{R_M},{mmxreg} +01100110,00001111,01100010,{Mod}{xmmreg}{R_m}:punpckldq {Mod}{R_m},{xmmreg} +00001111,01100010,{MOD}{mmxreg}{R_M}:punpckldq {MOD}{R_M},{mmxreg} +01100110,00001111,01100011,{Mod}{xmmreg}{R_m}:packsswb {Mod}{R_m},{xmmreg} +00001111,01100011,{MOD}{mmxreg}{R_M}:packsswb {MOD}{R_M},{mmxreg} +01100110,00001111,01100100,{Mod}{xmmreg}{R_m}:pcmpgtb {Mod}{R_m},{xmmreg} +00001111,01100100,{MOD}{mmxreg}{R_M}:pcmpgtb {MOD}{R_M},{mmxreg} +01100110,00001111,01100101,{Mod}{xmmreg}{R_m}:pcmpgtw {Mod}{R_m},{xmmreg} +00001111,01100101,{MOD}{mmxreg}{R_M}:pcmpgtw {MOD}{R_M},{mmxreg} +01100110,00001111,01100110,{Mod}{xmmreg}{R_m}:pcmpgtd {Mod}{R_m},{xmmreg} +00001111,01100110,{MOD}{mmxreg}{R_M}:pcmpgtd {MOD}{R_M},{mmxreg} +01100110,00001111,01100111,{Mod}{xmmreg}{R_m}:packuswb {Mod}{R_m},{xmmreg} +00001111,01100111,{MOD}{mmxreg}{R_M}:packuswb {MOD}{R_M},{mmxreg} +01100110,00001111,01101000,{Mod}{xmmreg}{R_m}:punpckhbw {Mod}{R_m},{xmmreg} +00001111,01101000,{MOD}{mmxreg}{R_M}:punpckhbw {MOD}{R_M},{mmxreg} +01100110,00001111,01101001,{Mod}{xmmreg}{R_m}:punpckhwd {Mod}{R_m},{xmmreg} +00001111,01101001,{MOD}{mmxreg}{R_M}:punpckhwd {MOD}{R_M},{mmxreg} +01100110,00001111,01101010,{Mod}{xmmreg}{R_m}:punpckhdq {Mod}{R_m},{xmmreg} +00001111,01101010,{MOD}{mmxreg}{R_M}:punpckhdq {MOD}{R_M},{mmxreg} +01100110,00001111,01101011,{Mod}{xmmreg}{R_m}:packssdw {Mod}{R_m},{xmmreg} +00001111,01101011,{MOD}{mmxreg}{R_M}:packssdw {MOD}{R_M},{mmxreg} +01100110,00001111,01101100,{Mod}{xmmreg}{R_m}:punpcklqdq {Mod}{R_m},{xmmreg} +01100110,00001111,01101101,{Mod}{xmmreg}{R_m}:punpckhqdq {Mod}{R_m},{xmmreg} +01100110,00001111,01101110,{mod}{xmmreg}{r_m}:movd {mod}{r_m},{xmmreg} +00001111,01101110,{mod}{mmxreg}{r_m}:movd {mod}{r_m},{mmxreg} +01100110,00001111,01101111,{Mod}{xmmreg}{R_m}:movdqa {Mod}{R_m},{xmmreg} +11110011,00001111,01101111,{Mod}{xmmreg}{R_m}:movdqu {Mod}{R_m},{xmmreg} +00001111,01101111,{MOD}{mmxreg}{R_M}:movq {MOD}{R_M},{mmxreg} +01100110,00001111,01110000,{Mod}{xmmreg}{R_m},{imm8}:pshufd {imm8},{Mod}{R_m},{xmmreg} +11110010,00001111,01110000,{Mod}{xmmreg}{R_m},{imm8}:pshuflw {imm8},{Mod}{R_m},{xmmreg} +11110011,00001111,01110000,{Mod}{xmmreg}{R_m},{imm8}:pshufhw {imm8},{Mod}{R_m},{xmmreg} +00001111,01110000,{MOD}{mmxreg}{R_M},{imm8}:pshufw {imm8},{MOD}{R_M},{mmxreg} +01100110,00001111,01110100,{Mod}{xmmreg}{R_m}:pcmpeqb {Mod}{R_m},{xmmreg} +00001111,01110100,{MOD}{mmxreg}{R_M}:pcmpeqb {MOD}{R_M},{mmxreg} +01100110,00001111,01110101,{Mod}{xmmreg}{R_m}:pcmpeqw {Mod}{R_m},{xmmreg} +00001111,01110101,{MOD}{mmxreg}{R_M}:pcmpeqw {MOD}{R_M},{mmxreg} +01100110,00001111,01110110,{Mod}{xmmreg}{R_m}:pcmpeqd {Mod}{R_m},{xmmreg} +00001111,01110110,{MOD}{mmxreg}{R_M}:pcmpeqd {MOD}{R_M},{mmxreg} +01100110,00001111,01111100,{Mod}{xmmreg}{R_m}:haddpd {Mod}{R_m},{xmmreg} +11110010,00001111,01111100,{Mod}{xmmreg}{R_m}:haddps {Mod}{R_m},{xmmreg} +01100110,00001111,01111101,{Mod}{xmmreg}{R_m}:hsubpd {Mod}{R_m},{xmmreg} +11110010,00001111,01111101,{Mod}{xmmreg}{R_m}:hsubps {Mod}{R_m},{xmmreg} +01100110,00001111,01111110,{mod}{xmmreg}{r_m}:movd {xmmreg},{mod}{r_m} +11110011,00001111,01111110,{Mod}{xmmreg}{R_m}:movq {Mod}{R_m},{xmmreg} +00001111,01111110,{mod}{mmxreg}{r_m}:movd {mmxreg},{mod}{r_m} +01100110,00001111,01111111,{Mod}{xmmreg}{R_m}:movdqa {xmmreg},{Mod}{R_m} +11110011,00001111,01111111,{Mod}{xmmreg}{R_m}:movdqu {xmmreg},{Mod}{R_m} +00001111,01111111,{MOD}{mmxreg}{R_M}:movq {mmxreg},{MOD}{R_M} +00001111,11000011,{mod}{reg}{r_m}:movnti {reg},{mod}{r_m} +01100110,00001111,11000100,{mod}{xmmreg}{r_m},{imm8}:pinsrw {imm8},{mod}{r_m},{xmmreg} +00001111,11000100,{mod}{mmxreg}{r_m},{imm8}:pinsrw {imm8},{mod}{r_m},{mmxreg} +01100110,00001111,11000101,11{reg}{xmmreg},{imm8}:pextrw {imm8},{xmmreg},{reg} +00001111,11000101,11{reg}{mmxreg},{imm8}:pextrw {imm8},{mmxreg},{reg} +01100110,00001111,11000110,{Mod}{xmmreg}{R_m},{imm8}:shufpd {imm8},{Mod}{R_m},{xmmreg} +00001111,11000110,{Mod}{xmmreg}{R_m},{imm8}:shufps {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,11010001,{Mod}{xmmreg}{R_m}:psrlw {Mod}{R_m},{xmmreg} +00001111,11010001,{MOD}{mmxreg}{R_M}:psrlw {MOD}{R_M},{mmxreg} +01100110,00001111,11010010,{Mod}{xmmreg}{R_m}:psrld {Mod}{R_m},{xmmreg} +00001111,11010010,{MOD}{mmxreg}{R_M}:psrld {MOD}{R_M},{mmxreg} +01100110,00001111,11010011,{Mod}{xmmreg}{R_m}:psrlq {Mod}{R_m},{xmmreg} +00001111,11010011,{MOD}{mmxreg}{R_M}:psrlq {MOD}{R_M},{mmxreg} +01100110,00001111,11010100,{Mod}{xmmreg}{R_m}:paddq {Mod}{R_m},{xmmreg} +00001111,11010100,{MOD}{mmxreg}{R_M}:paddq {MOD}{R_M},{mmxreg} +01100110,00001111,11010101,{Mod}{xmmreg}{R_m}:pmullw {Mod}{R_m},{xmmreg} +00001111,11010101,{MOD}{mmxreg}{R_M}:pmullw {MOD}{R_M},{mmxreg} +01100110,00001111,11010110,{Mod}{xmmreg}{R_m}:movq {xmmreg},{Mod}{R_m} +11110010,00001111,11010110,11{mmxreg}{xmmreg}:movdq2q {xmmreg},{mmxreg} +11110011,00001111,11010110,11{xmmreg}{mmxreg}:movq2dq {mmxreg},{xmmreg} +01100110,00001111,11010111,11{reg}{xmmreg}:pmovmskb {xmmreg},{reg} +00001111,11010111,11{reg}{mmxreg}:pmovmskb {mmxreg},{reg} +01100110,00001111,11011000,{Mod}{xmmreg}{R_m}:psubusb {Mod}{R_m},{xmmreg} +00001111,11011000,{MOD}{mmxreg}{R_M}:psubusb {MOD}{R_M},{mmxreg} +01100110,00001111,11011001,{Mod}{xmmreg}{R_m}:psubusw {Mod}{R_m},{xmmreg} +00001111,11011001,{MOD}{mmxreg}{R_M}:psubusw {MOD}{R_M},{mmxreg} +01100110,00001111,11011010,{Mod}{xmmreg}{R_m}:pminub {Mod}{R_m},{xmmreg} +00001111,11011010,{MOD}{mmxreg}{R_M}:pminub {MOD}{R_M},{mmxreg} +01100110,00001111,11011100,{Mod}{xmmreg}{R_m}:paddusb {Mod}{R_m},{xmmreg} +00001111,11011100,{MOD}{mmxreg}{R_M}:paddusb {MOD}{R_M},{mmxreg} +01100110,00001111,11011101,{Mod}{xmmreg}{R_m}:paddusw {Mod}{R_m},{xmmreg} +00001111,11011101,{MOD}{mmxreg}{R_M}:paddusw {MOD}{R_M},{mmxreg} +01100110,00001111,11011110,{Mod}{xmmreg}{R_m}:pmaxub {Mod}{R_m},{xmmreg} +00001111,11011110,{MOD}{mmxreg}{R_M}:pmaxub {MOD}{R_M},{mmxreg} +01100110,00001111,11100000,{Mod}{xmmreg}{R_m}:pavgb {Mod}{R_m},{xmmreg} +00001111,11100000,{MOD}{mmxreg}{R_M}:pavgb {MOD}{R_M},{mmxreg} +01100110,00001111,11100001,{Mod}{xmmreg}{R_m}:psraw {Mod}{R_m},{xmmreg} +00001111,11100001,{MOD}{mmxreg}{R_M}:psraw {MOD}{R_M},{mmxreg} +01100110,00001111,11100010,{Mod}{xmmreg}{R_m}:psrad {Mod}{R_m},{xmmreg} +00001111,11100010,{MOD}{mmxreg}{R_M}:psrad {MOD}{R_M},{mmxreg} +01100110,00001111,11100011,{Mod}{xmmreg}{R_m}:pavgw {Mod}{R_m},{xmmreg} +00001111,11100011,{MOD}{mmxreg}{R_M}:pavgw {MOD}{R_M},{mmxreg} +01100110,00001111,11100100,{Mod}{xmmreg}{R_m}:pmulhuw {Mod}{R_m},{xmmreg} +00001111,11100100,{MOD}{mmxreg}{R_M}:pmulhuw {MOD}{R_M},{mmxreg} +01100110,00001111,11100101,{Mod}{xmmreg}{R_m}:pmulhw {Mod}{R_m},{xmmreg} +00001111,11100101,{MOD}{mmxreg}{R_M}:pmulhw {MOD}{R_M},{mmxreg} +01100110,00001111,11100111,{Mod}{xmmreg}{R_m}:movntdq {xmmreg},{Mod}{R_m} +00001111,11100111,{MOD}{mmxreg}{R_M}:movntq {mmxreg},{MOD}{R_M} +01100110,00001111,11101000,{Mod}{xmmreg}{R_m}:psubsb {Mod}{R_m},{xmmreg} +00001111,11101000,{MOD}{mmxreg}{R_M}:psubsb {MOD}{R_M},{mmxreg} +01100110,00001111,11101001,{Mod}{xmmreg}{R_m}:psubsw {Mod}{R_m},{xmmreg} +00001111,11101001,{MOD}{mmxreg}{R_M}:psubsw {MOD}{R_M},{mmxreg} +01100110,00001111,11101010,{Mod}{xmmreg}{R_m}:pminsw {Mod}{R_m},{xmmreg} +00001111,11101010,{MOD}{mmxreg}{R_M}:pminsw {MOD}{R_M},{mmxreg} +01100110,00001111,11101100,{Mod}{xmmreg}{R_m}:paddsb {Mod}{R_m},{xmmreg} +00001111,11101100,{MOD}{mmxreg}{R_M}:paddsb {MOD}{R_M},{mmxreg} +01100110,00001111,11101101,{Mod}{xmmreg}{R_m}:paddsw {Mod}{R_m},{xmmreg} +00001111,11101101,{MOD}{mmxreg}{R_M}:paddsw {MOD}{R_M},{mmxreg} +01100110,00001111,11101110,{Mod}{xmmreg}{R_m}:pmaxsw {Mod}{R_m},{xmmreg} +00001111,11101110,{MOD}{mmxreg}{R_M}:pmaxsw {MOD}{R_M},{mmxreg} +11110010,00001111,11110000,{mod}{xmmreg}{r_m}:lddqu {mod}{r_m},{xmmreg} +01100110,00001111,11110001,{Mod}{xmmreg}{R_m}:psllw {Mod}{R_m},{xmmreg} +00001111,11110001,{MOD}{mmxreg}{R_M}:psllw {MOD}{R_M},{mmxreg} +01100110,00001111,11110010,{Mod}{xmmreg}{R_m}:pslld {Mod}{R_m},{xmmreg} +00001111,11110010,{MOD}{mmxreg}{R_M}:pslld {MOD}{R_M},{mmxreg} +01100110,00001111,11110011,{Mod}{xmmreg}{R_m}:psllq {Mod}{R_m},{xmmreg} +00001111,11110011,{MOD}{mmxreg}{R_M}:psllq {MOD}{R_M},{mmxreg} +01100110,00001111,11110100,{Mod}{xmmreg}{R_m}:pmuludq {Mod}{R_m},{xmmreg} +00001111,11110100,{MOD}{mmxreg}{R_M}:pmuludq {MOD}{R_M},{mmxreg} +01100110,00001111,11110110,{Mod}{xmmreg}{R_m}:psadbw {Mod}{R_m},{xmmreg} +00001111,11110110,{MOD}{mmxreg}{R_M}:psadbw {MOD}{R_M},{mmxreg} +01100110,00001111,11110111,11{xmmreg1}{xmmreg2}:maskmovdqu {xmmreg2},{xmmreg1} +00001111,11110111,11{mmxreg1}{mmxreg2}:maskmovq {mmxreg2},{mmxreg1} +01100110,00001111,11111000,{Mod}{xmmreg}{R_m}:psubb {Mod}{R_m},{xmmreg} +00001111,11111000,{MOD}{mmxreg}{R_M}:psubb {MOD}{R_M},{mmxreg} +01100110,00001111,11111001,{Mod}{xmmreg}{R_m}:psubw {Mod}{R_m},{xmmreg} +00001111,11111001,{MOD}{mmxreg}{R_M}:psubw {MOD}{R_M},{mmxreg} +01100110,00001111,11111010,{Mod}{xmmreg}{R_m}:psubd {Mod}{R_m},{xmmreg} +00001111,11111010,{MOD}{mmxreg}{R_M}:psubd {MOD}{R_M},{mmxreg} +01100110,00001111,11111011,{Mod}{xmmreg}{R_m}:psubq {Mod}{R_m},{xmmreg} +00001111,11111011,{MOD}{mmxreg}{R_M}:psubq {MOD}{R_M},{mmxreg} +01100110,00001111,11111100,{Mod}{xmmreg}{R_m}:paddb {Mod}{R_m},{xmmreg} +00001111,11111100,{MOD}{mmxreg}{R_M}:paddb {MOD}{R_M},{mmxreg} +01100110,00001111,11111101,{Mod}{xmmreg}{R_m}:paddw {Mod}{R_m},{xmmreg} +00001111,11111101,{MOD}{mmxreg}{R_M}:paddw {MOD}{R_M},{mmxreg} +01100110,00001111,11111110,{Mod}{xmmreg}{R_m}:paddd {Mod}{R_m},{xmmreg} +00001111,11111110,{MOD}{mmxreg}{R_M}:paddd {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000000,{Mod}{xmmreg}{R_m}:pshufb {Mod}{R_m},{xmmreg} +00001111,00111000,00000000,{MOD}{mmxreg}{R_M}:pshufb {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000001,{Mod}{xmmreg}{R_m}:phaddw {Mod}{R_m},{xmmreg} +00001111,00111000,00000001,{MOD}{mmxreg}{R_M}:phaddw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000010,{Mod}{xmmreg}{R_m}:phaddd {Mod}{R_m},{xmmreg} +00001111,00111000,00000010,{MOD}{mmxreg}{R_M}:phaddd {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000011,{Mod}{xmmreg}{R_m}:phaddsw {Mod}{R_m},{xmmreg} +00001111,00111000,00000011,{MOD}{mmxreg}{R_M}:phaddsw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000100,{Mod}{xmmreg}{R_m}:pmaddubsw {Mod}{R_m},{xmmreg} +00001111,00111000,00000100,{MOD}{mmxreg}{R_M}:pmaddubsw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000101,{Mod}{xmmreg}{R_m}:phsubw {Mod}{R_m},{xmmreg} +00001111,00111000,00000101,{MOD}{mmxreg}{R_M}:phsubw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000110,{Mod}{xmmreg}{R_m}:phsubd {Mod}{R_m},{xmmreg} +00001111,00111000,00000110,{MOD}{mmxreg}{R_M}:phsubd {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00000111,{Mod}{xmmreg}{R_m}:phsubsw {Mod}{R_m},{xmmreg} +00001111,00111000,00000111,{MOD}{mmxreg}{R_M}:phsubsw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00001000,{Mod}{xmmreg}{R_m}:psignb {Mod}{R_m},{xmmreg} +00001111,00111000,00001000,{MOD}{mmxreg}{R_M}:psignb {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00001001,{Mod}{xmmreg}{R_m}:psignw {Mod}{R_m},{xmmreg} +00001111,00111000,00001001,{MOD}{mmxreg}{R_M}:psignw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00001010,{Mod}{xmmreg}{R_m}:psignd {Mod}{R_m},{xmmreg} +00001111,00111000,00001010,{MOD}{mmxreg}{R_M}:psignd {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00001011,{Mod}{xmmreg}{R_m}:pmulhrsw {Mod}{R_m},{xmmreg} +00001111,00111000,00001011,{MOD}{mmxreg}{R_M}:pmulhrsw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00011100,{Mod}{xmmreg}{R_m}:pabsb {Mod}{R_m},{xmmreg} +00001111,00111000,00011100,{MOD}{mmxreg}{R_M}:pabsb {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00011101,{Mod}{xmmreg}{R_m}:pabsw {Mod}{R_m},{xmmreg} +00001111,00111000,00011101,{MOD}{mmxreg}{R_M}:pabsw {MOD}{R_M},{mmxreg} +01100110,00001111,00111000,00011110,{Mod}{xmmreg}{R_m}:pabsd {Mod}{R_m},{xmmreg} +00001111,00111000,00011110,{MOD}{mmxreg}{R_M}:pabsd {MOD}{R_M},{mmxreg} +01100110,00001111,00111010,00001111,{Mod}{xmmreg}{R_m},{imm8}:palignr {imm8},{Mod}{R_m},{xmmreg} +00001111,00111010,00001111,{MOD}{mmxreg}{R_M},{imm8}:palignr {imm8},{MOD}{R_M},{mmxreg} +01100110,00001111,11000111,{mod}110{r_m}:vmclear {mod}{r_m} +11110011,00001111,11000111,{mod}110{r_m}:vmxon {mod}{r_m} +00001111,11000111,{mod}110{r_m}:vmptrld {mod}{r_m} +00001111,11000111,{mod}111{r_m}:vmptrst {mod}{r_m} +01100110,00001111,01110001,11010{xmmreg},{imm8}:psrlw {imm8},{xmmreg} +00001111,01110001,11010{mmxreg},{imm8}:psrlw {imm8},{mmxreg} +01100110,00001111,01110001,11100{xmmreg},{imm8}:psraw {imm8},{xmmreg} +00001111,01110001,11100{mmxreg},{imm8}:psraw {imm8},{mmxreg} +01100110,00001111,01110001,11110{xmmreg},{imm8}:psllw {imm8},{xmmreg} +00001111,01110001,11110{mmxreg},{imm8}:psllw {imm8},{mmxreg} +01100110,00001111,01110010,11010{xmmreg},{imm8}:psrld {imm8},{xmmreg} +00001111,01110010,11010{mmxreg},{imm8}:psrld {imm8},{mmxreg} +01100110,00001111,01110010,11100{xmmreg},{imm8}:psrad {imm8},{xmmreg} +00001111,01110010,11100{mmxreg},{imm8}:psrad {imm8},{mmxreg} +01100110,00001111,01110010,11110{xmmreg},{imm8}:pslld {imm8},{xmmreg} +00001111,01110010,11110{mmxreg},{imm8}:pslld {imm8},{mmxreg} +01100110,00001111,01110011,11010{xmmreg},{imm8}:psrlq {imm8},{xmmreg} +00001111,01110011,11010{mmxreg},{imm8}:psrlq {imm8},{mmxreg} +01100110,00001111,01110011,11011{xmmreg},{imm8}:psrldq {imm8},{xmmreg} +01100110,00001111,01110011,11110{xmmreg},{imm8}:psllq {imm8},{xmmreg} +00001111,01110011,11110{mmxreg},{imm8}:psllq {imm8},{mmxreg} +01100110,00001111,01110011,11111{xmmreg},{imm8}:pslldq {imm8},{xmmreg} +00001111,10101110,11101000:lfence +00001111,10101110,11110000:mfence +00001111,10101110,11111000:sfence +00001111,10101110,{mod}111{r_m}:clflush {mod}{r_m} +00001111,00001111,{MOD}{mmxreg}{R_M}:INVALID {MOD}{R_M},{mmxreg} +01100110,00001111,00111010,00001100,{Mod}{xmmreg}{R_m},{imm8}:blendps {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001101,{Mod}{xmmreg}{R_m},{imm8}:blendpd {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00010100,{Mod}{xmmreg}{R_m}:blendvps %xmm0,{Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00010101,{Mod}{xmmreg}{R_m}:blendvpd %xmm0,{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01000000,{Mod}{xmmreg}{R_m},{imm8}:dpps {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01000001,{Mod}{xmmreg}{R_m},{imm8}:dppd {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00100001,{Mod}{xmmreg}{R_m},{imm8}:insertps {imm8},{Mod}{R_m},{xmmreg} +# Mod == 11 is not valid +01100110,00001111,00111000,00101010,{Mod}{xmmreg}{R_m}:movntdqa {Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01000010,{Mod}{xmmreg}{R_m},{imm8}:mpsadbw {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00101011,{Mod}{xmmreg}{R_m}:packusdw {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00010000,{Mod}{xmmreg}{R_m}:pblendvb %xmm0,{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001110,{Mod}{xmmreg}{R_m},{imm8}:pblendw {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00101001,{Mod}{xmmreg}{R_m}:pcmpeqq {Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01100001,{Mod}{xmmreg}{R_m},{imm8}:pcmpestri {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01100000,{Mod}{xmmreg}{R_m},{imm8}:pcmpestrm {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01100011,{Mod}{xmmreg}{R_m},{imm8}:pcmpistri {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,01100010,{Mod}{xmmreg}{R_m},{imm8}:pcmpistrm {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110111,{Mod}{xmmreg}{R_m}:pcmpgtq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,01000001,{Mod}{xmmreg}{R_m}:phminposuw {Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00100000,{mod}{xmmreg}{r_m},{imm8}:pinsrb {imm8},{mod}{r_m},{xmmreg} +01100110,00001111,00111010,00100010,{mod}{xmmreg}{r_m},{imm8}:pinsrd {imm8},{mod}{r_m},{xmmreg} +01100110,00001111,00111000,00111100,{Mod}{xmmreg}{R_m}:pmaxsb {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111101,{Mod}{xmmreg}{R_m}:pmaxsd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111111,{Mod}{xmmreg}{R_m}:pmaxud {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111110,{Mod}{xmmreg}{R_m}:pmaxuw {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111000,{Mod}{xmmreg}{R_m}:pminsb {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111001,{Mod}{xmmreg}{R_m}:pminsd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111011,{Mod}{xmmreg}{R_m}:pminud {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00111010,{Mod}{xmmreg}{R_m}:pminuw {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100000,{Mod}{xmmreg}{R_m}:pmovsxbw {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100001,{Mod}{xmmreg}{R_m}:pmovsxbd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100010,{Mod}{xmmreg}{R_m}:pmovsxbq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100011,{Mod}{xmmreg}{R_m}:pmovsxwd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100100,{Mod}{xmmreg}{R_m}:pmovsxwq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00100101,{Mod}{xmmreg}{R_m}:pmovsxdq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110000,{Mod}{xmmreg}{R_m}:pmovzxbw {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110001,{Mod}{xmmreg}{R_m}:pmovzxbd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110010,{Mod}{xmmreg}{R_m}:pmovzxbq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110011,{Mod}{xmmreg}{R_m}:pmovzxwd {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110100,{Mod}{xmmreg}{R_m}:pmovzxwq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00110101,{Mod}{xmmreg}{R_m}:pmovzxdq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00101000,{Mod}{xmmreg}{R_m}:pmuldq {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,01000000,{Mod}{xmmreg}{R_m}:pmulld {Mod}{R_m},{xmmreg} +01100110,00001111,00111000,00010111,{Mod}{xmmreg}{R_m}:ptest {Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001000,{Mod}{xmmreg}{R_m},{imm8}:roundps {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001001,{Mod}{xmmreg}{R_m},{imm8}:roundpd {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001010,{Mod}{xmmreg}{R_m},{imm8}:roundss {imm8},{Mod}{R_m},{xmmreg} +01100110,00001111,00111010,00001011,{Mod}{xmmreg}{R_m},{imm8}:roundsd {imm8},{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/i386_data.h b/libcpu/i386_data.h new file mode 100644 index 0000000..42e6650 --- /dev/null +++ b/libcpu/i386_data.h @@ -0,0 +1,1415 @@ +/* Helper routines for disassembler for x86/x86-64. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2007. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <libasm.h> + +struct instr_enc +{ + /* The mnemonic. Especially encoded for the optimized table. */ + unsigned int mnemonic : MNEMONIC_BITS; + + /* The rep/repe prefixes. */ + unsigned int rep : 1; + unsigned int repe : 1; + + /* Mnemonic suffix. */ + unsigned int suffix : SUFFIX_BITS; + + /* Nonzero if the instruction uses modr/m. */ + unsigned int modrm : 1; + + /* 1st parameter. */ + unsigned int fct1 : FCT1_BITS; +#ifdef STR1_BITS + unsigned int str1 : STR1_BITS; +#endif + unsigned int off1_1 : OFF1_1_BITS; + unsigned int off1_2 : OFF1_2_BITS; + unsigned int off1_3 : OFF1_3_BITS; + + /* 2nd parameter. */ + unsigned int fct2 : FCT2_BITS; +#ifdef STR2_BITS + unsigned int str2 : STR2_BITS; +#endif + unsigned int off2_1 : OFF2_1_BITS; + unsigned int off2_2 : OFF2_2_BITS; + unsigned int off2_3 : OFF2_3_BITS; + + /* 3rd parameter. */ + unsigned int fct3 : FCT3_BITS; +#ifdef STR3_BITS + unsigned int str3 : STR3_BITS; +#endif + unsigned int off3_1 : OFF3_1_BITS; +#ifdef OFF3_2_BITS + unsigned int off3_2 : OFF3_2_BITS; +#endif +#ifdef OFF3_3_BITS + unsigned int off3_3 : OFF3_3_BITS; +#endif +}; + + +typedef int (*opfct_t) (struct output_data *); + + +static int +data_prefix (struct output_data *d) +{ + char ch = '\0'; + if (*d->prefixes & has_cs) + { + ch = 'c'; + *d->prefixes &= ~has_cs; + } + else if (*d->prefixes & has_ds) + { + ch = 'd'; + *d->prefixes &= ~has_ds; + } + else if (*d->prefixes & has_es) + { + ch = 'e'; + *d->prefixes &= ~has_es; + } + else if (*d->prefixes & has_fs) + { + ch = 'f'; + *d->prefixes &= ~has_fs; + } + else if (*d->prefixes & has_gs) + { + ch = 'g'; + *d->prefixes &= ~has_gs; + } + else if (*d->prefixes & has_ss) + { + ch = 's'; + *d->prefixes &= ~has_ss; + } + else + return 0; + + if (*d->bufcntp + 4 > d->bufsize) + return *d->bufcntp + 4 - d->bufsize; + + d->bufp[(*d->bufcntp)++] = '%'; + d->bufp[(*d->bufcntp)++] = ch; + d->bufp[(*d->bufcntp)++] = 's'; + d->bufp[(*d->bufcntp)++] = ':'; + + return 0; +} + +#ifdef X86_64 +static const char hiregs[8][4] = + { + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; +static const char aregs[8][4] = + { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi" + }; +static const char dregs[8][4] = + { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" + }; +#else +static const char aregs[8][4] = + { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" + }; +# define dregs aregs +#endif + +static int +general_mod$r_m (struct output_data *d) +{ + int r = data_prefix (d); + if (r != 0) + return r; + + int prefixes = *d->prefixes; + const uint8_t *data = &d->data[d->opoff1 / 8]; + char *bufp = d->bufp; + size_t *bufcntp = d->bufcntp; + size_t bufsize = d->bufsize; + + uint_fast8_t modrm = data[0]; +#ifndef X86_64 + if (unlikely ((prefixes & has_addr16) != 0)) + { + int16_t disp = 0; + bool nodisp = false; + + if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80) + /* 16 bit displacement. */ + disp = read_2sbyte_unaligned (&data[1]); + else if ((modrm & 0xc0) == 0x40) + /* 8 bit displacement. */ + disp = *(const int8_t *) &data[1]; + else if ((modrm & 0xc0) == 0) + nodisp = true; + + char tmpbuf[sizeof ("-0x1234(%rr,%rr)")]; + int n; + if ((modrm & 0xc7) == 6) + n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx16, disp); + else + { + n = 0; + if (!nodisp) + n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx16, + disp < 0 ? "-" : "", disp < 0 ? -disp : disp); + + if ((modrm & 0x4) == 0) + n += snprintf (tmpbuf + n, sizeof (tmpbuf) - n, "(%%b%c,%%%ci)", + "xp"[(modrm >> 1) & 1], "sd"[modrm & 1]); + else + n += snprintf (tmpbuf + n, sizeof (tmpbuf) - n, "(%%%s)", + ((const char [4][3]) { "si", "di", "bp", "bx" })[modrm & 3]); + } + + if (*bufcntp + n + 1 > bufsize) + return *bufcntp + n + 1 - bufsize; + + memcpy (&bufp[*bufcntp], tmpbuf, n + 1); + *bufcntp += n; + } + else +#endif + { + 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[1]); + else if ((modrm & 0xc0) == 0x40) + /* 8 bit displacement. */ + disp = *(const int8_t *) &data[1]; + else if ((modrm & 0xc0) == 0) + nodisp = true; + + char tmpbuf[sizeof ("-0x12345678(%rrrr)")]; + int n; + if (nodisp) + { + n = snprintf (tmpbuf, sizeof (tmpbuf), "(%%%s)", +#ifdef X86_64 + (prefixes & has_rex_b) ? hiregs[modrm & 7] : +#endif + aregs[modrm & 7]); +#ifdef X86_64 + if (prefixes & has_addr16) + { + if (prefixes & has_rex_b) + tmpbuf[n++] = 'd'; + else + tmpbuf[2] = 'e'; + } +#endif + } + else if ((modrm & 0xc7) != 5) + { + int p; + n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%%n%s)", + disp < 0 ? "-" : "", disp < 0 ? -disp : disp, &p, +#ifdef X86_64 + (prefixes & has_rex_b) ? hiregs[modrm & 7] : +#endif + aregs[modrm & 7]); +#ifdef X86_64 + if (prefixes & has_addr16) + { + if (prefixes & has_rex_b) + tmpbuf[n++] = 'd'; + else + tmpbuf[p] = 'e'; + } +#endif + } + else + { +#ifdef X86_64 + n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%rip)", + disp < 0 ? "-" : "", disp < 0 ? -disp : disp); + + d->symaddr_use = addr_rel_always; + d->symaddr = disp; +#else + n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx32, disp); +#endif + } + + 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[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[2]); + else if ((modrm & 0xc0) == 0x40) + /* 8 bit displacement. */ + disp = *(const int8_t *) &data[2]; + else + nodisp = true; + + char tmpbuf[sizeof ("-0x12345678(%rrrr,%rrrr,N)")]; + char *cp = tmpbuf; + int n; + if ((modrm & 0xc0) != 0 || (sib & 0x3f) != 0x25 +#ifdef X86_64 + || (prefixes & has_rex_x) != 0 +#endif + ) + { + 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 = stpcpy (cp, +#ifdef X86_64 + (prefixes & has_rex_b) ? hiregs[sib & 7] : + (prefixes & has_addr16) ? dregs[sib & 7] : +#endif + aregs[sib & 7]); +#ifdef X86_64 + if ((prefixes & (has_rex_b | has_addr16)) + == (has_rex_b | has_addr16)) + *cp++ = 'd'; +#endif + } + + if ((sib & 0x38) != 0x20 +#ifdef X86_64 + || (prefixes & has_rex_x) != 0 +#endif + ) + { + *cp++ = ','; + *cp++ = '%'; + cp = stpcpy (cp, +#ifdef X86_64 + (prefixes & has_rex_x) + ? hiregs[(sib >> 3) & 7] : + (prefixes & has_addr16) + ? dregs[(sib >> 3) & 7] : +#endif + aregs[(sib >> 3) & 7]); +#ifdef X86_64 + if ((prefixes & (has_rex_b | has_addr16)) + == (has_rex_b | has_addr16)) + *cp++ = 'd'; +#endif + + *cp++ = ','; + *cp++ = '0' + (1 << (sib >> 6)); + } + + *cp++ = ')'; + } + else + { + assert (! nodisp); +#ifdef X86_64 + if ((prefixes & has_addr16) == 0) + n = snprintf (cp, sizeof (tmpbuf), "0x%" PRIx64, + (int64_t) disp); + else +#endif + 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 (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + assert (d->opoff1 / 8 == d->opoff2 / 8); + assert (d->opoff2 % 8 == 5); + //uint_fast8_t byte = d->data[d->opoff2 / 8] & 7; + uint_fast8_t byte = modrm & 7; + + size_t *bufcntp = d->bufcntp; + char *buf = d->bufp + *bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed; + if (*d->prefixes & (has_rep | has_repne)) + needed = snprintf (buf, avail, "%%%s", dregs[byte]); + else + needed = snprintf (buf, avail, "%%mm%" PRIxFAST8, byte); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; + } + + return general_mod$r_m (d); +} + + +static int +FCT_Mod$R_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + assert (d->opoff1 / 8 == d->opoff2 / 8); + assert (d->opoff2 % 8 == 5); + //uint_fast8_t byte = data[opoff2 / 8] & 7; + uint_fast8_t byte = modrm & 7; + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, + byte); + if ((size_t) needed > avail) + return needed - avail; + *d->bufcntp += needed; + return 0; + } + + return general_mod$r_m (d); +} + +static int +generic_abs (struct output_data *d, const char *absstring +#ifdef X86_64 + , int abslen +#else +# define abslen 4 +#endif + ) +{ + int r = data_prefix (d); + if (r != 0) + return r; + + assert (d->opoff1 % 8 == 0); + assert (d->opoff1 / 8 == 1); + if (*d->param_start + abslen > d->end) + return -1; + *d->param_start += abslen; +#ifndef X86_64 + uint32_t absval; +# define ABSPRIFMT PRIx32 +#else + uint64_t absval; +# define ABSPRIFMT PRIx64 + if (abslen == 8) + absval = read_8ubyte_unaligned (&d->data[1]); + else +#endif + absval = read_4ubyte_unaligned (&d->data[1]); + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%s0x%" ABSPRIFMT, + absstring, absval); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_absval (struct output_data *d) +{ + return generic_abs (d, "$" +#ifdef X86_64 + , 4 +#endif + ); +} + +static int +FCT_abs (struct output_data *d) +{ + return generic_abs (d, "" +#ifdef X86_64 + , 8 +#endif + ); +} + +static int +FCT_ax (struct output_data *d) +{ + int is_16bit = (*d->prefixes & has_data16) != 0; + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + size_t bufsize = d->bufsize; + + if (*bufcntp + 4 - is_16bit > bufsize) + return *bufcntp + 4 - is_16bit - bufsize; + + bufp[(*bufcntp)++] = '%'; + if (! is_16bit) + bufp[(*bufcntp)++] = ( +#ifdef X86_64 + (*d->prefixes & has_rex_w) ? 'r' : +#endif + 'e'); + bufp[(*bufcntp)++] = 'a'; + bufp[(*bufcntp)++] = 'x'; + + return 0; +} + + +static int +FCT_ax$w (struct output_data *d) +{ + if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) != 0) + return FCT_ax (d); + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + size_t bufsize = d->bufsize; + + if (*bufcntp + 3 > bufsize) + return *bufcntp + 3 - bufsize; + + bufp[(*bufcntp)++] = '%'; + bufp[(*bufcntp)++] = 'a'; + bufp[(*bufcntp)++] = 'l'; + + return 0; +} + + +static int +__attribute__ ((noinline)) +FCT_crdb (struct output_data *d, const char *regstr) +{ + if (*d->prefixes & has_data16) + return -1; + + size_t *bufcntp = d->bufcntp; + + // XXX If this assert is true, use absolute offset below + assert (d->opoff1 / 8 == 2); + assert (d->opoff1 % 8 == 2); + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%%%s%" PRIx32, + regstr, (uint32_t) (d->data[d->opoff1 / 8] >> 3) & 7); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_ccc (struct output_data *d) +{ + return FCT_crdb (d, "cr"); +} + + +static int +FCT_ddd (struct output_data *d) +{ + return FCT_crdb (d, "db"); +} + + +static int +FCT_disp8 (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + if (*d->param_start >= d->end) + return -1; + int32_t offset = *(const int8_t *) (*d->param_start)++; + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx32, + (uint32_t) (d->addr + (*d->param_start - d->data) + + offset)); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +__attribute__ ((noinline)) +FCT_ds_xx (struct output_data *d, const char *reg) +{ + int prefix = *d->prefixes & SEGMENT_PREFIXES; + + if (prefix == 0) + *d->prefixes |= prefix = has_ds; + /* Make sure only one bit is set. */ + else if ((prefix - 1) & prefix) + return -1; + + int r = data_prefix (d); + + assert ((*d->prefixes & prefix) == 0); + + if (r != 0) + return r; + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "(%%%s%s)", +#ifdef X86_64 + *d->prefixes & idx_addr16 ? "e" : "r", +#else + *d->prefixes & idx_addr16 ? "" : "e", +#endif + reg); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + + return 0; +} + + +static int +FCT_ds_bx (struct output_data *d) +{ + return FCT_ds_xx (d, "bx"); +} + + +static int +FCT_ds_si (struct output_data *d) +{ + return FCT_ds_xx (d, "si"); +} + + +static int +FCT_dx (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + + if (*bufcntp + 7 > d->bufsize) + return *bufcntp + 7 - d->bufsize; + + memcpy (&d->bufp[*bufcntp], "(%dx)", 5); + *bufcntp += 5; + + return 0; +} + + +static int +FCT_es_di (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%%es:(%%%sdi)", +#ifdef X86_64 + *d->prefixes & idx_addr16 ? "e" : "r" +#else + *d->prefixes & idx_addr16 ? "" : "e" +#endif + ); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + + return 0; +} + + +static int +FCT_imm (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed; + if (*d->prefixes & has_data16) + { + if (*d->param_start + 2 > d->end) + return -1; + uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); + needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); + } + else + { + if (*d->param_start + 4 > d->end) + return -1; + int32_t word = read_4sbyte_unaligned_inc (*d->param_start); +#ifdef X86_64 + if (*d->prefixes & has_rex_w) + needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, + (int64_t) word); + else +#endif + needed = snprintf (&d->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 (struct output_data *d) +{ + if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) != 0) + return FCT_imm (d); + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if (*d->param_start>= d->end) + return -1; + uint_fast8_t word = *(*d->param_start)++; + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIxFAST8, word); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +#ifdef X86_64 +static int +FCT_imm64$w (struct output_data *d) +{ + if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) == 0 + || (*d->prefixes & has_data16) != 0) + return FCT_imm$w (d); + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed; + if (*d->prefixes & has_rex_w) + { + if (*d->param_start + 8 > d->end) + return -1; + uint64_t word = read_8ubyte_unaligned_inc (*d->param_start); + needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, word); + } + else + { + if (*d->param_start + 4 > d->end) + return -1; + int32_t word = read_4sbyte_unaligned_inc (*d->param_start); + needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, word); + } + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} +#endif + + +static int +FCT_imms (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if (*d->param_start>= d->end) + return -1; + int8_t byte = *(*d->param_start)++; +#ifdef X86_64 + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, + (int64_t) byte); +#else + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, + (int32_t) byte); +#endif + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_imm$s (struct output_data *d) +{ + uint_fast8_t opcode = d->data[d->opoff2 / 8]; + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if ((opcode & 2) != 0) + return FCT_imms (d); + + if ((*d->prefixes & has_data16) == 0) + { + if (*d->param_start + 4 > d->end) + return -1; + int32_t word = read_4sbyte_unaligned_inc (*d->param_start); +#ifdef X86_64 + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, + (int64_t) word); +#else + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, word); +#endif + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + } + else + { + if (*d->param_start + 2 > d->end) + return -1; + uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + } + return 0; +} + + +static int +FCT_imm16 (struct output_data *d) +{ + if (*d->param_start + 2 > d->end) + return -1; + uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_imms8 (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if (*d->param_start >= d->end) + return -1; + int_fast8_t byte = *(*d->param_start)++; + int needed; +#ifdef X86_64 + if (*d->prefixes & has_rex_w) + needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, + (int64_t) byte); + else +#endif + needed = snprintf (&d->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 (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if (*d->param_start >= d->end) + return -1; + uint_fast8_t byte = *(*d->param_start)++; + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, + (uint32_t) byte); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_rel (struct output_data *d) +{ + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + if (*d->param_start + 4 > d->end) + return -1; + int32_t rel = read_4sbyte_unaligned_inc (*d->param_start); +#ifdef X86_64 + int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx64, + (uint64_t) (d->addr + rel + + (*d->param_start - d->data))); +#else + int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx32, + (uint32_t) (d->addr + rel + + (*d->param_start - d->data))); +#endif + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_mmxreg (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 == 2 || d->opoff1 % 8 == 5); + byte = (byte >> (5 - d->opoff1 % 8)) & 7; + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_mod$r_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + int prefixes = *d->prefixes; + if (prefixes & has_addr16) + return -1; + + int is_16bit = (prefixes & has_data16) != 0; + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + if (*bufcntp + 5 - is_16bit > d->bufsize) + return *bufcntp + 5 - is_16bit - d->bufsize; + bufp[(*bufcntp)++] = '%'; + + char *cp; +#ifdef X86_64 + if ((prefixes & has_rex_b) != 0 && !is_16bit) + { + cp = stpcpy (&bufp[*bufcntp], hiregs[modrm & 7]); + if ((prefixes & has_rex_w) == 0) + *cp++ = 'd'; + } + else +#endif + { + cp = stpcpy (&bufp[*bufcntp], dregs[modrm & 7] + is_16bit); +#ifdef X86_64 + if ((prefixes & has_rex_w) != 0) + bufp[*bufcntp] = 'r'; +#endif + } + *bufcntp = cp - bufp; + return 0; + } + + return general_mod$r_m (d); +} + + +#ifndef X86_64 +static int +FCT_moda$r_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + if (*d->prefixes & has_addr16) + return -1; + + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 3 > d->bufsize) + return *bufcntp + 3 - d->bufsize; + + memcpy (&d->bufp[*bufcntp], "???", 3); + *bufcntp += 3; + + return 0; + } + + return general_mod$r_m (d); +} +#endif + + +#ifdef X86_64 +static const char rex_8bit[8][3] = + { + [0] = "a", [1] = "c", [2] = "d", [3] = "b", + [4] = "sp", [5] = "bp", [6] = "si", [7] = "di" + }; +#endif + + +static int +FCT_mod$r_m$w (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + const uint8_t *data = d->data; + uint_fast8_t modrm = data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + int prefixes = *d->prefixes; + + if (prefixes & has_addr16) + return -1; + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + if (*bufcntp + 5 > d->bufsize) + return *bufcntp + 5 - d->bufsize; + + if ((data[d->opoff3 / 8] & (1 << (7 - (d->opoff3 & 7)))) == 0) + { + bufp[(*bufcntp)++] = '%'; + +#ifdef X86_64 + if (prefixes & has_rex) + { + if (prefixes & has_rex_r) + *bufcntp += snprintf (bufp + *bufcntp, d->bufsize - *bufcntp, + "r%db", 8 + (modrm & 7)); + else + { + char *cp = stpcpy (bufp + *bufcntp, hiregs[modrm & 7]); + *cp++ = 'l'; + *bufcntp = cp - bufp; + } + } + else +#endif + { + bufp[(*bufcntp)++] = "acdb"[modrm & 3]; + bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2]; + } + } + else + { + int is_16bit = (prefixes & has_data16) != 0; + + bufp[(*bufcntp)++] = '%'; + + char *cp; +#ifdef X86_64 + if ((prefixes & has_rex_b) != 0 && !is_16bit) + { + cp = stpcpy (&bufp[*bufcntp], hiregs[modrm & 7]); + if ((prefixes & has_rex_w) == 0) + *cp++ = 'd'; + } + else +#endif + { + cp = stpcpy (&bufp[*bufcntp], dregs[modrm & 7] + is_16bit); +#ifdef X86_64 + if ((prefixes & has_rex_w) != 0) + bufp[*bufcntp] = 'r'; +#endif + } + *bufcntp = cp - bufp; + } + return 0; + } + + return general_mod$r_m (d); +} + + +static int +FCT_mod$8r_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + if (*bufcntp + 3 > d->bufsize) + return *bufcntp + 3 - d->bufsize; + bufp[(*bufcntp)++] = '%'; + bufp[(*bufcntp)++] = "acdb"[modrm & 3]; + bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2]; + return 0; + } + + return general_mod$r_m (d); +} + + +static int +FCT_mod$16r_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + assert (d->opoff1 / 8 == d->opoff2 / 8); + //uint_fast8_t byte = data[opoff2 / 8] & 7; + uint_fast8_t byte = modrm & 7; + + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 3 > d->bufsize) + return *bufcntp + 3 - d->bufsize; + d->bufp[(*bufcntp)++] = '%'; + memcpy (&d->bufp[*bufcntp], dregs[byte] + 1, sizeof (dregs[0]) - 1); + *bufcntp += 2; + return 0; + } + + return general_mod$r_m (d); +} + + +#ifdef X86_64 +static int +FCT_mod$64r_m (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + uint_fast8_t modrm = d->data[d->opoff1 / 8]; + if ((modrm & 0xc0) == 0xc0) + { + assert (d->opoff1 / 8 == d->opoff2 / 8); + //uint_fast8_t byte = data[opoff2 / 8] & 7; + uint_fast8_t byte = modrm & 7; + + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 4 > d->bufsize) + return *bufcntp + 4 - d->bufsize; + char *cp = &d->bufp[*bufcntp]; + *cp++ = '%'; + cp = stpcpy (cp, + (*d->prefixes & has_rex_b) ? hiregs[byte] : aregs[byte]); + *bufcntp = cp - d->bufp; + return 0; + } + + return general_mod$r_m (d); +} +#else +static typeof (FCT_mod$r_m) FCT_mod$64r_m __attribute__ ((alias ("FCT_mod$r_m"))); +#endif + + +static int +FCT_reg (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 + 3 <= 8); + byte >>= 8 - (d->opoff1 % 8 + 3); + byte &= 7; + int is_16bit = (*d->prefixes & has_data16) != 0; + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 5 > d->bufsize) + return *bufcntp + 5 - d->bufsize; + d->bufp[(*bufcntp)++] = '%'; +#ifdef X86_64 + if ((*d->prefixes & has_rex_r) != 0 && !is_16bit) + { + *bufcntp += snprintf (&d->bufp[*bufcntp], d->bufsize - *bufcntp, "r%d", + 8 + byte); + if ((*d->prefixes & has_rex_w) == 0) + d->bufp[(*bufcntp)++] = 'd'; + } + else +#endif + { + memcpy (&d->bufp[*bufcntp], dregs[byte] + is_16bit, 3 - is_16bit); +#ifdef X86_64 + if ((*d->prefixes & has_rex_w) != 0 && !is_16bit) + d->bufp[*bufcntp] = 'r'; +#endif + *bufcntp += 3 - is_16bit; + } + return 0; +} + + +#ifdef X86_64 +static int +FCT_oreg (struct output_data *d) +{ + /* Special form where register comes from opcode. The rex.B bit is used, + rex.R and rex.X are ignored. */ + int save_prefixes = *d->prefixes; + + *d->prefixes = ((save_prefixes & ~has_rex_r) + | ((save_prefixes & has_rex_b) << (idx_rex_r - idx_rex_b))); + + int r = FCT_reg (d); + + *d->prefixes = save_prefixes; + + return r; +} +#endif + + +static int +FCT_reg64 (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 + 3 <= 8); + byte >>= 8 - (d->opoff1 % 8 + 3); + byte &= 7; + if ((*d->prefixes & has_data16) != 0) + return -1; + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 5 > d->bufsize) + return *bufcntp + 5 - d->bufsize; + d->bufp[(*bufcntp)++] = '%'; +#ifdef X86_64 + if ((*d->prefixes & has_rex_r) != 0) + { + *bufcntp += snprintf (&d->bufp[*bufcntp], d->bufsize - *bufcntp, "r%d", + 8 + byte); + if ((*d->prefixes & has_rex_w) == 0) + d->bufp[(*bufcntp)++] = 'd'; + } + else +#endif + { + memcpy (&d->bufp[*bufcntp], aregs[byte], 3); + *bufcntp += 3; + } + return 0; +} + + +static int +FCT_reg$w (struct output_data *d) +{ + if (d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) + return FCT_reg (d); + + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 + 3 <= 8); + byte >>= 8 - (d->opoff1 % 8 + 3); + byte &= 7; + + size_t *bufcntp = d->bufcntp; + if (*bufcntp + 4 > d->bufsize) + return *bufcntp + 4 - d->bufsize; + + d->bufp[(*bufcntp)++] = '%'; + +#ifdef X86_64 + if (*d->prefixes & has_rex) + { + if (*d->prefixes & has_rex_r) + *bufcntp += snprintf (d->bufp + *bufcntp, d->bufsize - *bufcntp, + "r%db", 8 + byte); + else + { + char* cp = stpcpy (d->bufp + *bufcntp, rex_8bit[byte]); + *cp++ = 'l'; + *bufcntp = cp - d->bufp; + } + } + else +#endif + { + d->bufp[(*bufcntp)++] = "acdb"[byte & 3]; + d->bufp[(*bufcntp)++] = "lh"[byte >> 2]; + } + return 0; +} + + +#ifdef X86_64 +static int +FCT_oreg$w (struct output_data *d) +{ + /* Special form where register comes from opcode. The rex.B bit is used, + rex.R and rex.X are ignored. */ + int save_prefixes = *d->prefixes; + + *d->prefixes = ((save_prefixes & ~has_rex_r) + | ((save_prefixes & has_rex_b) << (idx_rex_r - idx_rex_b))); + + int r = FCT_reg$w (d); + + *d->prefixes = save_prefixes; + + return r; +} +#endif + + +static int +FCT_freg (struct output_data *d) +{ + assert (d->opoff1 / 8 == 1); + assert (d->opoff1 % 8 == 5); + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "%%st(%" PRIx32 ")", + (uint32_t) (d->data[1] & 7)); + if ((size_t) needed > avail) + return (size_t) needed - avail; + *bufcntp += needed; + return 0; +} + + +#ifndef X86_64 +static int +FCT_reg16 (struct output_data *d) +{ + if (*d->prefixes & has_data16) + return -1; + + *d->prefixes |= has_data16; + return FCT_reg (d); +} +#endif + + +static int +FCT_sel (struct output_data *d) +{ + assert (d->opoff1 % 8 == 0); + assert (d->opoff1 / 8 == 5); + if (*d->param_start + 2 > d->end) + return -1; + *d->param_start += 2; + uint16_t absval = read_2ubyte_unaligned (&d->data[5]); + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, absval); + if ((size_t) needed > avail) + return needed - avail; + *bufcntp += needed; + return 0; +} + + +static int +FCT_sreg2 (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 + 3 <= 8); + byte >>= 8 - (d->opoff1 % 8 + 2); + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + if (*bufcntp + 3 > d->bufsize) + return *bufcntp + 3 - d->bufsize; + + bufp[(*bufcntp)++] = '%'; + bufp[(*bufcntp)++] = "ecsd"[byte & 3]; + bufp[(*bufcntp)++] = 's'; + + return 0; +} + + +static int +FCT_sreg3 (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 + 4 <= 8); + byte >>= 8 - (d->opoff1 % 8 + 3); + + if ((byte & 7) >= 6) + return -1; + + size_t *bufcntp = d->bufcntp; + char *bufp = d->bufp; + if (*bufcntp + 3 > d->bufsize) + return *bufcntp + 3 - d->bufsize; + + bufp[(*bufcntp)++] = '%'; + bufp[(*bufcntp)++] = "ecsdfg"[byte & 7]; + bufp[(*bufcntp)++] = 's'; + + return 0; +} + + +static int +FCT_string (struct output_data *d __attribute__ ((unused))) +{ + return 0; +} + + +static int +FCT_xmmreg (struct output_data *d) +{ + uint_fast8_t byte = d->data[d->opoff1 / 8]; + assert (d->opoff1 % 8 == 2 || d->opoff1 % 8 == 5); + byte = (byte >> (5 - d->opoff1 % 8)) & 7; + + size_t *bufcntp = d->bufcntp; + size_t avail = d->bufsize - *bufcntp; + int needed = snprintf (&d->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 0000000..c6bb0a5 --- /dev/null +++ b/libcpu/i386_disasm.c @@ -0,0 +1,1054 @@ +/* Disassembler for x86. + Copyright (C) 2007, 2008, 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2007. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <config.h> +#include <ctype.h> +#include <endian.h> +#include <errno.h> +#include <gelf.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#include "../libebl/libeblP.h" + +#define MACHINE_ENCODING __LITTLE_ENDIAN +#include "memory-access.h" + + +#ifndef MNEFILE +# define MNEFILE "i386.mnemonics" +#endif + +#define MNESTRFIELD(line) MNESTRFIELD1 (line) +#define MNESTRFIELD1(line) str##line +static const union mnestr_t +{ + struct + { +#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)]; +#include MNEFILE +#undef MNE + }; + char str[0]; +} mnestr = + { + { +#define MNE(name) #name, +#include MNEFILE +#undef MNE + } + }; + +/* The index can be stored in the instrtab. */ +enum + { +#define MNE(name) MNE_##name, +#include MNEFILE +#undef MNE + MNE_INVALID + }; + +static const unsigned short int mneidx[] = + { +#define MNE(name) \ + [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)), +#include MNEFILE +#undef MNE + }; + + +enum + { + idx_rex_b = 0, + idx_rex_x, + idx_rex_r, + idx_rex_w, + idx_rex, + idx_cs, + 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 (rex_b), + prefbit (rex_x), + prefbit (rex_r), + prefbit (rex_w), + prefbit (rex), + 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 + + +static const char amd3dnowstr[] = +#define MNE_3DNOW_PAVGUSB 1 + "pavgusb\0" +#define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8) + "pfadd\0" +#define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6) + "pfsub\0" +#define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6) + "pfsubr\0" +#define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7) + "pfacc\0" +#define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6) + "pfcmpge\0" +#define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8) + "pfcmpgt\0" +#define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8) + "pfcmpeq\0" +#define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8) + "pfmin\0" +#define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6) + "pfmax\0" +#define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6) + "pi2fd\0" +#define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6) + "pf2id\0" +#define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6) + "pfrcp\0" +#define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6) + "pfrsqrt\0" +#define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8) + "pfmul\0" +#define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6) + "pfrcpit1\0" +#define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9) + "pfrsqit1\0" +#define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9) + "pfrcpit2\0" +#define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9) + "pmulhrw"; + +#define AMD3DNOW_LOW_IDX 0x0d +#define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1) +#define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX) +static const unsigned char amd3dnow[] = + { + [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB, + [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD, + [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB, + [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR, + [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC, + [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE, + [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT, + [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ, + [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN, + [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX, + [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD, + [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID, + [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP, + [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT, + [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL, + [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1, + [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1, + [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2, + [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW + }; + + +struct output_data +{ + GElf_Addr addr; + int *prefixes; + size_t opoff1; + size_t opoff2; + size_t opoff3; + char *bufp; + size_t *bufcntp; + size_t bufsize; + const uint8_t *data; + const uint8_t **param_start; + const uint8_t *end; + char *labelbuf; + size_t labelbufsize; + enum + { + addr_none = 0, + addr_abs_symbolic, + addr_abs_always, + addr_rel_symbolic, + addr_rel_always + } symaddr_use; + GElf_Addr symaddr; +}; + + +#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) + + +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; + +#define BUFSIZE 512 + char initbuf[BUFSIZE]; + int prefixes; + size_t bufcnt; + size_t bufsize = BUFSIZE; + char *buf = initbuf; + const uint8_t *param_start; + + struct output_data output_data = + { + .prefixes = &prefixes, + .bufp = buf, + .bufsize = bufsize, + .bufcntp = &bufcnt, + .param_start = ¶m_start, + .end = end + }; + + int retval = 0; + while (1) + { + prefixes = 0; + + const uint8_t *data = *startp; + const uint8_t *begin = data; + + /* Recognize all prefixes. */ + int last_prefix_bit = 0; + while (data < end) + { + unsigned int i; + for (i = idx_cs; i < nknown_prefixes; ++i) + if (known_prefixes[i] == *data) + break; + if (i == nknown_prefixes) + break; + + prefixes |= last_prefix_bit = 1 << i; + + ++data; + } + +#ifdef X86_64 + if (data < end && (*data & 0xf0) == 0x40) + prefixes |= ((*data++) & 0xf) | has_rex; +#endif + + bufcnt = 0; + size_t cnt = 0; + + const uint8_t *curr = match_data; + const uint8_t *const match_end = match_data + sizeof (match_data); + + assert (data <= end); + if (data == end) + { + if (prefixes != 0) + goto print_prefix; + + retval = -1; + goto do_ret; + } + + next_match: + while (curr < match_end) + { + uint_fast8_t len = *curr++; + uint_fast8_t clen = len >> 4; + len &= 0xf; + const uint8_t *next_curr = curr + clen + (len - clen) * 2; + + assert (len > 0); + assert (curr + clen + 2 * (len - clen) <= match_end); + + const uint8_t *codep = data; + int correct_prefix = 0; + int opoff = 0; + + if (data > begin && codep[-1] == *curr && clen > 0) + { + /* We match a prefix byte. This is exactly one byte and + is matched exactly, without a mask. */ + --len; + --clen; + opoff = 8; + + ++curr; + + assert (last_prefix_bit != 0); + correct_prefix = last_prefix_bit; + } + + size_t avail = len; + while (clen > 0) + { + if (*codep++ != *curr++) + goto not; + --avail; + --clen; + if (codep == end && avail > 0) + goto do_ret; + } + + while (avail > 0) + { + uint_fast8_t masked = *codep++ & *curr++; + if (masked != *curr++) + { + not: + curr = next_curr; + ++cnt; + bufcnt = 0; + goto next_match; + } + + --avail; + if (codep == end && avail > 0) + goto do_ret; + } + + 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. */ + goto do_ret; + + assert (correct_prefix == 0 + || (prefixes & correct_prefix) != 0); + prefixes ^= correct_prefix; + + if (0) + { + /* Resize the buffer. */ + char *oldbuf; + enomem: + oldbuf = buf; + if (buf == initbuf) + buf = malloc (2 * bufsize); + else + buf = realloc (buf, 2 * bufsize); + if (buf == NULL) + { + buf = oldbuf; + retval = ENOMEM; + goto do_ret; + } + bufsize *= 2; + + output_data.bufp = buf; + output_data.bufsize = bufsize; + bufcnt = 0; + + if (data == end) + { + assert (prefixes != 0); + goto print_prefix; + } + + /* gcc is not clever enough to see the following variables + are not used uninitialized. */ + asm ("" + : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep), + "=mr" (next_curr), "=mr" (len)); + } + + 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; +#ifdef X86_64 + case 0x40 ... 0x4f: + ADD_STRING ("rex"); + if (byte != 0x40) + { + ADD_CHAR ('.'); + if (byte & 0x8) + ADD_CHAR ('w'); + if (byte & 0x4) + ADD_CHAR ('r'); + if (byte & 0x3) + ADD_CHAR ('x'); + if (byte & 0x1) + ADD_CHAR ('b'); + } + break; +#endif + default: + /* Cannot happen. */ + puts ("unknown prefix"); + abort (); + } + data = begin + 1; + ++addr; + + goto out; + } + + /* We have a match. First determine how many bytes are + needed for the adressing mode. */ + param_start = codep; + if (instrtab[cnt].modrm) + { + uint_fast8_t modrm = codep[-1]; + +#ifndef X86_64 + if (likely ((prefixes & has_addr16) != 0)) + { + /* Account for displacement. */ + if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80) + param_start += 2; + else if ((modrm & 0xc0) == 0x40) + param_start += 1; + } + else +#endif + { + /* 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; + } + + if (unlikely (param_start > end)) + goto not; + } + + output_data.addr = addr + (data - begin); + output_data.data = data; + + unsigned long string_end_idx = 0; + fmt = save_fmt; + 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: + retval = EINVAL; + goto do_ret; + } + } + 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++) + { + char mnebuf[16]; + const char *str; + + case 'm': + /* Mnemonic. */ + + if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID)) + { + switch (*data) + { +#ifdef X86_64 + case 0x90: + if (prefixes & has_rex_b) + goto not; + str = "nop"; + break; +#endif + + case 0x98: +#ifdef X86_64 + if (prefixes == (has_rex_w | has_rex)) + { + str = "cltq"; + break; + } +#endif + if (prefixes & ~has_data16) + goto print_prefix; + str = prefixes & has_data16 ? "cbtw" : "cwtl"; + break; + + case 0x99: +#ifdef X86_64 + if (prefixes == (has_rex_w | has_rex)) + { + str = "cqto"; + break; + } +#endif + if (prefixes & ~has_data16) + goto print_prefix; + str = prefixes & has_data16 ? "cwtd" : "cltd"; + break; + + case 0xe3: + if (prefixes & ~has_addr16) + goto print_prefix; +#ifdef X86_64 + str = prefixes & has_addr16 ? "jecxz" : "jrcxz"; +#else + str = prefixes & has_addr16 ? "jcxz" : "jecxz"; +#endif + break; + + case 0x0f: + if (data[1] == 0x0f) + { + /* AMD 3DNOW. We need one more byte. */ + if (param_start >= end) + goto not; + if (*param_start < AMD3DNOW_LOW_IDX + || *param_start > AMD3DNOW_HIGH_IDX) + goto not; + unsigned int idx + = amd3dnow[AMD3DNOW_IDX (*param_start)]; + if (idx == 0) + goto not; + str = amd3dnowstr + idx - 1; + /* Eat the immediate byte indicating the + operation. */ + ++param_start; + break; + } +#ifdef X86_64 + if (data[1] == 0xc7) + { + str = ((prefixes & has_rex_w) + ? "cmpxchg16b" : "cmpxchg8b"); + break; + } +#endif + if (data[1] == 0xc2) + { + if (param_start >= end) + goto not; + if (*param_start > 7) + goto not; + static const char cmpops[][9] = + { + [0] = "cmpeq", + [1] = "cmplt", + [2] = "cmple", + [3] = "cmpunord", + [4] = "cmpneq", + [5] = "cmpnlt", + [6] = "cmpnle", + [7] = "cmpord" + }; + char *cp = stpcpy (mnebuf, cmpops[*param_start]); + if (correct_prefix & (has_rep | has_repne)) + *cp++ = 's'; + else + *cp++ = 'p'; + if (correct_prefix & (has_data16 | has_repne)) + *cp++ = 'd'; + else + *cp++ = 's'; + *cp = '\0'; + str = mnebuf; + /* Eat the immediate byte indicating the + operation. */ + ++param_start; + break; + } + + default: + assert (! "INVALID not handled"); + } + } + 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'; +#ifdef X86_64 + else if (prefixes & has_rex_w) + ch = 'q'; +#endif + 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 + ADD_CHAR ('q'); +#endif + break; + + case suffix_W1: + if (prefixes & has_data16) + { + ADD_CHAR ('w'); + prefixes &= ~has_data16; + } +#ifdef X86_64 + else if (prefixes & has_rex_w) + ADD_CHAR ('q'); +#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 + + op1_str_idx[instrtab[cnt].str1 - 1]); + + output_data.opoff1 = (instrtab[cnt].off1_1 + + OFF1_1_BIAS - opoff); + output_data.opoff2 = (instrtab[cnt].off1_2 + + OFF1_2_BIAS - opoff); + output_data.opoff3 = (instrtab[cnt].off1_3 + + OFF1_3_BIAS - opoff); + int r = op1_fct[instrtab[cnt].fct1] (&output_data); + if (r < 0) + goto not; + if (r > 0) + goto enomem; + + string_end_idx = bufcnt; + } + else if (prec == 2 && instrtab[cnt].fct2 != 0) + { + /* Second parameter. */ + if (instrtab[cnt].str2 != 0) + ADD_STRING (op2_str + + op2_str_idx[instrtab[cnt].str2 - 1]); + + output_data.opoff1 = (instrtab[cnt].off2_1 + + OFF2_1_BIAS - opoff); + output_data.opoff2 = (instrtab[cnt].off2_2 + + OFF2_2_BIAS - opoff); + output_data.opoff3 = (instrtab[cnt].off2_3 + + OFF2_3_BIAS - opoff); + int r = op2_fct[instrtab[cnt].fct2] (&output_data); + if (r < 0) + goto not; + if (r > 0) + goto enomem; + + string_end_idx = bufcnt; + } + else if (prec == 3 && instrtab[cnt].fct3 != 0) + { + /* Third parameter. */ + if (instrtab[cnt].str3 != 0) + ADD_STRING (op3_str + + op3_str_idx[instrtab[cnt].str3 - 1]); + + output_data.opoff1 = (instrtab[cnt].off3_1 + + OFF3_1_BIAS - opoff); + output_data.opoff2 = (instrtab[cnt].off3_2 + + OFF3_2_BIAS - opoff); +#ifdef OFF3_3_BITS + output_data.opoff3 = (instrtab[cnt].off3_3 + + OFF3_3_BIAS - opoff); +#else + output_data.opoff3 = 0; +#endif + int r = op3_fct[instrtab[cnt].fct3] (&output_data); + if (r < 0) + goto not; + if (r > 0) + goto enomem; + + string_end_idx = bufcnt; + } + else + bufcnt = string_end_idx; + break; + + case 'e': + string_end_idx = bufcnt; + break; + + case 'a': + /* Pad to requested column. */ + while (bufcnt < (size_t) width) + ADD_CHAR (' '); + width = 0; + break; + + case 'l': + if (output_data.labelbuf != NULL + && output_data.labelbuf[0] != '\0') + { + ADD_STRING (output_data.labelbuf); + output_data.labelbuf[0] = '\0'; + string_end_idx = bufcnt; + } + else if (output_data.symaddr_use != addr_none) + { + GElf_Addr symaddr = output_data.symaddr; + if (output_data.symaddr_use >= addr_rel_symbolic) + symaddr += addr + param_start - begin; + + // XXX Lookup symbol based on symaddr + const char *symstr = NULL; + if (symcb != NULL + && symcb (0 /* XXX */, 0 /* XXX */, symaddr, + &output_data.labelbuf, + &output_data.labelbufsize, symcbarg) == 0) + symstr = output_data.labelbuf; + + size_t bufavail = bufsize - bufcnt; + int r = 0; + if (symstr != NULL) + r = snprintf (&buf[bufcnt], bufavail, "# <%s>", + symstr); + else if (output_data.symaddr_use == addr_abs_always + || output_data.symaddr_use == addr_rel_always) + r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64, + (uint64_t) symaddr); + + assert (r >= 0); + if ((size_t) r >= bufavail) + goto enomem; + bufcnt += r; + string_end_idx = bufcnt; + + output_data.symaddr_use = addr_none; + } + 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; + + assert (string_end_idx != ~0ul); + bufcnt = string_end_idx; + + 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; + + out: + if (bufcnt == bufsize) + goto enomem; + buf[bufcnt] = '\0'; + + *startp = data; + retval = outcb (buf, bufcnt, outcbarg); + if (retval != 0) + goto do_ret; + } + + do_ret: + free (output_data.labelbuf); + if (buf != initbuf) + free (buf); + + return retval; +} diff --git a/libcpu/i386_gendis.c b/libcpu/i386_gendis.c new file mode 100644 index 0000000..a8570f1 --- /dev/null +++ b/libcpu/i386_gendis.c @@ -0,0 +1,69 @@ +/* Generate tables for x86 disassembler. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2007. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <error.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +extern int i386_parse (void); + + +extern FILE *i386_in; +extern int i386_debug; +char *infname; + +FILE *outfile; + +int +main (int argc, char *argv[argc]) +{ + outfile = stdout; + + if (argc == 1) + error (EXIT_FAILURE, 0, "usage: %s <MNEDEFFILE>", argv[0]); + + //i386_debug = 1; + infname = argv[1]; + if (strcmp (infname, "-") == 0) + i386_in = stdin; + else + { + i386_in = fopen (infname, "r"); + if (i386_in == NULL) + error (EXIT_FAILURE, errno, "cannot open %s", argv[1]); + } + + i386_parse (); + + return error_message_count != 0; +} diff --git a/libcpu/i386_lex.c b/libcpu/i386_lex.c new file mode 100644 index 0000000..a4540b9 --- /dev/null +++ b/libcpu/i386_lex.c @@ -0,0 +1,2011 @@ + +#line 3 "i386_lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer i386__create_buffer +#define yy_delete_buffer i386__delete_buffer +#define yy_flex_debug i386__flex_debug +#define yy_init_buffer i386__init_buffer +#define yy_flush_buffer i386__flush_buffer +#define yy_load_buffer_state i386__load_buffer_state +#define yy_switch_to_buffer i386__switch_to_buffer +#define yyin i386_in +#define yyleng i386_leng +#define yylex i386_lex +#define yylineno i386_lineno +#define yyout i386_out +#define yyrestart i386_restart +#define yytext i386_text +#define yywrap i386_wrap +#define yyalloc i386_alloc +#define yyrealloc i386_realloc +#define yyfree i386_free + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE i386_restart(i386_in ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int i386_leng; + +extern FILE *i386_in, *i386_out; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE i386_lex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-i386_lineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < i386_leng; ++yyl )\ + if ( i386_text[yyl] == '\n' )\ + --i386_lineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up i386_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up i386_text again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via i386_restart()), so that the user can continue scanning by + * just pointing i386_in at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when i386_text is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int i386_leng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow i386_wrap()'s to do buffer switches + * instead of setting up a fresh i386_in. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void i386_restart (FILE *input_file ); +void i386__switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE i386__create_buffer (FILE *file,int size ); +void i386__delete_buffer (YY_BUFFER_STATE b ); +void i386__flush_buffer (YY_BUFFER_STATE b ); +void i386_push_buffer_state (YY_BUFFER_STATE new_buffer ); +void i386_pop_buffer_state (void ); + +static void i386_ensure_buffer_stack (void ); +static void i386__load_buffer_state (void ); +static void i386__init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER i386__flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE i386__scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE i386__scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE i386__scan_bytes (yyconst char *bytes,int len ); + +void *i386_alloc (yy_size_t ); +void *i386_realloc (void *,yy_size_t ); +void i386_free (void * ); + +#define yy_new_buffer i386__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + i386_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + i386__create_buffer(i386_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + i386_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + i386__create_buffer(i386_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define i386_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *i386_in = (FILE *) 0, *i386_out = (FILE *) 0; + +typedef int yy_state_type; + +extern int i386_lineno; + +int i386_lineno = 1; + +extern char *i386_text; +#define yytext_ptr i386_text + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up i386_text. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + i386_leng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 21 +#define YY_END_OF_BUFFER 22 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[62] = + { 0, + 0, 0, 0, 0, 22, 20, 17, 15, 20, 5, + 20, 14, 16, 19, 18, 15, 12, 7, 8, 13, + 11, 11, 19, 14, 16, 17, 6, 0, 0, 0, + 5, 0, 9, 18, 11, 11, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 11, 1, 0, 0, 0, + 11, 0, 0, 0, 11, 2, 3, 0, 10, 4, + 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 4, 1, 5, 1, 1, 1, + 1, 1, 1, 6, 1, 1, 7, 8, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 1, 1, + 1, 1, 1, 1, 12, 13, 13, 14, 13, 13, + 13, 13, 15, 13, 13, 16, 13, 17, 13, 13, + 13, 13, 13, 13, 13, 18, 13, 13, 13, 13, + 1, 1, 1, 1, 13, 1, 19, 13, 13, 13, + + 20, 21, 13, 13, 22, 13, 23, 13, 24, 25, + 26, 27, 13, 28, 29, 13, 30, 13, 13, 31, + 32, 13, 33, 1, 34, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[35] = + { 0, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 1, 3 + } ; + +static yyconst flex_int16_t yy_base[65] = + { 0, + 0, 32, 65, 3, 113, 114, 9, 11, 19, 7, + 78, 16, 114, 114, 18, 20, 114, 114, 114, 114, + 0, 94, 76, 23, 114, 25, 114, 90, 80, 0, + 41, 73, 114, 36, 0, 88, 76, 44, 42, 37, + 49, 37, 38, 37, 31, 40, 114, 33, 32, 28, + 37, 16, 14, 12, 17, 114, 114, 5, 0, 114, + 114, 99, 101, 2 + } ; + +static yyconst flex_int16_t yy_def[65] = + { 0, + 62, 62, 61, 3, 61, 61, 61, 61, 61, 61, + 63, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 64, 64, 63, 61, 61, 61, 61, 61, 61, 61, + 61, 63, 61, 61, 64, 64, 61, 61, 61, 61, + 64, 61, 61, 61, 61, 64, 61, 61, 61, 61, + 64, 61, 61, 61, 64, 61, 61, 61, 64, 61, + 0, 61, 61, 61 + } ; + +static yyconst flex_int16_t yy_nxt[149] = + { 0, + 61, 7, 8, 35, 9, 24, 25, 10, 10, 10, + 26, 26, 26, 26, 31, 31, 31, 26, 26, 34, + 34, 34, 34, 27, 34, 34, 26, 26, 60, 39, + 59, 40, 11, 7, 12, 13, 9, 34, 34, 10, + 10, 10, 28, 58, 57, 29, 56, 30, 31, 31, + 31, 55, 54, 53, 52, 51, 50, 49, 48, 47, + 46, 45, 44, 43, 11, 14, 15, 16, 14, 14, + 17, 14, 18, 19, 14, 20, 21, 21, 21, 22, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 23, 14, 6, + + 6, 6, 32, 32, 42, 41, 33, 38, 37, 33, + 36, 33, 61, 5, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61 + } ; + +static yyconst flex_int16_t yy_chk[149] = + { 0, + 0, 1, 1, 64, 1, 4, 4, 1, 1, 1, + 7, 7, 8, 8, 10, 10, 10, 12, 12, 15, + 15, 16, 16, 9, 24, 24, 26, 26, 58, 30, + 55, 30, 1, 2, 2, 2, 2, 34, 34, 2, + 2, 2, 9, 54, 53, 9, 52, 9, 31, 31, + 31, 51, 50, 49, 48, 46, 45, 44, 43, 42, + 41, 40, 39, 38, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 62, + + 62, 62, 63, 63, 37, 36, 32, 29, 28, 23, + 22, 11, 5, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[22] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, }; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int i386__flex_debug; +int i386__flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *i386_text; +#line 1 "i386_lex.l" +#line 2 "i386_lex.l" +/* Copyright (C) 2004, 2005, 2007, 2008 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <error.h> +#include <libintl.h> + +#include <system.h> +#include "i386_parse.h" + + +static void eat_to_eol (void); +static void invalid_char (int ch); + +#line 581 "i386_lex.c" + +#define INITIAL 0 +#define MAIN 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int i386_lex_destroy (void ); + +int i386_get_debug (void ); + +void i386_set_debug (int debug_flag ); + +YY_EXTRA_TYPE i386_get_extra (void ); + +void i386_set_extra (YY_EXTRA_TYPE user_defined ); + +FILE *i386_get_in (void ); + +void i386_set_in (FILE * in_str ); + +FILE *i386_get_out (void ); + +void i386_set_out (FILE * out_str ); + +int i386_get_leng (void ); + +char *i386_get_text (void ); + +int i386_get_lineno (void ); + +void i386_set_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int i386_wrap (void ); +#else +extern int i386_wrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( i386_text, i386_leng, 1, i386_out )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + unsigned n; \ + for ( n = 0; n < max_size && \ + (c = getc( i386_in )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( i386_in ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, i386_in))==0 && ferror(i386_in)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(i386_in); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int i386_lex (void); + +#define YY_DECL int i386_lex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after i386_text and i386_leng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( i386_leng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (i386_text[i386_leng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 54 "i386_lex.l" + + +#line 770 "i386_lex.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! i386_in ) + i386_in = stdin; + + if ( ! i386_out ) + i386_out = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + i386_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + i386__create_buffer(i386_in,YY_BUF_SIZE ); + } + + i386__load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of i386_text. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 62 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 61 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < i386_leng; ++yyl ) + if ( i386_text[yyl] == '\n' ) + + i386_lineno++; +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 56 "i386_lex.l" +{ return kMASK; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 58 "i386_lex.l" +{ return kPREFIX; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 59 "i386_lex.l" +{ return kSUFFIX; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 61 "i386_lex.l" +{ return kSYNONYM; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 63 "i386_lex.l" +{ i386_lval.num = strtoul (i386_text, NULL, 10); + return kNUMBER; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 66 "i386_lex.l" +{ BEGIN (MAIN); return kPERCPERC; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 69 "i386_lex.l" +{ return '0'; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 70 "i386_lex.l" +{ return '1'; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 72 "i386_lex.l" +{ i386_lval.str = xstrndup (i386_text + 1, + i386_leng - 2); + return kBITFIELD; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 76 "i386_lex.l" +{ i386_lval.str = (void *) -1l; + return kID; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 79 "i386_lex.l" +{ i386_lval.str = xstrndup (i386_text, i386_leng); + return kID; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 82 "i386_lex.l" +{ return ','; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 84 "i386_lex.l" +{ return ':'; } + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 86 "i386_lex.l" +{ /* IGNORE */ } + YY_BREAK +case 15: +/* rule 15 can match eol */ +YY_RULE_SETUP +#line 88 "i386_lex.l" +{ return '\n'; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 90 "i386_lex.l" +{ eat_to_eol (); } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 92 "i386_lex.l" +{ /* IGNORE */ } + YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +#line 94 "i386_lex.l" +{ return kSPACE; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 96 "i386_lex.l" +{ i386_lval.ch = *i386_text; return kCHAR; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 98 "i386_lex.l" +{ invalid_char (*i386_text); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 101 "i386_lex.l" +ECHO; + YY_BREAK +#line 974 "i386_lex.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(MAIN): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed i386_in at a new source and called + * i386_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = i386_in; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( i386_wrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * i386_text, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of i386_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + i386_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + i386_restart(i386_in ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) i386_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 62 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 62 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 61); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up i386_text */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --i386_lineno; + } + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + i386_restart(i386_in ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( i386_wrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve i386_text */ + (yy_hold_char) = *++(yy_c_buf_p); + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol ) + + i386_lineno++; +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void i386_restart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + i386_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + i386__create_buffer(i386_in,YY_BUF_SIZE ); + } + + i386__init_buffer(YY_CURRENT_BUFFER,input_file ); + i386__load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void i386__switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * i386_pop_buffer_state(); + * i386_push_buffer_state(new_buffer); + */ + i386_ensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + i386__load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (i386_wrap()) processing, but the only time this flag + * is looked at is after i386_wrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void i386__load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + i386_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE i386__create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) i386_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in i386__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) i386_alloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in i386__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + i386__init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with i386__create_buffer() + * + */ + void i386__delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + i386_free((void *) b->yy_ch_buf ); + + i386_free((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a i386_restart() or at EOF. + */ + static void i386__init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + i386__flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then i386__init_buffer was _probably_ + * called from i386_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void i386__flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + i386__load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void i386_push_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + i386_ensure_buffer_stack(); + + /* This block is copied from i386__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from i386__switch_to_buffer. */ + i386__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void i386_pop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + i386__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + i386__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void i386_ensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)i386_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in i386_ensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)i386_realloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in i386_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE i386__scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) i386_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in i386__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + i386__switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to i386_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * i386__scan_bytes() instead. + */ +YY_BUFFER_STATE i386__scan_string (yyconst char * yystr ) +{ + + return i386__scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to i386_lex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE i386__scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) i386_alloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in i386__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = i386__scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in i386__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up i386_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + i386_text[i386_leng] = (yy_hold_char); \ + (yy_c_buf_p) = i386_text + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + i386_leng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int i386_get_lineno (void) +{ + + return i386_lineno; +} + +/** Get the input stream. + * + */ +FILE *i386_get_in (void) +{ + return i386_in; +} + +/** Get the output stream. + * + */ +FILE *i386_get_out (void) +{ + return i386_out; +} + +/** Get the length of the current token. + * + */ +int i386_get_leng (void) +{ + return i386_leng; +} + +/** Get the current token. + * + */ + +char *i386_get_text (void) +{ + return i386_text; +} + +/** Set the current line number. + * @param line_number + * + */ +void i386_set_lineno (int line_number ) +{ + + i386_lineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see i386__switch_to_buffer + */ +void i386_set_in (FILE * in_str ) +{ + i386_in = in_str ; +} + +void i386_set_out (FILE * out_str ) +{ + i386_out = out_str ; +} + +int i386_get_debug (void) +{ + return i386__flex_debug; +} + +void i386_set_debug (int bdebug ) +{ + i386__flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from i386_lex_destroy(), so don't allocate here. + */ + + /* We do not touch i386_lineno unless the option is enabled. */ + i386_lineno = 1; + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + i386_in = stdin; + i386_out = stdout; +#else + i386_in = (FILE *) 0; + i386_out = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * i386_lex_init() + */ + return 0; +} + +/* i386_lex_destroy is for both reentrant and non-reentrant scanners. */ +int i386_lex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + i386__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + i386_pop_buffer_state(); + } + + /* Destroy the stack itself. */ + i386_free((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * i386_lex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *i386_alloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *i386_realloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void i386_free (void * ptr ) +{ + free( (char *) ptr ); /* see i386_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 101 "i386_lex.l" + + + +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, i386_lineno); +} + +// Local Variables: +// mode: C +// End: + diff --git a/libcpu/i386_lex.l b/libcpu/i386_lex.l new file mode 100644 index 0000000..828c558 --- /dev/null +++ b/libcpu/i386_lex.l @@ -0,0 +1,126 @@ +%{ +/* Copyright (C) 2004, 2005, 2007, 2008 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <error.h> +#include <libintl.h> + +#include <system.h> +#include "i386_parse.h" + + +static void eat_to_eol (void); +static void invalid_char (int ch); +%} + +ID [a-zA-Z_][a-zA-Z0-9_/]* +ID2 [a-zA-Z0-9_:/]* +NUMBER [0-9]+ +WHITE [[:space:]]+ + +%option yylineno +%option never-interactive +%option noyywrap + + +%x MAIN + +%% + +"%mask" { return kMASK; } + +"%prefix" { return kPREFIX; } +"%suffix" { return kSUFFIX; } + +"%synonym" { return kSYNONYM; } + +{NUMBER} { i386_lval.num = strtoul (yytext, NULL, 10); + return kNUMBER; } + +"%%" { BEGIN (MAIN); return kPERCPERC; } + + +<MAIN>"0" { return '0'; } +<MAIN>"1" { return '1'; } + +<INITIAL,MAIN>"{"{ID2}"}" { i386_lval.str = xstrndup (yytext + 1, + yyleng - 2); + return kBITFIELD; } + +<MAIN>"INVALID" { i386_lval.str = (void *) -1l; + return kID; } + +<MAIN>{ID} { i386_lval.str = xstrndup (yytext, yyleng); + return kID; } + +<MAIN>"," { return ','; } + +<MAIN>":" { return ':'; } + +<INITIAL,MAIN>^"\n" { /* IGNORE */ } + +<INITIAL,MAIN>"\n" { return '\n'; } + +<INITIAL,MAIN>^"#" { eat_to_eol (); } + +{WHITE} { /* IGNORE */ } + +<MAIN>{WHITE} { return kSPACE; } + +<MAIN>. { i386_lval.ch = *yytext; return kCHAR; } + +. { invalid_char (*yytext); } + + +%% + +static void +eat_to_eol (void) +{ + while (1) + { + int c = input (); + + if (c == EOF || c == '\n') + break; + } +} + +static void +invalid_char (int ch) +{ + error (0, 0, (isascii (ch) + ? gettext ("invalid character '%c' at line %d; ignored") + : gettext ("invalid character '\\%o' at line %d; ignored")), + ch, yylineno); +} + +// Local Variables: +// mode: C +// End: diff --git a/libcpu/i386_parse.c b/libcpu/i386_parse.c new file mode 100644 index 0000000..68e957b --- /dev/null +++ b/libcpu/i386_parse.c @@ -0,0 +1,3356 @@ +/* A Bison parser, made by GNU Bison 2.4.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse i386_parse +#define yylex i386_lex +#define yyerror i386_error +#define yylval i386_lval +#define yychar i386_char +#define yydebug i386_debug +#define yynerrs i386_nerrs + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 1 "i386_parse.y" + +/* Parser for i386 CPU description. + Copyright (C) 2004, 2005, 2007, 2008, 2009 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <error.h> +#include <inttypes.h> +#include <libintl.h> +#include <math.h> +#include <obstack.h> +#include <search.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#include <system.h> + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +/* The error handler. */ +static void yyerror (const char *s); + +extern int yylex (void); +extern int i386_lineno; +extern char *infname; + + +struct known_bitfield +{ + char *name; + unsigned long int bits; + int tmp; +}; + + +struct bitvalue +{ + enum bittype { zeroone, field, failure } type; + union + { + unsigned int value; + struct known_bitfield *field; + }; + struct bitvalue *next; +}; + + +struct argname +{ + enum nametype { string, nfield } type; + union + { + char *str; + struct known_bitfield *field; + }; + struct argname *next; +}; + + +struct argument +{ + struct argname *name; + struct argument *next; +}; + + +struct instruction +{ + /* The byte encoding. */ + struct bitvalue *bytes; + + /* Prefix possible. */ + int repe; + int rep; + + /* Mnemonic. */ + char *mnemonic; + + /* Suffix. */ + enum { suffix_none = 0, suffix_w, suffix_w0, suffix_W, suffix_tttn, + suffix_w1, suffix_W1, 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; + int off; +}; + + +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 + + +/* Line 189 of yacc.c */ +#line 294 "i386_parse.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + kMASK = 258, + kPREFIX = 259, + kSUFFIX = 260, + kSYNONYM = 261, + kID = 262, + kNUMBER = 263, + kPERCPERC = 264, + kBITFIELD = 265, + kCHAR = 266, + kSPACE = 267 + }; +#endif +/* Tokens. */ +#define kMASK 258 +#define kPREFIX 259 +#define kSUFFIX 260 +#define kSYNONYM 261 +#define kID 262 +#define kNUMBER 263 +#define kPERCPERC 264 +#define kBITFIELD 265 +#define kCHAR 266 +#define kSPACE 267 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 214 "i386_parse.y" + + unsigned long int num; + char *str; + char ch; + struct known_bitfield *field; + struct bitvalue *bit; + struct argname *name; + struct argument *arg; + + + +/* Line 214 of yacc.c */ +#line 366 "i386_parse.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 378 "i386_parse.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 12 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 37 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 18 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 14 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 32 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 49 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 267 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 15, 2, 2, 2, 16, 17, + 2, 2, 2, 2, 2, 2, 2, 2, 14, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 8, 12, 14, 18, 21, 24, 28, + 29, 33, 35, 42, 43, 45, 46, 50, 52, 55, + 57, 59, 61, 63, 66, 67, 71, 73, 76, 78, + 80, 82, 84 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 19, 0, -1, 20, 9, 13, 22, -1, 20, 13, + 21, -1, 21, -1, 3, 10, 8, -1, 4, 10, + -1, 5, 10, -1, 6, 10, 10, -1, -1, 22, + 13, 23, -1, 23, -1, 25, 14, 24, 7, 24, + 28, -1, -1, 10, -1, -1, 25, 15, 26, -1, + 26, -1, 26, 27, -1, 27, -1, 16, -1, 17, + -1, 10, -1, 12, 29, -1, -1, 29, 15, 30, + -1, 30, -1, 30, 31, -1, 31, -1, 10, -1, + 11, -1, 7, -1, 14, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 244, 244, 254, 255, 258, 260, 262, 264, 276, + 279, 280, 283, 366, 369, 385, 388, 398, 405, 413, + 417, 424, 431, 453, 456, 459, 469, 477, 485, 488, + 520, 529, 536 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "kMASK", "kPREFIX", "kSUFFIX", + "kSYNONYM", "kID", "kNUMBER", "kPERCPERC", "kBITFIELD", "kCHAR", + "kSPACE", "'\\n'", "':'", "','", "'0'", "'1'", "$accept", "spec", + "masks", "mask", "instrs", "instr", "bitfieldopt", "bytes", "byte", + "bit", "optargs", "args", "arg", "argcomp", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 10, 58, 44, 48, 49 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 18, 19, 20, 20, 21, 21, 21, 21, 21, + 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, + 27, 27, 27, 28, 28, 29, 29, 30, 30, 31, + 31, 31, 31 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 4, 3, 1, 3, 2, 2, 3, 0, + 3, 1, 6, 0, 1, 0, 3, 1, 2, 1, + 1, 1, 1, 2, 0, 3, 1, 2, 1, 1, + 1, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 9, 0, 0, 0, 0, 0, 0, 4, 0, 6, + 7, 0, 1, 0, 9, 5, 8, 13, 3, 22, + 20, 21, 2, 11, 0, 17, 19, 13, 15, 0, + 18, 10, 14, 0, 16, 15, 24, 0, 12, 31, + 29, 30, 32, 23, 26, 28, 0, 27, 25 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 5, 6, 7, 22, 23, 33, 24, 25, 26, + 38, 43, 44, 45 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -35 +static const yytype_int8 yypact[] = +{ + 12, 9, 10, 11, 13, 22, -2, -35, 16, -35, + -35, 15, -35, 14, 12, -35, -35, -4, -35, -35, + -35, -35, 17, -35, -12, -4, -35, -4, 18, -4, + -35, -35, -35, 19, -4, 18, 20, -6, -35, -35, + -35, -35, -35, 21, -6, -35, -6, -35, -6 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -35, -35, -35, 23, -35, 2, -1, -35, 4, -25, + -35, -35, -15, -34 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 30, 39, 28, 29, 40, 41, 19, 13, 42, 30, + 47, 14, 20, 21, 47, 1, 2, 3, 4, 8, + 9, 10, 12, 11, 15, 16, 35, 17, 32, 31, + 27, 48, 37, 34, 36, 0, 46, 18 +}; + +static const yytype_int8 yycheck[] = +{ + 25, 7, 14, 15, 10, 11, 10, 9, 14, 34, + 44, 13, 16, 17, 48, 3, 4, 5, 6, 10, + 10, 10, 0, 10, 8, 10, 7, 13, 10, 27, + 13, 46, 12, 29, 35, -1, 15, 14 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 19, 20, 21, 10, 10, + 10, 10, 0, 9, 13, 8, 10, 13, 21, 10, + 16, 17, 22, 23, 25, 26, 27, 13, 14, 15, + 27, 23, 10, 24, 26, 7, 24, 12, 28, 7, + 10, 11, 14, 29, 30, 31, 15, 31, 30 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1464 of yacc.c */ +#line 245 "i386_parse.y" + { + if (error_message_count != 0) + error (EXIT_FAILURE, 0, + "terminated due to previous error"); + + instrtable_out (); + } + break; + + case 5: + +/* Line 1464 of yacc.c */ +#line 259 "i386_parse.y" + { new_bitfield ((yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].num)); } + break; + + case 6: + +/* Line 1464 of yacc.c */ +#line 261 "i386_parse.y" + { new_bitfield ((yyvsp[(2) - (2)].str), -1); } + break; + + case 7: + +/* Line 1464 of yacc.c */ +#line 263 "i386_parse.y" + { new_bitfield ((yyvsp[(2) - (2)].str), -2); } + break; + + case 8: + +/* Line 1464 of yacc.c */ +#line 265 "i386_parse.y" + { + struct synonym *newp = xmalloc (sizeof (*newp)); + newp->from = (yyvsp[(2) - (3)].str); + newp->to = (yyvsp[(3) - (3)].str); + if (tfind (newp, &synonyms, compare_syn) != NULL) + error (0, 0, + "%d: duplicate definition for synonym '%s'", + i386_lineno, (yyvsp[(2) - (3)].str)); + else if (tsearch ( newp, &synonyms, compare_syn) == NULL) + error (EXIT_FAILURE, 0, "tsearch"); + } + break; + + case 12: + +/* Line 1464 of yacc.c */ +#line 284 "i386_parse.y" + { + if ((yyvsp[(3) - (6)].field) != NULL && strcmp ((yyvsp[(3) - (6)].field)->name, "RE") != 0 + && strcmp ((yyvsp[(3) - (6)].field)->name, "R") != 0) + { + error (0, 0, "%d: only 'R' and 'RE' prefix allowed", + i386_lineno - 1); + } + if (check_duplicates ((yyvsp[(1) - (6)].bit)) == 0 + && check_argsdef ((yyvsp[(1) - (6)].bit), (yyvsp[(6) - (6)].arg)) == 0 + && check_bitsused ((yyvsp[(1) - (6)].bit), (yyvsp[(5) - (6)].field), (yyvsp[(6) - (6)].arg)) == 0) + { + struct instruction *newp = xcalloc (sizeof (*newp), + 1); + if ((yyvsp[(3) - (6)].field) != NULL) + { + if (strcmp ((yyvsp[(3) - (6)].field)->name, "RE") == 0) + newp->repe = 1; + else if (strcmp ((yyvsp[(3) - (6)].field)->name, "R") == 0) + newp->rep = 1; + } + + newp->bytes = (yyvsp[(1) - (6)].bit); + newp->mnemonic = (yyvsp[(4) - (6)].str); + if (newp->mnemonic != (void *) -1l + && tfind ((yyvsp[(4) - (6)].str), &mnemonics, + (comparison_fn_t) strcmp) == NULL) + { + if (tsearch ((yyvsp[(4) - (6)].str), &mnemonics, + (comparison_fn_t) strcmp) == NULL) + error (EXIT_FAILURE, errno, "tsearch"); + ++nmnemonics; + } + + if ((yyvsp[(5) - (6)].field) != NULL) + { + if (strcmp ((yyvsp[(5) - (6)].field)->name, "w") == 0) + newp->suffix = suffix_w; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "w0") == 0) + newp->suffix = suffix_w0; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "tttn") == 0) + newp->suffix = suffix_tttn; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "w1") == 0) + newp->suffix = suffix_w1; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "W") == 0) + newp->suffix = suffix_W; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "W1") == 0) + newp->suffix = suffix_W1; + else if (strcmp ((yyvsp[(5) - (6)].field)->name, "D") == 0) + newp->suffix = suffix_D; + else + error (EXIT_FAILURE, 0, + "%s: %d: unknown suffix '%s'", + infname, i386_lineno - 1, (yyvsp[(5) - (6)].field)->name); + + struct suffix search = { .name = (yyvsp[(5) - (6)].field)->name }; + if (tfind (&search, &suffixes, compare_suf) + == NULL) + { + struct suffix *ns = xmalloc (sizeof (*ns)); + ns->name = (yyvsp[(5) - (6)].field)->name; + ns->idx = ++nsuffixes; + if (tsearch (ns, &suffixes, compare_suf) + == NULL) + error (EXIT_FAILURE, errno, "tsearch"); + } + } + + struct argument *args = (yyvsp[(6) - (6)].arg); + int n = 0; + while (args != NULL) + { + fillin_arg ((yyvsp[(1) - (6)].bit), args->name, newp, n); + + args = args->next; + ++n; + } + + newp->next = instructions; + instructions = newp; + ++ninstructions; + } + } + break; + + case 14: + +/* Line 1464 of yacc.c */ +#line 370 "i386_parse.y" + { + struct known_bitfield search; + search.name = (yyvsp[(1) - (1)].str); + struct known_bitfield **res; + res = tfind (&search, &bitfields, bitfield_compare); + if (res == NULL) + { + error (0, 0, "%d: unknown bitfield '%s'", + i386_lineno, search.name); + (yyval.field) = NULL; + } + else + (yyval.field) = *res; + } + break; + + case 15: + +/* Line 1464 of yacc.c */ +#line 385 "i386_parse.y" + { (yyval.field) = NULL; } + break; + + case 16: + +/* Line 1464 of yacc.c */ +#line 389 "i386_parse.y" + { + check_bits ((yyvsp[(3) - (3)].bit)); + + struct bitvalue *runp = (yyvsp[(1) - (3)].bit); + while (runp->next != NULL) + runp = runp->next; + runp->next = (yyvsp[(3) - (3)].bit); + (yyval.bit) = (yyvsp[(1) - (3)].bit); + } + break; + + case 17: + +/* Line 1464 of yacc.c */ +#line 399 "i386_parse.y" + { + check_bits ((yyvsp[(1) - (1)].bit)); + (yyval.bit) = (yyvsp[(1) - (1)].bit); + } + break; + + case 18: + +/* Line 1464 of yacc.c */ +#line 406 "i386_parse.y" + { + struct bitvalue *runp = (yyvsp[(1) - (2)].bit); + while (runp->next != NULL) + runp = runp->next; + runp->next = (yyvsp[(2) - (2)].bit); + (yyval.bit) = (yyvsp[(1) - (2)].bit); + } + break; + + case 19: + +/* Line 1464 of yacc.c */ +#line 414 "i386_parse.y" + { (yyval.bit) = (yyvsp[(1) - (1)].bit); } + break; + + case 20: + +/* Line 1464 of yacc.c */ +#line 418 "i386_parse.y" + { + (yyval.bit) = xmalloc (sizeof (struct bitvalue)); + (yyval.bit)->type = zeroone; + (yyval.bit)->value = 0; + (yyval.bit)->next = NULL; + } + break; + + case 21: + +/* Line 1464 of yacc.c */ +#line 425 "i386_parse.y" + { + (yyval.bit) = xmalloc (sizeof (struct bitvalue)); + (yyval.bit)->type = zeroone; + (yyval.bit)->value = 1; + (yyval.bit)->next = NULL; + } + break; + + case 22: + +/* Line 1464 of yacc.c */ +#line 432 "i386_parse.y" + { + (yyval.bit) = xmalloc (sizeof (struct bitvalue)); + struct known_bitfield search; + search.name = (yyvsp[(1) - (1)].str); + struct known_bitfield **res; + res = tfind (&search, &bitfields, bitfield_compare); + if (res == NULL) + { + error (0, 0, "%d: unknown bitfield '%s'", + i386_lineno, search.name); + (yyval.bit)->type = failure; + } + else + { + (yyval.bit)->type = field; + (yyval.bit)->field = *res; + } + (yyval.bit)->next = NULL; + } + break; + + case 23: + +/* Line 1464 of yacc.c */ +#line 454 "i386_parse.y" + { (yyval.arg) = (yyvsp[(2) - (2)].arg); } + break; + + case 24: + +/* Line 1464 of yacc.c */ +#line 456 "i386_parse.y" + { (yyval.arg) = NULL; } + break; + + case 25: + +/* Line 1464 of yacc.c */ +#line 460 "i386_parse.y" + { + struct argument *runp = (yyvsp[(1) - (3)].arg); + while (runp->next != NULL) + runp = runp->next; + runp->next = xmalloc (sizeof (struct argument)); + runp->next->name = combine ((yyvsp[(3) - (3)].name)); + runp->next->next = NULL; + (yyval.arg) = (yyvsp[(1) - (3)].arg); + } + break; + + case 26: + +/* Line 1464 of yacc.c */ +#line 470 "i386_parse.y" + { + (yyval.arg) = xmalloc (sizeof (struct argument)); + (yyval.arg)->name = combine ((yyvsp[(1) - (1)].name)); + (yyval.arg)->next = NULL; + } + break; + + case 27: + +/* Line 1464 of yacc.c */ +#line 478 "i386_parse.y" + { + struct argname *runp = (yyvsp[(1) - (2)].name); + while (runp->next != NULL) + runp = runp->next; + runp->next = (yyvsp[(2) - (2)].name); + (yyval.name) = (yyvsp[(1) - (2)].name); + } + break; + + case 28: + +/* Line 1464 of yacc.c */ +#line 486 "i386_parse.y" + { (yyval.name) = (yyvsp[(1) - (1)].name); } + break; + + case 29: + +/* Line 1464 of yacc.c */ +#line 489 "i386_parse.y" + { + (yyval.name) = xmalloc (sizeof (struct argname)); + (yyval.name)->type = nfield; + (yyval.name)->next = NULL; + + struct known_bitfield search; + search.name = (yyvsp[(1) - (1)].str); + struct known_bitfield **res; + res = tfind (&search, &bitfields, bitfield_compare); + if (res == NULL) + { + if (strcmp ((yyvsp[(1) - (1)].str), "ax") == 0) + (yyval.name)->field = &ax_reg; + else if (strcmp ((yyvsp[(1) - (1)].str), "dx") == 0) + (yyval.name)->field = &dx_reg; + else if (strcmp ((yyvsp[(1) - (1)].str), "es_di") == 0) + (yyval.name)->field = &di_reg; + else if (strcmp ((yyvsp[(1) - (1)].str), "ds_si") == 0) + (yyval.name)->field = &si_reg; + else if (strcmp ((yyvsp[(1) - (1)].str), "ds_bx") == 0) + (yyval.name)->field = &bx_reg; + else + { + error (0, 0, "%d: unknown bitfield '%s'", + i386_lineno, search.name); + (yyval.name)->field = NULL; + } + } + else + (yyval.name)->field = *res; + } + break; + + case 30: + +/* Line 1464 of yacc.c */ +#line 521 "i386_parse.y" + { + (yyval.name) = xmalloc (sizeof (struct argname)); + (yyval.name)->type = string; + (yyval.name)->next = NULL; + (yyval.name)->str = xmalloc (2); + (yyval.name)->str[0] = (yyvsp[(1) - (1)].ch); + (yyval.name)->str[1] = '\0'; + } + break; + + case 31: + +/* Line 1464 of yacc.c */ +#line 530 "i386_parse.y" + { + (yyval.name) = xmalloc (sizeof (struct argname)); + (yyval.name)->type = string; + (yyval.name)->next = NULL; + (yyval.name)->str = (yyvsp[(1) - (1)].str); + } + break; + + case 32: + +/* Line 1464 of yacc.c */ +#line 537 "i386_parse.y" + { + (yyval.name) = xmalloc (sizeof (struct argname)); + (yyval.name)->type = string; + (yyval.name)->next = NULL; + (yyval.name)->str = xmalloc (2); + (yyval.name)->str[0] = ':'; + (yyval.name)->str[1] = '\0'; + } + break; + + + +/* Line 1464 of yacc.c */ +#line 2006 "i386_parse.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1684 of yacc.c */ +#line 547 "i386_parse.y" + + +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 + { + char *fieldname = runp->field->name; + + struct synonym search = { .from = fieldname }; + + struct synonym **res = tfind (&search, &synonyms, compare_syn); + if (res != NULL) + fieldname = (*res)->to; + + obstack_grow_str (&ob, fieldname); + } + + /* 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); + + 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 int off_op_str; +static void +print_op_str (const void *nodep, VISIT value, + int level __attribute__ ((unused))) +{ + if (value == leaf || value == postorder) + { + const char *str = (*(struct argstring **) nodep)->str; + fprintf (outfile, "%s\n \"%s", + count_op_str == 0 ? "" : "\\0\"", str); + (*(struct argstring **) nodep)->idx = ++count_op_str; + (*(struct argstring **) nodep)->off = off_op_str; + off_op_str += strlen (str) + 1; + } +} + + +static void +print_op_str_idx (const void *nodep, VISIT value, + int level __attribute__ ((unused))) +{ + if (value == leaf || value == postorder) + printf (" %d,\n", (*(struct argstring **) nodep)->off); +} + + +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; + } +} + + +#if NMNES < 2 +# error "bogus NMNES value" +#endif + +static void +instrtable_out (void) +{ + find_numbers (); + +#if 0 + create_mnemonic_table (); + + fprintf (outfile, "#define MNEMONIC_BITS %zu\n", best_mnemonic_bits); +#else + fprintf (outfile, "#define MNEMONIC_BITS %ld\n", + lrint (ceil (log2 (NMNES)))); +#endif + fprintf (outfile, "#define SUFFIX_BITS %d\n", nbitsuf); + for (int i = 0; i < 3; ++i) + { + fprintf (outfile, "#define FCT%d_BITS %d\n", i + 1, nbitfct[i]); + if (nbitstr[i] != 0) + fprintf (outfile, "#define STR%d_BITS %d\n", i + 1, nbitstr[i]); + fprintf (outfile, "#define OFF%d_1_BITS %d\n", i + 1, nbitoff[i][0]); + fprintf (outfile, "#define OFF%d_1_BIAS %d\n", i + 1, minoff[i][0]); + if (nbitoff[i][1] != 0) + { + fprintf (outfile, "#define OFF%d_2_BITS %d\n", i + 1, nbitoff[i][1]); + fprintf (outfile, "#define OFF%d_2_BIAS %d\n", i + 1, minoff[i][1]); + } + if (nbitoff[i][2] != 0) + { + fprintf (outfile, "#define OFF%d_3_BITS %d\n", i + 1, nbitoff[i][2]); + fprintf (outfile, "#define OFF%d_3_BIAS %d\n", i + 1, minoff[i][2]); + } + } + + fputs ("\n#include <i386_data.h>\n\n", outfile); + + +#define APPEND(a, b) APPEND_ (a, b) +#define APPEND_(a, b) a##b +#define EMIT_SUFFIX(suf) \ + fprintf (outfile, "#define suffix_%s %d\n", #suf, APPEND (suffix_, suf)) + EMIT_SUFFIX (none); + EMIT_SUFFIX (w); + EMIT_SUFFIX (w0); + EMIT_SUFFIX (W); + EMIT_SUFFIX (tttn); + EMIT_SUFFIX (D); + EMIT_SUFFIX (w1); + EMIT_SUFFIX (W1); + + fputc_unlocked ('\n', outfile); + + for (int i = 0; i < 3; ++i) + { + /* Functions. */ + count_op_str = 0; + fprintf (outfile, "static const 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; + off_op_str = 0; + fprintf (outfile, "static const char op%d_str[] =", i + 1); + twalk (strs[i], print_op_str); + fputs ("\";\n", outfile); + + fprintf (outfile, "static const uint8_t op%d_str_idx[] = {\n", + i + 1); + twalk (strs[i], print_op_str_idx); + 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; + bool leading_p = true; + size_t leadingbits = 0; + struct bitvalue *b = instr->bytes; + while (b != NULL) + { + if (b->type == zeroone) + { + ++totalbits; + zerobits = 0; + if (leading_p) + ++leadingbits; + } + 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; + leading_p = false; + } + b = b->next; + } + size_t nbytes = (totalbits - zerobits + 7) / 8; + assert (nbytes > 0); + size_t leadingbytes = leadingbits / 8; + + fprintf (outfile, " %#zx,", nbytes | (leadingbytes << 4)); + + /* 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) + { + if (leadingbytes > 0) + { + assert (mask == 0xff); + fprintf (outfile, " %#" PRIx8 ",", byte); + --leadingbytes; + } + else + fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", + mask, byte); + byte = mask = nbits = 0; + if (--nbytes == 0) + break; + } + } + else + { + assert (leadingbytes == 0); + + 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; + } + + fputc_unlocked ('\n', outfile); + } + 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/i386_parse.h b/libcpu/i386_parse.h new file mode 100644 index 0000000..6b5df63 --- /dev/null +++ b/libcpu/i386_parse.h @@ -0,0 +1,95 @@ +/* A Bison parser, made by GNU Bison 2.4.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + kMASK = 258, + kPREFIX = 259, + kSUFFIX = 260, + kSYNONYM = 261, + kID = 262, + kNUMBER = 263, + kPERCPERC = 264, + kBITFIELD = 265, + kCHAR = 266, + kSPACE = 267 + }; +#endif +/* Tokens. */ +#define kMASK 258 +#define kPREFIX 259 +#define kSUFFIX 260 +#define kSYNONYM 261 +#define kID 262 +#define kNUMBER 263 +#define kPERCPERC 264 +#define kBITFIELD 265 +#define kCHAR 266 +#define kSPACE 267 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1685 of yacc.c */ +#line 214 "i386_parse.y" + + unsigned long int num; + char *str; + char ch; + struct known_bitfield *field; + struct bitvalue *bit; + struct argname *name; + struct argument *arg; + + + +/* Line 1685 of yacc.c */ +#line 87 "i386_parse.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE i386_lval; + + diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y new file mode 100644 index 0000000..bea0e33 --- /dev/null +++ b/libcpu/i386_parse.y @@ -0,0 +1,1684 @@ +%{ +/* Parser for i386 CPU description. + Copyright (C) 2004, 2005, 2007, 2008, 2009 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <error.h> +#include <inttypes.h> +#include <libintl.h> +#include <math.h> +#include <obstack.h> +#include <search.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#include <system.h> + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +/* The error handler. */ +static void yyerror (const char *s); + +extern int yylex (void); +extern int i386_lineno; +extern char *infname; + + +struct known_bitfield +{ + char *name; + unsigned long int bits; + int tmp; +}; + + +struct bitvalue +{ + enum bittype { zeroone, field, failure } type; + union + { + unsigned int value; + struct known_bitfield *field; + }; + struct bitvalue *next; +}; + + +struct argname +{ + enum nametype { string, nfield } type; + union + { + char *str; + struct known_bitfield *field; + }; + struct argname *next; +}; + + +struct argument +{ + struct argname *name; + struct argument *next; +}; + + +struct instruction +{ + /* The byte encoding. */ + struct bitvalue *bytes; + + /* Prefix possible. */ + int repe; + int rep; + + /* Mnemonic. */ + char *mnemonic; + + /* Suffix. */ + enum { suffix_none = 0, suffix_w, suffix_w0, suffix_W, suffix_tttn, + suffix_w1, suffix_W1, 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; + int off; +}; + + +static struct known_bitfield ax_reg = + { + .name = "ax", .bits = 0, .tmp = 0 + }; + +static struct known_bitfield dx_reg = + { + .name = "dx", .bits = 0, .tmp = 0 + }; + +static struct known_bitfield di_reg = + { + .name = "es_di", .bits = 0, .tmp = 0 + }; + +static struct known_bitfield si_reg = + { + .name = "ds_si", .bits = 0, .tmp = 0 + }; + +static struct known_bitfield bx_reg = + { + .name = "ds_bx", .bits = 0, .tmp = 0 + }; + + +static int bitfield_compare (const void *p1, const void *p2); +static void new_bitfield (char *name, unsigned long int num); +static void check_bits (struct bitvalue *value); +static int check_duplicates (struct bitvalue *val); +static int check_argsdef (struct bitvalue *bitval, struct argument *args); +static int check_bitsused (struct bitvalue *bitval, + struct known_bitfield *suffix, + struct argument *args); +static struct argname *combine (struct argname *name); +static void fillin_arg (struct bitvalue *bytes, struct argname *name, + struct instruction *instr, int n); +static void find_numbers (void); +static int compare_syn (const void *p1, const void *p2); +static int compare_suf (const void *p1, const void *p2); +static void instrtable_out (void); +#if 0 +static void create_mnemonic_table (void); +#endif + +static void *bitfields; +static struct instruction *instructions; +static size_t ninstructions; +static void *synonyms; +static void *suffixes; +static int nsuffixes; +static void *mnemonics; +size_t nmnemonics; +extern FILE *outfile; + +/* Number of bits used mnemonics. */ +#if 0 +static size_t best_mnemonic_bits; +#endif +%} + +%union { + unsigned long int num; + char *str; + char ch; + struct known_bitfield *field; + struct bitvalue *bit; + struct argname *name; + struct argument *arg; +} + +%token kMASK +%token kPREFIX +%token kSUFFIX +%token kSYNONYM +%token <str> kID +%token <num> kNUMBER +%token kPERCPERC +%token <str> kBITFIELD +%token <ch> kCHAR +%token kSPACE + +%type <bit> bit byte bytes +%type <field> bitfieldopt +%type <name> argcomp arg +%type <arg> args optargs + +%defines + +%% + +spec: masks kPERCPERC '\n' instrs + { + if (error_message_count != 0) + error (EXIT_FAILURE, 0, + "terminated due to previous error"); + + instrtable_out (); + } + ; + +masks: masks '\n' mask + | mask + ; + +mask: kMASK kBITFIELD kNUMBER + { new_bitfield ($2, $3); } + | kPREFIX kBITFIELD + { new_bitfield ($2, -1); } + | kSUFFIX kBITFIELD + { new_bitfield ($2, -2); } + | kSYNONYM kBITFIELD kBITFIELD + { + struct synonym *newp = xmalloc (sizeof (*newp)); + newp->from = $2; + newp->to = $3; + if (tfind (newp, &synonyms, compare_syn) != NULL) + error (0, 0, + "%d: duplicate definition for synonym '%s'", + i386_lineno, $2); + else if (tsearch ( newp, &synonyms, compare_syn) == NULL) + error (EXIT_FAILURE, 0, "tsearch"); + } + | + ; + +instrs: instrs '\n' instr + | instr + ; + +instr: bytes ':' bitfieldopt kID bitfieldopt optargs + { + if ($3 != NULL && strcmp ($3->name, "RE") != 0 + && strcmp ($3->name, "R") != 0) + { + error (0, 0, "%d: only 'R' and 'RE' prefix allowed", + i386_lineno - 1); + } + if (check_duplicates ($1) == 0 + && check_argsdef ($1, $6) == 0 + && check_bitsused ($1, $5, $6) == 0) + { + struct instruction *newp = xcalloc (sizeof (*newp), + 1); + if ($3 != NULL) + { + if (strcmp ($3->name, "RE") == 0) + newp->repe = 1; + else if (strcmp ($3->name, "R") == 0) + newp->rep = 1; + } + + newp->bytes = $1; + newp->mnemonic = $4; + if (newp->mnemonic != (void *) -1l + && tfind ($4, &mnemonics, + (comparison_fn_t) strcmp) == NULL) + { + if (tsearch ($4, &mnemonics, + (comparison_fn_t) strcmp) == NULL) + error (EXIT_FAILURE, errno, "tsearch"); + ++nmnemonics; + } + + if ($5 != NULL) + { + if (strcmp ($5->name, "w") == 0) + newp->suffix = suffix_w; + else if (strcmp ($5->name, "w0") == 0) + newp->suffix = suffix_w0; + else if (strcmp ($5->name, "tttn") == 0) + newp->suffix = suffix_tttn; + else if (strcmp ($5->name, "w1") == 0) + newp->suffix = suffix_w1; + else if (strcmp ($5->name, "W") == 0) + newp->suffix = suffix_W; + else if (strcmp ($5->name, "W1") == 0) + newp->suffix = suffix_W1; + 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 + { + char *fieldname = runp->field->name; + + struct synonym search = { .from = fieldname }; + + struct synonym **res = tfind (&search, &synonyms, compare_syn); + if (res != NULL) + fieldname = (*res)->to; + + obstack_grow_str (&ob, fieldname); + } + + /* 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); + + 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 int off_op_str; +static void +print_op_str (const void *nodep, VISIT value, + int level __attribute__ ((unused))) +{ + if (value == leaf || value == postorder) + { + const char *str = (*(struct argstring **) nodep)->str; + fprintf (outfile, "%s\n \"%s", + count_op_str == 0 ? "" : "\\0\"", str); + (*(struct argstring **) nodep)->idx = ++count_op_str; + (*(struct argstring **) nodep)->off = off_op_str; + off_op_str += strlen (str) + 1; + } +} + + +static void +print_op_str_idx (const void *nodep, VISIT value, + int level __attribute__ ((unused))) +{ + if (value == leaf || value == postorder) + printf (" %d,\n", (*(struct argstring **) nodep)->off); +} + + +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; + } +} + + +#if NMNES < 2 +# error "bogus NMNES value" +#endif + +static void +instrtable_out (void) +{ + find_numbers (); + +#if 0 + create_mnemonic_table (); + + fprintf (outfile, "#define MNEMONIC_BITS %zu\n", best_mnemonic_bits); +#else + fprintf (outfile, "#define MNEMONIC_BITS %ld\n", + lrint (ceil (log2 (NMNES)))); +#endif + fprintf (outfile, "#define SUFFIX_BITS %d\n", nbitsuf); + for (int i = 0; i < 3; ++i) + { + fprintf (outfile, "#define FCT%d_BITS %d\n", i + 1, nbitfct[i]); + if (nbitstr[i] != 0) + fprintf (outfile, "#define STR%d_BITS %d\n", i + 1, nbitstr[i]); + fprintf (outfile, "#define OFF%d_1_BITS %d\n", i + 1, nbitoff[i][0]); + fprintf (outfile, "#define OFF%d_1_BIAS %d\n", i + 1, minoff[i][0]); + if (nbitoff[i][1] != 0) + { + fprintf (outfile, "#define OFF%d_2_BITS %d\n", i + 1, nbitoff[i][1]); + fprintf (outfile, "#define OFF%d_2_BIAS %d\n", i + 1, minoff[i][1]); + } + if (nbitoff[i][2] != 0) + { + fprintf (outfile, "#define OFF%d_3_BITS %d\n", i + 1, nbitoff[i][2]); + fprintf (outfile, "#define OFF%d_3_BIAS %d\n", i + 1, minoff[i][2]); + } + } + + fputs ("\n#include <i386_data.h>\n\n", outfile); + + +#define APPEND(a, b) APPEND_ (a, b) +#define APPEND_(a, b) a##b +#define EMIT_SUFFIX(suf) \ + fprintf (outfile, "#define suffix_%s %d\n", #suf, APPEND (suffix_, suf)) + EMIT_SUFFIX (none); + EMIT_SUFFIX (w); + EMIT_SUFFIX (w0); + EMIT_SUFFIX (W); + EMIT_SUFFIX (tttn); + EMIT_SUFFIX (D); + EMIT_SUFFIX (w1); + EMIT_SUFFIX (W1); + + fputc_unlocked ('\n', outfile); + + for (int i = 0; i < 3; ++i) + { + /* Functions. */ + count_op_str = 0; + fprintf (outfile, "static const 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; + off_op_str = 0; + fprintf (outfile, "static const char op%d_str[] =", i + 1); + twalk (strs[i], print_op_str); + fputs ("\";\n", outfile); + + fprintf (outfile, "static const uint8_t op%d_str_idx[] = {\n", + i + 1); + twalk (strs[i], print_op_str_idx); + 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; + bool leading_p = true; + size_t leadingbits = 0; + struct bitvalue *b = instr->bytes; + while (b != NULL) + { + if (b->type == zeroone) + { + ++totalbits; + zerobits = 0; + if (leading_p) + ++leadingbits; + } + 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; + leading_p = false; + } + b = b->next; + } + size_t nbytes = (totalbits - zerobits + 7) / 8; + assert (nbytes > 0); + size_t leadingbytes = leadingbits / 8; + + fprintf (outfile, " %#zx,", nbytes | (leadingbytes << 4)); + + /* 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) + { + if (leadingbytes > 0) + { + assert (mask == 0xff); + fprintf (outfile, " %#" PRIx8 ",", byte); + --leadingbytes; + } + else + fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", + mask, byte); + byte = mask = nbits = 0; + if (--nbytes == 0) + break; + } + } + else + { + assert (leadingbytes == 0); + + 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; + } + + fputc_unlocked ('\n', outfile); + } + 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 0000000..c68eb4a --- /dev/null +++ b/libcpu/memory-access.h @@ -0,0 +1,179 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifndef _MEMORY_ACCESS_H +#define _MEMORY_ACCESS_H 1 + +#include <byteswap.h> +#include <endian.h> +#include <limits.h> +#include <stdint.h> + + +/* When loading this file we require the macro MACHINE_ENCODING to be + defined to signal the endianness of the architecture which is + defined. */ +#ifndef MACHINE_ENCODING +# error "MACHINE_ENCODING needs to be defined" +#endif +#if MACHINE_ENCODING != __BIG_ENDIAN && MACHINE_ENCODING != __LITTLE_ENDIAN +# error "MACHINE_ENCODING must signal either big or little endian" +#endif + + +/* We use simple memory access functions in case the hardware allows it. + The caller has to make sure we don't have alias problems. */ +#if ALLOW_UNALIGNED + +# define read_2ubyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? bswap_16 (*((const uint16_t *) (Addr))) \ + : *((const uint16_t *) (Addr))) +# define read_2sbyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \ + : *((const int16_t *) (Addr))) + +# define read_4ubyte_unaligned_noncvt(Addr) \ + *((const uint32_t *) (Addr)) +# define read_4ubyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? bswap_32 (*((const uint32_t *) (Addr))) \ + : *((const uint32_t *) (Addr))) +# define read_4sbyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \ + : *((const int32_t *) (Addr))) + +# define read_8ubyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? bswap_64 (*((const uint64_t *) (Addr))) \ + : *((const uint64_t *) (Addr))) +# define read_8sbyte_unaligned(Addr) \ + (unlikely (MACHINE_ENCODING != __BYTE_ORDER) \ + ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \ + : *((const int64_t *) (Addr))) + +#else + +union unaligned + { + void *p; + uint16_t u2; + uint32_t u4; + uint64_t u8; + int16_t s2; + int32_t s4; + int64_t s8; + } __attribute__ ((packed)); + +static inline uint16_t +read_2ubyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return bswap_16 (up->u2); + return up->u2; +} +static inline int16_t +read_2sbyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return (int16_t) bswap_16 (up->u2); + return up->s2; +} + +static inline uint32_t +read_4ubyte_unaligned_noncvt (const void *p) +{ + const union unaligned *up = p; + return up->u4; +} +static inline uint32_t +read_4ubyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return bswap_32 (up->u4); + return up->u4; +} +static inline int32_t +read_4sbyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return (int32_t) bswap_32 (up->u4); + return up->s4; +} + +static inline uint64_t +read_8ubyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return bswap_64 (up->u8); + return up->u8; +} +static inline int64_t +read_8sbyte_unaligned (const void *p) +{ + const union unaligned *up = p; + if (MACHINE_ENCODING != __BYTE_ORDER) + return (int64_t) bswap_64 (up->u8); + return up->s8; +} + +#endif /* allow unaligned */ + + +#define read_2ubyte_unaligned_inc(Addr) \ + ({ uint16_t t_ = read_2ubyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) +#define read_2sbyte_unaligned_inc(Addr) \ + ({ int16_t t_ = read_2sbyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) + +#define read_4ubyte_unaligned_inc(Addr) \ + ({ uint32_t t_ = read_4ubyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) +#define read_4sbyte_unaligned_inc(Addr) \ + ({ int32_t t_ = read_4sbyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) + +#define read_8ubyte_unaligned_inc(Addr) \ + ({ uint64_t t_ = read_8ubyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) +#define read_8sbyte_unaligned_inc(Addr) \ + ({ int64_t t_ = read_8sbyte_unaligned (Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) + +#endif /* memory-access.h */ diff --git a/libcpu/x86_64_disasm.c b/libcpu/x86_64_disasm.c new file mode 100644 index 0000000..b793b78 --- /dev/null +++ b/libcpu/x86_64_disasm.c @@ -0,0 +1,31 @@ +/* Disassembler for x86-64. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2007. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#define i386_disasm x86_64_disasm +#define DISFILE "x86_64_dis.h" +#define MNEFILE "x86_64.mnemonics" +#define X86_64 +#include "i386_disasm.c" |