propagate from branch 'com.redhat.elfutils.disasm' (head d15b4eb794e81e477f9896fe82a7...
authorUlrich Drepper <drepper@redhat.com>
Wed, 2 Jan 2008 17:44:39 +0000 (17:44 +0000)
committerUlrich Drepper <drepper@redhat.com>
Wed, 2 Jan 2008 17:44:39 +0000 (17:44 +0000)
            to branch 'com.redhat.elfutils' (head eaacbf01f8cc89d043ec6eca9b5e35cb5c4cde06)

62 files changed:
ChangeLog
backends/ChangeLog
backends/Makefile.am
backends/i386_init.c
backends/x86_64_init.c
configure.ac
libasm/ChangeLog
libasm/Makefile.am
libasm/asm_error.c
libasm/disasm_begin.c [new file with mode: 0644]
libasm/disasm_cb.c [new file with mode: 0644]
libasm/disasm_end.c [new file with mode: 0644]
libasm/disasm_str.c [new file with mode: 0644]
libasm/libasm.h
libasm/libasm.map
libasm/libasmP.h
libcpu/ChangeLog
libcpu/Makefile.am
libcpu/defs/i386 [new file with mode: 0644]
libcpu/defs/i386.doc [new file with mode: 0644]
libcpu/defs/x86_64 [new file with mode: 0644]
libcpu/i386_data.h [new file with mode: 0644]
libcpu/i386_disasm.c [new file with mode: 0644]
libcpu/i386_gendis.c [new file with mode: 0644]
libcpu/i386_lex.l [new file with mode: 0644]
libcpu/i386_parse.y [new file with mode: 0644]
libcpu/memory-access.h [new file with mode: 0644]
libcpu/x86_64_disasm.c [new file with mode: 0644]
libebl/Makefile.am
libebl/ebl-hooks.h
libebl/eblopenbackend.c
libebl/libeblP.h
libelf/ChangeLog
libelf/Makefile.am
libelf/elf32_getshdr.c
libelf/elf_begin.c
libelf/elf_scnshndx.c [new file with mode: 0644]
libelf/libelf.h
libelf/libelf.map
libelf/libelfP.h
src/ChangeLog
src/Makefile.am
src/addr2line.c
src/ar.c
src/debugpred.h [new file with mode: 0644]
src/elfcmp.c
src/elflint.c
src/findtextrel.c
src/ld.c
src/nm.c
src/objdump.c
src/ranlib.c
src/readelf.c
src/size.c
src/strings.c
src/strip.c
src/unstrip.c
tests/ChangeLog
tests/Makefile.am
tests/run-disasm.sh [new file with mode: 0755]
tests/testfile44.S.bz2 [new file with mode: 0644]
tests/testfile44.expect.bz2 [new file with mode: 0644]

index 9a55c00..fee15a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * configure.ac: Add support for --enable-debugpred.
+       Update likely/unlikely macros for it.
+
 2007-06-05  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile.am: Remove traces of mini builds.
index 97cddd2..3e35ef2 100644 (file)
        * sparc_retval.c: Likewise.
        * x86_64_retval.c: Likewise.
 
+2007-10-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile.am: More dependencies for the libebl_* libraries.
+
 2007-08-23  Roland McGrath  <roland@redhat.com>
 
        * x86_64_regs.c (x86_64_register_info): Put %rflags in "integer" set.
index 4174f8e..28e55f6 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Red Hat, Inc.
+## Copyright (C) 2000-2006, 2007 Red Hat, Inc.
 ## This file is part of Red Hat elfutils.
 ##
 ## Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@ AM_CFLAGS =
 endif
 AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 \
             -std=gnu99
-INCLUDES = -I$(srcdir) -I$(top_srcdir)/libebl \
+INCLUDES = -I$(srcdir) -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
           -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw \
           -I$(top_srcdir)/lib -I..
 
@@ -59,18 +59,10 @@ endif
 
 textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi
 
-libebl_%.so: libebl_%_pic.a libebl_%.map $(libelf) $(libdw)
-       $(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \
-               -Wl,--version-script,$(word 2,$^) \
-               -Wl,-z,defs -Wl,--as-needed $(libelf) $(libdw) $(libmudflap)
-       $(textrel_check)
-
-libebl_%.map: Makefile
-       echo 'ELFUTILS_$(PACKAGE_VERSION) { global: $*_init; local: *; };' > $@
-
 
 i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c \
            i386_retval.c i386_regs.c i386_auxv.c
+cpu_i386 = ../libcpu/libcpu_i386.a
 libebl_i386_pic_a_SOURCES = $(i386_SRCS)
 am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os)
 
@@ -80,6 +72,7 @@ am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os)
 
 x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c \
              x86_64_retval.c x86_64_regs.c i386_auxv.c
+cpu_x86_64 = ../libcpu/libcpu_x86_64.a
 libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS)
 am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os)
 
@@ -116,6 +109,21 @@ libebl_s390_pic_a_SOURCES = $(s390_SRCS)
 am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os)
 
 
+libebl_%.so: libebl_%_pic.a libebl_%.map $(libelf) $(libdw) \
+            $(cpu_$(@:libebl_%.so=%)
+       $(LINK) -shared -o $@ -Wl,--whole-archive,$<\
+               $(cpu_$(@:libebl_%.so=%)) -Wl,--no-whole-archive \
+               -Wl,--version-script,$(word 2,$^) \
+               -Wl,-z,defs -Wl,--as-needed $(libelf) $(libdw) $(libmudflap)
+       $(textrel_check)
+
+# XXX Should not be needed...
+libebl_i386.so: $(cpu_i386)
+libebl_x86_64.so: $(cpu_x86_64)
+
+libebl_%.map: Makefile
+       echo 'ELFUTILS_$(PACKAGE_VERSION) { global: $*_init; local: *; };' > $@
+
 %.os: %.c
        if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \
          -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \
index f25e1eb..bf6c130 100644 (file)
@@ -57,6 +57,7 @@ i386_init (elf, machine, eh, ehlen)
   HOOK (eh, return_value_location);
   HOOK (eh, register_info);
   HOOK (eh, auxv_info);
+  HOOK (eh, disasm);
 
   return MODVERSION;
 }
index b176483..c2d3de1 100644 (file)
@@ -54,6 +54,7 @@ x86_64_init (elf, machine, eh, ehlen)
   HOOK (eh, return_value_location);
   HOOK (eh, register_info);
   HOOK (eh, auxv_info);
+  HOOK (eh, disasm);
 
   return MODVERSION;
 }
index b89f9a4..0b943cc 100644 (file)
@@ -134,7 +134,15 @@ if test "$use_mudflap" = fail; then
 fi
 AM_CONDITIONAL(MUDFLAP, test "$use_mudflap" = yes)
 
-# Enable gprof suport.
+dnl enable debugging of branch prediction.
+use_debugpred=0
+AC_ARG_ENABLE([debugpred], 
+AC_HELP_STRING([--enable-debugpred],
+[build binaries with support to debug branch prediction]),
+[use_debugpred=1], [use_debugpred=0])
+AC_SUBST([DEBUGPRED], $use_debugpred)
+
+dnl Enable gprof suport.
 AC_ARG_ENABLE([gprof],
 AC_HELP_STRING([--enable-gprof],
 [build binaries with gprof support]), [use_gprof=yes], [use_gprof=no])
@@ -267,8 +275,47 @@ AH_BOTTOM([
 # define ALLOW_UNALIGNED       0
 #endif
 
-#define unlikely(expr) __builtin_expect (expr, 0)
-#define likely(expr) __builtin_expect (expr, 1)
+#if DEBUGPRED
+# ifdef __x86_64__
+asm (".section predict_data, \"aw\"; .previous\n"
+     ".section predict_line, \"a\"; .previous\n"
+     ".section predict_file, \"a\"; .previous");
+#  ifndef PIC
+#   define debugpred__(e, E) \
+  ({ long int _e = !!(e); \
+     asm volatile (".pushsection predict_data; ..predictcnt%=: .quad 0; .quad 0\n" \
+                   ".section predict_line; .quad %c1\n" \
+                   ".section predict_file; .quad %c2; .popsection\n" \
+                   "addq $1,..predictcnt%=(,%0,8)" \
+                   : : "r" (_e == E), "i" (__LINE__), "i" (__FILE__)); \
+    __builtin_expect (_e, E); \
+  })
+#  endif
+# elif defined __i386__
+asm (".section predict_data, \"aw\"; .previous\n"
+     ".section predict_line, \"a\"; .previous\n"
+     ".section predict_file, \"a\"; .previous");
+#  ifndef PIC
+#   define debugpred__(e, E) \
+  ({ long int _e = !!(e); \
+     asm volatile (".pushsection predict_data; ..predictcnt%=: .long 0; .long 0\n" \
+                   ".section predict_line; .long %c1\n" \
+                   ".section predict_file; .long %c2; .popsection\n" \
+                   "incl ..predictcnt%=(,%0,8)" \
+                   : : "r" (_e == E), "i" (__LINE__), "i" (__FILE__)); \
+    __builtin_expect (_e, E); \
+  })
+#  endif
+# endif
+# ifdef debugpred__
+#  define unlikely(e) debugpred__ (e,0)
+#  define likely(e) debugpred__ (e,1)
+# endif
+#endif
+#ifndef likely
+# define unlikely(expr) __builtin_expect (!!(expr), 0)
+# define likely(expr) __builtin_expect (!!(expr), 1)
+#endif
 
 #define obstack_calloc(ob, size) \
   ({ size_t _s = (size); memset (obstack_alloc (ob, _s), '\0', _s); })
index 99fb5e4..78a895c 100644 (file)
@@ -1,3 +1,14 @@
+2007-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * disasm_cb.c: Add initial support to resolve addresses to symbols.
+
+2007-02-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * disasm_begin.c: New file.
+       * disasm_cb.c: New file.
+       * disasm_end.c: New file.
+       * disasm_str.c: New file.
+
 2006-08-29  Roland McGrath  <roland@redhat.com>
 
        * Makefile.am (CLEANFILES): Add libasm.so.$(VERSION).
index 3bea374..9593961 100644 (file)
@@ -59,6 +59,7 @@ libasm_a_SOURCES = asm_begin.c asm_abort.c asm_end.c asm_error.c \
                   asm_addint32.c asm_adduint32.c \
                   asm_addint64.c asm_adduint64.c \
                   asm_adduleb128.c asm_addsleb128.c \
+                  disasm_begin.c disasm_cb.c disasm_end.c disasm_str.c \
                   symbolhash.c
 
 if !MUDFLAP
index f91bb78..29c54cb 100644 (file)
@@ -126,6 +126,7 @@ static const char *msgs[ASM_E_NUM] =
   [ASM_E_DUPLSYM] = N_("duplicate symbol"),
   [ASM_E_TYPE] = N_("invalid section type for operation"),
   [ASM_E_IOERROR] = N_("error during output of data"),
+  [ASM_E_ENOSUP] = N_("no backend support available"),
 };
 
 const char *
diff --git a/libasm/disasm_begin.c b/libasm/disasm_begin.c
new file mode 100644 (file)
index 0000000..5cdb542
--- /dev/null
@@ -0,0 +1,49 @@
+/* Create context descriptor for disassembler.
+   Copyright (C) 2005 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+DisasmCtx_t *
+disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb)
+{
+  if (ebl == NULL)
+    return NULL;
+
+  if (ebl->disasm == NULL)
+    {
+      __libasm_seterrno (ASM_E_ENOSUP);
+      return NULL;
+    }
+
+  DisasmCtx_t *ctx = (DisasmCtx_t *) malloc (sizeof (DisasmCtx_t));
+  if (ctx == NULL)
+    {
+      __libasm_seterrno (ASM_E_NOMEM);
+      return NULL;
+    }
+
+  ctx->ebl = ebl;
+  ctx->elf = elf;
+  ctx->symcb = symcb;
+
+  return ctx;
+}
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
new file mode 100644 (file)
index 0000000..a044162
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (C) 2005, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <string.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+struct symtoken
+{
+  DisasmCtx_t *ctx;
+  void *symcbarg;
+};
+
+
+static int
+default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value,
+                   char *buf, size_t buflen, void *arg)
+{
+  struct symtoken *symtoken = (struct symtoken *) arg;
+
+  /* First try the user provided function.  */
+  if (symtoken->ctx->symcb != NULL)
+    {
+      int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen,
+                                     symtoken->symcbarg);
+      if (res >= 0)
+       return res;
+    }
+
+  // XXX Look up in ELF file.
+
+  return -1;
+}
+
+
+struct symaddrpair
+{
+  GElf_Addr addr;
+  const char *name;
+};
+
+
+static void
+read_symtab_exec (DisasmCtx_t *ctx)
+{
+  /* We simply use all we can get our hands on.  This will produce
+     some duplicate information but this is no problem, we simply
+     ignore the latter definitions.  */
+  Elf_Scn *scn= NULL;
+  while ((scn = elf_nextscn (ctx->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      Elf_Data *data;
+      if (shdr == NULL || shdr->sh_type != SHT_SYMTAB
+         || (data = elf_getdata (scn, NULL)) == NULL)
+       continue;
+
+      int xndxscnidx = elf_scnshndx (scn);
+      Elf_Data *xndxdata = NULL;
+      if (xndxscnidx > 0)
+       xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL);
+
+      /* Iterate over all symbols.  Add all defined symbols.  */
+      int nsyms = shdr->sh_size / shdr->sh_entsize;
+      for (int cnt = 1; cnt < nsyms; ++cnt)
+       {
+         Elf32_Word xshndx;
+         GElf_Sym sym_mem;
+         GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem,
+                                           &xshndx);
+         if (sym == NULL)
+           continue;
+
+         /* Undefined symbols are useless here.  */
+         if (sym->st_shndx == SHN_UNDEF)
+           continue;
+
+
+       }
+    }
+}
+
+
+static void
+read_symtab (DisasmCtx_t *ctx)
+{
+  /* Find the symbol table(s).  */
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return;
+
+  switch (ehdr->e_type)
+    {
+    case ET_EXEC:
+    case ET_DYN:
+      read_symtab_exec (ctx);
+      break;
+
+    case ET_REL:
+      // XXX  Handle
+      break;
+
+    default:
+      break;
+    }
+}
+
+
+static int
+null_elf_getsym (GElf_Addr addr __attribute__ ((unused)),
+                Elf32_Word scnndx __attribute__ ((unused)),
+                GElf_Addr value __attribute__ ((unused)),
+                char *buf __attribute__ ((unused)),
+                size_t buflen __attribute__ ((unused)),
+                void *arg __attribute__ ((unused)))
+{
+  return -1;
+}
+
+
+int
+disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+          GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
+          void *outcbarg, void *symcbarg)
+{
+  struct symtoken symtoken;
+  DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym;
+
+  if (ctx->elf != NULL)
+    {
+      /* Read all symbols of the ELF file and stuff them into a hash
+        table.  The key is the address and the section index.  */
+      read_symtab (ctx);
+
+      symtoken.ctx = ctx;
+      symtoken.symcbarg = symcbarg;
+
+      symcbarg = &symtoken;
+
+      getsym = default_elf_getsym;
+    }
+
+  return ctx->ebl->disasm (startp, end, addr, fmt, outcb, getsym, outcbarg,
+                          symcbarg);
+}
+INTDEF (disasm_cb)
diff --git a/libasm/disasm_end.c b/libasm/disasm_end.c
new file mode 100644 (file)
index 0000000..3165c2d
--- /dev/null
@@ -0,0 +1,30 @@
+/* Release descriptor for disassembler.
+   Copyright (C) 2005 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "libasmP.h"
+
+
+int
+disasm_end (DisasmCtx_t *ctx)
+{
+  free (ctx);
+
+  return 0;
+}
diff --git a/libasm/disasm_str.c b/libasm/disasm_str.c
new file mode 100644 (file)
index 0000000..9f40737
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 Red Hat, Inc.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "libasmP.h"
+
+
+struct buffer
+{
+  char *buf;
+  size_t len;
+};
+
+
+static int
+buffer_cb (char *str, size_t len, void *arg)
+{
+  struct buffer *buffer = (struct buffer *) arg;
+
+  if (len > buffer->len)
+    /* Return additional needed space.  */
+    return len - buffer->len;
+
+  buffer->buf = mempcpy (buffer->buf, str, len);
+  buffer->len = len;
+
+  return 0;
+}
+
+
+int
+disasm_str (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+           GElf_Addr addr, const char *fmt, char **bufp, size_t len,
+           void *symcbarg)
+{
+  struct buffer buffer = { .buf = *bufp, .len = len };
+
+  int res = INTUSE(disasm_cb) (ctx, startp, end, addr, fmt, buffer_cb, &buffer,
+                              symcbarg);
+  *bufp = buffer.buf;
+  return res;
+}
index 6daf221..8a005f1 100644 (file)
@@ -45,6 +45,20 @@ typedef struct AsmScnGrp AsmScnGrp_t;
 typedef struct AsmSym AsmSym_t;
 
 
+/* Opaque type for the disassembler context descriptor.  */
+typedef struct DisasmCtx DisasmCtx_t;
+
+/* Type used for callback functions to retrieve symbol name.  The
+   symbol reference is in the section designated by the second parameter
+   at an offset described by the first parameter.  The value is the
+   third parameter.  */
+typedef int (*DisasmGetSymCB_t) (GElf_Addr, Elf32_Word, GElf_Addr, char *,
+                                size_t, void *);
+
+/* Output function callback.  */
+typedef int (*DisasmOutputCB_t) (char *, size_t, void *);
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -159,6 +173,25 @@ extern int asm_errno (void);
    string is returned.  */
 extern const char *asm_errmsg (int __error);
 
+
+/* Create context descriptor for disassembler.  */
+extern DisasmCtx_t *disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb);
+
+/* Release descriptor for disassembler.  */
+extern int disasm_end (DisasmCtx_t *ctx);
+
+/* Produce of disassembly output for given memory, store text in
+   provided buffer.  */
+extern int disasm_str (DisasmCtx_t *ctx, const uint8_t **startp,
+                      const uint8_t *end, GElf_Addr addr, const char *fmt,
+                      char **bufp, size_t len, void *symcbarg);
+
+/* Produce disassembly output for given memory and output it using the
+   given callback functions.  */
+extern int disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp,
+                     const uint8_t *end, GElf_Addr addr, const char *fmt,
+                     DisasmOutputCB_t outcb, void *outcbarg, void *symcbarg);
+
 #ifdef __cplusplus
 }
 #endif
index b0b5b5b..a36cdbf 100644 (file)
@@ -28,6 +28,11 @@ ELFUTILS_1.0 {
     asm_newsym;
     asm_scngrp_newsignature;
 
+    disasm_begin;
+    disasm_cb;
+    disasm_end;
+    disasm_str;
+
   local:
     *;
 };
index e640157..ee7005f 100644 (file)
@@ -47,6 +47,7 @@ enum
     ASM_E_LIBELF,              /* Refer to error in libelf.  */
     ASM_E_TYPE,                        /* Invalid section type for operation.  */
     ASM_E_IOERROR,             /* Error during output of data.  */
+    ASM_E_ENOSUP,              /* No backend support.  */
     ASM_E_NUM                  /* Keep this entry as the last.  */
   };
 
@@ -235,6 +236,21 @@ struct AsmScnGrp
 };
 
 
+/* Descriptor for disassembler.   */
+struct DisasmCtx
+{
+  /* Handle for the backend library with the disassembler routine.  */
+  Ebl *ebl;
+
+  /* ELF file containing all the data passed to the function.  This
+     allows to look up symbols.  */
+  Elf *elf;
+
+  /* Callback function to determine symbol names.  */
+  DisasmGetSymCB_t symcb;
+};
+
+
 /* The default fill pattern: one zero byte.  */
 extern const struct FillPattern *__libasm_default_pattern
      attribute_hidden;
@@ -269,6 +285,14 @@ extern int __asm_addint64_internal (AsmScn_t *asmscn, int64_t num)
      attribute_hidden;
 
 
+/* Produce disassembly output for given memory and output it using the
+   given callback functions.  */
+extern int __disasm_cb_internal (DisasmCtx_t *ctx, const uint8_t **startp,
+                                const uint8_t *end, GElf_Addr addr,
+                                const char *fmt, DisasmOutputCB_t outcb,
+                                void *outcbarp, void *symcbarg)
+     attribute_hidden;
+
 
 /* Test whether given symbol is an internal symbol and if yes, whether
    we should nevertheless emit it in the symbol table.  */
index 5c2a4ac..c5be1d7 100644 (file)
@@ -1,3 +1,184 @@
+2008-01-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: More 0f prefix support.
+       * i386_data.h (FCT_mmxreg): Implement.
+       (FCT_mmxreg2): Implement.
+       (FCT_mmreg): Remove.
+       * i386_disasm.c (i386_disasm): More special instructions.
+       Fix tttn suffix for cmov.
+       * i386_parse.y: Simplify test for mod/r_m mode.
+
+2007-12-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Fix order or arguments for mov of control/debug registers.
+       * i386_data.h (FCT_ccc): Implement
+       (FCT_ddd): Implement
+
+2007-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Fix 0f groups 6 and 7.
+       * i386_data.c (FCT_mod$16r_m): Implement.
+       * i386_disasm.c (i386_disasm): Third parameter can also have string.
+
+2007-12-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Add lots of floating point ops.
+       * i386_data.h (FCT_fmod$fr_m): Removed.
+       (FCT_freg): Implement.
+       * i386_disasm.c (i386_disasm): Implement suffix_D.
+       * i386_parse.y: Emit suffix_D.
+
+       * defs/i386: Use rel instead of dispA.
+       Fix lcall, dec, div, idiv, imul, inc, jmp, ljmp, mul, neg, not, push,
+       test.
+
+       * i386_data.h (FCT_dispA): Removed.
+       (FCT_ds_xx): Add test for end of input buffer.
+       * i386_disasm.c (ABORT_ENTRY): Removed.
+       (i386_disasm): Fix handling of SIB.  Pass correct address value to
+       operand callbacks.
+
+       * Makefile.am (*.mnemonics): Filter out INVALID entry.
+       * defs/i386: Define imms8 and use in appropriate places.
+       Add INVALID entries for special opcodes with special mnemonics.
+       Fix int3.  Fix typo in shl.  Correct xlat.
+       * i386_data.h (FCT_ds_xx): New function.
+       (FCT_ds_si): Use it.
+       (FCT_ds_bx): New function.
+       (FCT_imms8): New function.
+       * i386_disasm.c (MNE_INVALID): Define.
+       (i386_disasm): Handle invalid opcodes in mnemonics printing, not
+       separately.  Fix address value passed to operand handlers.
+       * i386_parse.y (bx_reg): Define.
+       (instrtable_out): Handle INVALID entries differently, just use
+       MNE_INVALID value for .mnemonic.
+
+2007-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Fix shift and mov immediate instructions.
+       * i386_data.h (FCT_imm16): Implement.
+
+       * defs/i386: Use absval instead of abs of lcall and ljmp.
+       Add parameters for cmps.  Fix test and mov immediate.
+       * i386_data.h: Implement FCT_absval.
+       * i386_disasm.c: Handle data16 for suffix_w  and FCT_imm.
+
+       * defs/i386: Move entries with 0x9b prefix together.
+       * i386_disasm.c (i386_disasm): Fix recognizing insufficient bytes in
+       input.  Handle data16 with suffix_W.
+
+       * i386_data.h (FCT_*): Add end parameter to all functions.  Check
+       before using more bytes.
+       (FCT_sel): Implement.
+       * i386_disasm.c (i386_disasm): Better handle end of input buffer.
+       Specal opcode 0x99.
+
+       * Makefile.am: Use m4 to preprocess defs/* files.
+       * defs/i386: Adjust appropriately.
+       * i386_data.c (FCT_ax): Implement.
+       (FCT_ax$w): Use FCT_ax.
+       * i386_disasm.c (ADD_STRING): Use _len instead of len.
+       (i386_disasm): If no instruction can be matched because of lack of
+       input and prefixes have been matched, print prefixes.
+       Recognize abort entries.
+       Handle special cases.
+       * i386_gendis.c: Recognize - input file name.
+       * i386_lex.c: Recognize INVALID token.
+       * i386_parse.y: Handle INVALID token input.
+
+       * defs/i386: Fix mov, pop.
+       * i386_data.h (FCT_sreg3): Implement.
+
+2007-12-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Fix adc, add, cmp, or, sbb, sub, xchg, xor.
+       * i386_data.h (FCT_imms): New function.
+       (FCT_imm$s): Use FCT_imms for handling of signed values.
+       (FCT_imm8): Sign extend values.
+       * i386_disasm.c (i386_disasm): Implement suffix_w0.
+       * i386_parse.y: Emit suffix w0.
+
+       * i386_data.h (FCT_disp8): Add 0x prefix.
+       (FCT_ds_si): Implement.
+       * i386_disasm.c (i386_disasm): Increment addr for invalid prefixes.
+       Implement tttn suffix.
+       * i386_parse.y: Emit tttn suffix definition.
+
+2007-12-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * i386_data.h (struct instr_enc): Use suffix field.
+       (FCT_dx): Fill in body.
+       (FCT_es_di): Likewise.
+       (FCT_imm$s): Sign-extended byte values.
+       * i386_disasm.c: Protect ADD_CHAR and ADD_STRING macros.  Adjust uses.
+       (i386_disasm): Handle suffix.
+       * i386_parse.y: Emit suffix information.
+       * defs/i386: Remove unnecessary suffixes.
+
+       * Makefile.am: Disable building x86-64 version for now.
+
+       * defs/i386: Fix and, bound, cmp, or, pop, sbb, sub, xor.
+       * i386_data.h: Pass pointer to prefix to functions.  If not prefixes
+       are consumed this means invalid input.
+       * i386_disasm.c: Fix prefix printing.  Adjust function calls for
+       parameter change.
+       * i386_parse.y: Recognize moda prefix.
+
+2007-12-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * i386_data.h: Fix SIB handling.
+       * i386_disasm.c: Likewise.
+
+2007-12-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * defs/i386: Fix up 'and' opcode.
+
+2007-10-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile.am: Add dependencies of the generated files on the source
+       files.
+       (i386_lex_CFLAGS): Add -Wno-sign-compare.
+
+       * defs/i386: A lot more data.
+       * defs/x86_64: Likewise.
+       * i386_data.h (struct instr_enc): Add off1_3, off2_3, and off3_3
+       fields.
+       (opfct_t): Add parameter for third operand.
+       (FCT_*): Likewise.
+       (data_prefix): New function.
+       (FCT_abs): Implement.
+       (FCT_ax): Renamed to FCT_ax$w amd implement.
+       (FCT_disp8): Implement.
+       (FCT_dispA): Implement.
+       (FCT_imm): Implement.
+       (FCT_imm$w): Implement.
+       (FCT_imm$s): Don't zero-pad numbers.
+       (FCT_imm8): Likewise.
+       (FCT_rel): Likewise.
+       (general_mod$r_m): New function.
+       (FCT_mod$r_m): Use it.
+       (FCT_mod$r_m$w): New function.
+       (FCT_mod$8r_m): New function.
+       (FCT_reg): Correctly handle 16-bit registers.
+       (FCT_reg$w): New function.
+       * i386_disasm.c (i386_disasm): Handle prefixes better.
+       Pass third parameter to operand functions.
+       * i386_parse.y (struct instruction): Add off3 field.
+       Handle third operand throughout.
+
+2007-02-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * i386_disasm.c: New file.
+       * i386_data.h: New file.
+       * i386_gendis.c: New file.
+       * i386_lex.l: New file.
+       * i386_parse.y: New file.
+       * memory-access.h: New file.
+       * x86_64_disasm.c: New file.
+       * defs/i386: New file.
+       * defs/i386.doc: New file.
+       * defs/x86_64: New file.
+
 2005-02-15  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2.
index 23222be..c511408 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2002, 2005 Red Hat, Inc.
+## Copyright (C) 2002, 2004, 2005, 2007 Red Hat, Inc.
 ## This file is part of Red Hat elfutils.
 ##
 ## Red Hat elfutils is free software; you can redistribute it and/or modify
 ## <http://www.openinventionnetwork.com>.
 ##
 DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H
-AM_CFLAGS = -Wall -Wshadow -Werror -Wextra -Wformat=2 -Wunused
-INCLUDES = -I$(srcdir)
+if MUDFLAP
+AM_CFLAGS = -fmudflap
+else
+AM_CFLAGS =
+endif
+AM_CFLAGS += -Wall -Wshadow -Werror -Wunused -Wextra -std=gnu99 -fpic \
+            $($(*F)_CFLAGS)
+INCLUDES = -I$(srcdir) -I$(srcdir)/../lib -I$(srcdir)/../libelf \
+          -I$(srcdir)/../libebl -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
+LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
+AM_YFLAGS = -p$(<F:parse.y=)
 
-noinst_LIBRARIES = libcpu_i386.a
+if MUDFLAP
+libmudflap = -lmudflap
+endif
 
-libcpu_i386_a_SOURCES = i386_dis.c
+# XXX x86-64 uncommented for now.
+noinst_LIBRARIES = libcpu_i386.a# libcpu_x86_64.a
+noinst_PROGRAMS = i386_gendis
+
+libcpu_i386_a_SOURCES = i386_disasm.c
+# XXX Unused for now.
+#libcpu_x86_64_a_SOURCES = x86_64_disasm.c
+
+i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y
+
+i386_disasm.o: i386.mnemonics i386_dis.h
+x86_64_disasm.o: x86_64.mnemonics x86_64_dis.h i386_disasm.c
+
+i386_dis.h: i386_gendis $(srcdir)/defs/i386
+       m4 -Di386 -DDISASSEMBLER $(srcdir)/defs/i386 | ./i386_gendis - > $@
+x86_64_dis.h: i386_gendis $(srcdir)/defs/x86_64
+       m4 -Dx86_64 -DDISASSEMBLER $(srcdir)/defs/x86_64 | ./i386_gendis - > $@
+
+i386.mnemonics x86_64.mnemonics: %.mnemonics: $(srcdir)/defs/%
+       m4 -D$(<F) -DDISASSEMBLER $^ \
+       | sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:]]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \
+       | sort -u > $@
+
+libeu = ../lib/libeu.a
+
+i386_lex_CFLAGS = -Wno-unused-label -Wno-unused-function -Wno-sign-compare
+i386_gendis.o: i386_parse.c i386.mnemonics
+i386_parse_CFLAGS = -DNMNES=$$(wc -l < i386.mnemonics)
+i386_lex.o: i386_parse.c
+i386_gendis_LDADD = $(libeu) -lm $(libmudflap)
+
+noinst_HEADERS = memory-access.h i386_parse.h i386_data.h
+
+EXTRA_DIST = defs/i386 defs/x86_64
+
+CLEANFILES = i386.mnemonics i386_dis.h x86_64.mnemonics x86_64_dis.h
diff --git a/libcpu/defs/i386 b/libcpu/defs/i386
new file mode 100644 (file)
index 0000000..b0cdfb4
--- /dev/null
@@ -0,0 +1,634 @@
+%mask {s}      1
+%mask {w}      1
+%mask {w1}     1
+dnl floating point reg suffix
+%mask {D}      1
+%mask {imm8}   8
+%mask {imms8}  8
+%mask {imm16}  16
+%mask {reg}    3
+%mask {reg16}  3
+%mask {tttn}   4
+%mask {gg}     2
+%mask {mod}    2
+%mask {moda}   2
+%mask {MOD}    2
+%mask {r_m}    3
+dnl like {r_m} but referencing byte register
+%mask {8r_m}   3
+dnl like {r_m} but referencing 16-bit register
+%mask {16r_m}  3
+%mask {disp8}  8
+dnl imm really is 8/16/32 bit depending on the situation.
+%mask {imm}    8
+%mask {imms}   8
+%mask {rel}    32
+%mask {abs}    32
+%mask {absval} 32
+%mask {sel}    16
+%mask {imm32}  32
+%mask {ccc}    3
+%mask {ddd}    3
+%mask {sreg3}  3
+%mask {sreg2}  2
+%mask {mmxreg} 3
+%mask {mmxreg2}        3
+%mask {R_M}    3
+%mask {0g}     2
+%mask {GG}     2
+%mask {gG}     2
+%mask {Mod}    2
+%mask {xmmreg} 3
+%mask {R_m}    3
+%mask {mmreg}  3
+%mask {xmmreg1} 3
+%mask {xmmreg2} 3
+%mask {predpd} 8
+%mask {predps} 8
+%mask {predsd} 8
+%mask {predss} 8
+%mask {freg}   3
+%mask {fmod}   2
+%mask {fr_m}   3
+%prefix {R}
+%prefix {RE}
+%suffix {W}
+%suffix {w0}
+%synonym {xmmreg1} {xmmreg}
+%synonym {xmmreg2} {xmmreg}
+
+%%
+ifdef(`i386',
+`00110111:aaa
+11010101,00001010:aad
+11010100,00001010:aam
+00111111:aas
+')dnl
+0001010{w},{imm}:adc {imm}{w},{ax}{w}
+1000000{w},{mod}010{r_m},{imm}:adc{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}010{r_m},{imms8}:adc{w} {imms8},{mod}{r_m}
+0001000{w},{mod}{reg}{r_m}:adc {reg}{w},{mod}{r_m}
+0001001{w},{mod}{reg}{r_m}:adc {mod}{r_m},{reg}{w}
+0000010{w},{imm}:add {imm}{w},{ax}{w}
+1000000{w},{mod}000{r_m},{imm}:add{w} {imm}{w},{mod}{r_m}{w}
+10000011,{mod}000{r_m},{imms8}:add{w0} {imms8},{mod}{r_m}
+0000000{w},{mod}{reg}{r_m}:add {reg}{w},{mod}{r_m}
+0000001{w},{mod}{reg}{r_m}:add {mod}{r_m},{reg}{w}
+11110010,00001111,01011000,{Mod}{xmmreg}{R_m}:addsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+01100110,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubpd {Mod}{R_m},{xmmreg}
+11110010,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubps {Mod}{R_m},{xmmreg}
+0010010{w},{imm}:and {imm}{w},{ax}{w}
+1000000{w},{mod}100{r_m},{imm}:and{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}100{r_m},{imms}:and{w} {imms},{mod}{r_m}
+0010000{w},{mod}{reg}{r_m}:and {reg}{w},{mod}{r_m}{w}
+0010001{w},{mod}{reg}{r_m}:and {mod}{r_m}{w},{reg}{w}
+01100110,00001111,01010100,{Mod}{xmmreg}{R_m}:andpd {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+01100110,00001111,01010101,{Mod}{xmmreg}{R_m}:andnpd {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+ifdef(`i386',
+`01100011,{mod}{reg16}{r_m}:arpl {reg16},{mod}{r_m}
+01100010,{moda}{reg}{r_m}:bound {reg},{moda}{r_m}
+')dnl
+00001111,10111100,{mod}{reg}{r_m}:bsf {reg},{mod}{r_m}
+00001111,10111101,{mod}{reg}{r_m}:bsr {reg},{mod}{r_m}
+00001111,11001{reg}:bswap {reg}
+00001111,10100011,{mod}{reg}{r_m}:bt {reg},{mod}{r_m}
+00001111,10111010,{mod}100{r_m},{imm8}:bt {imm8},{mod}{r_m}
+00001111,10111011,{mod}{reg}{r_m}:btc {reg},{mod}{r_m}
+00001111,10111010,{mod}111{r_m},{imm8}:btc {imm8},{mod}{r_m}
+00001111,10110011,{mod}{reg}{r_m}:btr {reg},{mod}{r_m}
+00001111,10111010,{mod}110{r_m},{imm8}:btr {imm8},{mod}{r_m}
+00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m}
+00001111,10111010,{mod}101{r_m},{imm8}:bts {imm8},{mod}{r_m}
+11101000,{rel}:call {rel}
+11111111,{mod}010{r_m}:call *{mod}{r_m}
+ifdef(`i386',
+`10011010,{absval},{sel}:lcall {sel},{absval}
+')dnl
+11111111,{mod}011{r_m}:lcall *{mod}{r_m}
+# SPECIAL 10011000:[{rex.w}?cltq:{dpfx}?cbtw:cwtl]
+10011000:INVALID
+# SPECIAL 10011001:[{rew.w}?cqto:{dpfx}?cltd:cwtd]
+10011001:INVALID
+11111000:clc
+11111100:cld
+00001111,10101110,{mod}111{r_m}:clflush {mod}{r_m}
+11111010:cli
+00001111,00000101:syscall
+00001111,00000110:clts
+00001111,00000111:sysret
+00001111,00110100:sysenter
+00001111,00110101:sysexit
+11110101:cmc
+00001111,0100{tttn},{mod}{reg}{r_m}:cmov{tttn} {mod}{r_m},{reg}
+0011110{w},{imm}:cmp {imm}{w},{ax}{w}
+1000000{w},{mod}111{r_m},{imm}:cmp{w} {imm}{w},{mod}{r_m}{w}
+10000011,{mod}111{r_m},{imms8}:cmp{w0} {imms8},{mod}{r_m}
+0011100{w},{mod}{reg}{r_m}:cmp {reg}{w},{mod}{r_m}{w}
+0011101{w},{mod}{reg}{r_m}:cmp {mod}{r_m}{w},{reg}{w}
+01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{predpd}:cmpl{predpd} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`01100110,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmppd {imm8},{Mod}{R_m},{xmmreg
+}')dnl
+00001111,11000010,{Mod}{xmmreg}{R_m},{predps}:cmpl{predps} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpps {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+1010011{w}:{RE}cmps{w} {es_di},{ds_si}
+11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{predsd}:cmpl{predsd} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`11110010,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpsd {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{predss}:cmpl{predss} {Mod}{R_m},{xmmreg}
+ifdef(`ASSEMBLER',
+`11110011,00001111,11000010,{Mod}{xmmreg}{R_m},{imm8}:cmpss {imm8},{Mod}{R_m},{xmmreg}
+')dnl
+00001111,1011000{w},{mod}{reg}{r_m}:cmpxchg{w} {reg},{mod}{r_m}
+# SPECIAL 00001111,11000111,{mod}001{r_m}:[{rex.w}?cmpxchg16b:cmpxchg8b] {reg},{mod}{r_m}
+00001111,10100010:cpuid
+11110011,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtdq2pd {Mod}{R_m},{xmmreg}
+00001111,01011011,{Mod}{xmmreg}{R_m}:cvtdq2ps {Mod}{R_m},{xmmreg}
+11110010,00001111,11100110,{Mod}{xmmreg}{R_m}:cvtpd2dq {Mod}{R_m},{xmmreg}
+01100110,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtpd2ps {Mod}{R_m},{xmmreg}
+01100110,00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2pd {MOD}{R_M},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:{R}INVALID {MOD}{R_M},{xmmreg}
+01100110,00001111,01011011,{Mod}{xmmreg}{R_m}:cvtps2dq {Mod}{R_m},{xmmreg}
+00001111,01011010,{Mod}{xmmreg}{R_m}:cvtps2pd {Mod}{R_m},{xmmreg}
+11110010,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtsd2ss {Mod}{R_m},{xmmreg}
+11110010,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2sd {mod}{r_m},{xmmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+11110011,00001111,01011010,{Mod}{xmmreg}{R_m}:cvtss2sd {Mod}{R_m},{xmmreg}
+01100110,00001111,11100110,{Mod}{xmmreg}{R_m}:cvttpd2dq {Mod}{R_m},{xmmreg}
+11110011,00001111,01011011,{Mod}{mmxreg}{R_m}:cvttps2dq {Mod}{R_m},{mmxreg}
+ifdef(`i386',
+`00100111:daa
+00101111:das
+')dnl
+1111111{w},{mod}001{r_m}:dec{w} {mod}{r_m}{w}
+ifdef(`i386',
+`01001{reg}:dec {reg}
+')dnl
+1111011{w},{mod}110{r_m}:div{w} {mod}{r_m}{w}
+01100110,00001111,01011110,{Mod}{xmmreg}{R_m}:divpd {Mod}{R_m},{xmmreg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110010,00001111,01011110,{Mod}{xmmreg}{R_m}:divsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,01110111:emms
+11001000,{imm16},{imm8}:enter {imm16},{imm8}
+11011001,11010000:fnop
+11011001,11100000:fchs
+11011001,11100001:fabs
+11011001,11100100:ftst
+11011001,11100101:fxam
+11011001,11101000:fld1
+11011001,11101001:fldl2t
+11011001,11101010:fldl2e
+11011001,11101011:fldpi
+11011001,11101100:fldlg2
+11011001,11101101:fldln2
+11011001,11101110:fldz
+11011001,11110000:f2xm1
+11011001,11110001:fyl2x
+11011001,11110010:fptan
+11011001,11110011:fpatan
+11011001,11110100:fxtract
+11011001,11110101:fprem1
+11011001,11110110:fdecstp
+11011001,11110111:fincstp
+11011001,11111000:fprem
+11011001,11111001:fyl2xp1
+11011001,11111010:fsqrt
+11011001,11111011:fsincos
+11011001,11111100:frndint
+11011001,11111101:fscale
+11011001,11111110:fsin
+11011001,11111111:fcos
+# ORDER
+11011000,11000{freg}:fadd {freg},%st
+11011100,11000{freg}:fadd %st,{freg}
+11011{D}00,{mod}000{r_m}:fadd{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11001{freg}:fmul {freg},%st
+11011100,11001{freg}:fmul %st,{freg}
+11011{D}00,{mod}001{r_m}:fmul{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11100{freg}:fsub {freg},%st
+11011100,11100{freg}:fsub %st,{freg}
+11011{D}00,{mod}100{r_m}:fsub{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011000,11101{freg}:fsubr {freg},%st
+11011100,11101{freg}:fsubr %st,{freg}
+11011{D}00,{mod}101{r_m}:fsubr{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11010{freg}:fst {freg}
+11011{D}01,{mod}010{r_m}:fst{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11011{freg}:fstp {freg}
+11011{D}01,{mod}011{r_m}:fstp{D} {mod}{r_m}
+# ORDER END
+11011001,{mod}100{r_m}:fldenv {mod}{r_m}
+11011001,{mod}101{r_m}:fldcw {mod}{r_m}
+11011001,{mod}110{r_m}:fnstenv {mod}{r_m}
+11011001,{mod}111{r_m}:fnstcw {mod}{r_m}
+11011001,11001{freg}:fxch {freg}
+# ORDER
+11011110,11000{freg}:faddp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11000001:faddp
+')dnl
+# ORDER
+11011010,11000{freg}:fcmovb {freg},%st
+11011{w1}10,{mod}000{r_m}:fiadd{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011010,11001{freg}:fcmove {freg},%st
+11011110,11001{freg}:fmulp %st,{freg}
+11011{w1}10,{mod}001{r_m}:fimul{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011110,11100{freg}:fsubp %st,{freg}
+11011{w1}10,{mod}100{r_m}:fisub{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011110,11101{freg}:fsubrp %st,{freg}
+11011{w1}10,{mod}101{r_m}:fisubr{w1} {mod}{r_m}
+# ORDER END
+# ORDER
+11011111,11100000:fnstsw %ax
+11011111,{mod}100{r_m}:fbld {mod}{r_m}
+# ORDER END
+# ORDER
+11011111,11110{freg}:fcomip {freg},%st
+11011111,{mod}110{r_m}:fbstp {mod}{r_m}
+# ORDER END
+11011001,11100000:fchs
+# ORDER
+10011011,11011011,11100010:fclex
+10011011,11011011,11100011:finit
+10011011:fwait
+# END ORDER
+11011011,11100010:fnclex
+11011010,11000{freg}:fcmovb {freg},%st
+11011010,11001{freg}:fcmove {freg},%st
+11011010,11010{freg}:fcmovbe {freg},%st
+11011010,11011{freg}:fcmovu {freg},%st
+11011011,11000{freg}:fcmovnb {freg},%st
+11011011,11001{freg}:fcmovne {freg},%st
+11011011,11010{freg}:fcmovnbe {freg},%st
+11011011,11011{freg}:fcmovnu {freg},%st
+# ORDER
+11011000,11010{freg}:fcom {freg}
+ifdef(`ASSEMBLER',
+`11011000,11010001:fcom
+')dnl
+11011{D}00,{mod}010{r_m}:fcom{D} {mod}{r_m}
+# END ORDER
+# ORDER
+11011000,11011{freg}:fcomp {freg}
+ifdef(`ASSEMBLER',
+`11011000,11011001:fcomp
+')dnl
+11011{D}00,{mod}011{r_m}:fcomp{D} {mod}{r_m}
+# END ORDER
+11011110,11011001:fcompp
+11011011,11110{freg}:fcomi {freg},%st
+11011111,11110{freg}:fcomip {freg},%st
+11011011,11101{freg}:fucomi {freg},%st
+11011111,11101{freg}:fucomip {freg},%st
+11011001,11111111:fcos
+11011001,11110110:fdecstp
+# ORDER
+11011000,11110{freg}:fdiv {freg},%st
+11011100,11110{freg}:fdiv %st,{freg}
+11011{D}00,{mod}110{r_m}:fdiv{D} {mod}{r_m}
+# END ORDER
+11011010,{mod}110{r_m}:fidivl {mod}{r_m}
+# ORDER
+11011110,11110{freg}:fdivp %st,{freg}
+11011110,{mod}110{r_m}:fidiv {mod}{r_m}
+# END ORDER
+11011110,11111{freg}:fdivrp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11111001:fdivp
+')dnl
+# ORDER
+11011000,11111{freg}:fdivr {freg},%st
+11011100,11111{freg}:fdivr %st,{freg}
+11011{D}00,{mod}111{r_m}:fdivr{D} {mod}{r_m}
+# END ORDER
+11011010,{mod}111{r_m}:fidivrl {mod}{r_m}
+11011110,{mod}111{r_m}:fidivr {mod}{r_m}
+11011110,11110{freg}:fdivrp %st,{freg}
+ifdef(`ASSEMBLER',
+`11011110,11110001:fdivrp
+')dnl
+11011101,11000{freg}:ffree {freg}
+11011010,11010{freg}:fcmovbe {freg}
+11011{w1}10,{mod}010{r_m}:ficom{w1} {mod}{r_m}
+11011010,11011{freg}:fcmovu {freg}
+11011{w1}10,{mod}011{r_m}:ficomp{w1} {mod}{r_m}
+11011111,{mod}000{r_m}:fild {mod}{r_m}
+11011011,{mod}000{r_m}:fildl {mod}{r_m}
+11011111,{mod}101{r_m}:fildll {mod}{r_m}
+11011001,11110111:fincstp
+11011011,11100011:fninit
+11011{w1}11,{mod}010{r_m}:fist{w1} {mod}{r_m}
+11011{w1}11,{mod}011{r_m}:fistp{w1} {mod}{r_m}
+11011111,{mod}111{r_m}:fistpll {mod}{r_m}
+11011{w1}11,{mod}001{r_m}:fisttp{w1} {mod}{r_m}
+11011101,{mod}001{r_m}:fisttpll {mod}{r_m}
+11011011,{mod}101{r_m}:fldt {mod}{r_m}
+11011011,{mod}111{r_m}:fstpt {mod}{r_m}
+# ORDER
+11011001,11000{freg}:fld {freg}
+11011{D}01,{mod}000{r_m}:fld{D} {mod}{r_m}
+# ORDER END
+# ORDER
+11011101,11100{freg}:fucom {freg}
+11011101,{mod}100{r_m}:frstor {mod}{r_m}
+# ORDER END
+11011101,11101{freg}:fucomp {freg}
+11011101,{mod}110{r_m}:fnsave {mod}{r_m}
+11011101,{mod}111{r_m}:fnstsw {mod}{r_m}
+#
+#
+#
+11110100:hlt
+1111011{w},{mod}111{r_m}:idiv{w} {mod}{r_m}{w}
+1111011{w},{mod}101{r_m}:imul{w} {mod}{r_m}{w}
+00001111,10101111,{mod}{reg}{r_m}:imul {reg},{mod}{r_m}
+011010{s}1,{mod}{reg}{r_m},{imm}:imul {imm}{s},{mod}{r_m},{reg}
+1110010{w},{imm8}:in {imm8},{ax}{w}
+1110110{w}:in {dx},{ax}{w}
+1111111{w},{mod}000{r_m}:inc{w} {mod}{r_m}{w}
+01000{reg}:inc {reg}
+0110110{w}:{R}ins{w} {dx},{es_di}
+11001101,{imm8}:int {imm8}
+11001100:int3
+11001110:into
+00001111,00001000:invd
+# ORDER
+00001111,00000001,11111000:swapgs
+00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m}
+# ORDER END
+11001111:iret{W}
+0111{tttn},{disp8}:j{tttn} {disp8}
+00001111,1000{tttn},{rel}:j{tttn} {rel}
+00001111,1001{tttn},{mod}000{8r_m}:set{tttn} {mod}{8r_m}
+# SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8}
+11100011,{disp8}:INVALID {disp8}
+11101011,{disp8}:jmp {disp8}
+11101001,{rel}:jmp {rel}
+11111111,{mod}100{r_m}:jmp *{mod}{r_m}
+11101010,{absval},{sel}:ljmp {sel},{absval}
+11111111,{mod}101{r_m}:ljmp *{mod}{r_m}
+10011111:lahf
+00001111,00000010,{mod}{reg}{16r_m}:lar {mod}{16r_m},{reg}
+11000101,{mod}{reg}{r_m}:lds {mod}{r_m},{reg}
+10001101,{mod}{reg}{r_m}:lea {mod}{r_m},{reg}
+11001001:leave
+11000100,{mod}{reg}{r_m}:les {mod}{r_m},{reg}
+00001111,10110100,{mod}{reg}{r_m}:lfs {mod}{r_m},{reg}
+00001111,00000001,{mod}010{r_m}:lgdt{w0} {mod}{r_m}
+00001111,10110101,{mod}{reg}{r_m}:lgs {mod}{r_m},{reg}
+00001111,00000001,{mod}011{r_m}:lidt{w0} {mod}{r_m}
+00001111,00000000,{mod}010{16r_m}:lldt {mod}{16r_m}
+00001111,00000001,{mod}110{16r_m}:lmsw {mod}{16r_m}
+11110000:lock
+1010110{w}:{R}lods {ds_si},{ax}{w}
+11100010,{disp8}:loop {disp8}
+11100001,{disp8}:loope {disp8}
+11100000,{disp8}:loopne {disp8}
+00001111,00000011,{mod}{reg}{16r_m}:lsl {mod}{16r_m},{reg}
+00001111,10110010,{mod}{reg}{r_m}:lss {mod}{r_m},{reg}
+00001111,00000000,{mod}011{16r_m}:ltr {mod}{16r_m}
+1000100{w},{mod}{reg}{r_m}:mov {reg}{w},{mod}{r_m}{w}
+1000101{w},{mod}{reg}{r_m}:mov {mod}{r_m}{w},{reg}{w}
+1100011{w},{mod}000{r_m},{imm}:mov{w} {imm}{w},{mod}{r_m}{w}
+1011{w}{reg},{imm}:mov {imm}{w},{reg}{w}
+1010000{w},{abs}:mov {abs},{ax}{w}
+1010001{w},{abs}:mov {ax}{w},{abs}
+00001111,00100000,11{ccc}{reg}:mov {ccc},{reg}
+00001111,00100010,11{ccc}{reg}:mov {reg},{ccc}
+00001111,00100001,11{ddd}{reg}:mov {ddd},{reg}
+00001111,00100011,11{ddd}{reg}:mov {reg},{ddd}
+10001100,{mod}{sreg3}{r_m}:mov {sreg3},{mod}{r_m}
+10001110,{mod}{sreg3}{r_m}:mov {mod}{r_m},{sreg3}
+1010010{w}:{R}movs{w} {ds_si},{es_di}
+00001111,1011111{w},{mod}{reg}{r_m}:movsx{w} {mod}{r_m},{reg}
+00001111,1011011{w},{mod}{reg}{r_m}:movzx{w} {mod}{r_m},{reg}
+1111011{w},{mod}100{r_m}:mul{w} {mod}{r_m}{w}
+1111011{w},{mod}011{r_m}:neg{w} {mod}{r_m}{w}
+ifdef(`ASSEMBLER',
+`10010000:nop
+11110011,10010000:pause
+',
+`10010000:{R}INVALID
+')dnl
+1111011{w},{mod}010{r_m}:not{w} {mod}{r_m}{w}
+0000100{w},{mod}{reg}{r_m}:or {reg}{w},{mod}{r_m}{w}
+0000101{w},{mod}{reg}{r_m}:or {mod}{r_m}{w},{reg}{w}
+1000000{w},{mod}001{r_m},{imm}:or{w} {imm}{w},{mod}{r_m}{w}
+100000{s}{w},{mod}001{r_m},{imm}:or{w} {imm}{s},{mod}{r_m}{w}
+0000110{w},{imm}:or {imm}{w},{ax}{w}
+1110011{w},{imm8}:out {ax}{w},{imm8}
+1110111{w}:out {ax}{w},{dx}
+0110111{w}:{R}outs{w} {ds_si},{dx}
+10001111,{mod}000{r_m}:pop{w} {mod}{r_m}
+01011{reg}:pop {reg}
+00001111,10{sreg3}001:pop {sreg3}
+01100001:popa{W}
+10011101:popf{W}
+11111111,{mod}110{r_m}:push{w} {mod}{r_m}
+01010{reg}:push {reg}
+011010{s}0,{imm}:push {imm}{s}
+000{sreg2}110:push {sreg2}
+00001111,10{sreg3}000:push {sreg3}
+01100000:pusha{W}
+10011100:pushf{W}
+1101000{w},{mod}010{r_m}:rcl{w} {mod}{r_m}{w}
+1101001{w},{mod}010{r_m}:rcl{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}010{r_m},{imm8}:rcl{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}011{r_m}:rcr{w} {mod}{r_m}{w}
+1101001{w},{mod}011{r_m}:rcr{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}011{r_m},{imm8}:rcr{w} {imm8},{mod}{r_m}{w}
+00001111,00110010:rdmsr
+00001111,00110011:rdpmc
+00001111,00110001:rdtsc
+11000011:ret
+11000010,{imm16}:ret {imm16}
+11001011:lret
+11001010,{imm16}:lret {imm16}
+1101000{w},{mod}000{r_m}:rol{w} {mod}{r_m}{w}
+1101001{w},{mod}000{r_m}:rol{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}000{r_m},{imm8}:rol{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}001{r_m}:ror{w} {mod}{r_m}{w}
+1101001{w},{mod}001{r_m}:ror{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}001{r_m},{imm8}:ror{w} {imm8},{mod}{r_m}{w}
+00001111,10101010:rsm
+10011110:sahf
+1101000{w},{mod}111{r_m}:sar{w} {mod}{r_m}{w}
+1101001{w},{mod}111{r_m}:sar{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}111{r_m},{imm8}:sar{w} {imm8},{mod}{r_m}{w}
+0001100{w},{mod}{reg}{r_m}:sbb {reg}{w},{mod}{r_m}{w}
+0001101{w},{mod}{reg}{r_m}:sbb {mod}{r_m}{w},{reg}{w}
+0001110{w},{imm}:sbb {imm}{w},{ax}{w}
+1000000{w},{mod}011{r_m},{imm}:sbb{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}011{r_m},{imms}:sbb{w} {imms},{mod}{r_m}
+1010111{w}:{RE}scas {es_di},{ax}{w}
+00001111,1001{tttn},{mod}000{r_m}:set{tttn} {mod}{r_m}
+1101000{w},{mod}100{r_m}:shl{w} {mod}{r_m}{w}
+1101001{w},{mod}100{r_m}:shl{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}100{r_m},{imm8}:shl{w} {imm8},{mod}{r_m}{w}
+1101000{w},{mod}101{r_m}:shr{w} {mod}{r_m}{w}
+00001111,10100100,{mod}{reg}{r_m},{imm8}:shld {imm8},{reg},{mod}{r_m}
+00001111,10100101,{mod}{reg}{r_m}:shld %cl,{reg},{mod}{r_m}
+1101001{w},{mod}101{r_m}:shr{w} %cl,{mod}{r_m}{w}
+1100000{w},{mod}101{r_m},{imm8}:shr{w} {imm8},{mod}{r_m}{w}
+00001111,10101100,{mod}{reg}{r_m},{imm8}:shrd {imm8},{reg},{mod}{r_m}
+00001111,10101101,{mod}{reg}{r_m}:shrd %cl,{reg},{mod}{r_m}
+# ORDER
+00001111,00000001,11000001:vmcall
+00001111,00000001,11000010:vmlaunch
+00001111,00000001,11000011:vmresume
+00001111,00000001,11000100:vmxoff
+00001111,00000001,{mod}000{r_m}:sgdtl {mod}{r_m}
+# ORDER END
+# ORDER
+00001111,00000001,11001000:monitor %eax,%ecx,%edx
+00001111,00000001,11001001:mwait %eax,%ecx
+00001111,00000001,{mod}001{r_m}:sidtl {mod}{r_m}
+# ORDER END
+00001111,00000000,{mod}000{r_m}:sldt {mod}{r_m}
+00001111,00000001,{mod}100{r_m}:smsw {mod}{r_m}
+11111001:stc
+11111101:std
+11111011:sti
+1010101{w}:{R}stos {ax}{w},{es_di}
+00001111,00000000,{mod}001{r_m}:str {mod}{r_m}
+0010100{w},{mod}{reg}{r_m}:sub {reg}{w},{mod}{r_m}{w}
+0010101{w},{mod}{reg}{r_m}:sub {mod}{r_m}{w},{reg}{w}
+0010110{w},{imm}:sub {imm}{w},{ax}{w}
+1000000{w},{mod}101{r_m},{imm}:sub{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}101{r_m},{imms}:sub{w} {imms},{mod}{r_m}
+1000010{w},{mod}{reg}{r_m}:test {reg}{w},{mod}{r_m}{w}
+1010100{w},{imm}:test {imm}{w},{ax}{w}
+1111011{w},{mod}000{r_m},{imm}:test{w} {imm}{w},{mod}{r_m}{w}
+00001111,00001011:ud2a
+00001111,00000000,{mod}100{16r_m}:verr {mod}{16r_m}
+00001111,00000000,{mod}101{16r_m}:verw {mod}{16r_m}
+00001111,00001001:wbinvd
+00001111,00001101,{mod}000{8r_m}:prefetch {mod}{8r_m}
+00001111,00001101,{mod}001{8r_m}:prefetchw {mod}{8r_m}
+00001111,00011000,{mod}000{r_m}:prefetchnta {mod}{r_m}
+00001111,00011000,{mod}001{r_m}:prefetcht0 {mod}{r_m}
+00001111,00011000,{mod}010{r_m}:prefetcht1 {mod}{r_m}
+00001111,00011000,{mod}011{r_m}:prefetcht2 {mod}{r_m}
+00001111,00011111,{mod}{reg}{r_m}:nop{w} {mod}{r_m}
+dnl without prefix: movups
+dnl with 0xf3: movss
+dnl with 0x66: movupd
+dnl with 0xf2: movsd
+00001111,00010000,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010001,{Mod}{xmmreg}{R_m}:{R}INVALID {xmmreg},{Mod}{R_m}
+00001111,00110000:wrmsr
+00001111,1100000{w},{mod}{reg}{r_m}:xadd{w} {reg},{mod}{r_m}
+1000011{w},{mod}{reg}{r_m}:xchg {reg}{w},{mod}{r_m}{w}
+10010{reg}:xchg {ax},{reg}
+11010111:xlat {ds_bx}
+0011000{w},{mod}{reg}{r_m}:xor {reg}{w},{mod}{r_m}{w}
+0011001{w},{mod}{reg}{r_m}:xor {mod}{r_m}{w},{reg}{w}
+0011010{w},{imm}:xor {imm}{w},{ax}{w}
+1000000{w},{mod}110{r_m},{imm}:xor{w} {imm}{w},{mod}{r_m}{w}
+1000001{w},{mod}110{r_m},{imms}:xor{w} {imms},{mod}{r_m}
+00001111,01110111:emms
+00001111,01101110,{mod}{mmxreg}{r_m}:movd {mod}{r_m},{mmxreg}
+00001111,01111110,{mod}{mmxreg}{r_m}:movd {mmxreg},{mod}{r_m}
+00001111,01101111,{MOD}{mmxreg}{R_M}:movq {MOD}{R_M},{mmxreg}
+00001111,01111111,{MOD}{mmxreg}{R_M}:movq {mmxreg},{MOD}{R_M}
+00001111,01101011,{MOD}{mmxreg}{R_M}:packssdw {MOD}{R_M},{mmxreg}
+00001111,01100011,{MOD}{mmxreg}{R_M}:packsswb {MOD}{R_M},{mmxreg}
+00001111,01100111,{MOD}{mmxreg}{R_M}:packuswb {MOD}{R_M},{mmxreg}
+00001111,111111{gg},{MOD}{mmxreg}{R_M}:padd{gg} {MOD}{R_M},{mmxreg}
+00001111,111111{0g},{MOD}{mmxreg}{R_M}:padds{0g} {MOD}{R_M},{mmxreg}
+00001111,110111{0g},{MOD}{mmxreg}{R_M}:paddus{0g} {MOD}{R_M},{mmxreg}
+00001111,11011011,{MOD}{mmxreg}{R_M}:pand {MOD}{R_M},{mmxreg}
+00001111,11011111,{MOD}{mmxreg}{R_M}:pandn {MOD}{R_M},{mmxreg}
+00001111,011101{gg},{MOD}{mmxreg}{R_M}:pcmpeq{gg} {MOD}{R_M},{mmxreg}
+00001111,011001{gg},{MOD}{mmxreg}{R_M}:pcmpgt{gg} {MOD}{R_M},{mmxreg}
+00001111,11110101,{MOD}{mmxreg}{R_M}:pmaddwd {MOD}{R_M},{mmxreg}
+00001111,11100101,{MOD}{mmxreg}{R_M}:pmulhw {MOD}{R_M},{mmxreg}
+00001111,11010101,{MOD}{mmxreg}{R_M}:pmullw {MOD}{R_M},{mmxreg}
+00001111,11101011,{MOD}{mmxreg}{R_M}:por {MOD}{R_M},{mmxreg}
+00001111,111100{GG},{MOD}{mmxreg}{R_M}:psll{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11110{mmxreg},{imm8}:psll{GG} {imm8},{mmxreg}
+00001111,111000{gG},{MOD}{mmxreg}{R_M}:psra{gG} {MOD}{R_M},{mmxreg}
+00001111,011100{gG},11100{mmxreg},{imm8}:psra{gG} {imm8},{mmxreg}
+00001111,110100{GG},{MOD}{mmxreg}{R_M}:psrl{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11010{mmxreg},{imm8}:psrl{GG} {imm8},{mmxreg}
+00001111,111110{gg},{MOD}{mmxreg}{R_M}:psub{gg} {MOD}{R_M},{mmxreg}
+00001111,111010{0g},{MOD}{mmxreg}{R_M}:psubs{0g} {MOD}{R_M},{mmxreg}
+00001111,110110{0g},{MOD}{mmxreg}{R_M}:psubus{0g} {MOD}{R_M},{mmxreg}
+00001111,011010{gg},{MOD}{mmxreg}{R_M}:punpckh{gg} {MOD}{R_M},{mmxreg}
+00001111,011000{gg},{MOD}{mmxreg}{R_M}:punpckl{gg} {MOD}{R_M},{mmxreg}
+00001111,11101111,{MOD}{mmxreg}{R_M}:pxor {MOD}{R_M},{mmxreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordps {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordss {Mod}{R_m},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2ps {MOD}{R_M},{xmmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,10101110,{mod}001{r_m}:fxrstor {mod}{r_m}
+00001111,10101110,{mod}000{r_m}:fxsave {mod}{r_m}
+00001111,10101110,{mod}010{r_m}:ldmxcsr {mod}{r_m}
+00001111,01011111,{Mod}{xmmreg}{R_m}:maxps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011111,{Mod}{xmmreg}{R_m}:maxss {Mod}{R_m},{xmmreg}
+00001111,01011101,{Mod}{xmmreg}{R_m}:minps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011101,{Mod}{xmmreg}{R_m}:minss {Mod}{R_m},{xmmreg}
+00001111,00101000,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00101001,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00010010,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010011,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00010100,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00010101,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00010110,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,00010111,{Mod}{xmmreg}{R_m}:INVALID {xmmreg},{Mod}{R_m}
+00001111,00101011,{mod}{xmmreg}{r_m}:INVALID {xmmreg},{mod}{r_m}
+00001111,00101100,{Mod}{mmxreg2}{R_m}:{R}INVALID {Mod}{R_m},{mmxreg2}
+00001111,00101101,{Mod}{mmxreg2}{R_m}:{R}INVALID {Mod}{R_m},{mmxreg2}
+00001111,00101110,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00101111,{Mod}{xmmreg}{R_m}:INVALID {Mod}{R_m},{xmmreg}
+00001111,00110111:getsec
+00001111,01010000,11{reg}{xmmreg}:INVALID {xmmreg},{reg}
+00001111,01010001,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,01010010,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+00001111,01010011,{Mod}{xmmreg}{R_m}:{R}INVALID {Mod}{R_m},{xmmreg}
+# ORDER:
+dnl Many previous entries depend on this being last.
+000{sreg2}111:pop {sreg2}
+# ORDER END:
diff --git a/libcpu/defs/i386.doc b/libcpu/defs/i386.doc
new file mode 100644 (file)
index 0000000..732cd23
--- /dev/null
@@ -0,0 +1,74 @@
+{imm} only parameter:
+  - is {s} in opcode: {s} == 0, unsigned (8/)16/32 bit immediate
+                      {s} == 1, signed 8 bit immediate
+
+{es:di}: segment register normally %es, can be overwritten
+         edi/di depending on apfx
+
+{ds:si}: segment register normally %ds, can be overwritten
+         esi/si depending on apfx
+
+{ax}     al/ax/eax depending of dpfx and w
+
+{dx}     (%edx) or (%dx) depending on apfx
+
+
+{w}      0 = b, 1 = { no dpfx = l, dpfx = w }
+
+{W}      no dpfx = <empty>, dpfx = w
+{WW}     no dpfx = l, dpfx = w
+
+{R} rep prefix possible
+{RE} repe or repne prefix possible
+
+{ccc} CRx registers
+{ddd} DRx registers
+
+{gg}  00 = b, 01 = w, 10 = d, 11 = <illegal>
+{0g}  00 = b, 01 = w, 10 = <illegal>, 11 = <illegal>
+{GG}  00 = <illegal>, 01 = w, 10 = d, 11 = q
+{gG}  00 = <illegal>, 01 = w, 10 = d, 11 = <illegal>
+
+{modr/m} normal registers
+{MODR/M} MMX registers
+{ModR/m} XMM registers
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Special opcodes (prefixes):
+
+
+01100111:{apfx}
+01100110:{dpfx}
+
+00101110:{cs}
+00111110:{ds}
+00100110:{es}
+01100100:{fs}
+01100101:{gs}
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+table format
+
+1bit RE flag
+1bit R flag
+16bit mnemonic
+3bit suffix
+
+5bit fct
+2bit string
+6bit offset1
+5bit offset2
+
+4bit fct
+1bit string
+6bit offset1
+4bit offset2
+
+2bit fct
+1bit string
+3bit offset1
+1bit offset2
+
+61bit
diff --git a/libcpu/defs/x86_64 b/libcpu/defs/x86_64
new file mode 100644 (file)
index 0000000..090c475
--- /dev/null
@@ -0,0 +1,341 @@
+%mask {s}      1
+%mask {w}      1
+%mask {D}      1
+%mask {imm8}   8
+%mask {imm16}  16
+%mask {reg}    3
+%mask {tttn}   4
+%mask {gg}     2
+%mask {mod}    2
+%mask {MOD}    2
+%mask {r_m}    3
+%mask {disp8}  8
+# imm really is 8/16/32 bit depending on the situation.
+%mask {imm}    8
+%mask {abs}    32
+%mask {sel}    16
+%mask {imm32}  32
+%mask {dispA}  32
+%mask {ccc}    3
+%mask {ddd}    3
+%mask {sreg3}  3
+%mask {sreg2}  2
+%mask {mmxreg} 3
+%mask {R_M}    3
+%mask {0g}     2
+%mask {GG}     2
+%mask {gG}     2
+%mask {Mod}    2
+%mask {xmmreg} 3
+%mask {R_m}    3
+%mask {xmmreg1} 3
+%mask {xmmreg2} 3
+%mask {mmreg}   3
+%prefix {R}
+%prefix {RE}
+%suffix {W}
+%suffix {WW}
+%synonym {xmmreg1} {xmmreg}
+%synonym {xmmreg2} {xmmreg}
+
+%%
+0001010{w},{imm}:adc {imm}{w},{ax}{w}
+1000000{w},{mod}010{r_m},{imm}:adc{w} {imm},{mod}{r_m}
+1000001{w},{mod}010{r_m},{imm8}:adc{w} {imm8},{mod}{r_m}
+0001000{w},{mod}{reg}{r_m}:adc{w} {reg},{mod}{r_m}
+0001001{w},{mod}{reg}{r_m}:adc{w} {mod}{r_m},{reg}
+0000010{w},{imm}:add {imm}{w},{ax}{w}
+1000000{w},{mod}000{r_m},{imm}:add{w} {imm},{mod}{r_m}
+1000001{w},{mod}000{r_m},{imm8}:add{w} {imm8},{mod}{r_m}
+0000000{w},{mod}{reg}{r_m}:add {reg}{w},{mod}{r_m}
+0000001{w},{mod}{reg}{r_m}:add {mod}{r_m},{reg}{w}
+01100110,00001111,01011000,{Mod}{xmmreg}{R_m}:addpd {Mod}{R_m},{xmmreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110010,00001111,01011000,{Mod}{xmmreg}{R_m}:addsd {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+01100110,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubpd {Mod}{R_m},{xmmreg}
+11110010,00001111,11010000,{Mod}{xmmreg}{R_m}:addsubps {Mod}{R_m},{xmmreg}
+#
+#
+#
+0010000{w},{mod}{reg}{r_m}:and{w} {reg},{mod}{r_m}
+0010001{w},{mod}{reg}{r_m}:and{w} {mod}{r_m},{reg}
+0010010{w},{imm}:and {imm}{w},{ax}{w}
+100000{s}{w},{mod}100{r_m},{imm}:and{w} {imm}{s},{mod}{r_m}
+01100011,{mod}{reg}{r_m}:arpl {reg},{mod}{r_m}
+01100010,{mod}{reg}{r_m}:bound {reg},{mod}{r_m}
+00001111,10111100,{mod}{reg}{r_m}:bsf {reg},{mod}{r_m}
+00001111,10111101,{mod}{reg}{r_m}:bsr {reg},{mod}{r_m}
+00001111,11001{reg}:bswap {reg}
+00001111,10111010,{mod}100{r_m},{imm8}:bt {imm8},{mod}{r_m}
+00001111,10100011,{mod}{reg}{r_m}:bt {reg},{mod}{r_m}
+00001111,10111010,{mod}111{r_m},{imm8}:btc {imm8},{mod}{r_m}
+00001111,10111011,{mod}{reg}{r_m}:btc {reg},{mod}{r_m}
+00001111,10111010,{mod}110{r_m},{imm8}:btr {imm8},{mod}{r_m}
+00001111,10110011,{mod}{reg}{r_m}:btr {reg},{mod}{r_m}
+00001111,10111010,{mod}101{r_m},{imm8}:bts {imm8},{mod}{r_m}
+00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m}
+11101000,{abs}:call {abs}
+11111111,{mod}010{r_m}:call *{mod}{r_m}
+10011010,{abs},{sel}:lcall {sel},{abs}
+11111111,{mod}011{r_m}:lcall {mod}{r_m}
+10011000:cbt{WW}
+#SPECIAL 10011001:[{dpfx}?cltd:cwtd]
+11111000:clc
+11111100:cld
+11111010:cli
+00001111,00000110:clts
+11110101:cmc
+00001111,0100{tttn},{mod}{reg}{r_m}:cmov{tttn} {mod}{r_m},{reg}
+0011100{w},{mod}{reg}{r_m}:cmp{w} {reg},{mod}{r_m}
+0011101{w},{mod}{reg}{r_m}:cmp{w} {mod}{r_m},{reg}
+0011110{w},{imm}:cmp {imm}{w},{ax}{w}
+100000{s}{w},{mod}111{r_m},{imm}:cmp{w} {imm}{s},{mod}{r_m}
+1010011{w}:{RE}cmps{w}
+00001111,1011000{w},{mod}{reg}{r_m}:cmpxchg{w} {reg},{mod}{r_m}
+00001111,11000111,{mod}{reg}{r_m}:cmpxchg8b {reg},{mod}{r_m}
+00001111,10100010:cpuid
+00100111:daa
+00101111:das
+1111111{w},{mod}001{r_m}:dec{w} {mod}{r_m}
+01001{reg}:dec {reg}
+1111011{w},{mod}110{r_m}:div{w} {mod}{r_m}
+11001000,{imm16},{imm8}:enter {imm16},{imm8}
+11110100:hlt
+1111011{w},{mod}111{r_m}:idiv{w} {mod}{r_m}
+1111011{w},{mod}101{r_m}:imul{w} {mod}{r_m}
+00001111,10101111,{mod}{reg}{r_m}:imul {reg},{mod}{r_m}
+011010{s}1,{mod}{reg}{r_m},{imm}:imul {imm}{s},{mod}{r_m},{reg}
+1110010{w},{imm8}:in {imm8},{ax}{w}
+1110110{w}:in {dx},{ax}{w}
+1111111{w},{mod}000{r_m}:inc{w} {mod}{r_m}
+01000{reg}:inc {reg}
+0110110{w}:{R}ins{w} {dx},{es_di}
+11001101,{imm8}:int {imm8}
+11001100:int 3
+11001110:into
+00001111,00001000:invd
+00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m}
+11001111:iret{W}
+0111{tttn},{disp8}:j{tttn} {disp8}
+00001111,1000{tttn},{dispA}:j{tttn} {dispA}
+#SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8}
+11101011,{disp8}:jmp {disp8}
+11101001,{dispA}:jmp {dispA}
+11111111,{mod}100{r_m}:jmp *{mod}{r_m}
+11101010,{abs},{sel}:ljmp {sel},{abs}
+11111111,{mod}101{r_m}:ljmp {mod}{r_m}
+10011111:lahf
+00001111,00000010,{mod}{reg}{r_m}:lar {mod}{r_m},{reg}
+11000101,{mod}{reg}{r_m}:lds {mod}{r_m},{reg}
+10001101,{mod}{reg}{r_m}:lea {mod}{r_m},{reg}
+11001001:leave
+11000100,{mod}{reg}{r_m}:les {mod}{r_m},{reg}
+00001111,10110100,{mod}{reg}{r_m}:lfs {mod}{r_m},{reg}
+00001111,00000001,{mod}010{r_m}:lgdt{WW} {mod}{r_m}
+00001111,10110101,{mod}{reg}{r_m}:lgs {mod}{r_m},{reg}
+00001111,00000001,{mod}011{r_m}:lidt{WW} {mod}{r_m}
+00001111,00000000,{mod}010{r_m}:lldt{WW} {mod}{r_m}
+00001111,00000001,{mod}110{r_m}:lmsw {mod}{r_m}
+11110000:lock
+1010110{w}:{R}lods {ds_si},{ax}{w}
+11100010,{disp8}:loop {disp8}
+11100001,{disp8}:loope {disp8}
+11100000,{disp8}:loopne {disp8}
+00001111,00000011,{mod}{reg}{r_m}:lsl {mod}{r_m},{reg}
+00001111,10110010,{mod}{reg}{r_m}:lss {mod}{r_m},{reg}
+00001111,00000000,{mod}011{r_m}:ltr {mod}{r_m}
+1000100{w},{mod}{reg}{r_m}:mov{w} {reg},{mod}{r_m}
+1000101{w},{mod}{reg}{r_m}:mov{w} {mod}{r_m},{reg}
+1100011{w},{mod}000{r_m},{imm}:mov{w} {imm},{mod}{r_m}
+1011{w}{reg},{imm}:mov{w} {imm},{reg}
+1010000{w},{abs}:mov {ax}{w},{abs}
+1010001{w},{abs}:mov {abs},{ax}{w}
+00001111,00100000,11{ccc}{reg}:mov {reg},{ccc}
+00001111,00100010,11{ccc}{reg}:mov {ccc},{reg}
+00001111,00100001,11{ddd}{reg}:mov {reg},{ddd}
+00001111,00100011,11{ddd}{reg}:mov {ddd},{reg}
+10001100,{mod}{sreg3}{r_m}:mov {sreg3},{mod}{r_m}
+10001110,{mod}{sreg3}{r_m}:mov {mod}{r_m},{sreg3}
+1010010{w}:{R}movs{w} {ds_si},{es_di}
+00001111,1011111{w},{mod}{reg}{r_m}:movsx{w} {mod}{r_m},{reg}
+00001111,1011011{w},{mod}{reg}{r_m}:movzx{w} {mod}{r_m},{reg}
+1111011{w},{mod}100{r_m}:mul{w} {mod}{r_m}
+1111011{w},{mod}011{r_m}:neg{w} {mod}{r_m}
+10010000:nop
+11110011,10010000:pause
+1111011{w},{mod}010{r_m}:not{w} {mod}{r_m}
+0000100{w},{mod}{reg}{r_m}:or{w} {reg},{mod}{r_m}
+0000101{w},{mod}{reg}{r_m}:or{w} {mod}{r_m},{reg}
+100000{s}{w},{mod}001{r_m},{imm}:or{w} {imm}{s},{mod}{r_m}
+0000110{w},{imm}:mov {imm}{w},{ax}{w}
+1110011{w},{imm8}:out {ax}{w},{imm8}
+1110111{w}:out {ax}{w},{dx}
+0110111{w}:{R}outs{w} {ds_si},{dx}
+10001111,{mod}000{r_m}:pop {mod}{r_m}
+01011{reg}:pop {reg}
+000{sreg2}111:pop {sreg2}
+00001111,10{sreg3}001:pop {sreg3}
+01100001:popa{W}
+10011101:popf{W}
+11111111,{mod}110{r_m}:push {mod}{r_m}
+01010{reg}:push {reg}
+011010{s}0,{imm}:push {imm}{s}
+000{sreg2}110:push {sreg2}
+00001111,10{sreg3}000:push {sreg3}
+01100000:pusha{W}
+10011100:pushf{W}
+1101000{w},{mod}010{r_m}:rcl{w} {mod}{r_m}
+1101001{w},{mod}010{r_m}:rcl{w} %cl,{mod}{r_m}
+1100000{w},{mod}010{r_m},{imm8}:rcl{w} {imm8},{mod}{r_m}
+1101000{w},{mod}011{r_m}:rcr{w} {mod}{r_m}
+1101001{w},{mod}011{r_m}:rcr{w} %cl,{mod}{r_m}
+1100000{w},{mod}011{r_m},{imm8}:rcr{w} {imm8},{mod}{r_m}
+00001111,00110010:rdmsr
+00001111,00110011:rdpmc
+00001111,00110001:rdtsc
+11000011:ret
+11000010,{imm16}:ret {imm16}
+11001011:lret
+11001010,{imm16}:lret {imm16}
+1101000{w},{mod}000{r_m}:rol{w} {mod}{r_m}
+1101001{w},{mod}000{r_m}:rol{w} %cl,{mod}{r_m}
+1100000{w},{mod}000{r_m},{imm8}:rol{w} {imm8},{mod}{r_m}
+1101000{w},{mod}001{r_m}:ror{w} {mod}{r_m}
+1101001{w},{mod}001{r_m}:ror{w} %cl,{mod}{r_m}
+1100000{w},{mod}001{r_m},{imm8}:ror{w} {imm8},{mod}{r_m}
+00001111,10101010:rsm
+10011110:sahf
+1101000{w},{mod}111{r_m}:sar{w} {mod}{r_m}
+1101001{w},{mod}111{r_m}:sar{w} %cl,{mod}{r_m}
+1100000{w},{mod}111{r_m},{imm8}:sar{w} {imm8},{mod}{r_m}
+0001100{w},{mod}{reg}{r_m}:sbb{w} {reg},{mod}{r_m}
+0001101{w},{mod}{reg}{r_m}:sbb{w} {mod}{r_m},{reg}
+0001110{w},{imm}:sbb {imm}{w},{ax}{w}
+100000{s}{w},{mod}011{r_m},{imm}:sbb{w} {imm}{s},{mod}{r_m}
+1010111{w}:{RE}scas {es_di},{ax}{w}
+00001111,1001{tttn},{mod}000{r_m}:set{tttn} {mod}{r_m}
+00001111,00000001,{mod}000{r_m}:sgdt {mod}{r_m}
+1101000{w},{mod}100{r_m}:shl{w} {mod}{r_m}
+1101001{w},{mod}100{r_m}:shl{w} %cl,{mod}{r_m}
+1100000{w},{mod}100{r_m},{imm8}:shl{w} {imm8},{mod}{r_m}
+1101000{w},{mod}101{r_m}:shr{w} {mod}{r_m}
+00001111,10100100,{mod}{reg}{r_m},{imm8}:shld {imm8},{reg},{mod}{r_m}
+00001111,10100101,{mod}{reg}{r_m}:shld %cl,{reg},{mod}{r_m}
+1101001{w},{mod}101{r_m}:shr{w} %cl,{mod}{r_m}
+1100000{w},{mod}101{r_m},{imm8}:shr{w} {imm8},{mod}{r_m}
+00001111,10101100,{mod}{reg}{r_m},{imm8}:shrd {imm8},{reg},{mod}{r_m}
+00001111,10101101,{mod}{reg}{r_m}:shrd %cl,{reg},{mod}{r_m}
+00001111,00000001,{mod}001{r_m}:sidt {mod}{r_m}
+00001111,00000000,{mod}000{r_m}:sldt {mod}{r_m}
+00001111,00000001,{mod}100{r_m}:smsw {mod}{r_m}
+11111001:stc
+11111101:std
+11111011:sti
+1010101{w}:{R}stos {ax}{w},{es_di}
+00001111,00000000,{mod}001{r_m}:str {mod}{r_m}
+0010100{w},{mod}{reg}{r_m}:sub{w} {reg},{mod}{r_m}
+0010101{w},{mod}{reg}{r_m}:sub{w} {mod}{r_m},{reg}
+0010110{w},{imm}:sub {imm}{w},{ax}{w}
+100000{s}{w},{mod}101{r_m},{imm}:sub{w} {imm}{s},{mod}{r_m}
+1000010{w},{mod}{reg}{r_m}:test{w} {reg},{mod}{r_m}{w}
+1000011{w},{mod}{reg}{r_m}:test{w} {mod}{r_m}{w},{reg}
+0010100{w},{imm}:test {imm}{w},{ax}{w}
+1111011{w},{mod}000{r_m},{imm}:test{w} {imm},{mod}{r_m}
+00001111,00001011:ud2a
+00001111,00000000,{mod}100{r_m}:verr {mod}{r_m}
+00001111,00000000,{mod}101{r_m}:verw {mod}{r_m}
+10011011:wait
+00001111,00001001:wbinvd
+00001111,00110000:wrmsr
+00001111,1100000{w},{mod}{reg}{r_m}:xadd{w} {reg},{mod}{r_m}
+1000011{w},{mod}{reg}{r_m}:xchg{w} {reg},{mod}{r_m}
+11010111:xlat
+0011000{w},{mod}{reg}{r_m}:xor{w} {reg},{mod}{r_m}
+0011001{w},{mod}{reg}{r_m}:xor{w} {mod}{r_m},{reg}
+0011010{w},{imm}:xor {imm}{w},{ax}{w}
+100000{s}{w},{mod}110{r_m},{imm}:xor{w} {imm}{s},{mod}{r_m}
+00001111,01110111:emms
+00001111,01101110,{mod}{mmxreg}{r_m}:movd {mod}{r_m},{mmxreg}
+00001111,01111110,{mod}{mmxreg}{r_m}:movd {mmxreg},{mod}{r_m}
+00001111,01101111,{MOD}{mmxreg}{R_M}:movq {MOD}{R_M},{mmxreg}
+00001111,01111111,{MOD}{mmxreg}{R_M}:movq {mmxreg},{MOD}{R_M}
+00001111,01101011,{MOD}{mmxreg}{R_M}:packssdw {MOD}{R_M},{mmxreg}
+00001111,01100011,{MOD}{mmxreg}{R_M}:packsswb {MOD}{R_M},{mmxreg}
+00001111,01100111,{MOD}{mmxreg}{R_M}:packuswb {MOD}{R_M},{mmxreg}
+00001111,111111{gg},{MOD}{mmxreg}{R_M}:padd{gg} {MOD}{R_M},{mmxreg}
+00001111,111111{0g},{MOD}{mmxreg}{R_M}:padds{0g} {MOD}{R_M},{mmxreg}
+00001111,110111{0g},{MOD}{mmxreg}{R_M}:paddus{0g} {MOD}{R_M},{mmxreg}
+00001111,11011011,{MOD}{mmxreg}{R_M}:pand {MOD}{R_M},{mmxreg}
+00001111,11011111,{MOD}{mmxreg}{R_M}:pandn {MOD}{R_M},{mmxreg}
+00001111,011101{gg},{MOD}{mmxreg}{R_M}:pcmpeq{gg} {MOD}{R_M},{mmxreg}
+00001111,011001{gg},{MOD}{mmxreg}{R_M}:pcmpgt{gg} {MOD}{R_M},{mmxreg}
+00001111,11110101,{MOD}{mmxreg}{R_M}:pmaddwd {MOD}{R_M},{mmxreg}
+00001111,11100101,{MOD}{mmxreg}{R_M}:pmulhw {MOD}{R_M},{mmxreg}
+00001111,11010101,{MOD}{mmxreg}{R_M}:pmullw {MOD}{R_M},{mmxreg}
+00001111,11101011,{MOD}{mmxreg}{R_M}:por {MOD}{R_M},{mmxreg}
+00001111,111100{GG},{MOD}{mmxreg}{R_M}:psll{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11110{mmxreg},{imm8}:psll{GG} {imm8},{mmxreg}
+00001111,111000{gG},{MOD}{mmxreg}{R_M}:psra{gG} {MOD}{R_M},{mmxreg}
+00001111,011100{gG},11100{mmxreg},{imm8}:psra{gG} {imm8},{mmxreg}
+00001111,110100{GG},{MOD}{mmxreg}{R_M}:psrl{GG} {MOD}{R_M},{mmxreg}
+00001111,011100{GG},11010{mmxreg},{imm8}:psrl{GG} {imm8},{mmxreg}
+00001111,111110{gg},{MOD}{mmxreg}{R_M}:psub{gg} {MOD}{R_M},{mmxreg}
+00001111,111010{0g},{MOD}{mmxreg}{R_M}:psubs{0g} {MOD}{R_M},{mmxreg}
+00001111,110110{0g},{MOD}{mmxreg}{R_M}:psubus{0g} {MOD}{R_M},{mmxreg}
+00001111,011010{gg},{MOD}{mmxreg}{R_M}:punpckh{gg} {MOD}{R_M},{mmxreg}
+00001111,011000{gg},{MOD}{mmxreg}{R_M}:punpckl{gg} {MOD}{R_M},{mmxreg}
+00001111,11101111,{MOD}{mmxreg}{R_M}:pxor {MOD}{R_M},{mmxreg}
+00001111,01011000,{Mod}{xmmreg}{R_m}:addps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011000,{Mod}{xmmreg}{R_m}:addss {Mod}{R_m},{xmmreg}
+00001111,01010101,{Mod}{xmmreg}{R_m}:andnps {Mod}{R_m},{xmmreg}
+00001111,01010100,{Mod}{xmmreg}{R_m}:andps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnleps {Mod}{R_m},{xmmreg}
+00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordps {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000000:cmpeqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000001:cmpltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000010:cmpless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000011:cmpunordss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000100:cmpneqss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000101:cmpnltss {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000110:cmpnless {Mod}{R_m},{xmmreg}
+11110011,00001111,11000010,{Mod}{xmmreg}{R_m},00000111:cmpordss {Mod}{R_m},{xmmreg}
+00001111,00101111,{Mod}{xmmreg}{R_m}:comiss {Mod}{R_m},{xmmreg}
+00001111,00101010,{MOD}{xmmreg}{R_M}:cvtpi2ps {MOD}{R_M},{xmmreg}
+00001111,00101101,{MOD}{mmreg}{R_M}:cvtps2pi {MOD}{R_M},{mmreg}
+11110011,00001111,00101010,{mod}{xmmreg}{r_m}:cvtsi2ss {mod}{r_m},{xmmreg}
+11110011,00001111,00101101,{Mod}{reg}{R_m}:cvtss2si {Mod}{R_m},{reg}
+00001111,00101100,{Mod}{mmreg}{R_m}:cvttps2pi {Mod}{R_m},{mmreg}
+11110011,00001111,00101100,{Mod}{reg}{R_m}:cvttss2si {Mod}{R_m},{reg}
+00001111,01011110,{Mod}{xmmreg}{R_m}:divps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011110,{Mod}{xmmreg}{R_m}:divss {Mod}{R_m},{xmmreg}
+00001111,10101110,{mod}001{r_m}:fxrstor {mod}{r_m}
+00001111,10101110,{mod}000{r_m}:fxsave {mod}{r_m}
+00001111,10101110,{mod}010{r_m}:ldmxcsr {mod}{r_m}
+00001111,01011111,{Mod}{xmmreg}{R_m}:maxps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011111,{Mod}{xmmreg}{R_m}:maxss {Mod}{R_m},{xmmreg}
+00001111,01011101,{Mod}{xmmreg}{R_m}:minps {Mod}{R_m},{xmmreg}
+11110011,00001111,01011101,{Mod}{xmmreg}{R_m}:minss {Mod}{R_m},{xmmreg}
+00001111,00101000,{Mod}{xmmreg}{R_m}:movaps {Mod}{R_m},{xmmreg}
+00001111,00101001,{Mod}{xmmreg}{R_m}:movaps {xmmreg},{Mod}{R_m}
+# ORDER:
+00001111,00010010,11{xmmreg1}{xmmreg2}:movhlps {xmmreg1},{xmmreg2}
+00001111,00010011,11{xmmreg1}{xmmreg2}:movhlps {xmmreg2},{xmmreg1}
+00001111,00010010,{Mod}{xmmreg}{R_m}:movlps {Mod}{R_m},{xmmreg}
+00001111,00010011,{Mod}{xmmreg}{R_m}:movlps {xmmreg},{Mod}{R_m}
+# ORDER END:
+# ORDER:
+00001111,00010110,11{xmmreg1}{xmmreg2}:movlhps {xmmreg1},{xmmreg2}
+00001111,00010111,11{xmmreg1}{xmmreg2}:movlhps {xmmreg2},{xmmreg1}
+00001111,00010110,{Mod}{xmmreg}{R_m}:movhps {Mod}{R_m},{xmmreg}
+00001111,00010111,{Mod}{xmmreg}{R_m}:movhps {xmmreg},{Mod}{R_m}
+# ORDER END:
+# BOGUS
+00000000,11{reg}111:fadd {reg}
+00001111,00000001,11000001:vmcall
diff --git a/libcpu/i386_data.h b/libcpu/i386_data.h
new file mode 100644 (file)
index 0000000..38e9935
--- /dev/null
@@ -0,0 +1,1406 @@
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libasm.h>
+
+struct instr_enc
+{
+  /* The mnemonic.  Especially encoded for the optimized table.  */
+  unsigned int mnemonic : MNEMONIC_BITS;
+
+  /* The rep/repe prefixes.  */
+  unsigned int rep : 1;
+  unsigned int repe : 1;
+
+  /* Mnemonic suffix.  */
+  unsigned int suffix : SUFFIX_BITS;
+
+  /* Nonzero if the instruction uses modr/m.  */
+  unsigned int modrm : 1;
+
+  /* 1st parameter.  */
+  unsigned int fct1 : FCT1_BITS;
+#ifdef STR1_BITS
+  unsigned int str1 : STR1_BITS;
+#endif
+  unsigned int off1_1 : OFF1_1_BITS;
+  unsigned int off1_2 : OFF1_2_BITS;
+  unsigned int off1_3 : OFF1_3_BITS;
+
+  /* 2nd parameter.  */
+  unsigned int fct2 : FCT2_BITS;
+#ifdef STR2_BITS
+  unsigned int str2 : STR2_BITS;
+#endif
+  unsigned int off2_1 : OFF2_1_BITS;
+  unsigned int off2_2 : OFF2_2_BITS;
+  unsigned int off2_3 : OFF2_3_BITS;
+
+  /* 3rd parameter.  */
+  unsigned int fct3 : FCT3_BITS;
+#ifdef STR3_BITS
+  unsigned int str3 : STR3_BITS;
+#endif
+  unsigned int off3_1 : OFF3_1_BITS;
+#ifdef OFF3_2_BITS
+  unsigned int off3_2 : OFF3_2_BITS;
+#endif
+#ifdef OFF3_3_BITS
+  unsigned int off3_3 : OFF3_3_BITS;
+#endif
+};
+
+
+typedef int (*opfct_t) (GElf_Addr, int *, const char *, size_t, size_t, size_t,
+                       char *, size_t *, size_t, const uint8_t *data,
+                       const uint8_t **param_start, const uint8_t *end,
+                       DisasmGetSymCB_t, void *);
+
+
+static int
+data_prefix (int *prefixes, char *bufp, size_t *bufcntp, size_t bufsize)
+{
+  char ch = '\0';
+  if (*prefixes & has_cs)
+    {
+      ch = 'c';
+      *prefixes &= ~has_cs;
+    }
+  else if (*prefixes & has_ds)
+    {
+      ch = 'd';
+      *prefixes &= ~has_ds;
+    }
+  else if (*prefixes & has_es)
+    {
+      ch = 'e';
+      *prefixes &= has_es;
+    }
+  else if (*prefixes & has_fs)
+    {
+      ch = 'f';
+      *prefixes &= ~has_fs;
+    }
+  else if (*prefixes & has_gs)
+    {
+      ch = 'g';
+      *prefixes &= ~has_gs;
+    }
+  else if (*prefixes & has_ss)
+    {
+      ch = 's';
+      *prefixes &= ~has_ss;
+    }
+  else
+    return 0;
+
+  if (*bufcntp + 4 > bufsize)
+    return *bufcntp + 4 - bufsize;
+
+  bufp[(*bufcntp)++] = '%';
+  bufp[(*bufcntp)++] = ch;
+  bufp[(*bufcntp)++] = 's';
+  bufp[(*bufcntp)++] = ':';
+
+  return 0;
+}
+
+static const char regs[8][4] =
+  {
+    "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
+  };
+
+static int
+general_mod$r_m (GElf_Addr addr __attribute__ ((unused)),
+                int *prefixes __attribute__ ((unused)),
+                const char *op1str __attribute__ ((unused)),
+                size_t opoff1 __attribute__ ((unused)),
+                size_t opoff2 __attribute__ ((unused)),
+                size_t opoff3 __attribute__ ((unused)),
+                char *bufp __attribute__ ((unused)),
+                size_t *bufcntp __attribute__ ((unused)),
+                size_t bufsize __attribute__ ((unused)),
+                const uint8_t *data __attribute__ ((unused)),
+                const uint8_t **param_start __attribute__ ((unused)),
+                const uint8_t *end __attribute__ ((unused)),
+                DisasmGetSymCB_t symcb __attribute__ ((unused)),
+                void *symcbarg __attribute__ ((unused)))
+{
+  int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+  if (r != 0)
+    return r;
+
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((*prefixes & has_addr16) == 0)
+    {
+      if ((modrm & 7) != 4)
+       {
+         int32_t disp = 0;
+         bool nodisp = false;
+
+         if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80)
+           /* 32 bit displacement.  */
+           disp = read_4sbyte_unaligned (&data[opoff1 / 8 + 1]);
+         else if ((modrm & 0xc0) == 0x40)
+           /* 8 bit displacement.  */
+           disp = *(const int8_t *) &data[opoff1 / 8 + 1];
+         else if ((modrm & 0xc0) == 0)
+           nodisp = true;
+
+         char tmpbuf[sizeof ("-0x12345678(%rrr)")];
+         int n;
+         if (nodisp)
+           n = snprintf (tmpbuf, sizeof (tmpbuf), "(%%%s)", regs[modrm & 7]);
+         else if ((modrm & 0xc7) != 5)
+           n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%%s)",
+                         disp < 0 ? "-" : "", disp < 0 ? -disp : disp,
+                         regs[modrm & 7]);
+         else
+           n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx32, disp);
+
+         if (*bufcntp + n + 1 > bufsize)
+           return *bufcntp + n + 1 - bufsize;
+
+         memcpy (&bufp[*bufcntp], tmpbuf, n + 1);
+         *bufcntp += n;
+       }
+      else
+       {
+         /* SIB */
+         uint_fast8_t sib = data[opoff1 / 8 + 1];
+         int32_t disp = 0;
+         bool nodisp = false;
+
+         if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
+             || ((modrm & 0xc7) == 0x4 && (sib & 0x7) == 0x5))
+           /* 32 bit displacement.  */
+           disp = read_4sbyte_unaligned (&data[opoff1 / 8 + 2]);
+         else if ((modrm & 0xc0) == 0x40)
+           /* 8 bit displacement.  */
+           disp = *(const int8_t *) &data[opoff1 / 8 + 2];
+         else
+           nodisp = true;
+
+         char tmpbuf[sizeof ("-0x12345678(%rrr,%rrr,N)")];
+         char *cp = tmpbuf;
+         int n;
+         if ((modrm & 0xc0) != 0 || (sib & 0x3f) != 0x25)
+           {
+             if (!nodisp)
+               {
+                 n = snprintf (cp, sizeof (tmpbuf), "%s0x%" PRIx32,
+                               disp < 0 ? "-" : "", disp < 0 ? -disp : disp);
+                 cp += n;
+               }
+
+             *cp++ = '(';
+
+             if ((modrm & 0xc7) != 0x4 || (sib & 0x7) != 0x5)
+               {
+                 *cp++ = '%';
+                 cp = mempcpy (cp, regs[sib & 7], 3);
+               }
+
+             if ((sib & 0x38) != 0x20)
+               {
+                 *cp++ = ',';
+                 *cp++ = '%';
+                 cp = mempcpy (cp, regs[(sib >> 3) & 7], 3);
+
+                 *cp++ = ',';
+                 *cp++ = '0' + (1 << (sib >> 6));
+               }
+
+             *cp++ = ')';
+           }
+         else
+           {
+             assert (! nodisp);
+             n = snprintf (cp, sizeof (tmpbuf), "0x%" PRIx32, disp);
+             cp += n;
+           }
+
+         if (*bufcntp + (cp - tmpbuf) > bufsize)
+           return *bufcntp + (cp - tmpbuf) - bufsize;
+
+         memcpy (&bufp[*bufcntp], tmpbuf, cp - tmpbuf);
+         *bufcntp += cp - tmpbuf;
+       }
+    }
+  return 0;
+}
+
+
+static int
+FCT_MOD$R_M (GElf_Addr addr __attribute__ ((unused)),
+            int *prefixes __attribute__ ((unused)),
+            const char *op1str __attribute__ ((unused)),
+            size_t opoff1 __attribute__ ((unused)),
+            size_t opoff2 __attribute__ ((unused)),
+            size_t opoff3 __attribute__ ((unused)),
+            char *bufp __attribute__ ((unused)),
+            size_t *bufcntp __attribute__ ((unused)),
+            size_t bufsize __attribute__ ((unused)),
+            const uint8_t *data __attribute__ ((unused)),
+            const uint8_t **param_start __attribute__ ((unused)),
+            const uint8_t *end __attribute__ ((unused)),
+            DisasmGetSymCB_t symcb __attribute__ ((unused)),
+            void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      uint_fast8_t byte = data[opoff2 / 8] & 7;
+      assert (opoff2 % 8 == 5);
+      size_t avail = bufsize - *bufcntp;
+      int needed;
+      if (*prefixes & (has_rep | has_repne))
+       needed = snprintf (&bufp[*bufcntp], avail, "%%%s", regs[byte]);
+      else
+       needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+      if ((size_t) needed > avail)
+       return needed - avail;
+      *bufcntp += needed;
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+
+
+static int
+FCT_Mod$R_m (GElf_Addr addr __attribute__ ((unused)),
+            int *prefixes __attribute__ ((unused)),
+            const char *op1str __attribute__ ((unused)),
+            size_t opoff1 __attribute__ ((unused)),
+            size_t opoff2 __attribute__ ((unused)),
+            size_t opoff3 __attribute__ ((unused)),
+            char *bufp __attribute__ ((unused)),
+            size_t *bufcntp __attribute__ ((unused)),
+            size_t bufsize __attribute__ ((unused)),
+            const uint8_t *data __attribute__ ((unused)),
+            const uint8_t **param_start __attribute__ ((unused)),
+            const uint8_t *end __attribute__ ((unused)),
+            DisasmGetSymCB_t symcb __attribute__ ((unused)),
+            void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      uint_fast8_t byte = data[opoff2 / 8] & 7;
+      assert (opoff2 % 8 == 5);
+      size_t avail = bufsize - *bufcntp;
+      int needed = snprintf (&bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, byte);
+      if ((size_t) needed > avail)
+       return needed - avail;
+      *bufcntp += needed;
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+
+static int
+generic_abs (int *prefixes __attribute__ ((unused)),
+            size_t opoff1 __attribute__ ((unused)),
+            char *bufp __attribute__ ((unused)),
+            size_t *bufcntp __attribute__ ((unused)),
+            size_t bufsize __attribute__ ((unused)),
+            const uint8_t *data __attribute__ ((unused)),
+            const uint8_t **param_start __attribute__ ((unused)),
+            const uint8_t *end __attribute__ ((unused)),
+            DisasmGetSymCB_t symcb __attribute__ ((unused)),
+            void *symcbarg __attribute__ ((unused)),
+            const char *absstring)
+{
+  int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+  if (r != 0)
+    return r;
+
+  assert (opoff1 % 8 == 0);
+  assert (opoff1 / 8 == 1);
+  if (*param_start + 4 > end)
+    return -1;
+  *param_start += 4;
+  uint32_t absval = read_4ubyte_unaligned (&data[1]);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%s0x%" PRIx32,
+                        absstring, absval);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_absval (GElf_Addr addr __attribute__ ((unused)),
+           int *prefixes __attribute__ ((unused)),
+           const char *op1str __attribute__ ((unused)),
+           size_t opoff1 __attribute__ ((unused)),
+           size_t opoff2 __attribute__ ((unused)),
+           size_t opoff3 __attribute__ ((unused)),
+           char *bufp __attribute__ ((unused)),
+           size_t *bufcntp __attribute__ ((unused)),
+           size_t bufsize __attribute__ ((unused)),
+           const uint8_t *data __attribute__ ((unused)),
+           const uint8_t **param_start __attribute__ ((unused)),
+           const uint8_t *end __attribute__ ((unused)),
+           DisasmGetSymCB_t symcb __attribute__ ((unused)),
+           void *symcbarg __attribute__ ((unused)))
+{
+  return generic_abs (prefixes, opoff1, bufp,
+                     bufcntp, bufsize, data, param_start, end, symcb,
+                     symcbarg, "$");
+}
+
+static int
+FCT_abs (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  return generic_abs (prefixes, opoff1, bufp,
+                     bufcntp, bufsize, data, param_start, end, symcb,
+                     symcbarg, "");
+}
+
+static int
+FCT_ax (GElf_Addr addr __attribute__ ((unused)),
+       int *prefixes __attribute__ ((unused)),
+       const char *op1str __attribute__ ((unused)),
+       size_t opoff1 __attribute__ ((unused)),
+       size_t opoff2 __attribute__ ((unused)),
+       size_t opoff3 __attribute__ ((unused)),
+       char *bufp __attribute__ ((unused)),
+       size_t *bufcntp __attribute__ ((unused)),
+       size_t bufsize __attribute__ ((unused)),
+       const uint8_t *data __attribute__ ((unused)),
+       const uint8_t **param_start __attribute__ ((unused)),
+       const uint8_t *end __attribute__ ((unused)),
+       DisasmGetSymCB_t symcb __attribute__ ((unused)),
+       void *symcbarg __attribute__ ((unused)))
+{
+  int is_16bit = (*prefixes & has_data16) != 0;
+
+  if (*bufcntp + 4 - is_16bit > bufsize)
+    return *bufcntp + 4 - is_16bit - bufsize;
+
+  bufp[(*bufcntp)++] = '%';
+  if (! is_16bit)
+    bufp[(*bufcntp)++] = 'e';
+  bufp[(*bufcntp)++] = 'a';
+  bufp[(*bufcntp)++] = 'x';
+
+  return 0;
+}
+
+static int
+FCT_ax$w (GElf_Addr addr __attribute__ ((unused)),
+         int *prefixes __attribute__ ((unused)),
+         const char *op1str __attribute__ ((unused)),
+         size_t opoff1 __attribute__ ((unused)),
+         size_t opoff2 __attribute__ ((unused)),
+         size_t opoff3 __attribute__ ((unused)),
+         char *bufp __attribute__ ((unused)),
+         size_t *bufcntp __attribute__ ((unused)),
+         size_t bufsize __attribute__ ((unused)),
+         const uint8_t *data __attribute__ ((unused)),
+         const uint8_t **param_start __attribute__ ((unused)),
+         const uint8_t *end __attribute__ ((unused)),
+         DisasmGetSymCB_t symcb __attribute__ ((unused)),
+         void *symcbarg __attribute__ ((unused)))
+{
+  if ((data[opoff2 / 8] & (1 << (7 - (opoff2 & 7)))) != 0)
+    return FCT_ax (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                  bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+
+  if (*bufcntp + 3 > bufsize)
+    return *bufcntp + 3 - bufsize;
+
+  bufp[(*bufcntp)++] = '%';
+  bufp[(*bufcntp)++] = 'a';
+  bufp[(*bufcntp)++] = 'l';
+
+  return 0;
+}
+
+static int
+FCT_ccc (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  if (*prefixes & has_data16)
+    return -1;
+
+  assert (opoff1 % 8 == 2);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%cr%" PRIx32,
+                        (uint32_t) (data[opoff1 / 8] >> 3) & 7);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_ddd (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  if (*prefixes & has_data16)
+    return -1;
+
+  assert (opoff1 % 8 == 2);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%db%" PRIx32,
+                        (uint32_t) (data[opoff1 / 8] >> 3) & 7);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_disp8 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  int32_t offset = *(const int8_t *) (*param_start)++;
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "0x%" PRIx32,
+                        (uint32_t) (addr + (*param_start - data) + offset));
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+__attribute__ ((noinline))
+FCT_ds_xx (const char *reg,
+          int *prefixes __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)))
+{
+  int prefix = *prefixes & SEGMENT_PREFIXES;
+
+  if (prefix == 0)
+    prefix = has_ds;
+  /* Make sure only one bit is set.  */
+  else if ((prefix - 1) & prefix)
+    return -1;
+  else
+    *prefixes ^= prefix;
+
+  int r = data_prefix (&prefix, bufp, bufcntp, bufsize);
+  if (r != 0)
+    return r;
+
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "(%%%s%s)",
+                        *prefixes & idx_addr16 ? "" : "e", reg);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+
+  return 0;
+}
+
+static int
+FCT_ds_bx (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  return FCT_ds_xx ("bx", prefixes, bufp, bufcntp, bufsize);
+}
+
+static int
+FCT_ds_si (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  return FCT_ds_xx ("si", prefixes, bufp, bufcntp, bufsize);
+}
+
+static int
+FCT_dx (GElf_Addr addr __attribute__ ((unused)),
+       int *prefixes __attribute__ ((unused)),
+       const char *op1str __attribute__ ((unused)),
+       size_t opoff1 __attribute__ ((unused)),
+       size_t opoff2 __attribute__ ((unused)),
+       size_t opoff3 __attribute__ ((unused)),
+       char *bufp __attribute__ ((unused)),
+       size_t *bufcntp __attribute__ ((unused)),
+       size_t bufsize __attribute__ ((unused)),
+       const uint8_t *data __attribute__ ((unused)),
+       const uint8_t **param_start __attribute__ ((unused)),
+       const uint8_t *end __attribute__ ((unused)),
+       DisasmGetSymCB_t symcb __attribute__ ((unused)),
+       void *symcbarg __attribute__ ((unused)))
+{
+  if (*bufcntp + 7 > bufsize)
+    return *bufcntp + 7 - bufsize;
+
+  memcpy (&bufp[*bufcntp], "(%dx)", 5);
+  *bufcntp += 5;
+
+  return 0;
+}
+
+static int
+FCT_es_di (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%es:(%%%sdi)",
+                        *prefixes & idx_addr16 ? "" : "e");
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+
+  return 0;
+}
+
+static int
+FCT_imm (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  int needed;
+  if (*prefixes & has_data16)
+    {
+      if (*param_start + 2 > end)
+       return -1;
+      uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+      needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+    }
+  else
+    {
+      if (*param_start + 4 > end)
+       return -1;
+      uint32_t word = read_4ubyte_unaligned_inc (*param_start);
+      needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32, word);
+    }
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_imm$w (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  if ((data[opoff2 / 8] & (1 << (7 - (opoff2 & 7)))) != 0)
+    return FCT_imm (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                   bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+
+  size_t avail = bufsize - *bufcntp;
+  uint_fast8_t word = *(*param_start)++;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIxFAST8, word);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_imms (GElf_Addr addr __attribute__ ((unused)),
+         int *prefixes __attribute__ ((unused)),
+         const char *op1str __attribute__ ((unused)),
+         size_t opoff1 __attribute__ ((unused)),
+         size_t opoff2 __attribute__ ((unused)),
+         size_t opoff3 __attribute__ ((unused)),
+         char *bufp __attribute__ ((unused)),
+         size_t *bufcntp __attribute__ ((unused)),
+         size_t bufsize __attribute__ ((unused)),
+         const uint8_t *data __attribute__ ((unused)),
+         const uint8_t **param_start __attribute__ ((unused)),
+         const uint8_t *end __attribute__ ((unused)),
+         DisasmGetSymCB_t symcb __attribute__ ((unused)),
+         void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  int_fast8_t byte = *(*param_start)++;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+                        (int32_t) byte);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_imm$s (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t opcode = data[opoff2 / 8];
+  size_t avail = bufsize - *bufcntp;
+  if ((opcode & 2) != 0)
+    return FCT_imms (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                    bufcntp, bufsize, data, param_start, end, symcb,
+                    symcbarg);
+
+  if ((*prefixes & has_data16) == 0)
+    {
+      if (*param_start + 4 > end)
+       return -1;
+      uint32_t word = read_4ubyte_unaligned_inc (*param_start);
+      int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32, word);
+      if ((size_t) needed > avail)
+       return (size_t) needed - avail;
+      *bufcntp += needed;
+    }
+  else
+    {
+      if (*param_start + 2 > end)
+       return -1;
+      uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+      int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+      if ((size_t) needed > avail)
+       return (size_t) needed - avail;
+      *bufcntp += needed;
+    }
+  return 0;
+}
+
+static int
+FCT_imm16 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  if (*param_start + 2 > end)
+    return -1;
+  uint16_t word = read_2ubyte_unaligned_inc (*param_start);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, word);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_imms8 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  int_fast8_t byte = *(*param_start)++;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+                        (int32_t) byte);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_imm8 (GElf_Addr addr __attribute__ ((unused)),
+         int *prefixes __attribute__ ((unused)),
+         const char *op1str __attribute__ ((unused)),
+         size_t opoff1 __attribute__ ((unused)),
+         size_t opoff2 __attribute__ ((unused)),
+         size_t opoff3 __attribute__ ((unused)),
+         char *bufp __attribute__ ((unused)),
+         size_t *bufcntp __attribute__ ((unused)),
+         size_t bufsize __attribute__ ((unused)),
+         const uint8_t *data __attribute__ ((unused)),
+         const uint8_t **param_start __attribute__ ((unused)),
+         const uint8_t *end __attribute__ ((unused)),
+         DisasmGetSymCB_t symcb __attribute__ ((unused)),
+         void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  uint_fast8_t byte = *(*param_start)++;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx32,
+                        (uint32_t) byte);
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+#ifndef X86_64
+static int
+FCT_rel (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  size_t avail = bufsize - *bufcntp;
+  if (*param_start + 4 > end)
+    return -1;
+  uint32_t rel = read_4ubyte_unaligned_inc (*param_start);
+  int needed = snprintf (&bufp[*bufcntp], avail, "0x%" PRIx32,
+                        (uint32_t) (addr + rel + (*param_start - data)));
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+#endif
+
+static int
+FCT_mmxreg (GElf_Addr addr __attribute__ ((unused)),
+           int *prefixes __attribute__ ((unused)),
+           const char *op1str __attribute__ ((unused)),
+           size_t opoff1 __attribute__ ((unused)),
+           size_t opoff2 __attribute__ ((unused)),
+           size_t opoff3 __attribute__ ((unused)),
+           char *bufp __attribute__ ((unused)),
+           size_t *bufcntp __attribute__ ((unused)),
+           size_t bufsize __attribute__ ((unused)),
+           const uint8_t *data __attribute__ ((unused)),
+           const uint8_t **param_start __attribute__ ((unused)),
+           const uint8_t *end __attribute__ ((unused)),
+           DisasmGetSymCB_t symcb __attribute__ ((unused)),
+           void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+  byte = (byte >> (5 - opoff1 % 8)) & 7;
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_mmxreg2 (GElf_Addr addr __attribute__ ((unused)),
+            int *prefixes __attribute__ ((unused)),
+            const char *op1str __attribute__ ((unused)),
+            size_t opoff1 __attribute__ ((unused)),
+            size_t opoff2 __attribute__ ((unused)),
+            size_t opoff3 __attribute__ ((unused)),
+            char *bufp __attribute__ ((unused)),
+            size_t *bufcntp __attribute__ ((unused)),
+            size_t bufsize __attribute__ ((unused)),
+            const uint8_t *data __attribute__ ((unused)),
+            const uint8_t **param_start __attribute__ ((unused)),
+            const uint8_t *end __attribute__ ((unused)),
+            DisasmGetSymCB_t symcb __attribute__ ((unused)),
+            void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+  byte = (byte >> (5 - opoff1 % 8)) & 7;
+  size_t avail = bufsize - *bufcntp;
+  int needed;
+  if (*prefixes & (has_rep | has_repne))
+    needed = snprintf (&bufp[*bufcntp], avail, "%%%s", regs[byte]);
+  else
+    needed = snprintf (&bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+
+static int
+FCT_mod$r_m (GElf_Addr addr __attribute__ ((unused)),
+            int *prefixes __attribute__ ((unused)),
+            const char *op1str __attribute__ ((unused)),
+            size_t opoff1 __attribute__ ((unused)),
+            size_t opoff2 __attribute__ ((unused)),
+            size_t opoff3 __attribute__ ((unused)),
+            char *bufp __attribute__ ((unused)),
+            size_t *bufcntp __attribute__ ((unused)),
+            size_t bufsize __attribute__ ((unused)),
+            const uint8_t *data __attribute__ ((unused)),
+            const uint8_t **param_start __attribute__ ((unused)),
+            const uint8_t *end __attribute__ ((unused)),
+            DisasmGetSymCB_t symcb __attribute__ ((unused)),
+            void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      int is_16bit = (*prefixes & has_data16) != 0;
+
+      if (*bufcntp + 5 - is_16bit > bufsize)
+       return *bufcntp + 5 - is_16bit - bufsize;
+      bufp[(*bufcntp)++] = '%';
+      memcpy (&bufp[*bufcntp], regs[modrm & 7] + is_16bit,
+             sizeof (regs[0]) - is_16bit);
+      *bufcntp += 3 - is_16bit;
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+
+
+#ifndef X86_64
+static int
+FCT_moda$r_m (GElf_Addr addr __attribute__ ((unused)),
+             int *prefixes __attribute__ ((unused)),
+             const char *op1str __attribute__ ((unused)),
+             size_t opoff1 __attribute__ ((unused)),
+             size_t opoff2 __attribute__ ((unused)),
+             size_t opoff3 __attribute__ ((unused)),
+             char *bufp __attribute__ ((unused)),
+             size_t *bufcntp __attribute__ ((unused)),
+             size_t bufsize __attribute__ ((unused)),
+             const uint8_t *data __attribute__ ((unused)),
+             const uint8_t **param_start __attribute__ ((unused)),
+             const uint8_t *end __attribute__ ((unused)),
+             DisasmGetSymCB_t symcb __attribute__ ((unused)),
+             void *symcbarg __attribute__ ((unused)))
+{
+  int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+  if (r != 0)
+    return r;
+
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      if (*bufcntp + 3 > bufsize)
+       return *bufcntp + 3 - bufsize;
+
+      memcpy (&bufp[*bufcntp], "???", 3);
+      *bufcntp += 3;
+
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+#endif
+
+
+static int
+FCT_mod$r_m$w (GElf_Addr addr __attribute__ ((unused)),
+              int *prefixes __attribute__ ((unused)),
+              const char *op1str __attribute__ ((unused)),
+              size_t opoff1 __attribute__ ((unused)),
+              size_t opoff2 __attribute__ ((unused)),
+              size_t opoff3 __attribute__ ((unused)),
+              char *bufp __attribute__ ((unused)),
+              size_t *bufcntp __attribute__ ((unused)),
+              size_t bufsize __attribute__ ((unused)),
+              const uint8_t *data __attribute__ ((unused)),
+              const uint8_t **param_start __attribute__ ((unused)),
+              const uint8_t *end __attribute__ ((unused)),
+              DisasmGetSymCB_t symcb __attribute__ ((unused)),
+              void *symcbarg __attribute__ ((unused)))
+{
+  int r = data_prefix (prefixes, bufp, bufcntp, bufsize);
+  if (r != 0)
+    return r;
+
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      if ((data[opoff3 / 8] & (1 << (7 - (opoff3 & 7)))) == 0)
+       {
+         if (*bufcntp + 3 > bufsize)
+           return *bufcntp + 3 - bufsize;
+         bufp[(*bufcntp)++] = '%';
+         bufp[(*bufcntp)++] = "acdb"[modrm & 3];
+         bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2];
+       }
+      else
+       {
+         int is_16bit = (*prefixes & has_data16) != 0;
+
+         if (*bufcntp + 5 - is_16bit > bufsize)
+           return *bufcntp + 5 - is_16bit - bufsize;
+         bufp[(*bufcntp)++] = '%';
+         memcpy (&bufp[*bufcntp], regs[modrm & 7] + is_16bit,
+                 sizeof (regs[0]) - is_16bit);
+         *bufcntp += 3 - is_16bit;
+       }
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+
+
+#ifndef X86_64
+static int
+FCT_mod$8r_m (GElf_Addr addr __attribute__ ((unused)),
+             int *prefixes __attribute__ ((unused)),
+             const char *op1str __attribute__ ((unused)),
+             size_t opoff1 __attribute__ ((unused)),
+             size_t opoff2 __attribute__ ((unused)),
+             size_t opoff3 __attribute__ ((unused)),
+             char *bufp __attribute__ ((unused)),
+             size_t *bufcntp __attribute__ ((unused)),
+             size_t bufsize __attribute__ ((unused)),
+             const uint8_t *data __attribute__ ((unused)),
+             const uint8_t **param_start __attribute__ ((unused)),
+             const uint8_t *end __attribute__ ((unused)),
+             DisasmGetSymCB_t symcb __attribute__ ((unused)),
+             void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      if (*bufcntp + 3 > bufsize)
+       return *bufcntp + 3 - bufsize;
+      bufp[(*bufcntp)++] = '%';
+      bufp[(*bufcntp)++] = "acdb"[modrm & 3];
+      bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2];
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+#endif
+
+static int
+FCT_mod$16r_m (GElf_Addr addr __attribute__ ((unused)),
+              int *prefixes __attribute__ ((unused)),
+              const char *op1str __attribute__ ((unused)),
+              size_t opoff1 __attribute__ ((unused)),
+              size_t opoff2 __attribute__ ((unused)),
+              size_t opoff3 __attribute__ ((unused)),
+              char *bufp __attribute__ ((unused)),
+              size_t *bufcntp __attribute__ ((unused)),
+              size_t bufsize __attribute__ ((unused)),
+              const uint8_t *data __attribute__ ((unused)),
+              const uint8_t **param_start __attribute__ ((unused)),
+              const uint8_t *end __attribute__ ((unused)),
+              DisasmGetSymCB_t symcb __attribute__ ((unused)),
+              void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  uint_fast8_t modrm = data[opoff1 / 8];
+  if ((modrm & 0xc0) == 0xc0)
+    {
+      uint_fast8_t byte = data[opoff1 / 8] & 7;
+      if (*bufcntp + 3 > bufsize)
+       return *bufcntp + 3 - bufsize;
+      bufp[(*bufcntp)++] = '%';
+      memcpy (&bufp[*bufcntp], regs[byte] + 1, sizeof (regs[0]) - 1);
+      *bufcntp += 2;
+      return 0;
+    }
+
+  return general_mod$r_m (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                         bufcntp, bufsize, data, param_start, end,
+                         symcb, symcbarg);
+}
+
+static int
+FCT_reg (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 + 3 <= 8);
+  byte >>= 8 - (opoff1 % 8 + 3);
+  byte &= 7;
+  int is_16bit = (*prefixes & has_data16) != 0;
+  if (*bufcntp + 4 > bufsize)
+    return *bufcntp + 4 - bufsize;
+  bufp[(*bufcntp)++] = '%';
+  memcpy (&bufp[*bufcntp], regs[byte] + is_16bit, sizeof (regs[0]) - is_16bit);
+  *bufcntp += 3 - is_16bit;
+  return 0;
+}
+
+static int
+FCT_reg$w (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  if (data[opoff2 / 8] & (1 << (7 - (opoff2 & 7))))
+    return FCT_reg (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                   bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 + 3 <= 8);
+  byte >>= 8 - (opoff1 % 8 + 3);
+  byte &= 7;
+  if (*bufcntp + 3 > bufsize)
+    return *bufcntp + 3 - bufsize;
+  bufp[(*bufcntp)++] = '%';
+  bufp[(*bufcntp)++] = "acdb"[byte & 3];
+  bufp[(*bufcntp)++] = "lh"[byte >> 2];
+  return 0;
+}
+
+#ifndef X86_64
+static int
+FCT_freg (GElf_Addr addr __attribute__ ((unused)),
+         int *prefixes __attribute__ ((unused)),
+         const char *op1str __attribute__ ((unused)),
+         size_t opoff1 __attribute__ ((unused)),
+         size_t opoff2 __attribute__ ((unused)),
+         size_t opoff3 __attribute__ ((unused)),
+         char *bufp __attribute__ ((unused)),
+         size_t *bufcntp __attribute__ ((unused)),
+         size_t bufsize __attribute__ ((unused)),
+         const uint8_t *data __attribute__ ((unused)),
+         const uint8_t **param_start __attribute__ ((unused)),
+         const uint8_t *end __attribute__ ((unused)),
+         DisasmGetSymCB_t symcb __attribute__ ((unused)),
+         void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 / 8 == 1);
+  assert (opoff1 % 8 == 5);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%st(%" PRIx32 ")",
+                        (uint32_t) (data[1] & 7));
+  if ((size_t) needed > avail)
+    return (size_t) needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_reg16 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  if (*prefixes & has_data16)
+    return -1;
+
+  *prefixes |= has_data16;
+  return FCT_reg (addr, prefixes, op1str, opoff1, opoff2, opoff3, bufp,
+                 bufcntp, bufsize, data, param_start, end, symcb, symcbarg);
+}
+#endif
+
+static int
+FCT_sel (GElf_Addr addr __attribute__ ((unused)),
+        int *prefixes __attribute__ ((unused)),
+        const char *op1str __attribute__ ((unused)),
+        size_t opoff1 __attribute__ ((unused)),
+        size_t opoff2 __attribute__ ((unused)),
+        size_t opoff3 __attribute__ ((unused)),
+        char *bufp __attribute__ ((unused)),
+        size_t *bufcntp __attribute__ ((unused)),
+        size_t bufsize __attribute__ ((unused)),
+        const uint8_t *data __attribute__ ((unused)),
+        const uint8_t **param_start __attribute__ ((unused)),
+        const uint8_t *end __attribute__ ((unused)),
+        DisasmGetSymCB_t symcb __attribute__ ((unused)),
+        void *symcbarg __attribute__ ((unused)))
+{
+  assert (opoff1 % 8 == 0);
+  assert (opoff1 / 8 == 5);
+  if (*param_start + 2 > end)
+    return -1;
+  *param_start += 2;
+  uint16_t absval = read_2ubyte_unaligned (&data[5]);
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "$0x%" PRIx16, absval);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
+
+static int
+FCT_sreg2 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 + 3 <= 8);
+  byte >>= 8 - (opoff1 % 8 + 2);
+
+  if (*bufcntp + 3 > bufsize)
+    return *bufcntp + 3 - bufsize;
+
+  bufp[(*bufcntp)++] = '%';
+  bufp[(*bufcntp)++] = "ecsd"[byte & 3];
+  bufp[(*bufcntp)++] = 's';
+
+  return 0;
+}
+
+static int
+FCT_sreg3 (GElf_Addr addr __attribute__ ((unused)),
+          int *prefixes __attribute__ ((unused)),
+          const char *op1str __attribute__ ((unused)),
+          size_t opoff1 __attribute__ ((unused)),
+          size_t opoff2 __attribute__ ((unused)),
+          size_t opoff3 __attribute__ ((unused)),
+          char *bufp __attribute__ ((unused)),
+          size_t *bufcntp __attribute__ ((unused)),
+          size_t bufsize __attribute__ ((unused)),
+          const uint8_t *data __attribute__ ((unused)),
+          const uint8_t **param_start __attribute__ ((unused)),
+          const uint8_t *end __attribute__ ((unused)),
+          DisasmGetSymCB_t symcb __attribute__ ((unused)),
+          void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 + 4 <= 8);
+  byte >>= 8 - (opoff1 % 8 + 3);
+
+  if ((byte & 7) >= 6)
+    return -1;
+
+  if (*bufcntp + 3 > bufsize)
+    return *bufcntp + 3 - bufsize;
+
+  bufp[(*bufcntp)++] = '%';
+  bufp[(*bufcntp)++] = "ecsdfg"[byte & 7];
+  bufp[(*bufcntp)++] = 's';
+
+  return 0;
+}
+
+static int
+FCT_string (GElf_Addr addr __attribute__ ((unused)),
+           int *prefixes __attribute__ ((unused)),
+           const char *op1str __attribute__ ((unused)),
+           size_t opoff1 __attribute__ ((unused)),
+           size_t opoff2 __attribute__ ((unused)),
+           size_t opoff3 __attribute__ ((unused)),
+           char *bufp __attribute__ ((unused)),
+           size_t *bufcntp __attribute__ ((unused)),
+           size_t bufsize __attribute__ ((unused)),
+           const uint8_t *data __attribute__ ((unused)),
+           const uint8_t **param_start __attribute__ ((unused)),
+           const uint8_t *end __attribute__ ((unused)),
+           DisasmGetSymCB_t symcb __attribute__ ((unused)),
+           void *symcbarg __attribute__ ((unused)))
+{
+  return 0;
+}
+
+static int
+FCT_xmmreg (GElf_Addr addr __attribute__ ((unused)),
+           int *prefixes __attribute__ ((unused)),
+           const char *op1str __attribute__ ((unused)),
+           size_t opoff1 __attribute__ ((unused)),
+           size_t opoff2 __attribute__ ((unused)),
+           size_t opoff3 __attribute__ ((unused)),
+           char *bufp __attribute__ ((unused)),
+           size_t *bufcntp __attribute__ ((unused)),
+           size_t bufsize __attribute__ ((unused)),
+           const uint8_t *data __attribute__ ((unused)),
+           const uint8_t **param_start __attribute__ ((unused)),
+           const uint8_t *end __attribute__ ((unused)),
+           DisasmGetSymCB_t symcb __attribute__ ((unused)),
+           void *symcbarg __attribute__ ((unused)))
+{
+  uint_fast8_t byte = data[opoff1 / 8];
+  assert (opoff1 % 8 == 2 || opoff1 % 8 == 5);
+  byte = (byte >> (5 - opoff1 % 8)) & 7;
+  size_t avail = bufsize - *bufcntp;
+  int needed = snprintf (&bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, byte);
+  if ((size_t) needed > avail)
+    return needed - avail;
+  *bufcntp += needed;
+  return 0;
+}
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
new file mode 100644 (file)
index 0000000..ca173cc
--- /dev/null
@@ -0,0 +1,914 @@
+#include <assert.h>
+#include <config.h>
+#include <ctype.h>
+#include <endian.h>
+#include <errno.h>
+#include <gelf.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include "../libebl/libeblP.h"
+
+#define MACHINE_ENCODING __LITTLE_ENDIAN
+#include "memory-access.h"
+
+
+#ifndef MNEFILE
+# define MNEFILE "i386.mnemonics"
+#endif
+
+#define MNESTRFIELD(line) MNESTRFIELD1 (line)
+#define MNESTRFIELD1(line) str##line
+static const union mnestr_t
+{
+  struct
+  {
+#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
+#include MNEFILE
+#undef MNE
+  };
+  char str[0];
+} mnestr =
+  {
+    {
+#define MNE(name) #name,
+#include MNEFILE
+#undef MNE
+    }
+  };
+
+/* The index can be stored in the instrtab.  */
+enum
+  {
+#define MNE(name) MNE_##name,
+#include MNEFILE
+#undef MNE
+    MNE_INVALID
+  };
+
+static const unsigned short int mneidx[] =
+  {
+#define MNE(name) \
+  [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
+#include MNEFILE
+#undef MNE
+  };
+
+
+enum
+  {
+    idx_cs = 0,
+    idx_ds,
+    idx_es,
+    idx_fs,
+    idx_gs,
+    idx_ss,
+    idx_data16,
+    idx_addr16,
+    idx_rep,
+    idx_repne,
+    idx_lock
+  };
+
+enum
+  {
+#define prefbit(pref) has_##pref = 1 << idx_##pref
+    prefbit (cs),
+    prefbit (ds),
+    prefbit (es),
+    prefbit (fs),
+    prefbit (gs),
+    prefbit (ss),
+    prefbit (data16),
+    prefbit (addr16),
+    prefbit (rep),
+    prefbit (repne),
+    prefbit (lock)
+#undef prefbit
+  };
+#define SEGMENT_PREFIXES \
+  (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
+
+#define prefix_cs      0x2e
+#define prefix_ds      0x3e
+#define prefix_es      0x26
+#define prefix_fs      0x64
+#define prefix_gs      0x65
+#define prefix_ss      0x36
+#define prefix_data16  0x66
+#define prefix_addr16  0x67
+#define prefix_rep     0xf3
+#define prefix_repne   0xf2
+#define prefix_lock    0xf0
+
+
+static const uint8_t known_prefixes[] =
+  {
+#define newpref(pref) [idx_##pref] = prefix_##pref
+    newpref (cs),
+    newpref (ds),
+    newpref (es),
+    newpref (fs),
+    newpref (gs),
+    newpref (ss),
+    newpref (data16),
+    newpref (addr16),
+    newpref (rep),
+    newpref (repne),
+    newpref (lock)
+#undef newpref
+  };
+#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
+
+
+#if 0
+static const char *prefix_str[] =
+  {
+#define newpref(pref) [idx_##pref] = #pref
+    newpref (cs),
+    newpref (ds),
+    newpref (es),
+    newpref (fs),
+    newpref (gs),
+    newpref (ss),
+    newpref (data16),
+    newpref (addr16),
+    newpref (rep),
+    newpref (repne),
+    newpref (lock)
+#undef newpref
+  };
+#endif
+
+
+#ifndef DISFILE
+# define DISFILE "i386_dis.h"
+#endif
+#include DISFILE
+
+
+#define ADD_CHAR(ch) \
+  do {                                                                       \
+    if (unlikely (bufcnt == bufsize))                                        \
+      goto enomem;                                                           \
+    buf[bufcnt++] = (ch);                                                    \
+  } while (0)
+
+#define ADD_STRING(str) \
+  do {                                                                       \
+    const char *_str = (str);                                                \
+    size_t _len = strlen (_str);                                             \
+    if (unlikely (bufcnt + _len > bufsize))                                  \
+      goto enomem;                                                           \
+    memcpy (buf + bufcnt, str, _len);                                        \
+    bufcnt += _len;                                                          \
+  } while (0)
+
+
+#include <stdio.h>
+int
+i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
+            const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
+            void *outcbarg, void *symcbarg)
+{
+  const char *save_fmt = fmt;
+
+  while (1)
+    {
+#define BUFSIZE 512
+      const size_t bufsize = BUFSIZE;
+      char initbuf[BUFSIZE];
+      char *buf = initbuf;
+      size_t bufcnt = 0;
+
+      int prefixes = 0;
+
+      const uint8_t *data = *startp;
+      const uint8_t *begin = data;
+
+      fmt = save_fmt;
+
+      /* Recognize all prefixes.  */
+      while (data < end)
+       {
+         unsigned int i;
+         for (i = 0; i < nknown_prefixes; ++i)
+           if (known_prefixes[i] == *data)
+             break;
+         if (i == nknown_prefixes)
+           break;
+
+         prefixes |= 1 << i;
+
+         ++data;
+       }
+
+      assert (data <= end);
+      if (data == end)
+       {
+         if (prefixes != 0)
+           goto print_prefix;
+
+         return -1;
+       }
+
+      const uint8_t *curr = match_data;
+      const uint8_t *const match_end = match_data + sizeof (match_data);
+
+    enomem:
+      ;
+
+      size_t cnt = 0;
+      while (curr < match_end)
+       {
+         const uint8_t *const start = curr;
+
+         uint_fast8_t len = *curr++;
+
+         assert (len > 0);
+         assert (curr + 2 * len + 2 <= match_end);
+
+         const uint8_t *codep = data;
+         size_t avail = len;
+
+         do
+           {
+             uint_fast8_t masked = *codep++ & *curr++;
+             if (masked != *curr++)
+               break;
+
+             --avail;
+             if (codep == end && avail > 0)
+               return 0;
+           }
+         while (avail > 0);
+
+         if (avail != 0)
+           {
+           not:
+             curr = start + 1 + 2 * len + 2;
+             ++cnt;
+             continue;
+           }
+
+         if (len > end - data)
+           /* There is not enough data for the entire instruction.  The
+              caller can figure this out by looking at the pointer into
+              the input data.  */
+           return 0;
+
+         size_t prefix_size = 0;
+
+         // XXXonly print as prefix if valid?
+         if ((prefixes & has_lock) != 0)
+           {
+             ADD_STRING ("lock ");
+             prefix_size += 5;
+           }
+
+         if (instrtab[cnt].rep)
+           {
+             if ((prefixes & has_rep) !=  0)
+               {
+                 ADD_STRING ("rep ");
+                 prefix_size += 4;
+               }
+           }
+         else if (instrtab[cnt].repe
+                  && (prefixes & (has_rep | has_repne)) != 0)
+           {
+             if ((prefixes & has_repne) != 0)
+               {
+                 ADD_STRING ("repne ");
+                 prefix_size += 6;
+               }
+             else if ((prefixes & has_rep) != 0)
+               {
+                 ADD_STRING ("repe ");
+                 prefix_size += 5;
+               }
+           }
+         else if ((prefixes & (has_rep | has_repne)) != 0)
+           {
+             uint_fast8_t byte;
+           print_prefix:
+             bufcnt = 0;
+             byte = *begin;
+             /* This is a prefix byte.  Print it.  */
+             switch (byte)
+               {
+               case prefix_rep:
+                 ADD_STRING ("rep");
+                 break;
+               case prefix_repne:
+                 ADD_STRING ("repne");
+                 break;
+               case prefix_cs:
+                 ADD_STRING ("cs");
+                 break;
+               case prefix_ds:
+                 ADD_STRING ("ds");
+                 break;
+               case prefix_es:
+                 ADD_STRING ("es");
+                 break;
+               case prefix_fs:
+                 ADD_STRING ("fs");
+                 break;
+               case prefix_gs:
+                 ADD_STRING ("gs");
+                 break;
+               case prefix_ss:
+                 ADD_STRING ("ss");
+                 break;
+               case prefix_data16:
+                 ADD_STRING ("data16");
+                 break;
+               case prefix_addr16:
+                 ADD_STRING ("addr16");
+                 break;
+               case prefix_lock:
+                 ADD_STRING ("lock");
+                 break;
+               default:
+                 /* Cannot happen.  */
+                 abort ();
+               }
+             data = begin + 1;
+             ++addr;
+
+             /* The string definitely fits.  */
+             buf[bufcnt++] = '\0';
+
+             goto out;
+           }
+
+         /* We have a match.  First determine how many bytes are
+            needed for the adressing mode.  */
+         const uint8_t *param_start = codep;
+         if (instrtab[cnt].modrm)
+           {
+             uint_fast8_t modrm = codep[-1];
+
+             if ((prefixes & has_addr16) == 0)
+               {
+                 /* Account for SIB.  */
+                 if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
+                   param_start += 1;
+               }
+
+             /* Account for displacement.  */
+             if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
+                 || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
+               param_start += 4;
+             else if ((modrm & 0xc0) == 0x40)
+               param_start += 1;
+           }
+
+         unsigned long string_end_idx = 0;
+         while (*fmt != '\0')
+           {
+             if (*fmt != '%')
+               {
+                 char ch = *fmt++;
+                 if (ch == '\\')
+                   {
+                     switch ((ch = *fmt++))
+                       {
+                       case '0' ... '7':
+                         {
+                           int val = ch - '0';
+                           ch = *fmt;
+                           if (ch >= '0' && ch <= '7')
+                             {
+                               val *= 8;
+                               val += ch - '0';
+                               ch = *++fmt;
+                               if (ch >= '0' && ch <= '7' && val < 32)
+                                 {
+                                   val *= 8;
+                                   val += ch - '0';
+                                   ++fmt;
+                                 }
+                             }
+                           ch = val;
+                         }
+                         break;
+
+                       case 'n':
+                         ch = '\n';
+                         break;
+
+                       case 't':
+                         ch = '\t';
+                         break;
+
+                       default:
+                         return EINVAL;
+                       }
+                   }
+                 ADD_CHAR (ch);
+                 continue;
+               }
+             ++fmt;
+
+             int width = 0;
+             while (isdigit (*fmt))
+               width = width * 10 + (*fmt++ - '0');
+
+             int prec = 0;
+             if (*fmt == '.')
+               while (isdigit (*++fmt))
+                 prec = prec * 10 + (*fmt - '0');
+
+             size_t start_idx = bufcnt;
+             switch (*fmt++)
+               {
+                 const char *str;
+
+               case 'm':
+                 /* Mnemonic.  */
+
+                 if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
+                   {
+                     switch (*data)
+                       {
+                       case 0x90:
+                         if (prefixes & ~has_rep)
+                           goto print_prefix;
+                         /* Discard the 'rep' prefix string possibly
+                            already in the buffer.  */
+                         bufcnt = 0;
+                         str = prefixes & has_rep ? "pause" : "nop";
+                         break;
+
+                       case 0x98:
+                         if (prefixes & ~has_data16)
+                           goto print_prefix;
+                         str = prefixes & has_data16 ? "cbtw" : "cwtl";
+                         break;
+
+                       case 0x99:
+                         if (prefixes & ~has_data16)
+                           goto print_prefix;
+                         str = prefixes & has_data16 ? "cwtd" : "cltd";
+                         break;
+
+                       case 0xe3:
+                         if (prefixes & ~has_addr16)
+                           goto print_prefix;
+                         str = prefixes & has_addr16 ? "jcxz" : "jecxz";
+                         break;
+
+                       case 0x0f:
+                         if (data[1] == 0x10 || data[1] == 0x11)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "movupd"
+                                    : mod & has_rep
+                                    ? "movss"
+                                    : mod & has_repne
+                                    ? "movsd"
+                                    : "movups");
+                             break;
+                           }
+                         if (data[1] == 0x12)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "movlpd"
+                                    : mod & has_rep
+                                    ? "movsldup"
+                                    : mod & has_repne
+                                    ? "movddup"
+                                    : (data[2] & 0xc0) == 0xc0
+                                    ? "movhlps"
+                                    : "movlps");
+                             break;
+                           }
+                         if (data[1] == 0x13)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? ((data[2] & 0xc0) == 0xc0
+                                       ? "movhlpd"
+                                       : "movlpd")
+                                    : (data[2] & 0xc0) == 0xc0
+                                    ? "movhlps"
+                                    : "movlps");
+                             break;
+                           }
+                         if (data[1] == 0x14)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "unpcklpd" : "unpcklps");
+                             break;
+                           }
+                         if (data[1] == 0x15)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "unpckhpd" : "unpckhps");
+                             break;
+                           }
+                         if (data[1] == 0x16)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "movhpd"
+                                    : mod & has_rep
+                                    ? "movshdup"
+                                    : (data[2] & 0xc0) == 0xc0
+                                    ? "movlhps"
+                                    : "movhps");
+                             break;
+                           }
+                         if (data[1] == 0x17)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? ((data[2] & 0xc0) == 0xc0
+                                       ? "movlhpd" : "movhpd")
+                                    : (data[2] & 0xc0) == 0xc0
+                                    ? "movlhps"
+                                    : "movhps");
+                             break;
+                           }
+                         if (data[1] == 0x28 || data[1] == 0x29)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16) ? "movapd" : "movaps";
+                             break;
+                           }
+                         if (data[1] == 0x2a)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "cvtpi2pd"
+                                    : mod & has_rep
+                                    ? "cvtsi2ss"
+                                    : mod & has_repne
+                                    ? "cvtsi2sd"
+                                    : "cvtpi2ps");
+                             break;
+                           }
+                         if (data[1] == 0x2b)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             prefixes ^= mod;
+                             str = (mod & has_data16) ? "movntpd" : "movntps";
+                             break;
+                           }
+                         if (data[1] == 0x2c)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "cvttpd2pi"
+                                    : mod & has_rep
+                                    ? "cvttss2si"
+                                    : mod & has_repne
+                                    ? "cvttsd2si"
+                                    : "cvttps2pi");
+                             break;
+                           }
+                         if (data[1] == 0x2d)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "cvtpd2pi"
+                                    : mod & has_rep
+                                    ? "cvtss2si"
+                                    : mod & has_repne
+                                    ? "cvtsd2si"
+                                    : "cvtps2pi");
+                             break;
+                           }
+                         if (data[1] == 0x2e)
+                           {
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "ucomisd" : "ucomiss");
+                             break;
+                           }
+                         if (data[1] == 0x2f)
+                           {
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "comisd" : "comiss");
+                             break;
+                           }
+                         if (data[1] == 0x50)
+                           {
+                             int mod = prefixes & has_data16;
+                             if (mod & (mod - 1))
+                               return -1;
+                             prefixes ^= mod;
+                             str = (mod & has_data16
+                                    ? "movmskpd" : "movmskps");
+                             break;
+                           }
+                         if (data[1] == 0x51)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & (has_data16 | has_rep
+                                                   | has_repne);
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = (mod & has_data16
+                                    ? "sqrtpd"
+                                    : mod & has_rep
+                                    ? "sqrtss"
+                                    : mod & has_repne
+                                    ? "sqrtsd"
+                                    : "sqrtps");
+                             break;
+                           }
+                         if (data[1] == 0x52)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_rep;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = mod & has_rep ? "rsqrtss" : "rsqrtps";
+                             break;
+                           }
+                         if (data[1] == 0x53)
+                           {
+                             bufcnt = 0;
+                             int mod = prefixes & has_rep;
+                             if (mod & (mod - 1))
+                               return -1;
+                             str = mod & has_rep ? "rcpss" : "rcpps";
+                             break;
+                           }
+                         /* FALLTHROUGH */
+
+                       default:
+                         abort ();
+                       }
+                   }
+                 else
+                   str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
+
+                 ADD_STRING (str);
+
+                 switch (instrtab[cnt].suffix)
+                   {
+                   case suffix_none:
+                     break;
+                   case suffix_w:
+                     if ((codep[-1] & 0xc0) != 0xc0)
+                       {
+                         char ch;
+
+                         if (data[0] & 1)
+                           {
+                             if (prefixes & has_data16)
+                               ch = 'w';
+                             else
+                               ch = 'l';
+                           }
+                         else
+                           ch = 'b';
+
+                         ADD_CHAR (ch);
+                       }
+                     break;
+                   case suffix_w0:
+                     if ((codep[-1] & 0xc0) != 0xc0)
+                       ADD_CHAR ('l');
+                     break;
+                   case suffix_w1:
+                     if ((data[0] & 0x4) == 0)
+                       ADD_CHAR ('l');
+                     break;
+                   case suffix_W:
+                     if (prefixes & has_data16)
+                       {
+                         ADD_CHAR ('w');
+                         prefixes &= ~has_data16;
+                       }
+#ifdef x86_64
+                     else
+                       abort ();
+#endif
+                     break;
+                   case suffix_tttn:;
+                     static const char tttn[16][3] =
+                       {
+                         "o", "no", "b", "ae", "e", "ne", "be", "a",
+                         "s", "ns", "p", "np", "l", "ge", "le", "g"
+                       };
+                     ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
+                     break;
+                   case suffix_D:
+                     if ((codep[-1] & 0xc0) != 0xc0)
+                       ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
+                     break;
+                   default:
+                     printf("unknown suffix %d\n", instrtab[cnt].suffix);
+                     abort ();
+                   }
+
+                 string_end_idx = bufcnt;
+                 break;
+
+               case 'o':
+                 if (prec == 1 && instrtab[cnt].fct1 != 0)
+                   {
+                     /* First parameter.  */
+                     if (instrtab[cnt].str1 != 0)
+                       ADD_STRING (op1_str[instrtab[cnt].str1]);
+
+                     int r = op1_fct[instrtab[cnt].fct1] (addr
+                                                          + (data - begin),
+                                                          &prefixes,
+#ifdef STR1_BITS
+                                                          op1_str[instrtab[cnt].str1],
+#else
+                                                          NULL,
+#endif
+                                                          instrtab[cnt].off1_1 + OFF1_1_BIAS,
+                                                          instrtab[cnt].off1_2 + OFF1_2_BIAS,
+                                                          instrtab[cnt].off1_3 + OFF1_3_BIAS,
+                                                          buf, &bufcnt, bufsize,
+                                                          data, &param_start,
+                                                          end,
+                                                          symcb, symcbarg);
+                     if (r < 0)
+                       goto not;
+                     if (r > 0)
+                       goto enomem;
+
+                     string_end_idx = ~0ul;
+                   }
+                 else if (prec == 2 && instrtab[cnt].fct2 != 0)
+                   {
+                     /* Second parameter.  */
+#ifdef STR2_BITS
+                     // XXX Probably not needed once the instruction
+                     // XXX tables are complete
+                     if (instrtab[cnt].str2 != 0)
+                       ADD_STRING (op2_str[instrtab[cnt].str2]);
+#endif
+
+                     int r = op2_fct[instrtab[cnt].fct2] (addr
+                                                          + (data - begin),
+                                                          &prefixes,
+#ifdef STR2_BITS
+                                                          op2_str[instrtab[cnt].str2],
+#else
+                                                          NULL,
+#endif
+                                                          instrtab[cnt].off2_1 + OFF2_1_BIAS,
+                                                          instrtab[cnt].off2_2 + OFF2_2_BIAS,
+                                                          instrtab[cnt].off2_3 + OFF2_3_BIAS,
+                                                          buf, &bufcnt, bufsize,
+                                                          data, &param_start,
+                                                          end,
+                                                          symcb, symcbarg);
+                     if (r < 0)
+                       goto not;
+                     if (r > 0)
+                       goto enomem;
+
+                     string_end_idx = ~0ul;
+                   }
+                 else if (prec == 3 && instrtab[cnt].fct3 != 0)
+                   {
+                     /* Third parameter.  */
+#ifdef STR3_BITS
+                     // XXX Probably not needed once the instruction
+                     // XXX tables are complete
+                     if (instrtab[cnt].str3 != 0)
+                       ADD_STRING (op3_str[instrtab[cnt].str3]);
+#endif
+
+                     int r = op3_fct[instrtab[cnt].fct3] (addr
+                                                          + (data - begin),
+                                                          &prefixes,
+#ifdef STR3_BITS
+                                                          op3_str[instrtab[cnt].str3],
+#else
+                                                          NULL,
+#endif
+                                                          instrtab[cnt].off3_1 + OFF3_1_BIAS,
+#ifdef OFF3_2_BITS
+                                                          instrtab[cnt].off3_2 + OFF3_2_BIAS,
+#else
+                                                          0,
+#endif
+#ifdef OFF3_3_BITS
+                                                          instrtab[cnt].off3_3 + OFF3_3_BIAS,
+#else
+                                                          0,
+#endif
+                                                          buf, &bufcnt, bufsize,
+                                                          data, &param_start,
+                                                          end,
+                                                          symcb, symcbarg);
+                     if (r < 0)
+                       goto not;
+                     if (r > 0)
+                       goto enomem;
+
+                     string_end_idx = ~0ul;
+                   }
+                 break;
+
+               case 'e':
+                 /* String end marker.  */
+                 if (string_end_idx == ~0ul)
+                   string_end_idx = bufcnt;
+                 /* No padding.  */
+                 width = 0;
+                 break;
+               }
+
+             /* Pad according to the specified width.  */
+             while (bufcnt + prefix_size < start_idx + width)
+               ADD_CHAR (' ');
+             prefix_size = 0;
+           }
+
+         if ((prefixes & SEGMENT_PREFIXES) != 0)
+           goto print_prefix;
+
+         if (string_end_idx != ~0ul)
+           buf[string_end_idx] = '\0';
+
+         addr += param_start - begin;
+         data = param_start;
+
+         goto out;
+       }
+
+      /* Invalid (or at least unhandled) opcode.  */
+      if (prefixes != 0)
+       goto print_prefix;
+      assert (*startp == data);
+      ++data;
+      ADD_STRING ("(bad)");
+      addr += data - begin;
+
+      buf[bufcnt++] = '\0';
+
+    out:
+      *startp = data;
+      int res = outcb (buf, strlen (buf), outcbarg);
+      if (res != 0)
+       return res;
+    }
+
+  return 0;
+}
diff --git a/libcpu/i386_gendis.c b/libcpu/i386_gendis.c
new file mode 100644 (file)
index 0000000..ca01db8
--- /dev/null
@@ -0,0 +1,39 @@
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+extern int i386_parse (void);
+
+
+extern FILE *i386_in;
+extern int i386_debug;
+char *infname;
+
+FILE *outfile;
+
+int
+main (int argc, char *argv[argc])
+{
+  outfile = stdout;
+
+  if (argc == 1)
+    error (EXIT_FAILURE, 0, "usage: %s <MNEDEFFILE>", argv[0]);
+
+  //i386_debug = 1;
+  infname = argv[1];
+  if (strcmp (infname, "-") == 0)
+    i386_in = stdin;
+  else
+    {
+      i386_in = fopen (infname, "r");
+      if (i386_in == NULL)
+       error (EXIT_FAILURE, errno, "cannot open %s", argv[1]);
+    }
+
+  i386_parse ();
+
+  return error_message_count != 0;
+}
diff --git a/libcpu/i386_lex.l b/libcpu/i386_lex.l
new file mode 100644 (file)
index 0000000..ea12190
--- /dev/null
@@ -0,0 +1,115 @@
+%{
+/* Copyright (C) 2004, 2005, 2007 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <error.h>
+#include <libintl.h>
+
+#include <system.h>
+#include "i386_parse.h"
+
+
+static void eat_to_eol (void);
+static void invalid_char (int ch);
+%}
+
+ID              [a-zA-Z_][a-zA-Z0-9_/]*
+ID2             [a-zA-Z0-9_:/]*
+NUMBER         [0-9]+
+WHITE          [[:space:]]+
+
+%option yylineno
+%option never-interactive
+%option noyywrap
+
+
+%x MAIN
+
+%%
+
+"%mask"                                { return kMASK; }
+
+"%prefix"                      { return kPREFIX; }
+"%suffix"                      { return kSUFFIX; }
+
+"%synonym"                     { return kSYNONYM; }
+
+{NUMBER}                       { i386_lval.num = strtoul (yytext, NULL, 10);
+                                 return kNUMBER; }
+
+"%%"                           { BEGIN (MAIN); return kPERCPERC; }
+
+
+<MAIN>"0"                      { return '0'; }
+<MAIN>"1"                      { return '1'; }
+
+<INITIAL,MAIN>"{"{ID2}"}"      { i386_lval.str = xstrndup (yytext + 1,
+                                                           yyleng - 2);
+                                 return kBITFIELD; }
+
+<MAIN>"INVALID"                        { i386_lval.str = (void *) -1l;
+                                 return kID; }
+
+<MAIN>{ID}                     { i386_lval.str = xstrndup (yytext, yyleng);
+                                 return kID; }
+
+<MAIN>","                      { return ','; }
+
+<MAIN>":"                      { return ':'; }
+
+<INITIAL,MAIN>^"\n"            { /* IGNORE */ }
+
+<INITIAL,MAIN>"\n"             { return '\n'; }
+
+<INITIAL,MAIN>^"#"             { eat_to_eol (); }
+
+{WHITE}                                { /* IGNORE */ }
+
+<MAIN>{WHITE}                  { return kSPACE; }
+
+<MAIN>.                                { i386_lval.ch = *yytext; return kCHAR; }
+
+.                              { invalid_char (*yytext); }
+
+
+%%
+
+static void
+eat_to_eol (void)
+{
+  while (1)
+    {
+      int c = input ();
+
+      if (c == EOF || c == '\n')
+       break;
+    }
+}
+
+static void
+invalid_char (int ch)
+{
+  error (0, 0, (isascii (ch)
+               ? gettext ("invalid character '%c' at line %d; ignored")
+               : gettext ("invalid character '\\%o' at line %d; ignored")),
+        ch, yylineno);
+}
+
+// Local Variables:
+// mode: C
+// End:
diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y
new file mode 100644 (file)
index 0000000..9ad1162
--- /dev/null
@@ -0,0 +1,1641 @@
+%{
+/* Parser for i386 CPU description.
+   Copyright (C) 2004, 2005, 2007 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <error.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <math.h>
+#include <obstack.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include <system.h>
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* The error handler.  */
+static void yyerror (const char *s);
+
+extern int yylex (void);
+extern int i386_lineno;
+extern char *infname;
+
+
+struct known_bitfield
+{
+  char *name;
+  unsigned long int bits;
+  int tmp;
+};
+
+
+struct bitvalue
+{
+  enum bittype { zeroone, field, failure } type;
+  union
+  {
+    unsigned int value;
+    struct known_bitfield *field;
+  };
+  struct bitvalue *next;
+};
+
+
+struct argname
+{
+  enum nametype { string, nfield } type;
+  union
+  {
+    char *str;
+    struct known_bitfield *field;
+  };
+  struct argname *next;
+};
+
+
+struct argument
+{
+  struct argname *name;
+  struct argument *next;
+};
+
+
+struct instruction
+{
+  /* The byte encoding.  */
+  struct bitvalue *bytes;
+
+  /* Prefix possible.  */
+  int repe;
+  int rep;
+
+  /* Mnemonic.  */
+  char *mnemonic;
+
+  /* Suffix.  */
+  enum { suffix_none = 0, suffix_w, suffix_w0, suffix_W, suffix_tttn,
+        suffix_w1, suffix_gg, suffix_GG, suffix_0g, suffix_gG,
+         suffix_predpd, suffix_predps, suffix_predsd, suffix_predss,
+        suffix_D } suffix;
+
+  /* Flag set if modr/m is used.  */
+  int modrm;
+
+  /* Operands.  */
+  struct operand
+  {
+    char *fct;
+    char *str;
+    int off1;
+    int off2;
+    int off3;
+  } operands[3];
+
+  struct instruction *next;
+};
+
+
+struct synonym
+{
+  char *from;
+  char *to;
+};
+
+
+struct suffix
+{
+  char *name;
+  int idx;
+};
+
+
+struct argstring
+{
+  char *str;
+  int idx;
+};
+
+
+static struct known_bitfield ax_reg =
+  {
+    .name = "ax", .bits = 0, .tmp = 0
+  };
+
+static struct known_bitfield dx_reg =
+  {
+    .name = "dx", .bits = 0, .tmp = 0
+  };
+
+static struct known_bitfield di_reg =
+  {
+    .name = "es_di", .bits = 0, .tmp = 0
+  };
+
+static struct known_bitfield si_reg =
+  {
+    .name = "ds_si", .bits = 0, .tmp = 0
+  };
+
+static struct known_bitfield bx_reg =
+  {
+    .name = "ds_bx", .bits = 0, .tmp = 0
+  };
+
+
+static int bitfield_compare (const void *p1, const void *p2);
+static void new_bitfield (char *name, unsigned long int num);
+static void check_bits (struct bitvalue *value);
+static int check_duplicates (struct bitvalue *val);
+static int check_argsdef (struct bitvalue *bitval, struct argument *args);
+static int check_bitsused (struct bitvalue *bitval,
+                          struct known_bitfield *suffix,
+                          struct argument *args);
+static struct argname *combine (struct argname *name);
+static void fillin_arg (struct bitvalue *bytes, struct argname *name,
+                       struct instruction *instr, int n);
+static void find_numbers (void);
+static int compare_syn (const void *p1, const void *p2);
+static int compare_suf (const void *p1, const void *p2);
+static void instrtable_out (void);
+#if 0
+static void create_mnemonic_table (void);
+#endif
+
+static void *bitfields;
+static struct instruction *instructions;
+static size_t ninstructions;
+static void *synonyms;
+static void *suffixes;
+static int nsuffixes;
+static void *mnemonics;
+size_t nmnemonics;
+extern FILE *outfile;
+
+/* Number of bits used mnemonics.  */
+#if 0
+static size_t best_mnemonic_bits;
+#endif
+%}
+
+%union {
+  unsigned long int num;
+  char *str;
+  char ch;
+  struct known_bitfield *field;
+  struct bitvalue *bit;
+  struct argname *name;
+  struct argument *arg;
+}
+
+%token kMASK
+%token kPREFIX
+%token kSUFFIX
+%token kSYNONYM
+%token <str> kID
+%token <num> kNUMBER
+%token kPERCPERC
+%token <str> kBITFIELD
+%token <ch> kCHAR
+%token kSPACE
+
+%type <bit> bit byte bytes
+%type <field> bitfieldopt
+%type <name> argcomp arg
+%type <arg> args optargs
+
+%defines
+
+%%
+
+spec:            masks kPERCPERC '\n' instrs
+                   {
+                     if (error_message_count != 0)
+                       error (EXIT_FAILURE, 0,
+                              "terminated due to previous error");
+
+                     instrtable_out ();
+                   }
+               ;
+
+masks:           masks '\n' mask
+               | mask
+               ;
+
+mask:            kMASK kBITFIELD kNUMBER
+                   { new_bitfield ($2, $3); }
+               | kPREFIX kBITFIELD
+                   { new_bitfield ($2, -1); }
+               | kSUFFIX kBITFIELD
+                   { new_bitfield ($2, -2); }
+               | kSYNONYM kBITFIELD kBITFIELD
+                   {
+                     struct synonym *newp = xmalloc (sizeof (*newp));
+                     newp->from = $2;
+                     newp->to = $3;
+                     if (tfind (newp, &synonyms, compare_syn) != NULL)
+                       error (0, 0,
+                              "%d: duplicate definition for synonym '%s'",
+                              i386_lineno, $2);
+                     else if (tsearch ( newp, &synonyms, compare_syn) == NULL)
+                       error (EXIT_FAILURE, 0, "tsearch");
+                   }
+               |
+               ;
+
+instrs:                  instrs '\n' instr
+               | instr
+               ;
+
+instr:           bytes ':' bitfieldopt kID bitfieldopt optargs
+                   {
+                     if ($3 != NULL && strcmp ($3->name, "RE") != 0
+                         && strcmp ($3->name, "R") != 0)
+                       {
+                         error (0, 0, "%d: only 'R' and 'RE' prefix allowed",
+                                i386_lineno - 1);
+                       }
+                     if (check_duplicates ($1) == 0
+                         && check_argsdef ($1, $6) == 0
+                         && check_bitsused ($1, $5, $6) == 0)
+                       {
+                         struct instruction *newp = xcalloc (sizeof (*newp),
+                                                             1);
+                         if ($3 != NULL)
+                           {
+                             if (strcmp ($3->name, "RE") == 0)
+                               newp->repe = 1;
+                             else if (strcmp ($3->name, "R") == 0)
+                               newp->rep = 1;
+                           }
+
+                         newp->bytes = $1;
+                         newp->mnemonic = $4;
+                         if (newp->mnemonic != (void *) -1l
+                             && tfind ($4, &mnemonics,
+                                       (comparison_fn_t) strcmp) == NULL)
+                           {
+                             if (tsearch ($4, &mnemonics,
+                                          (comparison_fn_t) strcmp) == NULL)
+                               error (EXIT_FAILURE, errno, "tsearch");
+                             ++nmnemonics;
+                           }
+
+                         if ($5 != NULL)
+                           {
+                             if (strcmp ($5->name, "w") == 0)
+                               newp->suffix = suffix_w;
+                             else if (strcmp ($5->name, "w0") == 0)
+                               newp->suffix = suffix_w0;
+                             else if (strcmp ($5->name, "tttn") == 0)
+                               newp->suffix = suffix_tttn;
+                             else if (strcmp ($5->name, "w1") == 0)
+                               newp->suffix = suffix_w1;
+                             else if (strcmp ($5->name, "W") == 0)
+                               newp->suffix = suffix_W;
+                             else if (strcmp ($5->name, "gg") == 0)
+                               newp->suffix = suffix_gg;
+                             else if (strcmp ($5->name, "GG") == 0)
+                               newp->suffix = suffix_GG;
+                             else if (strcmp ($5->name, "0g") == 0)
+                               newp->suffix = suffix_0g;
+                             else if (strcmp ($5->name, "gG") == 0)
+                               newp->suffix = suffix_gG;
+                             else if (strcmp ($5->name, "predpd") == 0)
+                               newp->suffix = suffix_predpd;
+                             else if (strcmp ($5->name, "predps") == 0)
+                               newp->suffix = suffix_predps;
+                             else if (strcmp ($5->name, "predsd") == 0)
+                               newp->suffix = suffix_predsd;
+                             else if (strcmp ($5->name, "predss") == 0)
+                               newp->suffix = suffix_predss;
+                             else if (strcmp ($5->name, "D") == 0)
+                               newp->suffix = suffix_D;
+                             else
+                               error (EXIT_FAILURE, 0,
+                                      "%s: %d: unknown suffix '%s'",
+                                      infname, i386_lineno - 1, $5->name);
+
+                             struct suffix search = { .name = $5->name };
+                             if (tfind (&search, &suffixes, compare_suf)
+                                 == NULL)
+                               {
+                                 struct suffix *ns = xmalloc (sizeof (*ns));
+                                 ns->name = $5->name;
+                                 ns->idx = ++nsuffixes;
+                                 if (tsearch (ns, &suffixes, compare_suf)
+                                     == NULL)
+                                   error (EXIT_FAILURE, errno, "tsearch");
+                               }
+                           }
+
+                         struct argument *args = $6;
+                         int n = 0;
+                         while (args != NULL)
+                           {
+                             fillin_arg ($1, args->name, newp, n);
+
+                             args = args->next;
+                             ++n;
+                           }
+
+                         newp->next = instructions;
+                         instructions = newp;
+                         ++ninstructions;
+                       }
+                   }
+               |
+               ;
+
+bitfieldopt:     kBITFIELD
+                   {
+                     struct known_bitfield search;
+                     search.name = $1;
+                     struct known_bitfield **res;
+                     res = tfind (&search, &bitfields, bitfield_compare);
+                     if (res == NULL)
+                       {
+                         error (0, 0, "%d: unknown bitfield '%s'",
+                                i386_lineno, search.name);
+                         $$ = NULL;
+                       }
+                     else
+                       $$ = *res;
+                   }
+               |
+                   { $$ = NULL; }
+               ;
+
+bytes:           bytes ',' byte
+                   {
+                     check_bits ($3);
+
+                     struct bitvalue *runp = $1;
+                     while (runp->next != NULL)
+                       runp = runp->next;
+                     runp->next = $3;
+                     $$ = $1;
+                   }
+               | byte
+                   {
+                     check_bits ($1);
+                     $$ = $1;
+                   }
+               ;
+
+byte:            byte bit
+                   {
+                     struct bitvalue *runp = $1;
+                     while (runp->next != NULL)
+                       runp = runp->next;
+                     runp->next = $2;
+                     $$ = $1;
+                   }
+               | bit
+                   { $$ = $1; }
+               ;
+
+bit:             '0'
+                   {
+                     $$ = xmalloc (sizeof (struct bitvalue));
+                     $$->type = zeroone;
+                     $$->value = 0;
+                     $$->next = NULL;
+                   }
+               | '1'
+                   {
+                     $$ = xmalloc (sizeof (struct bitvalue));
+                     $$->type = zeroone;
+                     $$->value = 1;
+                     $$->next = NULL;
+                   }
+               | kBITFIELD
+                   {
+                     $$ = xmalloc (sizeof (struct bitvalue));
+                     struct known_bitfield search;
+                     search.name = $1;
+                     struct known_bitfield **res;
+                     res = tfind (&search, &bitfields, bitfield_compare);
+                     if (res == NULL)
+                       {
+                         error (0, 0, "%d: unknown bitfield '%s'",
+                                i386_lineno, search.name);
+                         $$->type = failure;
+                       }
+                     else
+                       {
+                         $$->type = field;
+                         $$->field = *res;
+                       }
+                     $$->next = NULL;
+                   }
+               ;
+
+optargs:         kSPACE args
+                   { $$ = $2; }
+               |
+                   { $$ = NULL; }
+               ;
+
+args:            args ',' arg
+                   {
+                     struct argument *runp = $1;
+                     while (runp->next != NULL)
+                       runp = runp->next;
+                     runp->next = xmalloc (sizeof (struct argument));
+                     runp->next->name = combine ($3);
+                     runp->next->next = NULL;
+                     $$ = $1;
+                   }
+               | arg
+                   {
+                     $$ = xmalloc (sizeof (struct argument));
+                     $$->name = combine ($1);
+                     $$->next = NULL;
+                   }
+               ;
+
+arg:             arg argcomp
+                   {
+                     struct argname *runp = $1;
+                     while (runp->next != NULL)
+                       runp = runp->next;
+                     runp->next = $2;
+                     $$ = $1;
+                   }
+               | argcomp
+                   { $$ = $1; }
+               ;
+argcomp:         kBITFIELD
+                   {
+                     $$ = xmalloc (sizeof (struct argname));
+                     $$->type = nfield;
+                     $$->next = NULL;
+
+                     struct known_bitfield search;
+                     search.name = $1;
+                     struct known_bitfield **res;
+                     res = tfind (&search, &bitfields, bitfield_compare);
+                     if (res == NULL)
+                       {
+                         if (strcmp ($1, "ax") == 0)
+                           $$->field = &ax_reg;
+                         else if (strcmp ($1, "dx") == 0)
+                           $$->field = &dx_reg;
+                         else if (strcmp ($1, "es_di") == 0)
+                           $$->field = &di_reg;
+                         else if (strcmp ($1, "ds_si") == 0)
+                           $$->field = &si_reg;
+                         else if (strcmp ($1, "ds_bx") == 0)
+                           $$->field = &bx_reg;
+                         else
+                           {
+                             error (0, 0, "%d: unknown bitfield '%s'",
+                                    i386_lineno, search.name);
+                             $$->field = NULL;
+                           }
+                       }
+                     else
+                       $$->field = *res;
+                   }
+               | kCHAR
+                   {
+                     $$ = xmalloc (sizeof (struct argname));
+                     $$->type = string;
+                     $$->next = NULL;
+                     $$->str = xmalloc (2);
+                     $$->str[0] = $1;
+                     $$->str[1] = '\0';
+                   }
+               | kID
+                   {
+                     $$ = xmalloc (sizeof (struct argname));
+                     $$->type = string;
+                     $$->next = NULL;
+                     $$->str = $1;
+                   }
+               | ':'
+                   {
+                     $$ = xmalloc (sizeof (struct argname));
+                     $$->type = string;
+                     $$->next = NULL;
+                     $$->str = xmalloc (2);
+                     $$->str[0] = ':';
+                     $$->str[1] = '\0';
+                   }
+               ;
+
+%%
+
+static void
+yyerror (const char *s)
+{
+  error (0, 0, gettext ("while reading i386 CPU description: %s at line %d"),
+         gettext (s), i386_lineno);
+}
+
+
+static int
+bitfield_compare (const void *p1, const void *p2)
+{
+  struct known_bitfield *f1 = (struct known_bitfield *) p1;
+  struct known_bitfield *f2 = (struct known_bitfield *) p2;
+
+  return strcmp (f1->name, f2->name);
+}
+
+
+static void
+new_bitfield (char *name, unsigned long int num)
+{
+  struct known_bitfield *newp = xmalloc (sizeof (struct known_bitfield));
+  newp->name = name;
+  newp->bits = num;
+  newp->tmp = 0;
+
+  if (tfind (newp, &bitfields, bitfield_compare) != NULL)
+    {
+      error (0, 0, "%d: duplicated definition of bitfield '%s'",
+            i386_lineno, name);
+      free (name);
+      return;
+    }
+
+  if (tsearch (newp, &bitfields, bitfield_compare) == NULL)
+    error (EXIT_FAILURE, errno, "%d: cannot insert new bitfield '%s'",
+          i386_lineno, name);
+}
+
+
+/* Check that the number of bits is a multiple of 8.  */
+static void
+check_bits (struct bitvalue *val)
+{
+  struct bitvalue *runp = val;
+  unsigned int total = 0;
+
+  while (runp != NULL)
+    {
+      if (runp->type == zeroone)
+       ++total;
+      else if (runp->field == NULL)
+       /* No sense doing anything, the field is not known.  */
+       return;
+      else
+       total += runp->field->bits;
+
+      runp = runp->next;
+    }
+
+  if (total % 8 != 0)
+    {
+      struct obstack os;
+      obstack_init (&os);
+
+      while (val != NULL)
+       {
+         if (val->type == zeroone)
+           obstack_printf (&os, "%u", val->value);
+         else
+           obstack_printf (&os, "{%s}", val->field->name);
+         val = val->next;
+       }
+      obstack_1grow (&os, '\0');
+
+      error (0, 0, "%d: field '%s' not a multiple of 8 bits in size",
+            i386_lineno, (char *) obstack_finish (&os));
+
+      obstack_free (&os, NULL);
+    }
+}
+
+
+static int
+check_duplicates (struct bitvalue *val)
+{
+  static int testcnt;
+  ++testcnt;
+
+  int result = 0;
+  while (val != NULL)
+    {
+      if (val->type == field && val->field != NULL)
+       {
+         if (val->field->tmp == testcnt)
+           {
+             error (0, 0, "%d: bitfield '%s' used more than once",
+                    i386_lineno - 1, val->field->name);
+             result = 1;
+           }
+         val->field->tmp = testcnt;
+       }
+
+      val = val->next;
+    }
+
+  return result;
+}
+
+
+static int
+check_argsdef (struct bitvalue *bitval, struct argument *args)
+{
+  int result = 0;
+
+  while (args != NULL)
+    {
+      for (struct argname *name = args->name; name != NULL; name = name->next)
+       if (name->type == nfield && name->field != NULL
+           && name->field != &ax_reg && name->field != &dx_reg
+           && name->field != &di_reg && name->field != &si_reg
+           && name->field != &bx_reg)
+         {
+           struct bitvalue *runp = bitval;
+
+           while (runp != NULL)
+             if (runp->type == field && runp->field == name->field)
+               break;
+             else
+               runp = runp->next;
+
+           if (runp == NULL)
+             {
+               error (0, 0, "%d: unknown bitfield '%s' used in output format",
+                      i386_lineno - 1, name->field->name);
+               result = 1;
+             }
+         }
+
+      args = args->next;
+    }
+
+  return result;
+}
+
+
+static int
+check_bitsused (struct bitvalue *bitval, struct known_bitfield *suffix,
+               struct argument *args)
+{
+  int result = 0;
+
+  while (bitval != NULL)
+    {
+      if (bitval->type == field && bitval->field != NULL
+         && bitval->field != suffix
+         /* {w} is handled special.  */
+         && strcmp (bitval->field->name, "w") != 0)
+       {
+         struct argument *runp;
+         for (runp = args; runp != NULL; runp = runp->next)
+           {
+             struct argname *name = runp->name;
+
+             while (name != NULL)
+               if (name->type == nfield && name->field == bitval->field)
+                 break;
+               else
+                 name = name->next;
+
+             if (name != NULL)
+               break;
+           }
+
+#if 0
+         if (runp == NULL)
+           {
+             error (0, 0, "%d: bitfield '%s' not used",
+                    i386_lineno - 1, bitval->field->name);
+             result = 1;
+           }
+#endif
+       }
+
+      bitval = bitval->next;
+    }
+
+  return result;
+}
+
+
+static struct argname *
+combine (struct argname *name)
+{
+  struct argname *last_str = NULL;
+  for (struct argname *runp = name; runp != NULL; runp = runp->next)
+    {
+      if (runp->type == string)
+       {
+         if (last_str == NULL)
+           last_str = runp;
+         else
+           {
+             last_str->str = xrealloc (last_str->str,
+                                       strlen (last_str->str)
+                                       + strlen (runp->str) + 1);
+             strcat (last_str->str, runp->str);
+             last_str->next = runp->next;
+           }
+       }
+      else
+       last_str = NULL;
+    }
+  return name;
+}
+
+
+#define obstack_grow_str(ob, str) obstack_grow (ob, str, strlen (str))
+
+
+static void
+fillin_arg (struct bitvalue *bytes, struct argname *name,
+           struct instruction *instr, int n)
+{
+  static struct obstack ob;
+  static int initialized;
+  if (! initialized)
+    {
+      initialized = 1;
+      obstack_init (&ob);
+    }
+
+  struct argname *runp = name;
+  int cnt = 0;
+  while (runp != NULL)
+    {
+      /* We ignore strings in the function name.  */
+      if (runp->type == string)
+       {
+         if (instr->operands[n].str != NULL)
+           error (EXIT_FAILURE, 0,
+                  "%d: cannot have more than one string parameter",
+                  i386_lineno - 1);
+
+         instr->operands[n].str = runp->str;
+       }
+      else
+       {
+         assert (runp->type == nfield);
+
+         /* Construct the function name.  */
+         if (cnt++ > 0)
+           obstack_1grow (&ob, '$');
+
+         if (runp->field == NULL)
+           /* Add some string which contains invalid characters.  */
+           obstack_grow_str (&ob, "!!!INVALID!!!");
+         else
+           obstack_grow_str (&ob, runp->field->name);
+
+         /* Now compute the bit offset of the field.  */
+         struct bitvalue *b = bytes;
+         int bitoff = 0;
+         if (runp->field != NULL)
+           while (b != NULL)
+             {
+               if (b->type == field && b->field != NULL)
+                 {
+                   if (strcmp (b->field->name, runp->field->name) == 0)
+                     break;
+                   bitoff += b->field->bits;
+                 }
+               else
+                 ++bitoff;
+
+               b = b->next;
+             }
+         if (instr->operands[n].off1 == 0)
+           instr->operands[n].off1 = bitoff;
+         else if (instr->operands[n].off2 == 0)
+           instr->operands[n].off2 = bitoff;
+         else if (instr->operands[n].off3 == 0)
+           instr->operands[n].off3 = bitoff;
+         else
+           error (EXIT_FAILURE, 0,
+                  "%d: cannot have more than three fields in parameter",
+                  i386_lineno - 1);
+
+         if  (runp->field != NULL
+              && strncasecmp (runp->field->name, "mod", 3) == 0)
+           instr->modrm = 1;
+       }
+
+      runp = runp->next;
+    }
+  if (obstack_object_size (&ob) == 0)
+    obstack_grow_str (&ob, "string");
+  obstack_1grow (&ob, '\0');
+  char *fct = obstack_finish (&ob);
+
+  struct synonym search = { .from = fct };
+  struct synonym **res = tfind (&search, &synonyms, compare_syn);
+  if (res != NULL)
+    fct = (*res)->to;
+
+  instr->operands[n].fct = fct;
+}
+
+
+#if 0
+static void
+nameout (const void *nodep, VISIT value, int level)
+{
+  if (value == leaf || value == postorder)
+    printf ("  %s\n", *(const char **) nodep);
+}
+#endif
+
+
+static int
+compare_argstring (const void *p1, const void *p2)
+{
+  const struct argstring *a1 = (const struct argstring *) p1;
+  const struct argstring *a2 = (const struct argstring *) p2;
+
+  return strcmp (a1->str, a2->str);
+}
+
+
+static int maxoff[3][3];
+static int minoff[3][3] = { { 1000, 1000, 1000 },
+                           { 1000, 1000, 1000 },
+                           { 1000, 1000, 1000 } };
+static int nbitoff[3][3];
+static void *fct_names[3];
+static int nbitfct[3];
+static int nbitsuf;
+static void *strs[3];
+static int nbitstr[3];
+static int total_bits = 2;     // Already counted the rep/repe bits.
+
+static void
+find_numbers (void)
+{
+  int nfct_names[3] = { 0, 0, 0 };
+  int nstrs[3] = { 0, 0, 0 };
+
+  /* We reverse the order of the instruction list while processing it.
+     Later phases need it in the order in which the input file has
+     them.  */
+  struct instruction *reversed = NULL;
+
+  struct instruction *runp = instructions;
+  while (runp != NULL)
+    {
+      for (int i = 0; i < 3; ++i)
+       if (runp->operands[i].fct != NULL)
+         {
+           struct argstring search = { .str = runp->operands[i].fct };
+           if (tfind (&search, &fct_names[i], compare_argstring) == NULL)
+             {
+               struct argstring *newp = xmalloc (sizeof (*newp));
+               newp->str = runp->operands[i].fct;
+               newp->idx = 0;
+               if (tsearch (newp, &fct_names[i], compare_argstring) == NULL)
+                 error (EXIT_FAILURE, errno, "tsearch");
+               ++nfct_names[i];
+             }
+
+           if (runp->operands[i].str != NULL)
+             {
+               search.str = runp->operands[i].str;
+               if (tfind (&search, &strs[i], compare_argstring) == NULL)
+                 {
+                   struct argstring *newp = xmalloc (sizeof (*newp));
+                   newp->str = runp->operands[i].str;
+                   newp->idx = 0;
+                   if (tsearch (newp, &strs[i], compare_argstring) == NULL)
+                     error (EXIT_FAILURE, errno, "tsearch");
+                   ++nstrs[i];
+                 }
+             }
+
+           maxoff[i][0] = MAX (maxoff[i][0], runp->operands[i].off1);
+           maxoff[i][1] = MAX (maxoff[i][1], runp->operands[i].off2);
+           maxoff[i][2] = MAX (maxoff[i][2], runp->operands[i].off3);
+
+           if (runp->operands[i].off1 > 0)
+             minoff[i][0] = MIN (minoff[i][0], runp->operands[i].off1);
+           if (runp->operands[i].off2 > 0)
+             minoff[i][1] = MIN (minoff[i][1], runp->operands[i].off2);
+           if (runp->operands[i].off3 > 0)
+             minoff[i][2] = MIN (minoff[i][2], runp->operands[i].off3);
+         }
+
+      struct instruction *old = runp;
+      runp = runp->next;
+
+      old->next = reversed;
+      reversed = old;
+    }
+  instructions = reversed;
+
+  int d;
+  int c;
+  for (int i = 0; i < 3; ++i)
+    {
+      // printf ("min1 = %d, min2 = %d, min3 = %d\n", minoff[i][0], minoff[i][1], minoff[i][2]);
+      // printf ("max1 = %d, max2 = %d, max3 = %d\n", maxoff[i][0], maxoff[i][1], maxoff[i][2]);
+
+      if (minoff[i][0] == 1000)
+       nbitoff[i][0] = 0;
+      else
+       {
+         nbitoff[i][0] = 1;
+         d = maxoff[i][0] - minoff[i][0];
+         c = 1;
+         while (c < d)
+           {
+             ++nbitoff[i][0];
+             c *= 2;
+           }
+         total_bits += nbitoff[i][0];
+       }
+
+      if (minoff[i][1] == 1000)
+       nbitoff[i][1] = 0;
+      else
+       {
+         nbitoff[i][1] = 1;
+         d = maxoff[i][1] - minoff[i][1];
+         c = 1;
+         while (c < d)
+           {
+             ++nbitoff[i][1];
+             c *= 2;
+           }
+         total_bits += nbitoff[i][1];
+       }
+
+      if (minoff[i][2] == 1000)
+       nbitoff[i][2] = 0;
+      else
+       {
+         nbitoff[i][2] = 1;
+         d = maxoff[i][2] - minoff[i][2];
+         c = 1;
+         while (c < d)
+           {
+             ++nbitoff[i][2];
+             c *= 2;
+           }
+         total_bits += nbitoff[i][2];
+       }
+      // printf ("off1 = %d, off2 = %d, off3 = %d\n", nbitoff[i][0], nbitoff[i][1], nbitoff[i][2]);
+
+      nbitfct[i] = 1;
+      d = nfct_names[i];
+      c = 1;
+      while (c < d)
+       {
+         ++nbitfct[i];
+         c *= 2;
+       }
+      total_bits += nbitfct[i];
+      // printf ("%d fct[%d], %d bits\n", nfct_names[i], i, nbitfct[i]);
+
+      if (nstrs[i] != 0)
+       {
+         nbitstr[i] = 1;
+         d = nstrs[i];
+         c = 1;
+         while (c < d)
+           {
+             ++nbitstr[i];
+             c *= 2;
+           }
+         total_bits += nbitstr[i];
+       }
+
+      // twalk (fct_names[i], nameout);
+    }
+
+  nbitsuf = 0;
+  d = nsuffixes;
+  c = 1;
+  while (c < d)
+    {
+      ++nbitsuf;
+      c *= 2;
+    }
+  total_bits += nbitsuf;
+  // printf ("%d suffixes, %d bits\n", nsuffixes, nbitsuf);
+}
+
+
+static int
+compare_syn (const void *p1, const void *p2)
+{
+  const struct synonym *s1 = (const struct synonym *) p1;
+  const struct synonym *s2 = (const struct synonym *) p2;
+
+  return strcmp (s1->from, s2->from);
+}
+
+
+static int
+compare_suf (const void *p1, const void *p2)
+{
+  const struct suffix *s1 = (const struct suffix *) p1;
+  const struct suffix *s2 = (const struct suffix *) p2;
+
+  return strcmp (s1->name, s2->name);
+}
+
+
+static int count_op_str;
+static void
+print_op_str (const void *nodep, VISIT value,
+             int level __attribute__ ((unused)))
+{
+  if (value == leaf || value == postorder)
+    {
+      fprintf (outfile, "  \"%s\",\n", (*(struct argstring **) nodep)->str);
+      (*(struct argstring **) nodep)->idx = ++count_op_str;
+    }
+}
+
+
+static void
+print_op_fct (const void *nodep, VISIT value,
+             int level __attribute__ ((unused)))
+{
+  if (value == leaf || value == postorder)
+    {
+      fprintf (outfile, "  FCT_%s,\n", (*(struct argstring **) nodep)->str);
+      (*(struct argstring **) nodep)->idx = ++count_op_str;
+    }
+}
+
+
+static void
+instrtable_out (void)
+{
+  find_numbers ();
+
+#if 0
+  create_mnemonic_table ();
+
+  fprintf (outfile, "#define MNEMONIC_BITS %zu\n", best_mnemonic_bits);
+#else
+  fprintf (outfile, "#define MNEMONIC_BITS %ld\n",
+          lrint (ceil (log2 (NMNES))));
+#endif
+  fprintf (outfile, "#define SUFFIX_BITS %d\n", nbitsuf);
+  for (int i = 0; i < 3; ++i)
+    {
+      fprintf (outfile, "#define FCT%d_BITS %d\n", i + 1, nbitfct[i]);
+      if (nbitstr[i] != 0)
+       fprintf (outfile, "#define STR%d_BITS %d\n", i + 1, nbitstr[i]);
+      fprintf (outfile, "#define OFF%d_1_BITS %d\n", i + 1, nbitoff[i][0]);
+      fprintf (outfile, "#define OFF%d_1_BIAS %d\n", i + 1, minoff[i][0]);
+      if (nbitoff[i][1] != 0)
+       {
+         fprintf (outfile, "#define OFF%d_2_BITS %d\n", i + 1, nbitoff[i][1]);
+         fprintf (outfile, "#define OFF%d_2_BIAS %d\n", i + 1, minoff[i][1]);
+       }
+      if (nbitoff[i][2] != 0)
+       {
+         fprintf (outfile, "#define OFF%d_3_BITS %d\n", i + 1, nbitoff[i][2]);
+         fprintf (outfile, "#define OFF%d_3_BIAS %d\n", i + 1, minoff[i][2]);
+       }
+    }
+
+  fputs ("\n#include <i386_data.h>\n\n", outfile);
+
+
+#define APPEND(a, b) APPEND_ (a, b)
+#define APPEND_(a, b) a##b
+#define EMIT_SUFFIX(suf) \
+  fprintf (outfile, "#define suffix_%s %d\n", #suf, APPEND (suffix_, suf))
+  EMIT_SUFFIX (none);
+  EMIT_SUFFIX (w);
+  EMIT_SUFFIX (w0);
+  EMIT_SUFFIX (W);
+  EMIT_SUFFIX (tttn);
+  EMIT_SUFFIX (D);
+  EMIT_SUFFIX (w1);
+
+  fputc_unlocked ('\n', outfile);
+
+  for (int i = 0; i < 3; ++i)
+    {
+      /* Functions.  */
+      count_op_str = 0;
+      fprintf (outfile, "static opfct_t op%d_fct[] =\n{\n  NULL,\n", i + 1);
+      twalk (fct_names[i], print_op_fct);
+      fputs ("};\n", outfile);
+
+      /* The operand strings.  */
+      if (nbitstr[i] != 0)
+       {
+         count_op_str = 0;
+         fprintf (outfile, "static const char *op%d_str[] =\n{\n  NULL,\n",
+                  i + 1);
+         twalk (strs[i], print_op_str);
+         fputs ("};\n", outfile);
+       }
+    }
+
+
+  fputs ("static const struct instr_enc instrtab[] =\n{\n", outfile);
+  struct instruction *instr;
+  for (instr = instructions; instr != NULL; instr = instr->next)
+    {
+      fputs ("  {", outfile);
+      if (instr->mnemonic == (void *) -1l)
+       fputs (" .mnemonic = MNE_INVALID,", outfile);
+      else
+       fprintf (outfile, " .mnemonic = MNE_%s,", instr->mnemonic);
+      fprintf (outfile, " .rep = %d,", instr->rep);
+      fprintf (outfile, " .repe = %d,", instr->repe);
+      fprintf (outfile, " .suffix = %d,", instr->suffix);
+      fprintf (outfile, " .modrm = %d,", instr->modrm);
+
+      for (int i = 0; i < 3; ++i)
+       {
+         int idx = 0;
+         if (instr->operands[i].fct != NULL)
+           {
+             struct argstring search = { .str = instr->operands[i].fct };
+             struct argstring **res = tfind (&search, &fct_names[i],
+                                             compare_argstring);
+             assert (res != NULL);
+             idx = (*res)->idx;
+           }
+         fprintf (outfile, " .fct%d = %d,", i + 1, idx);
+
+         idx = 0;
+         if (instr->operands[i].str != NULL)
+           {
+             struct argstring search = { .str = instr->operands[i].str };
+             struct argstring **res = tfind (&search, &strs[i],
+                                             compare_argstring);
+             assert (res != NULL);
+             idx = (*res)->idx;
+           }
+         if (nbitstr[i] != 0)
+           fprintf (outfile, " .str%d = %d,", i + 1, idx);
+
+         fprintf (outfile, " .off%d_1 = %d,", i + 1,
+                  MAX (0, instr->operands[i].off1 - minoff[i][0]));
+
+         if (nbitoff[i][1] != 0)
+           fprintf (outfile, " .off%d_2 = %d,", i + 1,
+                    MAX (0, instr->operands[i].off2 - minoff[i][1]));
+
+         if (nbitoff[i][2] != 0)
+           fprintf (outfile, " .off%d_3 = %d,", i + 1,
+                    MAX (0, instr->operands[i].off3 - minoff[i][2]));
+       }
+
+      fputs (" },\n", outfile);
+    }
+  fputs ("};\n", outfile);
+
+  fputs ("static const uint8_t match_data[] =\n{\n", outfile);
+  size_t cnt = 0;
+  for (instr = instructions; instr != NULL; instr = instr->next, ++cnt)
+    {
+      /* First count the number of bytes.  */
+      size_t totalbits = 0;
+      size_t zerobits = 0;
+      struct bitvalue *b = instr->bytes;
+      while (b != NULL)
+       {
+         if (b->type == zeroone)
+           {
+             ++totalbits;
+             zerobits = 0;
+           }
+         else
+           {
+             totalbits += b->field->bits;
+             /* We must always count the mod/rm byte.  */
+             if (strncasecmp (b->field->name, "mod", 3) == 0)
+               zerobits = 0;
+             else
+               zerobits += b->field->bits;
+           }
+         b = b->next;
+       }
+      size_t nbytes = (totalbits - zerobits + 7) / 8;
+      assert (nbytes > 0);
+
+      fprintf (outfile, "  %#zx,", nbytes);
+
+      /* Now create the mask and byte values.  */
+      uint8_t byte = 0;
+      uint8_t mask = 0;
+      int nbits = 0;
+      b = instr->bytes;
+      while (b != NULL)
+       {
+         if (b->type == zeroone)
+           {
+             byte = (byte << 1) | b->value;
+             mask = (mask << 1) | 1;
+             if (++nbits == 8)
+               {
+                 fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", mask, byte);
+                 byte = mask = nbits = 0;
+                 if (--nbytes == 0)
+                   break;
+               }
+           }
+         else
+           {
+             unsigned long int remaining = b->field->bits;
+             while (nbits + remaining > 8)
+               {
+                 fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",",
+                          mask << (8 - nbits), byte << (8 - nbits));
+                 remaining = nbits + remaining - 8;
+                 byte = mask = nbits = 0;
+                 if (--nbytes == 0)
+                   break;
+               }
+             byte <<= remaining;
+             mask <<= remaining;
+             nbits += remaining;
+             if (nbits == 8)
+               {
+                 fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", mask, byte);
+                 byte = mask = nbits = 0;
+                 if (--nbytes == 0)
+                   break;
+               }
+           }
+         b = b->next;
+       }
+
+      fprintf (outfile, " %#zx, %#zx,\n", cnt & 0xff, cnt >> 8);
+    }
+  fputs ("};\n", outfile);
+}
+
+
+#if 0
+static size_t mnemonic_maxlen;
+static size_t mnemonic_minlen;
+static size_t
+which_chars (const char *str[], size_t nstr)
+{
+  char used_char[256];
+  memset (used_char, '\0', sizeof (used_char));
+  mnemonic_maxlen = 0;
+  mnemonic_minlen = 10000;
+  for (size_t cnt = 0; cnt < nstr; ++cnt)
+    {
+      const unsigned char *cp = (const unsigned char *) str[cnt];
+      mnemonic_maxlen = MAX (mnemonic_maxlen, strlen ((char *) cp));
+      mnemonic_minlen = MIN (mnemonic_minlen, strlen ((char *) cp));
+      do
+        used_char[*cp++] = 1;
+      while (*cp != '\0');
+    }
+  size_t nused_char = 0;
+  for (size_t cnt = 0; cnt < 256; ++cnt)
+    if (used_char[cnt] != 0)
+      ++nused_char;
+  return nused_char;
+}
+
+
+static const char **mnemonic_strs;
+static size_t nmnemonic_strs;
+static void
+add_mnemonics (const void *nodep, VISIT value,
+              int level __attribute__ ((unused)))
+{
+  if (value == leaf || value == postorder)
+    mnemonic_strs[nmnemonic_strs++] = *(const char **) nodep;
+}
+
+
+struct charfreq
+{
+  char ch;
+  int freq;
+};
+static struct charfreq pfxfreq[256];
+static struct charfreq sfxfreq[256];
+
+
+static int
+compare_freq (const void *p1, const void *p2)
+{
+  const struct charfreq *c1 = (const struct charfreq *) p1;
+  const struct charfreq *c2 = (const struct charfreq *) p2;
+
+  if (c1->freq > c2->freq)
+    return -1;
+  if (c1->freq < c2->freq)
+    return 1;
+  return 0;
+}
+
+
+static size_t
+compute_pfxfreq (const char *str[], size_t nstr)
+{
+  memset (pfxfreq, '\0', sizeof (pfxfreq));
+
+  for (size_t i = 0; i < nstr; ++i)
+    pfxfreq[i].ch = i;
+
+  for (size_t i = 0; i < nstr; ++i)
+    ++pfxfreq[*((const unsigned char *) str[i])].freq;
+
+  qsort (pfxfreq, 256, sizeof (struct charfreq), compare_freq);
+
+  size_t n = 0;
+  while (n < 256 && pfxfreq[n].freq != 0)
+    ++n;
+  return n;
+}
+
+
+struct strsnlen
+{
+  const char *str;
+  size_t len;
+};
+
+static size_t
+compute_sfxfreq (size_t nstr, struct strsnlen *strsnlen)
+{
+  memset (sfxfreq, '\0', sizeof (sfxfreq));
+
+  for (size_t i = 0; i < nstr; ++i)
+    sfxfreq[i].ch = i;
+
+  for (size_t i = 0; i < nstr; ++i)
+    ++sfxfreq[((const unsigned char *) strchrnul (strsnlen[i].str, '\0'))[-1]].freq;
+
+  qsort (sfxfreq, 256, sizeof (struct charfreq), compare_freq);
+
+  size_t n = 0;
+  while (n < 256 && sfxfreq[n].freq != 0)
+    ++n;
+  return n;
+}
+
+
+static void
+create_mnemonic_table (void)
+{
+  mnemonic_strs = xmalloc (nmnemonics * sizeof (char *));
+
+  twalk (mnemonics, add_mnemonics);
+
+  (void) which_chars (mnemonic_strs, nmnemonic_strs);
+
+  size_t best_so_far = 100000000;
+  char *best_prefix = NULL;
+  char *best_suffix = NULL;
+  char *best_table = NULL;
+  size_t best_table_size = 0;
+  size_t best_table_bits = 0;
+  size_t best_prefix_bits = 0;
+
+  /* We can precompute the prefix characters.  */
+  size_t npfx_char = compute_pfxfreq (mnemonic_strs, nmnemonic_strs);
+
+  /* Compute best size for string representation including explicit NUL.  */
+  for (size_t pfxbits = 0; (1u << pfxbits) < 2 * npfx_char; ++pfxbits)
+    {
+      char prefix[1 << pfxbits];
+      size_t i;
+      for (i = 0; i < (1u << pfxbits) - 1; ++i)
+       prefix[i] = pfxfreq[i].ch;
+      prefix[i] = '\0';
+
+      struct strsnlen strsnlen[nmnemonic_strs];
+
+      for (i = 0; i < nmnemonic_strs; ++i)
+       {
+         if (strchr (prefix, *mnemonic_strs[i]) != NULL)
+           strsnlen[i].str = mnemonic_strs[i] + 1;
+         else
+           strsnlen[i].str = mnemonic_strs[i];
+         strsnlen[i].len = strlen (strsnlen[i].str);
+       }
+
+      /* With the prefixes gone, try to combine strings.  */
+      size_t nstrsnlen = 1;
+      for (i = 1; i < nmnemonic_strs; ++i)
+       {
+         size_t j;
+         for (j = 0; j < nstrsnlen; ++j)
+           if (strsnlen[i].len > strsnlen[j].len
+               && strcmp (strsnlen[j].str,
+                          strsnlen[i].str + (strsnlen[i].len
+                                             - strsnlen[j].len)) == 0)
+             {
+               strsnlen[j] = strsnlen[i];
+               break;
+             }
+           else if (strsnlen[i].len < strsnlen[j].len
+                    && strcmp (strsnlen[i].str,
+                               strsnlen[j].str + (strsnlen[j].len
+                                                  - strsnlen[i].len)) == 0)
+             break;
+;
+         if (j == nstrsnlen)
+             strsnlen[nstrsnlen++] = strsnlen[i];
+       }
+
+      size_t nsfx_char = compute_sfxfreq (nstrsnlen, strsnlen);
+
+      for (size_t sfxbits = 0; (1u << sfxbits) < 2 * nsfx_char; ++sfxbits)
+       {
+         char suffix[1 << sfxbits];
+
+         for (i = 0; i < (1u << sfxbits) - 1; ++i)
+           suffix[i] = sfxfreq[i].ch;
+         suffix[i] = '\0';
+
+         size_t newlen[nstrsnlen];
+
+         for (i = 0; i < nstrsnlen; ++i)
+           if (strchr (suffix, strsnlen[i].str[strsnlen[i].len - 1]) != NULL)
+             newlen[i] = strsnlen[i].len - 1;
+           else
+             newlen[i] = strsnlen[i].len;
+
+         char charused[256];
+         memset (charused, '\0', sizeof (charused));
+         size_t ncharused = 0;
+
+         const char *tablestr[nstrsnlen];
+         size_t ntablestr = 1;
+         tablestr[0] = strsnlen[0].str;
+         size_t table = newlen[0] + 1;
+         for (i = 1; i < nstrsnlen; ++i)
+           {
+             size_t j;
+             for (j = 0; j < ntablestr; ++j)
+               if (newlen[i] > newlen[j]
+                   && memcmp (tablestr[j],
+                              strsnlen[i].str + (newlen[i] - newlen[j]),
+                              newlen[j]) == 0)
+                 {
+                   table += newlen[i] - newlen[j];
+                   tablestr[j] = strsnlen[i].str;
+                   newlen[j] = newlen[i];
+                   break;
+                 }
+               else if (newlen[i] < newlen[j]
+                    && memcmp (strsnlen[i].str,
+                               tablestr[j] + (newlen[j] - newlen[i]),
+                               newlen[i]) == 0)
+                 break;
+
+             if (j == ntablestr)
+               {
+                 table += newlen[i] + 1;
+                 tablestr[ntablestr] = strsnlen[i].str;
+                 newlen[ntablestr] = newlen[i];
+
+                 ++ntablestr;
+               }
+
+             for (size_t x = 0; x < newlen[j]; ++x)
+               if (charused[((const unsigned char *) tablestr[j])[x]]++ == 0)
+                 ++ncharused;
+           }
+
+         size_t ncharused_bits = 0;
+         i = 1;
+         while (i < ncharused)
+           {
+             i *= 2;
+             ++ncharused_bits;
+           }
+
+         size_t table_bits = 0;
+         i = 1;
+         while (i < table)
+           {
+             i *= 2;
+             ++table_bits;
+           }
+
+         size_t mnemonic_bits = table_bits + pfxbits + sfxbits;
+         size_t new_total = (((table + 7) / 8) * ncharused_bits + ncharused
+                             + (pfxbits == 0 ? 0 : (1 << pfxbits) - 1)
+                             + (sfxbits == 0 ? 0 : (1 << sfxbits) - 1)
+                             + (((total_bits + mnemonic_bits + 7) / 8)
+                                * ninstructions));
+
+         if (new_total < best_so_far)
+           {
+             best_so_far = new_total;
+             best_mnemonic_bits = mnemonic_bits;
+
+             free (best_suffix);
+             best_suffix = xstrdup (suffix);
+
+             free (best_prefix);
+             best_prefix = xstrdup (prefix);
+             best_prefix_bits = pfxbits;
+
+             best_table_size = table;
+             best_table_bits = table_bits;
+             char *cp = best_table = xrealloc (best_table, table);
+             for (i = 0; i < ntablestr; ++i)
+               {
+                 assert (cp + newlen[i] + 1 <= best_table + table);
+                 cp = mempcpy (cp, tablestr[i], newlen[i]);
+                 *cp++ = '\0';
+               }
+             assert (cp == best_table + table);
+           }
+       }
+    }
+
+  fputs ("static const char mnemonic_table[] =\n\"", outfile);
+  for (size_t i = 0; i < best_table_size; ++i)
+    {
+      if (((i + 1) % 60) == 0)
+       fputs ("\"\n\"", outfile);
+      if (!isascii (best_table[i]) || !isprint (best_table[i]))
+       fprintf (outfile, "\\%03o", best_table[i]);
+      else
+       fputc (best_table[i], outfile);
+    }
+  fputs ("\";\n", outfile);
+
+  if (best_prefix[0] != '\0')
+    fprintf (outfile,
+            "static const char prefix[%zu] = \"%s\";\n"
+            "#define PREFIXCHAR_BITS %zu\n",
+            strlen (best_prefix), best_prefix, best_prefix_bits);
+  else
+    fputs ("#define NO_PREFIX\n", outfile);
+
+  if (best_suffix[0] != '\0')
+    fprintf (outfile, "static const char suffix[%zu] = \"%s\";\n",
+            strlen (best_suffix), best_suffix);
+  else
+    fputs ("#define NO_SUFFIX\n", outfile);
+
+  for (size_t i = 0; i < nmnemonic_strs; ++i)
+    {
+      const char *mne = mnemonic_strs[i];
+
+      size_t pfxval = 0;
+      char *cp = strchr (best_prefix, *mne);
+      if (cp != NULL)
+       {
+         pfxval = 1 + (cp - best_prefix);
+         ++mne;
+       }
+
+      size_t l = strlen (mne);
+
+      size_t sfxval = 0;
+      cp = strchr (best_suffix, mne[l - 1]);
+      if (cp != NULL)
+       {
+         sfxval = 1 + (cp - best_suffix);
+         --l;
+       }
+
+      char *off = memmem (best_table, best_table_size, mne, l);
+      while (off[l] != '\0')
+       {
+         off = memmem (off + 1, best_table_size, mne, l);
+         assert (off != NULL);
+       }
+
+      fprintf (outfile, "#define MNE_%s %#zx\n",
+              mnemonic_strs[i],
+              (off - best_table)
+              + ((pfxval + (sfxval << best_prefix_bits)) << best_table_bits));
+    }
+}
+#endif
diff --git a/libcpu/memory-access.h b/libcpu/memory-access.h
new file mode 100644 (file)
index 0000000..0d61f48
--- /dev/null
@@ -0,0 +1,168 @@
+/* Unaligned memory access functionality.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifndef _MEMORY_ACCESS_H
+#define _MEMORY_ACCESS_H 1
+
+#include <byteswap.h>
+#include <endian.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+/* When loading this file we require the macro MACHINE_ENCODING to be
+   defined to signal the endianness of the architecture which is
+   defined.  */
+#ifndef MACHINE_ENCODING
+# error "MACHINE_ENCODING needs to be defined"
+#endif
+#if MACHINE_ENCODING != __BIG_ENDIAN && MACHINE_ENCODING != __LITTLE_ENDIAN
+# error "MACHINE_ENCODING must signal either big or little endian"
+#endif
+
+
+/* We use simple memory access functions in case the hardware allows it.
+   The caller has to make sure we don't have alias problems.  */
+#if ALLOW_UNALIGNED
+
+# define read_2ubyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? bswap_16 (*((const uint16_t *) (Addr)))                                 \
+   : *((const uint16_t *) (Addr)))
+# define read_2sbyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? (int16_t) bswap_16 (*((const int16_t *) (Addr)))                        \
+   : *((const int16_t *) (Addr)))
+
+# define read_4ubyte_unaligned_noncvt(Addr) \
+   *((const uint32_t *) (Addr))
+# define read_4ubyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? bswap_32 (*((const uint32_t *) (Addr)))                                 \
+   : *((const uint32_t *) (Addr)))
+# define read_4sbyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))                        \
+   : *((const int32_t *) (Addr)))
+
+# define read_8ubyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? bswap_64 (*((const uint64_t *) (Addr)))                                 \
+   : *((const uint64_t *) (Addr)))
+# define read_8sbyte_unaligned(Addr) \
+  (unlikely (MACHINE_ENCODING != __BYTE_ORDER)                               \
+   ? (int64_t) bswap_64 (*((const int64_t *) (Addr)))                        \
+   : *((const int64_t *) (Addr)))
+
+#else
+
+union unaligned
+  {
+    void *p;
+    uint16_t u2;
+    uint32_t u4;
+    uint64_t u8;
+    int16_t s2;
+    int32_t s4;
+    int64_t s8;
+  } __attribute__ ((packed));
+
+static inline uint16_t
+read_2ubyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return bswap_16 (up->u2);
+  return up->u2;
+}
+static inline int16_t
+read_2sbyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return (int16_t) bswap_16 (up->u2);
+  return up->s2;
+}
+
+static inline uint32_t
+read_4ubyte_unaligned_noncvt (const void *p)
+{
+  const union unaligned *up = p;
+  return up->u4;
+}
+static inline uint32_t
+read_4ubyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return bswap_32 (up->u4);
+  return up->u4;
+}
+static inline int32_t
+read_4sbyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return (int32_t) bswap_32 (up->u4);
+  return up->s4;
+}
+
+static inline uint64_t
+read_8ubyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return bswap_64 (up->u8);
+  return up->u8;
+}
+static inline int64_t
+read_8sbyte_unaligned (const void *p)
+{
+  const union unaligned *up = p;
+  if (MACHINE_ENCODING != __BYTE_ORDER)
+    return (int64_t) bswap_64 (up->u8);
+  return up->s8;
+}
+
+#endif /* allow unaligned */
+
+
+#define read_2ubyte_unaligned_inc(Addr) \
+  ({ uint16_t t_ = read_2ubyte_unaligned (Addr);                             \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                    \
+     t_; })
+#define read_2sbyte_unaligned_inc(Addr) \
+  ({ int16_t t_ = read_2sbyte_unaligned (Addr);                                      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                    \
+     t_; })
+
+#define read_4ubyte_unaligned_inc(Addr) \
+  ({ uint32_t t_ = read_4ubyte_unaligned (Addr);                             \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                    \
+     t_; })
+#define read_4sbyte_unaligned_inc(Addr) \
+  ({ int32_t t_ = read_4sbyte_unaligned (Addr);                                      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                    \
+     t_; })
+
+#define read_8ubyte_unaligned_inc(Addr) \
+  ({ uint64_t t_ = read_8ubyte_unaligned (Addr);                             \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                    \
+     t_; })
+#define read_8sbyte_unaligned_inc(Addr) \
+  ({ int64_t t_ = read_8sbyte_unaligned (Addr);                                      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                    \
+     t_; })
+
+#endif /* memory-access.h */
diff --git a/libcpu/x86_64_disasm.c b/libcpu/x86_64_disasm.c
new file mode 100644 (file)
index 0000000..f6ae795
--- /dev/null
@@ -0,0 +1,5 @@
+#define i386_disasm x86_64_disasm
+#define DISFILE "x86_64_dis.h"
+#define MNEFILE "x86_64.mnemonics"
+#define X86_64
+#include "i386_disasm.c"
index 993800c..2cf570e 100644 (file)
@@ -34,7 +34,7 @@ AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 \
             -std=gnu99
 
 INCLUDES = -I$(srcdir) -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw \
-          -I$(top_srcdir)/lib -I..
+          -I$(top_srcdir)/lib -I.. -I$(srcdir)/../libasm
 VERSION = 1
 PACKAGE_VERSION = @PACKAGE_VERSION@
 LIBEBL_SUBDIR = @LIBEBL_SUBDIR@
index d466a1f..c0c929b 100644 (file)
@@ -148,6 +148,11 @@ ssize_t EBLHOOK(register_info) (Ebl *ebl,
                                const char **prefix, const char **setname,
                                int *bits, int *type);
 
+  /* Disassembler function.  */
+int EBLHOOK(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);
+
 
 /* Destructor for ELF backend handle.  */
 void EBLHOOK(destr) (struct ebl *);
index 63e64a1..8a44f90 100644 (file)
@@ -246,6 +246,7 @@ fill_defaults (Ebl *result)
   result->bss_plt_p = default_bss_plt_p;
   result->return_value_location = default_return_value_location;
   result->register_info = default_register_info;
+  result->disasm = NULL;
   result->destr = default_destr;
   result->sysvhash_entrysize = sizeof (Elf32_Word);
 }
index 7bb4c37..7bfa650 100644 (file)
@@ -51,6 +51,7 @@
 #define _LIBEBLP_H 1
 
 #include <gelf.h>
+#include <libasm.h>
 #include <libebl.h>
 #include <libintl.h>
 
index 57a40d9..daa78e4 100644 (file)
@@ -1,3 +1,14 @@
+2007-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile.am (libelf_a_SOURCES): Add elf_scnshndx.
+       * libelfP.h (struct Elf_Scn): Add shndx_index field.
+       Declare __elf_scnshndx_internal.
+       * elf32_getshdr.c: Record location of extended section header.
+       * elf_begin.c (file_read_elf): Likewise.
+       * elf_scnshndx.c: New file.
+       * libelf.h: Declare elf_scnshndx.
+       * libelf.map: Add elf_scnshndx to version ELFUTILS_1.4.
+
 2007-11-12  Roland McGrath  <roland@redhat.com>
 
        * libelf.h: Replace off64_t with loff_t throughout.
index 58c9b5a..3cb858d 100644 (file)
@@ -99,7 +99,8 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \
                   gelf_getlib.c gelf_update_lib.c \
                   elf32_offscn.c elf64_offscn.c gelf_offscn.c \
                   elf_getaroff.c \
-                  elf_gnu_hash.c
+                  elf_gnu_hash.c \
+                  elf_scnshndx.c
 
 if !MUDFLAP
 libelf_pic_a_SOURCES =
index cafb1d4..c7f75bb 100644 (file)
@@ -165,6 +165,20 @@ elfw2(LIBELFBITS,getshdr) (scn)
                  CONVERT_TO (shdr[cnt].sh_addralign,
                              notcvt[cnt].sh_addralign);
                  CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
+
+                 /* If this is a section with an extended index add a
+                    reference in the section which uses the extended
+                    index.  */
+                 if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
+                     && shdr[cnt].sh_link < shnum)
+                   elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
+                     = cnt;
+
+                 /* Set the own shndx_index field in case it has not yet
+                    been set.  */
+                 if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
+                   elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
+                     = -1;
                }
            }
        }
index 13f965f..d84f904 100644 (file)
@@ -327,6 +327,19 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
                ((char *) map_address + offset
                 + elf->state.elf32.shdr[cnt].sh_offset);
              elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
+
+             /* If this is a section with an extended index add a
+                reference in the section which uses the extended
+                index.  */
+             if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
+                 && elf->state.elf32.shdr[cnt].sh_link < scncnt)
+               elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
+                 = cnt;
+
+             /* Set the own shndx_index field in case it has not yet
+                been set.  */
+             if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
+               elf->state.elf32.scns.data[cnt].shndx_index = -1;
            }
        }
       else
@@ -402,6 +415,19 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
                ((char *) map_address + offset
                 + elf->state.elf64.shdr[cnt].sh_offset);
              elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
+
+             /* If this is a section with an extended index add a
+                reference in the section which uses the extended
+                index.  */
+             if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
+                 && elf->state.elf64.shdr[cnt].sh_link < scncnt)
+               elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
+                 = cnt;
+
+             /* Set the own shndx_index field in case it has not yet
+                been set.  */
+             if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
+               elf->state.elf64.scns.data[cnt].shndx_index = -1;
            }
        }
       else
diff --git a/libelf/elf_scnshndx.c b/libelf/elf_scnshndx.c
new file mode 100644 (file)
index 0000000..987d23e
--- /dev/null
@@ -0,0 +1,71 @@
+/* Get the section index of the extended section index table.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Contributed 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.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   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 "libelfP.h"
+
+
+int
+elf_scnshndx (Elf_Scn *scn)
+{
+  if (unlikely (scn->shndx_index == 0))
+    {
+      /* We do not have the value yet.  We get it as a side effect of
+        getting a section header.  */
+      GElf_Shdr shdr_mem;
+      (void) INTUSE(gelf_getshdr) (scn, &shdr_mem);
+    }
+
+  return scn->shndx_index;
+}
+INTDEF(elf_scnshndx)
index 90a588e..5427122 100644 (file)
@@ -248,6 +248,10 @@ extern Elf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn);
 /* Create a new section and append it at the end of the table.  */
 extern Elf_Scn *elf_newscn (Elf *__elf);
 
+/* Get the section index of the extended section index table for the
+   given symbol table.  */
+extern int elf_scnshndx (Elf_Scn *__scn);
+
 /* Get the number of sections in the ELF file.  If the file uses more
    sections than can be represented in the e_shnum field of the ELF
    header the information from the sh_size field in the zeroth section
index aaaf916..c253777 100644 (file)
@@ -122,4 +122,9 @@ ELFUTILS_1.3 {
     gelf_getauxv;
     gelf_update_auxv;
     gelf_getnote;
-};
+} ELFUTILS_1.2;
+
+ELFUTILS_1.4 {
+  global:
+    elf_scnshndx;
+} ELFUTILS_1.3;
index 7e6305c..5e3d57c 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal interfaces for libelf.
-   Copyright (C) 1998,1999,2000,2001,2002,2003,2005,2006,2007 Red Hat, Inc.
+   Copyright (C) 1998-2003, 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
 
@@ -224,6 +224,9 @@ struct Elf_Scn
   int data_read;               /* Nonzero if the section was created by the
                                   user or if the data from the file/memory
                                   is read.  */
+  int shndx_index;             /* Index of the extended section index
+                                  table for this symbol table (if this
+                                  section is a symbol table).  */
 
   size_t index;                        /* Index of this section.  */
   struct Elf *elf;             /* The underlying ELF file.  */
@@ -532,6 +535,7 @@ extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index)
      attribute_hidden;
 extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn)
      attribute_hidden;
+extern int __elf_scnshndx_internal (Elf_Scn *__scn) attribute_hidden;
 extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data)
      attribute_hidden;
 extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data)
index 3107b2f..79ce2e8 100644 (file)
        * strip.c: Likewise.
        * unstrip.c: Likewise.
 
+2007-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * objdump (show_disasm): Use %e after third parameter.
+
+2007-12-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * strip.c: Fix wrong parenthesis in a few branch predictions.
+       * strings.c: Likewise.
+
+2007-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile.am (DEFS): Add DEBUGPRED.
+       * addr2line.c: Include debugpred.h.
+       * ar.c: Likewise.
+       * elfcmp.c: Likewise.
+       * elflint.c: Likewise.
+       * findtextrel.c: Likewise.
+       * nm.c: Likewise.
+       * objdump.c: Likewise.
+       * ranlib.c: Likewise.
+       * readelf.c: Likewise.
+       * size.c: Likewise.
+       * strings.c: Likewise.
+       * strip.c: Likewise.
+       * unstrip.c: Likewise.
+       * debugpred.h: New file.
+
+       * readelf.c (handle_relocs_rel): Use elf_scnshndx.
+       (handle_relocs_rela): Likewise.
+
+       * readelf.c: Add lots of likely/unlikely.
+
+       * elflint.c: Minor cleanups.
+
 2007-11-19  Roland McGrath  <roland@redhat.com>
 
        * readelf.c (print_ops): Handle all bad op codes gracefully.
index 138be5a..f72bb45 100644 (file)
@@ -24,7 +24,7 @@
 ## Network licensing program, please visit www.openinventionnetwork.com
 ## <http://www.openinventionnetwork.com>.
 ##
-DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) \
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) -DDEBUGPRED=@DEBUGPRED@ \
        -DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\"
 if MUDFLAP
 AM_CFLAGS = -fmudflap
@@ -38,7 +38,7 @@ AM_CFLAGS += -Wall -Wshadow -std=gnu99 $(native_ld_cflags) \
 
 INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
           -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl \
-          -I$(srcdir)/../lib -I..
+          -I$(srcdir)/../libasm -I$(srcdir)/../lib -I..
 
 AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw
 
@@ -81,7 +81,8 @@ libar_a_SOURCES = arlib.c arlib2.c
 noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \
                 ldscript.h xelf.h unaligned.h
 
-EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) arlib.h
+EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) arlib.h \
+            debugpred.h
 ld_modules = i386_ld.c
 
 bin_SCRIPTS = make-debug-archive
@@ -93,9 +94,11 @@ libmudflap = -lmudflap
 endif
 
 if BUILD_STATIC
+libasm = ../libasm/libasm.a
 libdw = ../libdw/libdw.a $(libelf) $(libebl) -ldl
 libelf = ../libelf/libelf.a
 else
+libasm = ../libasm/libasm.so
 libdw = ../libdw/libdw.so
 libelf = ../libelf/libelf.so
 endif
@@ -122,7 +125,7 @@ elflint_LDADD  = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
 findtextrel_LDADD = $(libdw) $(libelf) $(libmudflap)
 addr2line_LDADD = $(libdw) $(libmudflap)
 elfcmp_LDADD = $(libebl) $(libelf) $(libmudflap) -ldl
-objdump_LDADD  = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
+objdump_LDADD  = $(libasm) $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
 ranlib_LDADD = libar.a $(libelf) $(libeu) $(libmudflap)
 strings_LDADD = $(libelf) $(libeu) $(libmudflap)
 ar_LDADD = libar.a $(libelf) $(libeu) $(libmudflap)
index 5e0c2da..4b1d13e 100644 (file)
@@ -373,3 +373,6 @@ handle_address (GElf_Addr addr, Dwfl *dwfl)
   else
     puts ("??:0");
 }
+
+
+#include "debugpred.h"
index 8d3b91a..aade351 100644 (file)
--- a/src/ar.c
+++ b/src/ar.c
@@ -1513,3 +1513,6 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
 
   return status;
 }
+
+
+#include "debugpred.h"
diff --git a/src/debugpred.h b/src/debugpred.h
new file mode 100644 (file)
index 0000000..867f4ac
--- /dev/null
@@ -0,0 +1,53 @@
+/* Support to debug branch prediction.
+   Copyright (C) 2007 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 <stdio.h>
+
+#if DEBUGPRED
+extern const unsigned long int __start_predict_data;
+extern const unsigned long int __stop_predict_data;
+extern const unsigned long int __start_predict_line;
+extern const char *__start_predict_file;
+
+static void
+__attribute__ ((destructor))
+predprint (void)
+{
+  const unsigned long int *s = &__start_predict_data;
+  const unsigned long int *e = &__stop_predict_data;
+  const unsigned long int *sl = &__start_predict_line;
+  const char **sf = &__start_predict_file;
+  while (s < e)
+    {
+      if (s[0] != 0 || s[1] != 0)
+       printf ("%s:%lu: wrong=%lu, correct=%lu%s\n", *sf, *sl, s[0], s[1],
+               s[0] > s[1] ? "   <==== WARNING" : "");
+      ++sl;
+      ++sf;
+      s += 2;
+    }
+}
+#endif
index cbc8cd8..be9aacc 100644 (file)
@@ -744,3 +744,6 @@ hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
 
   return false;
 }
+
+
+#include "debugpred.h"
index 0121832..85b2495 100644 (file)
@@ -579,11 +579,10 @@ check_symtab (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
           idx, section_name (ebl, idx));
 
   /* Search for an extended section index table section.  */
-  size_t cnt;
   Elf_Data *xndxdata = NULL;
   Elf32_Word xndxscnidx = 0;
   bool found_xndx = false;
-  for (cnt = 1; cnt < shnum; ++cnt)
+  for (size_t cnt = 1; cnt < shnum; ++cnt)
     if (cnt != (size_t) idx)
       {
        Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt);
@@ -608,8 +607,8 @@ section [%2d] '%s': symbol table cannot have more than one extended index sectio
 
   if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
     ERROR (gettext ("\
-section [%2zu] '%s': entry size is does not match ElfXX_Sym\n"),
-          cnt, section_name (ebl, cnt));
+section [%2u] '%s': entry size is does not match ElfXX_Sym\n"),
+          idx, section_name (ebl, idx));
 
   /* Test the zeroth entry.  */
   GElf_Sym sym_mem;
@@ -644,7 +643,7 @@ section [%2d] '%s': XINDEX for zeroth entry not zero\n"),
               xndxscnidx, section_name (ebl, xndxscnidx));
     }
 
-  for (cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
+  for (size_t cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
     {
       sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx);
       if (sym == NULL)
@@ -3958,3 +3957,6 @@ process_elf_file (Elf *elf, const char *prefix, const char *suffix,
   /* Free the resources.  */
   ebl_closebackend (ebl);
 }
+
+
+#include "debugpred.h"
index d2de3a6..245db7f 100644 (file)
@@ -606,3 +606,6 @@ a relocation modifies memory at offset %llu in a write-protected segment\n"),
        break;
       }
 }
+
+
+#include "debugpred.h"
index aae938e..bede0e8 100644 (file)
--- a/src/ld.c
+++ b/src/ld.c
@@ -1525,3 +1525,6 @@ create_special_section_symbol (struct symbol **symp, const char *name)
 
   ++ld_state.nsymtab;
 }
+
+
+#include "debugpred.h"
index 6ddae61..1bef49f 100644 (file)
--- a/src/nm.c
+++ b/src/nm.c
@@ -1294,3 +1294,6 @@ handle_elf (Elf *elf, const char *prefix, const char *fname,
 
   return result;
 }
+
+
+#include "debugpred.h"
index 8c62ee2..92ab84f 100644 (file)
@@ -681,12 +681,87 @@ show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
 }
 
 
+struct disasm_info
+{
+  GElf_Addr addr;
+  const uint8_t *cur;
+  const uint8_t *last_end;
+};
+
+
+// XXX This is not the preferred output for all architectures.  Needs
+// XXX customization, too.
 static int
-show_disasm (Ebl *ebl __attribute__ ((unused)),
-            const char *fname __attribute__ ((unused)),
-            uint32_t shstrndx __attribute__ ((unused)))
+disasm_output (char *buf, size_t buflen, void *arg)
 {
-  /// XXX For now nothing.
+  struct disasm_info *info = (struct disasm_info *) arg;
+
+  printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
+  size_t cnt;
+  for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
+    printf (" %02" PRIx8, info->last_end[cnt]);
+  printf ("%*s %.*s\n",
+         (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
+
+  info->addr += cnt;
+
+  /* We limit the number of bytes printed before the mnemonic to 8.
+     Print the rest on a separate, following line.  */
+  if (info->cur - info->last_end > 8)
+    {
+      printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
+      for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
+       printf (" %02" PRIx8, info->last_end[cnt]);
+      putchar_unlocked ('\n');
+      info->addr += info->cur - info->last_end - 8;
+    }
+
+  info->last_end = info->cur;
+
+  return 0;
+}
+
+
+static int
+show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
+{
+  DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
+  if (ctx == NULL)
+    error (EXIT_FAILURE, 0, gettext ("cannot disassemble"));
+
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+      if (shdr == NULL)
+       INTERNAL_ERROR (fname);
+
+      if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
+         && (shdr->sh_flags & SHF_EXECINSTR) != 0)
+       {
+         if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
+           continue;
+
+         Elf_Data *data = elf_getdata (scn, NULL);
+         if (data == NULL)
+           continue;
+
+         printf ("Disassembly of section %s:\n\n",
+                 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
+
+         struct disasm_info info;
+         info.addr = shdr->sh_addr;
+         info.last_end = info.cur = data->d_buf;
+
+         disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
+                    "%7m%e %.1o%e,%.2o%e,%.3o%e", disasm_output, &info,
+                    NULL /* XXX */);
+       }
+    }
+
+  (void) disasm_end (ctx);
 
   return 0;
 }
@@ -735,3 +810,6 @@ handle_elf (Elf *elf, const char *prefix, const char *fname,
 
   return result;
 }
+
+
+#include "debugpred.h"
index f82b4f9..a915e55 100644 (file)
@@ -304,3 +304,6 @@ handle_file (const char *fname)
 
   return status;
 }
+
+
+#include "debugpred.h"
index 0a55562..d65f810 100644 (file)
@@ -535,7 +535,7 @@ process_file (int fd, const char *fname, bool only_one)
       struct stat64 st;
       if (fstat64 (fd, &st) != 0)
        error (0, errno, gettext ("cannot stat input file"));
-      else if (st.st_size == 0)
+      else if (unlikely (st.st_size == 0))
        error (0, 0, gettext ("input file is empty"));
       else
        error (0, 0, gettext ("failed reading '%s': %s"),
@@ -575,7 +575,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
     }
 
   Ebl *ebl = ebl_openbackend (elf);
-  if (ebl == NULL)
+  if (unlikely (ebl == NULL))
     {
     ebl_error:
       error (0, errno, gettext ("cannot create EBL handle"));
@@ -583,7 +583,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
     }
 
   /* Determine the number of sections.  */
-  if (elf_getshnum (ebl->elf, &shnum) < 0)
+  if (unlikely (elf_getshnum (ebl->elf, &shnum) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot determine number of sections: %s"),
           elf_errmsg (-1));
@@ -665,7 +665,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
 static void
 print_file_type (unsigned short int e_type)
 {
-  if (e_type <= ET_CORE)
+  if (likely (e_type <= ET_CORE))
     {
       static const char *const knowntypes[] =
       {
@@ -764,7 +764,7 @@ print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
     }
   fputc_unlocked ('\n', stdout);
 
-  if (ehdr->e_shstrndx == SHN_XINDEX)
+  if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
     {
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
@@ -820,7 +820,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
            ehdr->e_shnum, ehdr->e_shoff);
 
   /* Get the section header string table index.  */
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -835,14 +835,14 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
     {
       Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
 
-      if (scn == NULL)
+      if (unlikely (scn == NULL))
        error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
               elf_errmsg (-1));
 
       /* Get the section header.  */
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-      if (shdr == NULL)
+      if (unlikely (shdr == NULL))
        error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
               elf_errmsg (-1));
 
@@ -920,7 +920,7 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
 
       /* If for some reason the header cannot be returned show this.  */
-      if (phdr == NULL)
+      if (unlikely (phdr == NULL))
        {
          puts ("  ???");
          continue;
@@ -959,7 +959,7 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -973,7 +973,7 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
       GElf_Phdr phdr_mem;
       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
       /* This must not happen.  */
-      if (phdr == NULL)
+      if (unlikely (phdr == NULL))
        error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
               elf_errmsg (-1));
 
@@ -984,14 +984,14 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
        {
          Elf_Scn *scn = elf_getscn (ebl->elf, inner);
          /* This should not happen.  */
-         if (scn == NULL)
+         if (unlikely (scn == NULL))
            error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
                   elf_errmsg (-1));
 
          /* Get the section header.  */
          GElf_Shdr shdr_mem;
          GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-         if (shdr == NULL)
+         if (unlikely (shdr == NULL))
            error (EXIT_FAILURE, 0,
                   gettext ("cannot get section header: %s"),
                   elf_errmsg (-1));
@@ -1100,7 +1100,7 @@ handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -1282,7 +1282,7 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
     return;
 
   /* Get the section header string table index.  */
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -1431,7 +1431,7 @@ print_relocs (Ebl *ebl)
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
-      if (shdr != NULL)
+      if (likely (shdr != NULL))
        {
          if (shdr->sh_type == SHT_REL)
            handle_relocs_rel (ebl, scn, shdr);
@@ -1465,7 +1465,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
                                      &destshdr_mem);
 
-  if (symshdr == NULL || symdata == NULL || destshdr == NULL)
+  if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
     {
       printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
              shdr->sh_offset);
@@ -1473,24 +1473,14 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
     }
 
   /* Search for the optional extended section index table.  */
-  Elf_Scn *xndxscn = NULL;
   Elf_Data *xndxdata = NULL;
-  while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
-    {
-      GElf_Shdr xndxshdr_mem;
-      GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
-      if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
-         && xndxshdr->sh_link == elf_ndxscn (symscn))
-       {
-         /* Found it.  */
-         xndxdata = elf_getdata (xndxscn, NULL);
-         break;
-       }
-    }
+  int xndxscnidx = elf_scnshndx (scn);
+  if (unlikely (xndxscnidx > 0))
+    xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -1530,7 +1520,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
     {
       GElf_Rel relmem;
       GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
-      if (rel != NULL)
+      if (likely (rel != NULL))
        {
          char buf[128];
          GElf_Sym symmem;
@@ -1538,7 +1528,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
                                            GELF_R_SYM (rel->r_info),
                                            &symmem, &xndx);
-         if (sym == NULL)
+         if (unlikely (sym == NULL))
            printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
                    class == ELFCLASS32 ? 10 : 18, rel->r_offset,
                    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1552,7 +1542,8 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
            printf ("  %#0*" PRIx64 "  %-20s %#0*" PRIx64 "  %s\n",
                    class == ELFCLASS32 ? 10 : 18, rel->r_offset,
-                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   likely (ebl_reloc_type_check (ebl,
+                                                 GELF_R_TYPE (rel->r_info)))
                    /* Avoid the leading R_ which isn't carrying any
                       information.  */
                    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
@@ -1567,7 +1558,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                                   ? xndx : sym->st_shndx),
                                       &destshdr_mem);
 
-             if (destshdr == NULL)
+             if (unlikely (destshdr == NULL))
                printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
                        class == ELFCLASS32 ? 10 : 18, rel->r_offset,
                        ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1619,7 +1610,7 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
                                      &destshdr_mem);
 
-  if (symshdr == NULL || symdata == NULL || destshdr == NULL)
+  if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
     {
       printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
              shdr->sh_offset);
@@ -1628,23 +1619,13 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Search for the optional extended section index table.  */
   Elf_Data *xndxdata = NULL;
-  Elf_Scn *xndxscn = NULL;
-  while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
-    {
-      GElf_Shdr xndxshdr_mem;
-      GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
-      if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
-         && xndxshdr->sh_link == elf_ndxscn (symscn))
-       {
-         /* Found it.  */
-         xndxdata = elf_getdata (xndxscn, NULL);
-         break;
-       }
-    }
+  int xndxscnidx = elf_scnshndx (scn);
+  if (unlikely (xndxscnidx > 0))
+    xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -1670,7 +1651,7 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
     {
       GElf_Rela relmem;
       GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
-      if (rel != NULL)
+      if (likely (rel != NULL))
        {
          char buf[64];
          GElf_Sym symmem;
@@ -1679,7 +1660,7 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                            GELF_R_SYM (rel->r_info),
                                            &symmem, &xndx);
 
-         if (sym == NULL)
+         if (unlikely (sym == NULL))
            printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
                    class == ELFCLASS32 ? 10 : 18, rel->r_offset,
                    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1694,7 +1675,8 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
            printf ("\
   %#0*" PRIx64 "  %-15s %#0*" PRIx64 "  %+6" PRId64 " %s\n",
                    class == ELFCLASS32 ? 10 : 18, rel->r_offset,
-                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   likely (ebl_reloc_type_check (ebl,
+                                                 GELF_R_TYPE (rel->r_info)))
                    /* Avoid the leading R_ which isn't carrying any
                       information.  */
                    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
@@ -1710,7 +1692,7 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                                   ? xndx : sym->st_shndx),
                                       &destshdr_mem);
 
-             if (shdr == NULL)
+             if (unlikely (shdr == NULL))
                printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
                        class == ELFCLASS32 ? 10 : 18, rel->r_offset,
                        ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1784,7 +1766,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       GElf_Shdr runshdr_mem;
       GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
 
-      if (runshdr != NULL)
+      if (likely (runshdr != NULL))
        {
          if (runshdr->sh_type == SHT_GNU_versym
              && runshdr->sh_link == elf_ndxscn (scn))
@@ -1811,7 +1793,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -1851,11 +1833,11 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       GElf_Sym sym_mem;
       GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
 
-      if (sym == NULL)
+      if (unlikely (sym == NULL))
        continue;
 
       /* Determine the real section index.  */
-      if (sym->st_shndx != SHN_XINDEX)
+      if (likely (sym->st_shndx != SHN_XINDEX))
        xndx = sym->st_shndx;
 
       printf (gettext ("\
@@ -1945,7 +1927,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                              (unsigned int) vernaux->vna_other);
                      check_def = 0;
                    }
-                 else if (! is_nobits)
+                 else if (unlikely (! is_nobits))
                    error (0, 0, gettext ("bad dynamic symbol"));
                  else
                    check_def = 1;
@@ -2008,7 +1990,7 @@ print_verinfo (Ebl *ebl)
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
-      if (shdr != NULL)
+      if (likely (shdr != NULL))
        {
          if (shdr->sh_type == SHT_GNU_verneed)
            handle_verneed (ebl, scn, shdr);
@@ -2043,7 +2025,7 @@ get_ver_flags (unsigned int flags)
       endp = stpcpy (endp, "WEAK ");
     }
 
-  if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK))
+  if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
     {
       strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
       buf[sizeof (buf) - 1] = '\0';
@@ -2065,7 +2047,7 @@ handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -2090,7 +2072,7 @@ handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       /* Get the data at the next offset.  */
       GElf_Verneed needmem;
       GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
-      if (need == NULL)
+      if (unlikely (need == NULL))
        break;
 
       printf (gettext ("  %#06x: Version: %hu  File: %s  Cnt: %hu\n"),
@@ -2103,7 +2085,7 @@ handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
        {
          GElf_Vernaux auxmem;
          GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
-         if (aux == NULL)
+         if (unlikely (aux == NULL))
            break;
 
          printf (gettext ("  %#06x: Name: %s  Flags: %s  Version: %hu\n"),
@@ -2131,7 +2113,7 @@ handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -2158,13 +2140,13 @@ handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       /* Get the data at the next offset.  */
       GElf_Verdef defmem;
       GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
-      if (def == NULL)
+      if (unlikely (def == NULL))
        break;
 
       unsigned int auxoffset = offset + def->vd_aux;
       GElf_Verdaux auxmem;
       GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
-      if (aux == NULL)
+      if (unlikely (aux == NULL))
        break;
 
       printf (gettext ("\
@@ -2179,7 +2161,7 @@ handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
        {
          aux = gelf_getverdaux (data, auxoffset, &auxmem);
-         if (aux == NULL)
+         if (unlikely (aux == NULL))
            break;
 
          printf (gettext ("  %#06x: Parent %d: %s\n"),
@@ -2209,7 +2191,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -2224,7 +2206,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
       GElf_Shdr vershdr_mem;
       GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
 
-      if (vershdr != NULL)
+      if (likely (vershdr != NULL))
        {
          if (vershdr->sh_type == SHT_GNU_verdef)
            defscn = verscn;
@@ -2249,11 +2231,11 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          GElf_Shdr *defshdr;
 
          defdata = elf_getdata (defscn, NULL);
-         if (defdata == NULL)
+         if (unlikely (defdata == NULL))
            return;
 
          defshdr = gelf_getshdr (defscn, &defshdrmem);
-         if (defshdr == NULL)
+         if (unlikely (defshdr == NULL))
            return;
 
          for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
@@ -2263,7 +2245,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
              /* Get the data at the next offset.  */
              def = gelf_getverdef (defdata, offset, &defmem);
-             if (def == NULL)
+             if (unlikely (def == NULL))
                break;
 
              nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
@@ -2279,11 +2261,11 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          GElf_Shdr *needshdr;
 
          needdata = elf_getdata (needscn, NULL);
-         if (needdata == NULL)
+         if (unlikely (needdata == NULL))
            return;
 
          needshdr = gelf_getshdr (needscn, &needshdrmem);
-         if (needshdr == NULL)
+         if (unlikely (needshdr == NULL))
            return;
 
          for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
@@ -2295,7 +2277,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
              /* Get the data at the next offset.  */
              need = gelf_getverneed (needdata, offset, &needmem);
-             if (need == NULL)
+             if (unlikely (need == NULL))
                break;
 
              /* Run through the auxiliary entries.  */
@@ -2306,7 +2288,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                  GElf_Vernaux *aux;
 
                  aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
-                 if (aux == NULL)
+                 if (unlikely (aux == NULL))
                    break;
 
                  nvername = MAX (nvername,
@@ -2337,11 +2319,11 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          GElf_Shdr *defshdr;
 
          defdata = elf_getdata (defscn, NULL);
-         if (defdata == NULL)
+         if (unlikely (defdata == NULL))
            return;
 
          defshdr = gelf_getshdr (defscn, &defshdrmem);
-         if (defshdr == NULL)
+         if (unlikely (defshdr == NULL))
            return;
 
          for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
@@ -2354,7 +2336,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
              GElf_Verdaux *aux = gelf_getverdaux (defdata,
                                                   offset + def->vd_aux,
                                                   &auxmem);
-             if (def == NULL || aux == NULL)
+             if (unlikely (def == NULL || aux == NULL))
                break;
 
              vername[def->vd_ndx & 0x7fff]
@@ -2371,7 +2353,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
          Elf_Data *needdata = elf_getdata (needscn, NULL);
          GElf_Shdr needshdrmem;
          GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
-         if (needdata == NULL || needshdr == NULL)
+         if (unlikely (needdata == NULL || needshdr == NULL))
            return;
 
          for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
@@ -2380,7 +2362,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
              GElf_Verneed needmem;
              GElf_Verneed *need = gelf_getverneed (needdata, offset,
                                                    &needmem);
-             if (need == NULL)
+             if (unlikely (need == NULL))
                break;
 
              /* Run through the auxiliary entries.  */
@@ -2390,7 +2372,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                  GElf_Vernaux auxmem;
                  GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
                                                       &auxmem);
-                 if (aux == NULL)
+                 if (unlikely (aux == NULL))
                    break;
 
                  vername[aux->vna_other & 0x7fff]
@@ -2499,7 +2481,7 @@ print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
   if (extrastr != NULL)
     fputs (extrastr, stdout);
 
-  if (nbucket > 0)
+  if (likely (nbucket > 0))
     {
       uint64_t success = 0;
 
@@ -2541,7 +2523,7 @@ static void
 handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 {
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL)
+  if (unlikely (data == NULL))
     {
       error (0, 0, gettext ("cannot get data for section %d: %s"),
             (int) elf_ndxscn (scn), elf_errmsg (-1));
@@ -2583,7 +2565,7 @@ static void
 handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 {
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL)
+  if (unlikely (data == NULL))
     {
       error (0, 0, gettext ("cannot get data for section %d: %s"),
             (int) elf_ndxscn (scn), elf_errmsg (-1));
@@ -2624,7 +2606,7 @@ static void
 handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 {
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL)
+  if (unlikely (data == NULL))
     {
       error (0, 0, gettext ("cannot get data for section %d: %s"),
             (int) elf_ndxscn (scn), elf_errmsg (-1));
@@ -2680,13 +2662,15 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
     }
 
   char *str;
-  if (asprintf (&str, gettext ("\
+  if (unlikely (asprintf (&str, gettext ("\
  Symbol Bias: %u\n\
  Bitmask Size: %zu bytes  %" PRIuFAST32 "%% bits set  2nd hash shift: %u\n"),
-               (unsigned int) symbias, bitmask_words * sizeof (Elf32_Word),
-               ((nbits * 100 + 50)
-                / (uint_fast32_t) (bitmask_words * sizeof (Elf32_Word) * 8)),
-               (unsigned int) shift) == -1)
+                         (unsigned int) symbias,
+                         bitmask_words * sizeof (Elf32_Word),
+                         ((nbits * 100 + 50)
+                          / (uint_fast32_t) (bitmask_words
+                                             * sizeof (Elf32_Word) * 8)),
+                         (unsigned int) shift) == -1))
     error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
 
   print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
@@ -2704,7 +2688,7 @@ handle_hash (Ebl *ebl)
 {
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -2715,7 +2699,7 @@ handle_hash (Ebl *ebl)
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
-      if (shdr != NULL)
+      if (likely (shdr != NULL))
        {
          if (shdr->sh_type == SHT_HASH)
            {
@@ -2740,7 +2724,7 @@ print_liblist (Ebl *ebl)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -2773,12 +2757,12 @@ print_liblist (Ebl *ebl)
            {
              GElf_Lib lib_mem;
              GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
-             if (lib == NULL)
+             if (unlikely (lib == NULL))
                continue;
 
              time_t t = (time_t) lib->l_time_stamp;
              struct tm *tm = gmtime (&t);
-             if (tm == NULL)
+             if (unlikely (tm == NULL))
                continue;
 
              printf ("  [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
@@ -2936,10 +2920,10 @@ dwarf_tag_string (unsigned int tag)
   static char buf[40];
   const char *result = NULL;
 
-  if (tag < nknown_tags)
+  if (likely (tag < nknown_tags))
     result = known_tags[tag];
 
-  if (result == NULL)
+  if (unlikely (result == NULL))
     /* There are a few known extensions.  */
     switch (tag)
       {
@@ -3072,10 +3056,10 @@ dwarf_attr_string (unsigned int attrnum)
   static char buf[40];
   const char *result = NULL;
 
-  if (attrnum < nknown_attrs)
+  if (likely (attrnum < nknown_attrs))
     result = known_attrs[attrnum];
 
-  if (result == NULL)
+  if (unlikely (result == NULL))
     /* There are a few known extensions.  */
     switch (attrnum)
       {
@@ -3218,10 +3202,10 @@ dwarf_form_string (unsigned int form)
   static char buf[40];
   const char *result = NULL;
 
-  if (form < nknown_forms)
+  if (likely (form < nknown_forms))
     result = known_forms[form];
 
-  if (result == NULL)
+  if (unlikely (result == NULL))
     snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64),
              (uint64_t) form);
 
@@ -3255,7 +3239,7 @@ dwarf_lang_string (unsigned int lang)
       [DW_LANG_D] = "D",
     };
 
-  if (lang < sizeof (known) / sizeof (known[0]))
+  if (likely (lang < sizeof (known) / sizeof (known[0])))
     return known[lang];
   else if (lang == DW_LANG_Mips_Assembler)
     /* This language tag is used for assembler in general.  */
@@ -3283,7 +3267,7 @@ dwarf_inline_string (unsigned int code)
       [DW_INL_declared_inlined] = "declared_inlined"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3313,7 +3297,7 @@ dwarf_encoding_string (unsigned int code)
       [DW_ATE_decimal_float] = "decimal_float",
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   if (code >= DW_ATE_lo_user && code <= DW_ATE_hi_user)
@@ -3337,7 +3321,7 @@ dwarf_access_string (unsigned int code)
       [DW_ACCESS_private] = "private"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3354,7 +3338,7 @@ dwarf_visibility_string (unsigned int code)
       [DW_VIS_qualified] = "qualified"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3371,7 +3355,7 @@ dwarf_virtuality_string (unsigned int code)
       [DW_VIRTUALITY_pure_virtual] = "pure_virtual"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3389,7 +3373,7 @@ dwarf_identifier_case_string (unsigned int code)
       [DW_ID_case_insensitive] = "insensitive"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3406,7 +3390,7 @@ dwarf_calling_convention_string (unsigned int code)
       [DW_CC_nocall] = "nocall",
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   if (code >= DW_CC_lo_user && code <= DW_CC_hi_user)
@@ -3429,7 +3413,7 @@ dwarf_ordering_string (unsigned int code)
       [DW_ORD_col_major] = "col_major"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3445,7 +3429,7 @@ dwarf_discr_list_string (unsigned int code)
       [DW_DSC_range] = "range"
     };
 
-  if (code < sizeof (known) / sizeof (known[0]))
+  if (likely (code < sizeof (known) / sizeof (known[0])))
     return known[code];
 
   return "???";
@@ -3828,7 +3812,7 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
          int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
          if (res != 0)
            {
-             if (res < 0)
+             if (unlikely (res < 0))
                {
                  printf (gettext ("\
  *** error while reading abbreviation: %s\n"),
@@ -3884,7 +3868,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 {
   Dwarf_Aranges *aranges;
   size_t cnt;
-  if (dwarf_getaranges (dbg, &aranges, &cnt) != 0)
+  if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
     {
       error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
             dwarf_errmsg (-1));
@@ -3910,7 +3894,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
   for (size_t n = 0; n < cnt; ++n)
     {
       Dwarf_Arange *runp = dwarf_onearange (aranges, n);
-      if (runp == NULL)
+      if (unlikely (runp == NULL))
        {
          printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
          return;
@@ -3920,7 +3904,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
       Dwarf_Word length;
       Dwarf_Off offset;
 
-      if (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0)
+      if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
        printf (gettext (" [%*zu] ???\n"), digits, n);
       else
        printf (gettext (" [%*zu] start: %0#*" PRIx64
@@ -3940,7 +3924,7 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
 {
   Elf_Data *data = elf_rawdata (scn, NULL);
 
-  if (data == NULL)
+  if (unlikely (data == NULL))
     {
       error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
             elf_errmsg (-1));
@@ -3959,7 +3943,7 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
     {
       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
 
-      if (data->d_size - offset < address_size * 2)
+      if (unlikely (data->d_size - offset < address_size * 2))
        {
          printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
          break;
@@ -4291,7 +4275,7 @@ print_debug_info_section (Dwfl_Module *dwflmod,
   do
     {
       offset = dwarf_dieoffset (&dies[level]);
-      if (offset == ~0ul)
+      if (unlikely (offset == ~0ul))
        {
          error (0, 0, gettext ("cannot get DIE offset: %s"),
                 dwarf_errmsg (-1));
@@ -4299,7 +4283,7 @@ print_debug_info_section (Dwfl_Module *dwflmod,
        }
 
       int tag = dwarf_tag (&dies[level]);
-      if (tag == DW_TAG_invalid)
+      if (unlikely (tag == DW_TAG_invalid))
        {
          error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
                                " in section '%s': %s"),
@@ -4328,7 +4312,7 @@ print_debug_info_section (Dwfl_Module *dwflmod,
            if (level-- == 0)
              break;
 
-         if (res == -1)
+         if (unlikely (res == -1))
            {
              error (0, 0, gettext ("cannot get next DIE: %s\n"),
                     dwarf_errmsg (-1));
@@ -4370,7 +4354,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
   /* There is no functionality in libdw to read the information in the
      way it is represented here.  Hardcode the decoder.  */
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL || data->d_buf == NULL)
+  if (unlikely (data == NULL || data->d_buf == NULL))
     {
       error (0, 0, gettext ("cannot get line data section data: %s"),
             elf_errmsg (-1));
@@ -4483,7 +4467,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
       while (*linep != 0)
        {
          unsigned char *endp = memchr (linep, '\0', lineendp - linep);
-         if (endp == NULL)
+         if (unlikely (endp == NULL))
            goto invalid_unit;
 
          printf (" %s\n", (char *) linep);
@@ -4502,7 +4486,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
          /* First comes the file name.  */
          char *fname = (char *) linep;
          unsigned char *endp = memchr (fname, '\0', lineendp - linep);
-         if (endp == NULL)
+         if (unlikely (endp == NULL))
            goto invalid_unit;
          linep = endp + 1;
 
@@ -4635,7 +4619,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
                    char *fname = (char *) linep;
                    unsigned char *endp = memchr (linep, '\0',
                                                  lineendp - linep);
-                   if (endp == NULL)
+                   if (unlikely (endp == NULL))
                      goto invalid_unit;
                    linep = endp + 1;
 
@@ -4801,7 +4785,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
 {
   Elf_Data *data = elf_rawdata (scn, NULL);
 
-  if (data == NULL)
+  if (unlikely (data == NULL))
     {
       error (0, 0, gettext ("cannot get .debug_loc content: %s"),
             elf_errmsg (-1));
@@ -4820,7 +4804,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
     {
       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
 
-      if (data->d_size - offset < address_size * 2)
+      if (unlikely (data->d_size - offset < address_size * 2))
        {
          printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
          break;
@@ -4911,7 +4895,7 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
   /* There is no function in libdw to iterate over the raw content of
      the section but it is easy enough to do.  */
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL || data->d_buf == NULL)
+  if (unlikely (data == NULL || data->d_buf == NULL))
     {
       error (0, 0, gettext ("cannot get macro information section data: %s"),
             elf_errmsg (-1));
@@ -4990,7 +4974,7 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
          get_uleb128 (u128, readp);
 
          endp = memchr (readp, '\0', readendp - readp);
-         if (endp == NULL)
+         if (unlikely (endp == NULL))
            {
              printf (gettext ("\
 %*s*** non-terminated string at end of section"),
@@ -5045,7 +5029,7 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 
        default:
          // XXX gcc seems to generate files with a trailing zero.
-         if (opcode != 0 || readp != readendp)
+         if (unlikely (opcode != 0 || readp != readendp))
            printf ("%*s*** invalid opcode %u\n", level, "", opcode);
          break;
        }
@@ -5112,7 +5096,7 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
     {
       size_t len;
       const char *str = dwarf_getstring (dbg, offset, &len);
-      if (str == NULL)
+      if (unlikely (str == NULL))
        {
          printf (gettext (" *** error while reading strings: %s\n"),
                  dwarf_errmsg (-1));
@@ -5140,7 +5124,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
 
   /* Get the section header string table index.  */
   size_t shstrndx;
-  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+  if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
@@ -6052,7 +6036,7 @@ for_each_section_argument (Elf *elf, const struct section_argument *list,
     {
       Elf_Scn *scn;
       GElf_Shdr shdr_mem;
-      const char *name;
+      const char *name = NULL;
 
       char *endp = NULL;
       unsigned long int shndx = strtoul (a->arg, &endp, 0);
@@ -6085,7 +6069,7 @@ for_each_section_argument (Elf *elf, const struct section_argument *list,
                break;
            }
 
-         if (scn == NULL)
+         if (unlikely (scn == NULL))
            {
              error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
              continue;
@@ -6186,3 +6170,5 @@ dump_archive_index (Elf *elf, const char *fname)
       printf ("\t%s\n", s->as_name);
     }
 }
+
+#include "debugpred.h"
index 825f3e9..d226f40 100644 (file)
@@ -685,3 +685,6 @@ handle_elf (Elf *elf, const char *prefix, const char *fname)
       show_bsd (elf, prefix, fname, fullname);
     }
 }
+
+
+#include "debugpred.h"
index b9c559b..b210996 100644 (file)
@@ -422,13 +422,13 @@ process_chunk (const char *fname, const unsigned char *buf, off64_t to,
          if (curlen >= min_len)
            {
              /* We found a match.  */
-             if (unlikely (fname != NULL))
+             if (likely (fname != NULL))
                {
                  fputs_unlocked (fname, stdout);
                  fputs_unlocked (": ", stdout);
                }
 
-             if (unlikely (locfmt != NULL))
+             if (likely (locfmt != NULL))
                printf (locfmt, (int64_t) to - len - (buf - start));
 
              if (unlikely (*unprinted != NULL))
@@ -739,3 +739,6 @@ read_elf (Elf *elf, int fd, const char *fname, off64_t fdlen)
 
   return result;
 }
+
+
+#include "debugpred.h"
index 7858e8b..1e61911 100644 (file)
@@ -843,7 +843,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          if (discard_section)
            debugshdr.sh_type = SHT_NOBITS;
 
-         if (unlikely (gelf_update_shdr (scn, &debugshdr)) == 0)
+         if (unlikely (gelf_update_shdr (scn, &debugshdr) == 0))
            /* There cannot be any overflows.  */
            INTERNAL_ERROR (fname);
 
@@ -881,7 +881,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       debugehdr->e_flags = ehdr->e_flags;
       debugehdr->e_shstrndx = ehdr->e_shstrndx;
 
-      if (unlikely (gelf_update_ehdr (debugelf, debugehdr)) == 0)
+      if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0))
        {
          error (0, 0, gettext ("%s: error while creating ELF header: %s"),
                 debug_fname, elf_errmsg (-1));
@@ -1547,7 +1547,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        };
 
       /* Finally write the file.  */
-      if (unlikely (elf_update (debugelf, ELF_C_WRITE)) == -1)
+      if (unlikely (elf_update (debugelf, ELF_C_WRITE) == -1))
        {
          error (0, 0, gettext ("while writing '%s': %s"),
                 debug_fname, elf_errmsg (-1));
@@ -1772,3 +1772,6 @@ cannot set access and modification date of '%s'"), fname);
 
   return result;
 }
+
+
+#include "debugpred.h"
index 53ea3b8..676a0c7 100644 (file)
@@ -2312,3 +2312,6 @@ or - if no debuginfo was found, or . if FILE contains the debug information.\
 
   return 0;
 }
+
+
+#include "debugpred.h"
index 888f156..2c7ed91 100644 (file)
@@ -1,3 +1,52 @@
+2008-01-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.expect.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.expect.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.expect.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.expect.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.S.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.S.bz2: New tests.
+       * testfile44.expect.bz2: Adjust.
+
+2007-12-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.S.bz2: New tests.
+       * testfile44.expect.bz2: Adjust
+
+2007-12-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * testfile44.S.bz2: More tests.
+       * testfile44.expect.bz2: Adjust appropriately.
+
+2007-12-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile.am (TESTS): Add run-disasm.sh.
+       (EXTRA_DIST): Add run-disasm.sh, testfile44.S.bz2, and
+       testfile44.expect.bz2.
+       * run-disasm.sh: New file.
+       * testfile44.S.bz2: New file.
+       * testfile44.expect.bz2: New file.
+
 2007-12-15  Roland McGrath  <roland@redhat.com>
 
        * run-allregs.sh: Change expected output for powerpc spefscr.
index 4556078..25631e3 100644 (file)
@@ -83,7 +83,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-native-test.sh run-bug1-test.sh \
        dwfl-bug-addr-overflow run-addrname-test.sh \
        dwfl-bug-fd-leak dwfl-bug-report \
-       run-dwfl-bug-offline-rel.sh run-dwfl-addr-sect.sh
+       run-dwfl-bug-offline-rel.sh run-dwfl-addr-sect.sh \
+       run-disasm.sh
 # run-show-ciefde.sh
 
 if !STANDALONE
@@ -133,7 +134,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile36.bz2 testfile36.debug.bz2 \
             testfile37.bz2 testfile37.debug.bz2 \
             testfile38.bz2 testfile39.bz2 testfile40.bz2 testfile40.debug.bz2 \
-            testfile41.bz2 testfile42.bz2 testfile43.bz2
+            testfile41.bz2 testfile42.bz2 testfile43.bz2 \
+            testfile44.S.bz2 testfile44.expect.bz2 run-disasm.sh
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
                              bindir=$(DESTDIR)$(bindir) \
diff --git a/tests/run-disasm.sh b/tests/run-disasm.sh
new file mode 100755 (executable)
index 0000000..efbb81f
--- /dev/null
@@ -0,0 +1,36 @@
+#! /bin/sh
+# Copyright (C) 2007 Red Hat, Inc.
+# This file is part of Red Hat elfutils.
+#
+# Red Hat elfutils is free software; you can redistribute it and/or modify
+# 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>.
+
+. $srcdir/test-subr.sh
+
+# Run x86 test.
+case "$(arch)" in
+  x86_64 | i?86 )
+    tempfiles testfile44.o
+    testfiles testfile44.S testfile44.expect
+    gcc -m32 -c -o testfile44.o testfile44.S
+    testrun_compare ../src/objdump -d testfile44.o < testfile44.expect
+    ;;
+esac
diff --git a/tests/testfile44.S.bz2 b/tests/testfile44.S.bz2
new file mode 100644 (file)
index 0000000..30b0770
Binary files /dev/null and b/tests/testfile44.S.bz2 differ
diff --git a/tests/testfile44.expect.bz2 b/tests/testfile44.expect.bz2
new file mode 100644 (file)
index 0000000..6e0d653
Binary files /dev/null and b/tests/testfile44.expect.bz2 differ