Multiple architectures, more solutions.
[xchg-rax-rax] / main.c
diff --git a/main.c b/main.c
index 9ab4c2e..df4b941 100644 (file)
--- a/main.c
+++ b/main.c
@@ -12,10 +12,42 @@ union reg {
   long u;
 };
 
+#if defined(__i386__)
+#  define GPREGS(_)                                                    \
+       _(a) _(b) _(c) _(d) _(si) _(di) _(bp)
+#elif defined(__x86_64__)
+#  define GPREGS(_)                                                    \
+       _(a) _(b) _(c) _(d) _(si) _(di) _(bp)                           \
+       _(r8) _(r9) _(r10) _(r11) _(r12) _(r13) _(r14) _(r15)
+#elif defined(__arm__)
+#  define GPREGS(_)                                                    \
+       _(r0) _(r1) _(r2) _(r3) _(r4) _(r5) _(r6) _(r7)                 \
+       _(r8) _(r9) _(r10) _(r11) _(r12)
+#elif defined(__aarch64__)
+#  define GPREGS(_)                                                    \
+       _(x0) _(x1) _(x2) _(x3) _(x4) _(x5) _(x6) _(x7)                 \
+       _(x8) _(x9) _(x10) _(x11) _(x12) _(x13) _(x14) _(x15)
+#else
+#  error "not supported"
+#endif
+
+enum {
+#define DEFCONST(r) R_##r,
+  GPREGS(DEFCONST)
+#undef DEFCONST
+  R_flags,
+  NREGS
+};
+
+static const char *const rname[] = {
+#define DEFNAME(r) #r,
+  GPREGS(DEFNAME)
+#undef DEFNAME
+  "f"
+};
+
 struct regs {
-  union reg
-    a, b, c, d, si, di, bp, f,
-    r8, r9, r10, r11, r12, r13, r14, r15;
+  union reg r[NREGS];
 };
 
 struct seg {
@@ -25,6 +57,8 @@ struct seg {
 
 #define N(v) (sizeof(v)/sizeof((v)[0]))
 
+#define STRCMP(a, op, b) (strcmp((a), (b)) op 0)
+#define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0)
 #define CTYPE_HACK(func, ch) func((unsigned char)(ch))
 #define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
 #define ISSPACE(ch) CTYPE_HACK(isspace, ch)
@@ -106,12 +140,10 @@ static int hex_digit(char ch)
   else return (-1);
 }
 
-static void setreg(union reg *r,
-                  struct seg **seg_inout,
-                  int *i_inout, int argc, char *argv[])
+static void setreg(union reg *r, struct seg **seg_inout, const char *p)
 {
   struct seg *seg;
-  const char *p, *pp;
+  const char *pp;
   unsigned char *q;
   int hi, lo;
   size_t n;
@@ -119,11 +151,9 @@ static void setreg(union reg *r,
 #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;
@@ -154,6 +184,12 @@ static void setreg(union reg *r,
       }
       r->p = seg->p;
       break;
+    case 'z':
+      if (p[1] != ':') goto bad;
+      n = parse_ulong("buffer length", p + 2, 0, ~(size_t)0);
+      seg = (*seg_inout)++; seg->p = q = xmalloc(n); seg->sz = n;
+      r->p = q; memset(q, 0, n);
+      break;
     default:
       if (ISDIGIT(*p)) r->u = ULONG_REG(p);
       else if (*p == '+') r->i = LONG_REG(p);
@@ -173,7 +209,11 @@ static void dumpreg(const char *name, const union reg *r,
 {
   size_t i;
 
+#if ULONG_MAX == 0xffffffff
+  printf("%3s =         0x%08lx = %20ld = %20lu", name, r->u, r->i, r->u);
+#else
   printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u);
+#endif
   if (r->u >= ' ' && r->u <= '~') printf(" = '%c'", (int)r->u);
   for (i = 0; i < nseg; i++) {
     if (r->p == seg[i].p)
@@ -212,54 +252,54 @@ int main(int argc, char *argv[])
 {
   struct regs r;
   struct seg seg[16], *segp = seg;
-  size_t nseg;
-  int i, j;
+  size_t nseg, n;
+  const char *p;
+  char *q;
+  unsigned long f;
+  int i, j, k;
+  unsigned long l;
 
   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]",
+    barf("usage: %s I [REG...]",
         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;
+#if ULONG_MAX == 0xffffffff
+#  define DEAD 0xdeadbeef
+#else
+#  define DEAD 0xdeadbeefdeadbeef
+#endif
+  for (i = 0; i < NREGS - 1; i++) r.r[i].u = DEAD;
+#undef DEAD
+  r.r[R_flags].u = 0;
+
+  i = 0;
+  argv += 2;
+  while (*argv) {
+    p = *argv++;
+    if (ISDIGIT(*p)) {
+      l = strtoul(p, &q, 10);
+      if (l < NREGS && *q == '=') { p = q + 1; i = l; }
+    } else for (k = 0; k < NREGS; k++) {
+      n = strlen(rname[k]);
+      if (STRNCMP(p, ==, rname[k], n) && p[n] == '=')
+       { i = k; p += n + 1; break; }
+    }
+    if (i >= NREGS) barf("too many registers");
+    setreg(&r.r[i], &segp, p); i++;
+  }
 
+  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);
+  for (i = 0; i < NREGS; i++) dumpreg(rname[i], &r.r[i], seg, nseg);
+
+  f = r.r[R_flags].u;
+
+#if defined(__i386__) || defined(__x86_64__)
 
 #define CF (1 <<  0)
 #define PF (1 <<  2)
@@ -267,38 +307,37 @@ int main(int argc, char *argv[])
 #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 ? '+' : '-');
+        (f >>  0)&1u ? '+' : '-',
+        (f >>  2)&1u ? '+' : '-',
+        (f >>  4)&1u ? '+' : '-',
+        (f >>  6)&1u ? '+' : '-',
+        (f >>  7)&1u ? '+' : '-',
+        (f >> 10)&1u ? '+' : '-',
+        (f >> 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))
+  if (f&CF) printf(" c/b/nae"); else printf(" nc/ae/nb");
+  if (f&ZF) printf(" e/z"); else printf(" ne/nz");
+  if (f&SF) printf(" s"); else printf(" ns");
+  if (f&OF) printf(" o"); else printf(" no");
+  if (f&PF) printf(" p"); else printf(" np");
+  if ((f&CF) || (f&ZF)) printf(" be/na"); else printf(" a/nbe");
+  if (!(f&OF) == !(f&SF)) printf(" ge/nl"); else printf(" l/nge");
+  if (!(f&OF) == !(f&SF) && !(f&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 ? '+' : '-');
+        (f >>  8)&1u ? '+' : '-',
+        (f >>  9)&1u ? '+' : '-',
+        (int)((f >> 12)&1u),
+        (f >> 14)&1u ? '+' : '-',
+        (f >> 16)&1u ? '+' : '-',
+        (f >> 17)&1u ? '+' : '-',
+        (f >> 18)&1u ? '+' : '-',
+        (f >> 19)&1u ? '+' : '-',
+        (f >> 20)&1u ? '+' : '-',
+        (f >> 21)&1u ? '+' : '-');
 
 #undef CF
 #undef PF
@@ -306,6 +345,90 @@ int main(int argc, char *argv[])
 #undef SF
 #undef OF
 
+#elif defined(__arm__)
+
+#define NF (1u << 31)
+#define ZF (1u << 30)
+#define CF (1u << 29)
+#define VF (1u << 28)
+
+  {
+  static const char
+    *modetab[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07",
+                  "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15",
+                  "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt",
+                  "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" },
+    *condtab[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+                  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
+
+  printf("\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c;",
+        (f >> 31)&1u ? '+' : '-',
+        (f >> 30)&1u ? '+' : '-',
+        (f >> 29)&1u ? '+' : '-',
+        (f >> 28)&1u ? '+' : '-',
+        (f >> 27)&1u ? '+' : '-',
+        (f >> 19)&1u ? '1' : '0',
+        (f >> 18)&1u ? '1' : '0',
+        (f >> 17)&1u ? '1' : '0',
+        (f >> 16)&1u ? '1' : '0');
+  if (f&NF) printf(" mi"); else printf(" pl");
+  if (f&ZF) printf(" eq"); else printf(" ne");
+  if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
+  if (f&VF) printf(" vs"); else printf(" vc");
+  if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
+  if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
+  if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
+  putchar('\n');
+  printf("\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n",
+        (f >> 24)&1u ? '+' : '-',
+        condtab[(f >> 12)&15u],
+        (f >> 11)&1u ? '1' : '0',
+        (f >> 10)&1u ? '1' : '0',
+        (f >> 26)&1u ? '1' : '0',
+        (f >> 25)&1u ? '1' : '0',
+        (f >>  9)&1u ? '+' : '-',
+        (f >>  8)&1u ? '+' : '-',
+        (f >>  7)&1u ? '+' : '-',
+        (f >>  6)&1u ? '+' : '-',
+        (f >>  5)&1u ? '+' : '-',
+        modetab[(f >>  0)&31u]);
+  }
+
+#undef NF
+#undef ZF
+#undef CF
+#undef VF
+
+#elif defined(__aarch64__)
+
+#define NF (1u << 31)
+#define ZF (1u << 30)
+#define CF (1u << 29)
+#define VF (1u << 28)
+
+  printf("\tuser: %cn %cz %cc %cv;",
+        (f >> 31)&1u ? '+' : '-',
+        (f >> 30)&1u ? '+' : '-',
+        (f >> 29)&1u ? '+' : '-',
+        (f >> 28)&1u ? '+' : '-');
+  if (f&NF) printf(" mi"); else printf(" pl");
+  if (f&ZF) printf(" eq"); else printf(" ne");
+  if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
+  if (f&VF) printf(" vs"); else printf(" vc");
+  if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
+  if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
+  if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
+  putchar('\n');
+
+#undef NF
+#undef ZF
+#undef CF
+#undef VF
+
+#else
+#  error "not supported"
+#endif
+
   for (i = 0; i < nseg; i++)
     { printf("seg[%d] (%p):\n", i, seg[i].p); dumpseg(&seg[i]); }