Initial version. AMD64 only, and only as far as 0x16.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 13 Oct 2020 18:49:43 +0000 (19:49 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 13 Oct 2020 18:49:43 +0000 (19:49 +0100)
Makefile [new file with mode: 0644]
main.c [new file with mode: 0644]
xchg.S [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ca069ff
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+### -*-makefile-*-
+
+V                       = 0
+vcond                   = $(call vcond_$V,$1,$2)
+vcond_0                         = $1
+vcond_1                         = $2
+V_AT                    = $(call vcond,@)
+vtag                    = \
+       $(call vcond,@printf "  %-8s %s\n" "$1" "$(or $2,$@)";)
+
+CC                      = gcc -m64
+CFLAGS                  = -O2 -g -Wall -Werror
+
+AS                      = gcc -m64
+ASFLAGS                         = -O2 -g
+
+LD                      = gcc -m64
+LDFLAGS                         =
+
+%.o: %.c
+       $(call vtag,CC)$(CC) -c -o $@ $(CFLAGS) $<
+
+%.o: %.S
+       $(call vtag,AS)$(AS) -c -o $@ $(ASFLAGS) $<
+
+all:: xchg
+xchg: xchg.o main.o
+       $(call vtag,LD)$(LD) -o $@ $^
+
+clean::; rm -f xchg *.o
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..9ab4c2e
--- /dev/null
+++ b/main.c
@@ -0,0 +1,313 @@
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+union reg {
+  unsigned char *p;
+  long i;
+  long u;
+};
+
+struct regs {
+  union reg
+    a, b, c, d, si, di, bp, f,
+    r8, r9, r10, r11, r12, r13, r14, r15;
+};
+
+struct seg {
+  unsigned char *p;
+  size_t sz;
+};
+
+#define N(v) (sizeof(v)/sizeof((v)[0]))
+
+#define CTYPE_HACK(func, ch) func((unsigned char)(ch))
+#define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
+#define ISSPACE(ch) CTYPE_HACK(isspace, ch)
+
+#define XCHG(_)                                                                \
+  _(x00) _(x01) _(x02) _(x03) _(x04) _(x05) _(x06) _(x07)              \
+  _(x08) _(x09) _(x0a) _(x0b) _(x0c) _(x0d) _(x0e) _(x0f)              \
+  _(x10) _(x11) _(x12) _(x13) _(x14) _(x15) _(x16) _(x17)              \
+  _(x18) _(x19) _(x1a) _(x1b) _(x1c) _(x1d) _(x1e) _(x1f)              \
+  _(x20) _(x21) _(x22) _(x23) _(x24) _(x25) _(x26) _(x27)              \
+  _(x28) _(x29) _(x2a) _(x2b) _(x2c) _(x2d) _(x2e) _(x2f)              \
+  _(x30) _(x31) _(x32) _(x33) _(x34) _(x35) _(x36) _(x37)              \
+  _(x38) _(x39) _(x3a) _(x3b) _(x3c) _(x3d) _(x3e) _(x3f)
+
+#define DECL(x) extern const int x;
+XCHG(DECL)
+extern const int nop;
+
+static const int *x[] = {
+#define SLOT(x) &x,
+  XCHG(SLOT)
+};
+
+extern void call_example(const int *f, struct regs *r);
+
+static const char *prog = "???";
+
+__attribute__((format(printf, 1, 2), noreturn))
+static void barf(const char *m, ...)
+{
+  va_list ap;
+
+  va_start(ap, m);
+  fprintf(stderr, "%s: ", prog);
+  vfprintf(stderr, m, ap);
+  putc('\n', stderr);
+  va_end(ap);
+  exit(127);
+}
+
+static void *xmalloc(size_t sz)
+{
+  void *p;
+
+  if (!sz) return (0);
+  p = malloc(sz);
+  if (!p) barf("malloc failed");
+  return (p);
+}
+
+#define DEF_PARSEINT(name, ty, strto)                                  \
+  static ty parse_##name(const char *what, const char *p, ty min, ty max) \
+  {                                                                    \
+    const char *pp = p;                                                        \
+    char *q;                                                           \
+    ty i;                                                              \
+    int err;                                                           \
+                                                                       \
+    if (ISSPACE(*p)) goto bad;                                         \
+    err = errno; errno = 0;                                            \
+    i = strto(p, &q, 0);                                               \
+    if (errno) goto bad;                                               \
+    if (*q) goto bad;                                                  \
+    if (i < min || i > max) goto bad;                                  \
+    errno = err;                                                       \
+    return (i);                                                                \
+                                                                       \
+  bad:                                                                 \
+    barf("bad %s `%s'", what, pp);                                     \
+  }
+DEF_PARSEINT(long, long, strtol)
+DEF_PARSEINT(ulong, unsigned long, strtoul)
+
+static int hex_digit(char ch)
+{
+  if ('0' <= ch && ch <= '9') return (ch - '0');
+  else if ('A' <= ch && ch <= 'F') return (ch - 'A' + 10);
+  else if ('a' <= ch && ch <= 'f') return (ch - 'a' + 10);
+  else return (-1);
+}
+
+static void setreg(union reg *r,
+                  struct seg **seg_inout,
+                  int *i_inout, int argc, char *argv[])
+{
+  struct seg *seg;
+  const char *p, *pp;
+  unsigned char *q;
+  int hi, lo;
+  size_t n;
+
+#define LONG_REG(p) (parse_long("signed register", (p), LONG_MIN, LONG_MAX))
+#define ULONG_REG(p) (parse_ulong("unsigned register", (p), 0, ULONG_MAX))
+
+  p = *i_inout >= argc ? "-" : argv[(*i_inout)++];
+  switch (*p) {
+    case '-':
+      if (p[1]) r->i = LONG_REG(p);
+      else r->u = 0xdeadbeefdeadbeef;
+      break;
+    case 'i':
+      if (p[1] != ':') goto bad;
+      r->i = LONG_REG(p + 2);
+      break;
+    case 'u':
+      if (p[1] != ':') goto bad;
+      r->u = ULONG_REG(p + 2);
+      break;
+    case 'c':
+      if (p[1] != ':' || p[3]) goto bad;
+      r->u = p[2];
+      break;
+    case 's':
+      if (p[1] != ':') goto bad;
+      pp = p + 2; n = strlen(pp) + 1;
+      seg = (*seg_inout)++; seg->p = xmalloc(n); seg->sz = n;
+      memcpy(seg->p, pp, n); r->p = seg->p;
+      break;
+    case 'm':
+      if (p[1] != ':') goto bad;
+      pp = p + 2; n = strlen(pp); if (n%2) goto bad;
+      seg = (*seg_inout)++; seg->p = q = xmalloc(n/2); seg->sz = n/2;
+      while (n) {
+       hi = hex_digit(pp[0]); lo = hex_digit(pp[1]);
+       if (hi < 0 || lo < 0) goto bad;
+       *q++ = 16*hi + lo; n -= 2; pp += 2;
+      }
+      r->p = seg->p;
+      break;
+    default:
+      if (ISDIGIT(*p)) r->u = ULONG_REG(p);
+      else if (*p == '+') r->i = LONG_REG(p);
+      else if (*p == '\'' && p[2] == '\'' && !p[3]) r->u = p[1];
+      else goto bad;
+      break;
+    bad:
+      barf("bad regspec `%s'", p);
+  }
+
+#undef LONG_REG
+#undef ULONG_REG
+}
+
+static void dumpreg(const char *name, const union reg *r,
+                   const struct seg *seg, size_t nseg)
+{
+  size_t i;
+
+  printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u);
+  if (r->u >= ' ' && r->u <= '~') printf(" = '%c'", (int)r->u);
+  for (i = 0; i < nseg; i++) {
+    if (r->p == seg[i].p)
+      printf(" = seg[%zu] base", i);
+    else if (r->p == seg[i].p + seg[i].sz)
+      printf(" = seg[%zu] limit", i);
+    else if (seg[i].p < r->p && r->p < seg[i].p + seg[i].sz)
+      printf(" = seg[%zu] + %zu", i, (size_t)(r->p - seg[i].p));
+  }
+  putchar('\n');
+}
+
+static void dumpseg(const struct seg *seg)
+{
+  size_t i, j;
+  unsigned char ch;
+
+  for (i = 0; i < seg->sz; i += 8) {
+    printf("\t%8zx :", i);
+    for (j = 0; j < 8; j++)
+      if (i + j >= seg->sz) printf(" **");
+      else printf(" %02x", seg->p[i + j]);
+    printf(" : ");
+    for (j = 0; j < 8; j++)
+      if (i + j >= seg->sz) putchar('*');
+      else {
+       ch = seg->p[i + j];
+       if (' ' <= ch && ch <= '~') putchar(ch);
+       else putchar('.');
+      }
+    putchar('\n');
+  }
+}
+
+int main(int argc, char *argv[])
+{
+  struct regs r;
+  struct seg seg[16], *segp = seg;
+  size_t nseg;
+  int i, j;
+
+  prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0];
+
+  if (argc < 2)
+    barf("usage: %s I [A B C D SI DI BP R8 R9 R10 R11 R12 R13 R14 R15 F]",
+        prog);
+
+  j = parse_long("program index", argv[1], -1, N(x) - 1);
+
+  i = 2;
+  setreg(&r.a, &segp, &i, argc, argv);
+  setreg(&r.b, &segp, &i, argc, argv);
+  setreg(&r.c, &segp, &i, argc, argv);
+  setreg(&r.d, &segp, &i, argc, argv);
+  setreg(&r.si, &segp, &i, argc, argv);
+  setreg(&r.di, &segp, &i, argc, argv);
+  setreg(&r.bp, &segp, &i, argc, argv);
+  setreg(&r.r8, &segp, &i, argc, argv);
+  setreg(&r.r9, &segp, &i, argc, argv);
+  setreg(&r.r10, &segp, &i, argc, argv);
+  setreg(&r.r11, &segp, &i, argc, argv);
+  setreg(&r.r12, &segp, &i, argc, argv);
+  setreg(&r.r13, &segp, &i, argc, argv);
+  setreg(&r.r14, &segp, &i, argc, argv);
+  setreg(&r.r15, &segp, &i, argc, argv);
+  setreg(&r.f, &segp, &i, argc, argv);
+  nseg = segp - seg;
+
+  call_example(j < 0 ? &nop : x[j], &r);
+
+  dumpreg("rax", &r.a, seg, nseg);
+  dumpreg("rbx", &r.b, seg, nseg);
+  dumpreg("rcx", &r.c, seg, nseg);
+  dumpreg("rdx", &r.d, seg, nseg);
+  dumpreg("rsi", &r.si, seg, nseg);
+  dumpreg("rdi", &r.di, seg, nseg);
+  dumpreg("rbp", &r.bp, seg, nseg);
+  dumpreg("rbp", &r.bp, seg, nseg);
+  dumpreg("r8", &r.r8, seg, nseg);
+  dumpreg("r9", &r.r9, seg, nseg);
+  dumpreg("r10", &r.r10, seg, nseg);
+  dumpreg("r11", &r.r11, seg, nseg);
+  dumpreg("r12", &r.r12, seg, nseg);
+  dumpreg("r13", &r.r13, seg, nseg);
+  dumpreg("r14", &r.r14, seg, nseg);
+  dumpreg("r15", &r.r15, seg, nseg);
+
+#define CF (1 <<  0)
+#define PF (1 <<  2)
+#define ZF (1 <<  6)
+#define SF (1 <<  7)
+#define OF (1 << 11)
+
+  dumpreg("f", &r.f, seg, nseg);
+  printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
+        (r.f.u >>  0)&1u ? '+' : '-',
+        (r.f.u >>  2)&1u ? '+' : '-',
+        (r.f.u >>  4)&1u ? '+' : '-',
+        (r.f.u >>  6)&1u ? '+' : '-',
+        (r.f.u >>  7)&1u ? '+' : '-',
+        (r.f.u >> 10)&1u ? '+' : '-',
+        (r.f.u >> 11)&1u ? '+' : '-');
+  printf("\tcond:");
+  if (r.f.u&CF) printf(" c/b/nae"); else printf(" nc/ae/nb");
+  if (r.f.u&ZF) printf(" e/z"); else printf(" ne/nz");
+  if (r.f.u&SF) printf(" s"); else printf(" ns");
+  if (r.f.u&OF) printf(" o"); else printf(" no");
+  if (r.f.u&PF) printf(" p"); else printf(" np");
+  if ((r.f.u&CF) || (r.f.u&ZF)) printf(" be/na"); else printf(" a/nbe");
+  if (!(r.f.u&OF) == !(r.f.u&SF)) printf(" ge/nl"); else printf(" l/nge");
+  if (!(r.f.u&OF) == !(r.f.u&SF) && !(r.f.u&ZF))
+    printf(" g/nle"); else printf(" le/ng");
+  putchar('\n');
+  printf("\tsystem: %ctf %cif iopl=%d %cnt "
+                       "%crf %cvm %cac %cvif %cvip %cid\n",
+        (r.f.u >>  8)&1u ? '+' : '-',
+        (r.f.u >>  9)&1u ? '+' : '-',
+        (int)((r.f.u >> 12)&1u),
+        (r.f.u >> 14)&1u ? '+' : '-',
+        (r.f.u >> 16)&1u ? '+' : '-',
+        (r.f.u >> 17)&1u ? '+' : '-',
+        (r.f.u >> 18)&1u ? '+' : '-',
+        (r.f.u >> 19)&1u ? '+' : '-',
+        (r.f.u >> 20)&1u ? '+' : '-',
+        (r.f.u >> 21)&1u ? '+' : '-');
+
+#undef CF
+#undef PF
+#undef ZF
+#undef SF
+#undef OF
+
+  for (i = 0; i < nseg; i++)
+    { printf("seg[%d] (%p):\n", i, seg[i].p); dumpseg(&seg[i]); }
+
+  return (0);
+}
diff --git a/xchg.S b/xchg.S
new file mode 100644 (file)
index 0000000..5374727
--- /dev/null
+++ b/xchg.S
@@ -0,0 +1,745 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+
+       .intel_syntax noprefix
+
+       .section .note.GNU-stack, "", @progbits
+
+.macro proc    name
+       .globl  \name
+       .type   \name, STT_FUNC
+       .p2align 4
+\name\():
+  .macro endproc
+       .size   \name, . - \name
+       .purgem endproc
+  .endm
+.endm
+
+.macro ch c
+       pushf
+       push    rax
+       push    rcx
+       push    rdx
+       push    rsi
+       push    rdi
+       push    r8
+       push    r9
+       push    rbp
+       mov     rbp, rsp
+       and     rsp, -16
+
+       mov     rdi, \c
+       call    putchar@plt
+
+       mov     rdi, [rip + stdout]
+       call    fflush@plt
+
+       mov     rsp, rbp
+       pop     rbp
+       pop     r9
+       pop     r8
+       pop     rdi
+       pop     rsi
+       pop     rdx
+       pop     rcx
+       pop     rax
+       popf
+.endm
+
+       .text
+
+proc   call_example
+
+       push    rbx                     // rbx
+       push    r10
+       push    r11
+       push    r12
+       push    r13
+       push    r14
+       push    r15
+       push    rbp                     // flags, rbp, ..., rbx
+       pushf
+
+       push    rsi                     // regs, flags, rbp, ..., rbx
+
+       lea     rax, [rip + 9f]
+       push    rax                     // cont, regs, flags, rbp, ..., rbx
+       push    rdi                 // func, cont, regs, flags, rbp, ..., rbx
+
+       mov     rax, [rsi + 56]
+       pushf
+       pop     rcx
+       and     rax,  0x0cd5
+       and     rcx, ~0x0cd5
+       or      rax, rcx
+       push    rax
+       popf
+       mov     rax, [rsi +  0]
+       mov     rbx, [rsi +  8]
+       mov     rcx, [rsi + 16]
+       mov     rdx, [rsi + 24]
+       mov     rdi, [rsi + 40]
+       mov     rbp, [rsi + 48]
+       mov     rsi, [rsi + 32]
+
+       ret                            // -> func; regs, flags, rbp, ..., rbx
+
+9:     pushf                           // rflags, regs, flags, rbp, ..., rbx
+       push    rsi                // rsi, rflags, regs, flags, rbp, ..., rbx
+       mov     rsi, [rsp + 16]
+       mov     [rsi +  0], rax
+       mov     [rsi +  8], rbx
+       mov     [rsi + 16], rcx
+       mov     [rsi + 24], rdx
+       mov     [rsi + 40], rdi
+       mov     [rsi + 48], rbp
+       pop     rax                     // rflags, regs, flags, rbp, ..., rbx
+       mov     [rsi + 32], rax
+       pop     rax                     // regs, flags, rbp, ..., rbx
+       mov     [rsi + 56], rax
+
+       add     rsp, 8                  // flags, rbp, ..., rbx
+       popf                            // rbp, ..., rbx
+       pop     rbp                     // ..., rbx
+       pop     r15
+       pop     r14
+       pop     r13
+       pop     r12
+       pop     r11
+       pop     r10
+       pop     rbx                     //
+       ret
+
+endproc
+
+proc   nop
+
+       ret
+
+endproc
+
+///--------------------------------------------------------------------------
+
+proc   x00
+
+       // clear all 64 bits of extended traditional registers
+       xor      eax,eax                // clear rax
+       lea      rbx,[0]                // rbx -> _|_
+       loop     .                      // iterate, decrement rcx until zero
+       mov      rdx,0                  // set rdx = 0
+       and      esi,0                  // clear all bits of rsi
+       sub      edi,edi                // set rdi = edi - edi = 0
+       push     0
+       pop      rbp                    // pop 0 into rbp
+
+       ret
+
+endproc
+
+proc   x01
+
+       // advance a fibonacci pair by c steps
+       //
+       // on entry, a and d are f_{i+1} and f_i; on exit, they are f_{i+c+1}
+       // and f_{i+c}, where f_{i+1} = f_i + f_{i-1}
+0:     xadd    rax, rdx                // a, d = a + d, a
+                                       //      = f_{i+1} + f_i, f_{i+1}
+                                       //      = f_{i+2}, f_{i+1}
+       loop    0b                      // advance i, decrement c, iterate
+
+       ret
+
+endproc
+
+proc   x02
+
+       // boolean canonify a: if a = 0 on entry, leave it zero; otherwise
+       // set a = 1
+       neg     rax                     // set cf iff a /= 0
+       sbb     rax, rax                // a = a - a - cf = -cf
+       neg     rax                     // a = cf
+
+       ret
+
+endproc
+
+proc   x03
+
+       // set a = min(a, d) (unsigned); clobber c, d
+       sub     rdx, rax                // d' = d - a; set cf if a > d
+       sbb     rcx, rcx                // c = -cf = -[a > d]
+       and     rcx, rdx                // c = a > d ? d - a : 0
+       add     rax, rcx                // a' = a > d ? d : a
+
+       ret
+
+endproc
+
+proc   x04
+
+       // switch case?
+       xor     al, 0x20
+
+       ret
+
+endproc
+
+proc   x05
+
+       // answer whether 5 <= a </<= 9.
+       sub     rax, 5                  // a' = a - 5
+       cmp     rax, 4                  // is a' - 5 </<= 4?
+
+       // cc           a'                      a
+       //
+       // z/e          a' = 4                  a = 9
+       // nz/ne        a' /= 4                 a /= 9
+       //
+       // a/nbe        a' > 4                  a > 9 or a < 5
+       // nc/ae/nb     a' >= 4                 a >= 9 or a < 5
+       // c/b/nae      a' < 4                  5 <= a < 9
+       // be/na        a' <= 4                 5 <= a <= 9
+       //
+       // o            a' < -2^63 + 4          -2^63 + 5 <= a < -2^63 + 9
+       // no           a' >= -2^63 + 4         a >= -2^63 + 9 or
+       //                                              a < -2^63 + 5
+       // s            -2^63 + 4 <= a' < 4     -2^63 + 9 <= a < 9
+       // ns           a' < -2^63 + 4 or       a < -2^63 + 9 or a >= 9
+       //                      a' >= 4
+       // ge/nl        a' >= 4                 a >= 9 or a < -2^63 + 5
+       // l/nge        a' < 4                  -2^63 + 5 <= a < 9
+       // g/nle        a' > 4                  a > 9 or a < -2^63 + 5
+       // le/ng        a' <= 4                 -2^63 + 5 <= a <= 9
+
+       ret
+
+endproc
+
+proc   x06
+
+       // leave a unchanged, but set zf if a = 0, cf if a /= 0, clear of,
+       // set sf to msb(a)
+       not     rax                     // a' = -a - 1
+       inc     rax                     // a' = -a
+       neg     rax                     // a' = a
+
+       ret
+
+endproc
+
+proc   x07
+
+       // same as before (?)
+       inc     rax                     // a' = a + 1
+       neg     rax                     // a' = -a - 1
+       inc     rax                     // a' = -a
+       neg     rax                     // a' = a
+
+       ret
+
+endproc
+
+proc   x08
+
+       // floor((a + d)/2), correctly handling overflow conditions; final cf
+       // is lsb(a + d), probably uninteresting
+       add     rax, rdx                // cf || a' = a + d
+       rcr     rax, 1                  // shift 65-bit result right by one
+                                       // place; lsb moves into carry
+
+       ret
+
+endproc
+
+proc   x09
+
+       // a = a/8, rounded to nearest; i.e., floor(a/8) if a == 0, 1, 2, 3
+       // (mod 8), or ceil(a/8) if a == 4, 5, 6, 7 (mod 8).
+       shr     rax, 3                  // a' = floor(a/8); cf = 1 if a ==
+                                       // 4, 5, 6, 7 (mod 8)
+       adc     rax, 0                  // a' = floor(a/8) + cf
+
+       ret
+
+endproc
+
+proc   x0a
+
+       // increment c-byte little-endian bignum at rdi
+       add     byte ptr [rdi], 1
+0:     inc     rdi
+       adc     byte ptr [rdi], 0
+       loop    0b
+
+       ret
+
+endproc
+
+proc   x0b
+
+       // negate double-precision d:a
+       not     rdx                     // d' = -d - 1
+       neg     rax                     // a' = -a;
+                                       // cf = 1 iff a /= 0
+       sbb     rdx, -1                 // d' = -d - cf
+
+       ret
+
+endproc
+
+proc   x0c
+
+       // rotate is distributive over xor.
+
+       // rax                          // = a_1 || a_0
+       // rbx                          // = b_1 || b_0
+       mov     rcx, rax                // = a_1 || a_0
+
+       xor     rcx, rbx                // = (a_1 XOR b_1) || (a_0 XOR b_0)
+       ror     rcx, 0xd                // = (a_0 XOR b_0) || (a_1 XOR b_1)
+
+       ror     rax, 0xd                // = a_0 || a_1
+       ror     rbx, 0xd                // = b_0 || b_1
+       xor     rax, rbx                // = (a_0 XOR b_0) || (a_1 XOR b_1)
+
+       cmp     rax, rcx                // always equal
+
+       ret
+
+endproc
+
+proc   x0d
+
+       // and is distributive over xor.
+
+       mov     rdx, rbx                // = b
+
+       xor     rbx, rcx                // = b XOR c
+       and     rbx, rax                // = a AND (b XOR c)
+
+       and     rdx, rax                // = a AND b
+       and     rax, rcx                // = a AND c
+       xor     rax, rdx                // = (a AND b) XOR (a AND c)
+                                       // = a AND (b XOR c)
+
+       cmp     rax, rbx                // always equal
+
+       ret
+
+endproc
+
+proc   x0e
+
+       // de morgan's law
+
+       mov     rcx, rax                // = a
+
+       and     rcx, rbx                // = a AND b
+       not     rcx                     // = NOT (a AND b)
+
+       not     rax                     // = NOT a
+       not     rbx                     // = NOT b
+       or      rax, rbx                // = (NOT a) OR (NOT b)
+                                       // = NOT (a AND b)
+
+       cmp     rax, rcx
+
+       ret
+
+endproc
+
+proc   x0f
+
+       // replace input buffer bytes with cumulative XORs with initial a;
+       // final a is XOR of all buffer bytes and initial a.
+       //
+       // not sure why you'd do this.
+
+       cld
+
+0:     xor     [rsi], al
+       lodsb
+       loop    0b
+
+       ret
+
+endproc
+
+proc   x10
+
+       // four different ways to swap a pair of registers.
+
+       push    rax
+       push    rcx
+       pop     rax
+       pop     rcx
+
+       xor     rax, rcx
+       xor     rcx, rax
+       xor     rax, rcx
+
+       add     rax, rcx
+       sub     rcx, rax
+       add     rax, rcx
+       neg     rcx
+
+       xchg    rax, rcx
+
+       ret
+
+endproc
+
+proc   x11
+
+       // assuming a is initialized to zero, set a to the inclusive or of
+       // the xor-differences of corresponding bytes in the c-byte strings
+       // at si and di.
+       //
+       // in particular, a will be zero (and zf set) if and only if the two
+       // strings are equal.
+
+0:     mov     dl, [rsi]
+       xor     dl, [rdi]
+       inc     rsi
+       inc     rdi
+       or      al, dl
+       loop    0b
+
+       ret
+
+endproc
+
+proc   x12
+
+       // an obtuse way of adding two registers.  for any bit position, a
+       // OR d is set if and only if at least one of a and d has a bit set
+       // in that position, and a AND d is set if and only if both have a
+       // bit set in that position.  essentially, then, what we've done is
+       // move all of the set bits in d to a, unless there's already a bit
+       // there.  this clearly doesn't change the sum.
+
+       mov     rcx, rdx                // c' = d
+       and     rdx, rax                // d' = a AND d
+       or      rax, rcx                // a' = a OR d
+       add     rax, rdx
+
+       ret
+
+endproc
+
+proc   x13
+
+       // ok, so this is a really obtuse way of adding a and b; the result
+       // is in a and d.  but why does it work?
+
+       mov     rcx, 0x40               // carry chains at most 64 long
+0:     mov     rdx, rax                // copy a'
+       xor     rax, rbx                // low bits of each bitwise sum
+       and     rbx, rdx                // carry bits from each bitwise sum
+       shl     rbx, 001                // carry them into next position
+       loop    0b
+
+       ret
+
+endproc
+
+proc   x14
+
+       // floor((a + d)/2), like x08.
+
+       mov     rcx, rax                // copy a for later
+       and     rcx, rdx                // carry bits
+
+       xor     rax, rdx                // low bits of each bitwise sum
+       shr     rax, 1                  // divide by 2; carries now in place
+
+       add     rax, rcx                // add the carries; done
+
+       ret
+
+endproc
+
+proc   x15
+
+       // sign extension 32 -> 64 bits.
+
+       //movsx rbx, eax                // like this?
+
+       mov     rdx, 0xffffffff80000000
+       add     rax, rdx                // if bit 31 of a is set then bits
+                                       // 31--63 of a' are clear; otherwise,
+                                       // these bits are all set -- which is
+                                       // exactly backwards
+       xor     rax, rdx                // so fix it
+
+       ret
+
+endproc
+
+proc   x16
+
+  shl rax, 56
+  shl rbx, 56
+  shl rcx, 56
+
+       xor     rax, rbx                // a' = a XOR b
+       xor     rbx, rcx                // b' = b XOR c
+       mov     rsi, rax                // t = a XOR b
+       add     rsi, rbx                // t = (a XOR b) + (b XOR c)
+       cmovc   rax, rbx                // a' = cf ? b XOR c : a XOR b
+       xor     rax, rbx                // a' = cf ? 0 : a XOR c
+       cmp     rax, rsi
+
+       ret
+
+endproc
+
+proc   x17
+
+       ud2
+
+endproc
+
+proc   x18
+
+       ud2
+
+endproc
+
+proc   x19
+
+       ud2
+
+endproc
+
+proc   x1a
+
+       ud2
+
+endproc
+
+proc   x1b
+
+       ud2
+
+endproc
+
+proc   x1c
+
+       ud2
+
+endproc
+
+proc   x1d
+
+       ud2
+
+endproc
+
+proc   x1e
+
+       ud2
+
+endproc
+
+proc   x1f
+
+       ud2
+
+endproc
+
+proc   x20
+
+       ud2
+
+       ret
+
+endproc
+
+proc   x21
+
+       ud2
+
+endproc
+
+proc   x22
+
+       ud2
+
+endproc
+
+proc   x23
+
+       ud2
+
+endproc
+
+proc   x24
+
+       ud2
+
+endproc
+
+proc   x25
+
+       ud2
+
+endproc
+
+proc   x26
+
+       ud2
+
+endproc
+
+proc   x27
+
+       ud2
+
+endproc
+
+proc   x28
+
+       ud2
+
+endproc
+
+proc   x29
+
+       ud2
+
+endproc
+
+proc   x2a
+
+       ud2
+
+endproc
+
+proc   x2b
+
+       ud2
+
+endproc
+
+proc   x2c
+
+       ud2
+
+endproc
+
+proc   x2d
+
+       ud2
+
+endproc
+
+proc   x2e
+
+       ud2
+
+endproc
+
+proc   x2f
+
+       ud2
+
+endproc
+
+proc   x30
+
+       ud2
+
+       ret
+
+endproc
+
+proc   x31
+
+       ud2
+
+endproc
+
+proc   x32
+
+       ud2
+
+endproc
+
+proc   x33
+
+       ud2
+
+endproc
+
+proc   x34
+
+       ud2
+
+endproc
+
+proc   x35
+
+       ud2
+
+endproc
+
+proc   x36
+
+       ud2
+
+endproc
+
+proc   x37
+
+       ud2
+
+endproc
+
+proc   x38
+
+       ud2
+
+endproc
+
+proc   x39
+
+       ud2
+
+endproc
+
+proc   x3a
+
+       ud2
+
+endproc
+
+proc   x3b
+
+       ud2
+
+endproc
+
+proc   x3c
+
+       ud2
+
+endproc
+
+proc   x3d
+
+       ud2
+
+endproc
+
+proc   x3e
+
+       ud2
+
+endproc
+
+proc   x3f
+
+       ud2
+
+endproc