--- /dev/null
+#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);
+}
--- /dev/null
+/// -*- 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