xchg.S: Add missing `ret' in ARM64 version of `call_example'.
[xchg-rax-rax] / main.c
CommitLineData
06297a93
MW
1#include <ctype.h>
2#include <errno.h>
3#include <limits.h>
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9union reg {
10 unsigned char *p;
11 long i;
12 long u;
13};
14
90c4eee3
MW
15#if defined(__i386__)
16# define GPREGS(_) \
17 _(a) _(b) _(c) _(d) _(si) _(di) _(bp)
18#elif defined(__x86_64__)
19# define GPREGS(_) \
20 _(a) _(b) _(c) _(d) _(si) _(di) _(bp) \
21 _(r8) _(r9) _(r10) _(r11) _(r12) _(r13) _(r14) _(r15)
22#elif defined(__arm__)
23# define GPREGS(_) \
24 _(r0) _(r1) _(r2) _(r3) _(r4) _(r5) _(r6) _(r7) \
25 _(r8) _(r9) _(r10) _(r11) _(r12)
26#elif defined(__aarch64__)
27# define GPREGS(_) \
28 _(x0) _(x1) _(x2) _(x3) _(x4) _(x5) _(x6) _(x7) \
29 _(x8) _(x9) _(x10) _(x11) _(x12) _(x13) _(x14) _(x15)
30#else
31# error "not supported"
32#endif
33
34enum {
35#define DEFCONST(r) R_##r,
36 GPREGS(DEFCONST)
37#undef DEFCONST
38 R_flags,
39 NREGS
40};
41
42static const char *const rname[] = {
43#define DEFNAME(r) #r,
44 GPREGS(DEFNAME)
45#undef DEFNAME
46 "f"
47};
48
06297a93 49struct regs {
90c4eee3 50 union reg r[NREGS];
06297a93
MW
51};
52
53struct seg {
54 unsigned char *p;
55 size_t sz;
56};
57
58#define N(v) (sizeof(v)/sizeof((v)[0]))
59
90c4eee3
MW
60#define STRCMP(a, op, b) (strcmp((a), (b)) op 0)
61#define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0)
06297a93
MW
62#define CTYPE_HACK(func, ch) func((unsigned char)(ch))
63#define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
64#define ISSPACE(ch) CTYPE_HACK(isspace, ch)
65
66#define XCHG(_) \
67 _(x00) _(x01) _(x02) _(x03) _(x04) _(x05) _(x06) _(x07) \
68 _(x08) _(x09) _(x0a) _(x0b) _(x0c) _(x0d) _(x0e) _(x0f) \
69 _(x10) _(x11) _(x12) _(x13) _(x14) _(x15) _(x16) _(x17) \
70 _(x18) _(x19) _(x1a) _(x1b) _(x1c) _(x1d) _(x1e) _(x1f) \
71 _(x20) _(x21) _(x22) _(x23) _(x24) _(x25) _(x26) _(x27) \
72 _(x28) _(x29) _(x2a) _(x2b) _(x2c) _(x2d) _(x2e) _(x2f) \
73 _(x30) _(x31) _(x32) _(x33) _(x34) _(x35) _(x36) _(x37) \
74 _(x38) _(x39) _(x3a) _(x3b) _(x3c) _(x3d) _(x3e) _(x3f)
75
76#define DECL(x) extern const int x;
77XCHG(DECL)
78extern const int nop;
79
80static const int *x[] = {
81#define SLOT(x) &x,
82 XCHG(SLOT)
83};
84
85extern void call_example(const int *f, struct regs *r);
86
87static const char *prog = "???";
88
89__attribute__((format(printf, 1, 2), noreturn))
90static void barf(const char *m, ...)
91{
92 va_list ap;
93
94 va_start(ap, m);
95 fprintf(stderr, "%s: ", prog);
96 vfprintf(stderr, m, ap);
97 putc('\n', stderr);
98 va_end(ap);
99 exit(127);
100}
101
102static void *xmalloc(size_t sz)
103{
104 void *p;
105
106 if (!sz) return (0);
107 p = malloc(sz);
108 if (!p) barf("malloc failed");
109 return (p);
110}
111
112#define DEF_PARSEINT(name, ty, strto) \
113 static ty parse_##name(const char *what, const char *p, ty min, ty max) \
114 { \
115 const char *pp = p; \
116 char *q; \
117 ty i; \
118 int err; \
119 \
120 if (ISSPACE(*p)) goto bad; \
121 err = errno; errno = 0; \
122 i = strto(p, &q, 0); \
123 if (errno) goto bad; \
124 if (*q) goto bad; \
125 if (i < min || i > max) goto bad; \
126 errno = err; \
127 return (i); \
128 \
129 bad: \
130 barf("bad %s `%s'", what, pp); \
131 }
132DEF_PARSEINT(long, long, strtol)
133DEF_PARSEINT(ulong, unsigned long, strtoul)
134
135static int hex_digit(char ch)
136{
137 if ('0' <= ch && ch <= '9') return (ch - '0');
138 else if ('A' <= ch && ch <= 'F') return (ch - 'A' + 10);
139 else if ('a' <= ch && ch <= 'f') return (ch - 'a' + 10);
140 else return (-1);
141}
142
90c4eee3 143static void setreg(union reg *r, struct seg **seg_inout, const char *p)
06297a93
MW
144{
145 struct seg *seg;
90c4eee3 146 const char *pp;
06297a93
MW
147 unsigned char *q;
148 int hi, lo;
149 size_t n;
150
151#define LONG_REG(p) (parse_long("signed register", (p), LONG_MIN, LONG_MAX))
152#define ULONG_REG(p) (parse_ulong("unsigned register", (p), 0, ULONG_MAX))
153
06297a93
MW
154 switch (*p) {
155 case '-':
156 if (p[1]) r->i = LONG_REG(p);
06297a93
MW
157 break;
158 case 'i':
159 if (p[1] != ':') goto bad;
160 r->i = LONG_REG(p + 2);
161 break;
162 case 'u':
163 if (p[1] != ':') goto bad;
164 r->u = ULONG_REG(p + 2);
165 break;
166 case 'c':
167 if (p[1] != ':' || p[3]) goto bad;
168 r->u = p[2];
169 break;
170 case 's':
171 if (p[1] != ':') goto bad;
172 pp = p + 2; n = strlen(pp) + 1;
173 seg = (*seg_inout)++; seg->p = xmalloc(n); seg->sz = n;
174 memcpy(seg->p, pp, n); r->p = seg->p;
175 break;
176 case 'm':
177 if (p[1] != ':') goto bad;
178 pp = p + 2; n = strlen(pp); if (n%2) goto bad;
179 seg = (*seg_inout)++; seg->p = q = xmalloc(n/2); seg->sz = n/2;
180 while (n) {
181 hi = hex_digit(pp[0]); lo = hex_digit(pp[1]);
182 if (hi < 0 || lo < 0) goto bad;
183 *q++ = 16*hi + lo; n -= 2; pp += 2;
184 }
185 r->p = seg->p;
186 break;
90c4eee3
MW
187 case 'z':
188 if (p[1] != ':') goto bad;
189 n = parse_ulong("buffer length", p + 2, 0, ~(size_t)0);
190 seg = (*seg_inout)++; seg->p = q = xmalloc(n); seg->sz = n;
191 r->p = q; memset(q, 0, n);
192 break;
06297a93
MW
193 default:
194 if (ISDIGIT(*p)) r->u = ULONG_REG(p);
195 else if (*p == '+') r->i = LONG_REG(p);
196 else if (*p == '\'' && p[2] == '\'' && !p[3]) r->u = p[1];
197 else goto bad;
198 break;
199 bad:
200 barf("bad regspec `%s'", p);
201 }
202
203#undef LONG_REG
204#undef ULONG_REG
205}
206
207static void dumpreg(const char *name, const union reg *r,
208 const struct seg *seg, size_t nseg)
209{
210 size_t i;
211
90c4eee3
MW
212#if ULONG_MAX == 0xffffffff
213 printf("%3s = 0x%08lx = %20ld = %20lu", name, r->u, r->i, r->u);
214#else
06297a93 215 printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u);
90c4eee3 216#endif
06297a93
MW
217 if (r->u >= ' ' && r->u <= '~') printf(" = '%c'", (int)r->u);
218 for (i = 0; i < nseg; i++) {
219 if (r->p == seg[i].p)
220 printf(" = seg[%zu] base", i);
221 else if (r->p == seg[i].p + seg[i].sz)
222 printf(" = seg[%zu] limit", i);
223 else if (seg[i].p < r->p && r->p < seg[i].p + seg[i].sz)
224 printf(" = seg[%zu] + %zu", i, (size_t)(r->p - seg[i].p));
225 }
226 putchar('\n');
227}
228
229static void dumpseg(const struct seg *seg)
230{
231 size_t i, j;
232 unsigned char ch;
233
234 for (i = 0; i < seg->sz; i += 8) {
235 printf("\t%8zx :", i);
236 for (j = 0; j < 8; j++)
237 if (i + j >= seg->sz) printf(" **");
238 else printf(" %02x", seg->p[i + j]);
239 printf(" : ");
240 for (j = 0; j < 8; j++)
241 if (i + j >= seg->sz) putchar('*');
242 else {
243 ch = seg->p[i + j];
244 if (' ' <= ch && ch <= '~') putchar(ch);
245 else putchar('.');
246 }
247 putchar('\n');
248 }
249}
250
251int main(int argc, char *argv[])
252{
253 struct regs r;
254 struct seg seg[16], *segp = seg;
90c4eee3
MW
255 size_t nseg, n;
256 const char *p;
257 char *q;
258 unsigned long f;
259 int i, j, k;
260 unsigned long l;
06297a93
MW
261
262 prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0];
263
264 if (argc < 2)
90c4eee3 265 barf("usage: %s I [REG...]",
06297a93
MW
266 prog);
267
268 j = parse_long("program index", argv[1], -1, N(x) - 1);
269
90c4eee3
MW
270#if ULONG_MAX == 0xffffffff
271# define DEAD 0xdeadbeef
272#else
273# define DEAD 0xdeadbeefdeadbeef
274#endif
275 for (i = 0; i < NREGS - 1; i++) r.r[i].u = DEAD;
276#undef DEAD
277 r.r[R_flags].u = 0;
278
279 i = 0;
280 argv += 2;
281 while (*argv) {
282 p = *argv++;
283 if (ISDIGIT(*p)) {
284 l = strtoul(p, &q, 10);
285 if (l < NREGS && *q == '=') { p = q + 1; i = l; }
286 } else for (k = 0; k < NREGS; k++) {
287 n = strlen(rname[k]);
288 if (STRNCMP(p, ==, rname[k], n) && p[n] == '=')
289 { i = k; p += n + 1; break; }
290 }
291 if (i >= NREGS) barf("too many registers");
292 setreg(&r.r[i], &segp, p); i++;
293 }
06297a93 294
90c4eee3 295 nseg = segp - seg;
06297a93
MW
296 call_example(j < 0 ? &nop : x[j], &r);
297
90c4eee3
MW
298 for (i = 0; i < NREGS; i++) dumpreg(rname[i], &r.r[i], seg, nseg);
299
300 f = r.r[R_flags].u;
301
302#if defined(__i386__) || defined(__x86_64__)
06297a93
MW
303
304#define CF (1 << 0)
305#define PF (1 << 2)
306#define ZF (1 << 6)
307#define SF (1 << 7)
308#define OF (1 << 11)
309
06297a93 310 printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
90c4eee3
MW
311 (f >> 0)&1u ? '+' : '-',
312 (f >> 2)&1u ? '+' : '-',
313 (f >> 4)&1u ? '+' : '-',
314 (f >> 6)&1u ? '+' : '-',
315 (f >> 7)&1u ? '+' : '-',
316 (f >> 10)&1u ? '+' : '-',
317 (f >> 11)&1u ? '+' : '-');
06297a93 318 printf("\tcond:");
90c4eee3
MW
319 if (f&CF) printf(" c/b/nae"); else printf(" nc/ae/nb");
320 if (f&ZF) printf(" e/z"); else printf(" ne/nz");
321 if (f&SF) printf(" s"); else printf(" ns");
322 if (f&OF) printf(" o"); else printf(" no");
323 if (f&PF) printf(" p"); else printf(" np");
324 if ((f&CF) || (f&ZF)) printf(" be/na"); else printf(" a/nbe");
325 if (!(f&OF) == !(f&SF)) printf(" ge/nl"); else printf(" l/nge");
326 if (!(f&OF) == !(f&SF) && !(f&ZF))
06297a93
MW
327 printf(" g/nle"); else printf(" le/ng");
328 putchar('\n');
329 printf("\tsystem: %ctf %cif iopl=%d %cnt "
330 "%crf %cvm %cac %cvif %cvip %cid\n",
90c4eee3
MW
331 (f >> 8)&1u ? '+' : '-',
332 (f >> 9)&1u ? '+' : '-',
333 (int)((f >> 12)&1u),
334 (f >> 14)&1u ? '+' : '-',
335 (f >> 16)&1u ? '+' : '-',
336 (f >> 17)&1u ? '+' : '-',
337 (f >> 18)&1u ? '+' : '-',
338 (f >> 19)&1u ? '+' : '-',
339 (f >> 20)&1u ? '+' : '-',
340 (f >> 21)&1u ? '+' : '-');
06297a93
MW
341
342#undef CF
343#undef PF
344#undef ZF
345#undef SF
346#undef OF
347
90c4eee3
MW
348#elif defined(__arm__)
349
350#define NF (1u << 31)
351#define ZF (1u << 30)
352#define CF (1u << 29)
353#define VF (1u << 28)
354
355 {
356 static const char
357 *modetab[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07",
358 "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15",
359 "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt",
360 "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" },
361 *condtab[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
362 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
363
364 printf("\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c;",
365 (f >> 31)&1u ? '+' : '-',
366 (f >> 30)&1u ? '+' : '-',
367 (f >> 29)&1u ? '+' : '-',
368 (f >> 28)&1u ? '+' : '-',
369 (f >> 27)&1u ? '+' : '-',
370 (f >> 19)&1u ? '1' : '0',
371 (f >> 18)&1u ? '1' : '0',
372 (f >> 17)&1u ? '1' : '0',
373 (f >> 16)&1u ? '1' : '0');
374 if (f&NF) printf(" mi"); else printf(" pl");
375 if (f&ZF) printf(" eq"); else printf(" ne");
376 if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
377 if (f&VF) printf(" vs"); else printf(" vc");
378 if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
379 if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
380 if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
381 putchar('\n');
382 printf("\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n",
383 (f >> 24)&1u ? '+' : '-',
384 condtab[(f >> 12)&15u],
385 (f >> 11)&1u ? '1' : '0',
386 (f >> 10)&1u ? '1' : '0',
387 (f >> 26)&1u ? '1' : '0',
388 (f >> 25)&1u ? '1' : '0',
389 (f >> 9)&1u ? '+' : '-',
390 (f >> 8)&1u ? '+' : '-',
391 (f >> 7)&1u ? '+' : '-',
392 (f >> 6)&1u ? '+' : '-',
393 (f >> 5)&1u ? '+' : '-',
394 modetab[(f >> 0)&31u]);
395 }
396
397#undef NF
398#undef ZF
399#undef CF
400#undef VF
401
402#elif defined(__aarch64__)
403
404#define NF (1u << 31)
405#define ZF (1u << 30)
406#define CF (1u << 29)
407#define VF (1u << 28)
408
409 printf("\tuser: %cn %cz %cc %cv;",
410 (f >> 31)&1u ? '+' : '-',
411 (f >> 30)&1u ? '+' : '-',
412 (f >> 29)&1u ? '+' : '-',
413 (f >> 28)&1u ? '+' : '-');
414 if (f&NF) printf(" mi"); else printf(" pl");
415 if (f&ZF) printf(" eq"); else printf(" ne");
416 if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
417 if (f&VF) printf(" vs"); else printf(" vc");
418 if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
419 if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
420 if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
421 putchar('\n');
422
423#undef NF
424#undef ZF
425#undef CF
426#undef VF
427
428#else
429# error "not supported"
430#endif
431
06297a93
MW
432 for (i = 0; i < nseg; i++)
433 { printf("seg[%d] (%p):\n", i, seg[i].p); dumpseg(&seg[i]); }
434
435 return (0);
436}