summaryrefslogtreecommitdiff
path: root/dynasm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dynasm/dasm_proto.h69
-rw-r--r--dynasm/dasm_x86.h467
-rw-r--r--dynasm/dasm_x86.lua1799
-rw-r--r--dynasm/dynasm.lua1070
4 files changed, 3405 insertions, 0 deletions
diff --git a/dynasm/dasm_proto.h b/dynasm/dasm_proto.h
new file mode 100644
index 00000000..94d9a9e2
--- /dev/null
+++ b/dynasm/dasm_proto.h
@@ -0,0 +1,69 @@
1/*
2** DynASM encoding engine prototypes.
3** Copyright (C) 2005-2009 Mike Pall. All rights reserved.
4** Released under the MIT/X license. See dynasm.lua for full copyright notice.
5*/
6
7#ifndef _DASM_PROTO_H
8#define _DASM_PROTO_H
9
10#include <stddef.h>
11#include <stdarg.h>
12
13#define DASM_IDENT "DynASM 1.2.1"
14#define DASM_VERSION 10201 /* 1.2.1 */
15
16#ifndef Dst_DECL
17#define Dst_DECL dasm_State *Dst
18#endif
19
20#ifndef Dst_GET
21#define Dst_GET (Dst)
22#endif
23
24#ifndef DASM_FDEF
25#define DASM_FDEF extern
26#endif
27
28
29/* Internal DynASM encoder state. */
30typedef struct dasm_State dasm_State;
31
32/* Action list type. */
33typedef const unsigned char *dasm_ActList;
34
35
36/* Initialize and free DynASM state. */
37DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
38DASM_FDEF void dasm_free(Dst_DECL);
39
40/* Setup global array. Must be called before dasm_setup(). */
41DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
42
43/* Grow PC label array. Can be called after dasm_setup(), too. */
44DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
45
46/* Setup encoder. */
47DASM_FDEF void dasm_setup(Dst_DECL, dasm_ActList actionlist);
48
49/* Feed encoder with actions. Calls are generated by pre-processor. */
50DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
51
52/* Link sections and return the resulting size. */
53DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
54
55/* Encode sections into buffer. */
56DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
57
58/* Get PC label offset. */
59DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
60
61#ifdef DASM_CHECKS
62/* Optional sanity checker to call between isolated encoding steps. */
63DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
64#else
65#define dasm_checkstep(a, b) 0
66#endif
67
68
69#endif /* _DASM_PROTO_H */
diff --git a/dynasm/dasm_x86.h b/dynasm/dasm_x86.h
new file mode 100644
index 00000000..dab33e5a
--- /dev/null
+++ b/dynasm/dasm_x86.h
@@ -0,0 +1,467 @@
1/*
2** DynASM x86 encoding engine.
3** Copyright (C) 2005-2009 Mike Pall. All rights reserved.
4** Released under the MIT/X license. See dynasm.lua for full copyright notice.
5*/
6
7#include <stddef.h>
8#include <stdarg.h>
9#include <string.h>
10#include <stdlib.h>
11
12#define DASM_ARCH "x86"
13
14#ifndef DASM_EXTERN
15#define DASM_EXTERN(a,b,c,d) 0
16#endif
17
18/* Action definitions. DASM_STOP must be 255. */
19enum {
20 DASM_DISP = 233,
21 DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
22 DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
23 DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
24 DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
25};
26
27/* Maximum number of section buffer positions for a single dasm_put() call. */
28#define DASM_MAXSECPOS 25
29
30/* DynASM encoder status codes. Action list offset or number are or'ed in. */
31#define DASM_S_OK 0x00000000
32#define DASM_S_NOMEM 0x01000000
33#define DASM_S_PHASE 0x02000000
34#define DASM_S_MATCH_SEC 0x03000000
35#define DASM_S_RANGE_I 0x11000000
36#define DASM_S_RANGE_SEC 0x12000000
37#define DASM_S_RANGE_LG 0x13000000
38#define DASM_S_RANGE_PC 0x14000000
39#define DASM_S_RANGE_VREG 0x15000000
40#define DASM_S_UNDEF_L 0x21000000
41#define DASM_S_UNDEF_PC 0x22000000
42
43/* Macros to convert positions (8 bit section + 24 bit index). */
44#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
45#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
46#define DASM_SEC2POS(sec) ((sec)<<24)
47#define DASM_POS2SEC(pos) ((pos)>>24)
48#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
49
50/* Per-section structure. */
51typedef struct dasm_Section {
52 int *rbuf; /* Biased buffer pointer (negative section bias). */
53 int *buf; /* True buffer pointer. */
54 size_t bsize; /* Buffer size in bytes. */
55 int pos; /* Biased buffer position. */
56 int epos; /* End of biased buffer position - max single put. */
57 int ofs; /* Byte offset into section. */
58} dasm_Section;
59
60/* Core structure holding the DynASM encoding state. */
61struct dasm_State {
62 size_t psize; /* Allocated size of this structure. */
63 dasm_ActList actionlist; /* Current actionlist pointer. */
64 int *lglabels; /* Local/global chain/pos ptrs. */
65 size_t lgsize;
66 int *pclabels; /* PC label chains/pos ptrs. */
67 size_t pcsize;
68 void **globals; /* Array of globals (bias -10). */
69 dasm_Section *section; /* Pointer to active section. */
70 size_t codesize; /* Total size of all code sections. */
71 int maxsection; /* 0 <= sectionidx < maxsection. */
72 int status; /* Status code. */
73 dasm_Section sections[1]; /* All sections. Alloc-extended. */
74};
75
76/* The size of the core structure depends on the max. number of sections. */
77#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
78
79
80/* Initialize DynASM state. */
81void dasm_init(Dst_DECL, int maxsection)
82{
83 dasm_State *D;
84 size_t psz = 0;
85 int i;
86 Dst_REF = NULL;
87 DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
88 D = Dst_REF;
89 D->psize = psz;
90 D->lglabels = NULL;
91 D->lgsize = 0;
92 D->pclabels = NULL;
93 D->pcsize = 0;
94 D->globals = NULL;
95 D->maxsection = maxsection;
96 for (i = 0; i < maxsection; i++) {
97 D->sections[i].buf = NULL; /* Need this for pass3. */
98 D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
99 D->sections[i].bsize = 0;
100 D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
101 }
102}
103
104/* Free DynASM state. */
105void dasm_free(Dst_DECL)
106{
107 dasm_State *D = Dst_REF;
108 int i;
109 for (i = 0; i < D->maxsection; i++)
110 if (D->sections[i].buf)
111 DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
112 if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
113 if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
114 DASM_M_FREE(Dst, D, D->psize);
115}
116
117/* Setup global label array. Must be called before dasm_setup(). */
118void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
119{
120 dasm_State *D = Dst_REF;
121 D->globals = gl - 10; /* Negative bias to compensate for locals. */
122 DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
123}
124
125/* Grow PC label array. Can be called after dasm_setup(), too. */
126void dasm_growpc(Dst_DECL, unsigned int maxpc)
127{
128 dasm_State *D = Dst_REF;
129 size_t osz = D->pcsize;
130 DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
131 memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
132}
133
134/* Setup encoder. */
135void dasm_setup(Dst_DECL, dasm_ActList actionlist)
136{
137 dasm_State *D = Dst_REF;
138 int i;
139 D->actionlist = actionlist;
140 D->status = DASM_S_OK;
141 D->section = &D->sections[0];
142 memset((void *)D->lglabels, 0, D->lgsize);
143 if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
144 for (i = 0; i < D->maxsection; i++) {
145 D->sections[i].pos = DASM_SEC2POS(i);
146 D->sections[i].ofs = 0;
147 }
148}
149
150
151#ifdef DASM_CHECKS
152#define CK(x, st) \
153 do { if (!(x)) { \
154 D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
155#define CKPL(kind, st) \
156 do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
157 D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
158#else
159#define CK(x, st) ((void)0)
160#define CKPL(kind, st) ((void)0)
161#endif
162
163/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
164void dasm_put(Dst_DECL, int start, ...)
165{
166 va_list ap;
167 dasm_State *D = Dst_REF;
168 dasm_ActList p = D->actionlist + start;
169 dasm_Section *sec = D->section;
170 int pos = sec->pos, ofs = sec->ofs, mrm = 4;
171 int *b;
172
173 if (pos >= sec->epos) {
174 DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
175 sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
176 sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
177 sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
178 }
179
180 b = sec->rbuf;
181 b[pos++] = start;
182
183 va_start(ap, start);
184 while (1) {
185 int action = *p++;
186 if (action < DASM_DISP) {
187 ofs++;
188 } else if (action <= DASM_REL_A) {
189 int n = va_arg(ap, int);
190 b[pos++] = n;
191 switch (action) {
192 case DASM_DISP:
193 if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; }
194 case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
195 case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
196 case DASM_IMM_D: ofs += 4; break;
197 case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
198 case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
199 case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
200 case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
201 case DASM_SPACE: p++; ofs += n; break;
202 case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
203 case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG);
204 if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue;
205 }
206 mrm = 4;
207 } else {
208 int *pl, n;
209 switch (action) {
210 case DASM_REL_LG:
211 case DASM_IMM_LG:
212 n = *p++; pl = D->lglabels + n;
213 if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
214 pl -= 246; n = *pl;
215 if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
216 goto linkrel;
217 case DASM_REL_PC:
218 case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
219 putrel:
220 n = *pl;
221 if (n < 0) { /* Label exists. Get label pos and store it. */
222 b[pos] = -n;
223 } else {
224 linkrel:
225 b[pos] = n; /* Else link to rel chain, anchored at label. */
226 *pl = pos;
227 }
228 pos++;
229 ofs += 4; /* Maximum offset needed. */
230 if (action == DASM_REL_LG || action == DASM_REL_PC)
231 b[pos++] = ofs; /* Store pass1 offset estimate. */
232 break;
233 case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
234 case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
235 putlabel:
236 n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
237 while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
238 *pl = -pos; /* Label exists now. */
239 b[pos++] = ofs; /* Store pass1 offset estimate. */
240 break;
241 case DASM_ALIGN:
242 ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
243 b[pos++] = ofs; /* Store pass1 offset estimate. */
244 break;
245 case DASM_EXTERN: p += 2; ofs += 4; break;
246 case DASM_ESC: p++; ofs++; break;
247 case DASM_MARK: mrm = p[-2]; break;
248 case DASM_SECTION:
249 n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
250 case DASM_STOP: goto stop;
251 }
252 }
253 }
254stop:
255 va_end(ap);
256 sec->pos = pos;
257 sec->ofs = ofs;
258}
259#undef CK
260
261/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
262int dasm_link(Dst_DECL, size_t *szp)
263{
264 dasm_State *D = Dst_REF;
265 int secnum;
266 int ofs = 0;
267
268#ifdef DASM_CHECKS
269 *szp = 0;
270 if (D->status != DASM_S_OK) return D->status;
271 {
272 int pc;
273 for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
274 if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
275 }
276#endif
277
278 { /* Handle globals not defined in this translation unit. */
279 int idx;
280 for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
281 int n = D->lglabels[idx];
282 /* Undefined label: Collapse rel chain and replace with marker (< 0). */
283 while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
284 }
285 }
286
287 /* Combine all code sections. No support for data sections (yet). */
288 for (secnum = 0; secnum < D->maxsection; secnum++) {
289 dasm_Section *sec = D->sections + secnum;
290 int *b = sec->rbuf;
291 int pos = DASM_SEC2POS(secnum);
292 int lastpos = sec->pos;
293
294 while (pos != lastpos) {
295 dasm_ActList p = D->actionlist + b[pos++];
296 while (1) {
297 int op, action = *p++;
298 switch (action) {
299 case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
300 case DASM_REL_PC: op = p[-2]; rel_pc: {
301 int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
302 if (shrink) { /* Shrinkable branch opcode? */
303 int lofs, lpos = b[pos];
304 if (lpos < 0) goto noshrink; /* Ext global? */
305 lofs = *DASM_POS2PTR(D, lpos);
306 if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
307 int i;
308 for (i = secnum; i < DASM_POS2SEC(lpos); i++)
309 lofs += D->sections[i].ofs;
310 } else {
311 lofs -= ofs; /* Bkwd label: unfix offset. */
312 }
313 lofs -= b[pos+1]; /* Short branch ok? */
314 if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
315 else { noshrink: shrink = 0; } /* No, cannot shrink op. */
316 }
317 b[pos+1] = shrink;
318 pos += 2;
319 break;
320 }
321 case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
322 case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
323 case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
324 case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
325 case DASM_LABEL_LG: p++;
326 case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
327 case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
328 case DASM_EXTERN: p += 2; break;
329 case DASM_ESC: p++; break;
330 case DASM_MARK: break;
331 case DASM_SECTION: case DASM_STOP: goto stop;
332 }
333 }
334 stop: (void)0;
335 }
336 ofs += sec->ofs; /* Next section starts right after current section. */
337 }
338
339 D->codesize = ofs; /* Total size of all code sections */
340 *szp = ofs;
341 return DASM_S_OK;
342}
343
344#define dasmb(x) *cp++ = (unsigned char)(x)
345#ifndef DASM_ALIGNED_WRITES
346#define dasmw(x) \
347 do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
348#define dasmd(x) \
349 do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
350#else
351#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
352#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
353#endif
354
355/* Pass 3: Encode sections. */
356int dasm_encode(Dst_DECL, void *buffer)
357{
358 dasm_State *D = Dst_REF;
359 unsigned char *base = (unsigned char *)buffer;
360 unsigned char *cp = base;
361 int secnum;
362
363 /* Encode all code sections. No support for data sections (yet). */
364 for (secnum = 0; secnum < D->maxsection; secnum++) {
365 dasm_Section *sec = D->sections + secnum;
366 int *b = sec->buf;
367 int *endb = sec->rbuf + sec->pos;
368
369 while (b != endb) {
370 dasm_ActList p = D->actionlist + *b++;
371 unsigned char *mark = NULL;
372 while (1) {
373 int action = *p++;
374 int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
375 switch (action) {
376 case DASM_DISP: if (!mark) mark = cp; {
377 unsigned char *mm = mark;
378 if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
379 if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
380 if (mrm != 5) { mm[-1] -= 0x80; break; } }
381 if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
382 }
383 case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
384 case DASM_IMM_DB: if (((n+128)&-256) == 0) {
385 db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
386 } else mark = NULL;
387 case DASM_IMM_D: wd: dasmd(n); break;
388 case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
389 case DASM_IMM_W: dasmw(n); break;
390 case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; }
391 case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
392 b++; n = (int)(ptrdiff_t)D->globals[-n];
393 case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
394 case DASM_REL_PC: rel_pc: {
395 int shrink = *b++;
396 int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
397 n = *pb - ((int)(cp-base) + 4-shrink);
398 if (shrink == 0) goto wd;
399 if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
400 goto wb;
401 }
402 case DASM_IMM_LG:
403 p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
404 case DASM_IMM_PC: {
405 int *pb = DASM_POS2PTR(D, n);
406 n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
407 goto wd;
408 }
409 case DASM_LABEL_LG: {
410 int idx = *p++;
411 if (idx >= 10)
412 D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
413 break;
414 }
415 case DASM_LABEL_PC: case DASM_SETLABEL: break;
416 case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
417 case DASM_ALIGN:
418 n = *p++;
419 while (((cp-base) & n)) *cp++ = 0x90; /* nop */
420 break;
421 case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
422 case DASM_MARK: mark = cp; break;
423 case DASM_ESC: action = *p++;
424 default: *cp++ = action; break;
425 case DASM_SECTION: case DASM_STOP: goto stop;
426 }
427 }
428 stop: (void)0;
429 }
430 }
431
432 if (base + D->codesize != cp) /* Check for phase errors. */
433 return DASM_S_PHASE;
434 return DASM_S_OK;
435}
436
437/* Get PC label offset. */
438int dasm_getpclabel(Dst_DECL, unsigned int pc)
439{
440 dasm_State *D = Dst_REF;
441 if (pc*sizeof(int) < D->pcsize) {
442 int pos = D->pclabels[pc];
443 if (pos < 0) return *DASM_POS2PTR(D, -pos);
444 if (pos > 0) return -1; /* Undefined. */
445 }
446 return -2; /* Unused or out of range. */
447}
448
449#ifdef DASM_CHECKS
450/* Optional sanity checker to call between isolated encoding steps. */
451int dasm_checkstep(Dst_DECL, int secmatch)
452{
453 dasm_State *D = Dst_REF;
454 if (D->status == DASM_S_OK) {
455 int i;
456 for (i = 1; i <= 9; i++) {
457 if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
458 D->lglabels[i] = 0;
459 }
460 }
461 if (D->status == DASM_S_OK && secmatch >= 0 &&
462 D->section != &D->sections[secmatch])
463 D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
464 return D->status;
465}
466#endif
467
diff --git a/dynasm/dasm_x86.lua b/dynasm/dasm_x86.lua
new file mode 100644
index 00000000..82210806
--- /dev/null
+++ b/dynasm/dasm_x86.lua
@@ -0,0 +1,1799 @@
1------------------------------------------------------------------------------
2-- DynASM x86 module.
3--
4-- Copyright (C) 2005-2009 Mike Pall. All rights reserved.
5-- See dynasm.lua for full copyright notice.
6------------------------------------------------------------------------------
7
8-- Module information:
9local _info = {
10 arch = "x86",
11 description = "DynASM x86 (i386) module",
12 version = "1.2.1",
13 vernum = 10201,
14 release = "2009-04-16",
15 author = "Mike Pall",
16 license = "MIT",
17}
18
19-- Exported glue functions for the arch-specific module.
20local _M = { _info = _info }
21
22-- Cache library functions.
23local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24local assert, unpack = assert, unpack
25local _s = string
26local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
28local concat, sort = table.concat, table.sort
29local char, unpack = string.char, unpack
30
31-- Inherited tables and callbacks.
32local g_opt, g_arch
33local wline, werror, wfatal, wwarn
34
35-- Action name list.
36-- CHECK: Keep this in sync with the C code!
37local action_names = {
38 -- int arg, 1 buffer pos:
39 "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB",
40 -- action arg (1 byte), int arg, 1 buffer pos (reg/num):
41 "VREG", "SPACE",
42 -- ptrdiff_t arg, 1 buffer pos (address): !x64
43 "SETLABEL", "REL_A",
44 -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
45 "REL_LG", "REL_PC",
46 -- action arg (1 byte) or int arg, 1 buffer pos (link):
47 "IMM_LG", "IMM_PC",
48 -- action arg (1 byte) or int arg, 1 buffer pos (offset):
49 "LABEL_LG", "LABEL_PC",
50 -- action arg (1 byte), 1 buffer pos (offset):
51 "ALIGN",
52 -- action args (2 bytes), no buffer pos.
53 "EXTERN",
54 -- action arg (1 byte), no buffer pos.
55 "ESC",
56 -- no action arg, no buffer pos.
57 "MARK",
58 -- action arg (1 byte), no buffer pos, terminal action:
59 "SECTION",
60 -- no args, no buffer pos, terminal action:
61 "STOP"
62}
63
64-- Maximum number of section buffer positions for dasm_put().
65-- CHECK: Keep this in sync with the C code!
66local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
67
68-- Action name -> action number (dynamically generated below).
69local map_action = {}
70-- First action number. Everything below does not need to be escaped.
71local actfirst = 256-#action_names
72
73-- Action list buffer and string (only used to remove dupes).
74local actlist = {}
75local actstr = ""
76
77-- Argument list for next dasm_put(). Start with offset 0 into action list.
78local actargs = { 0 }
79
80-- Current number of section buffer positions for dasm_put().
81local secpos = 1
82
83------------------------------------------------------------------------------
84
85-- Compute action numbers for action names.
86for n,name in ipairs(action_names) do
87 local num = actfirst + n - 1
88 map_action[name] = num
89end
90
91-- Dump action names and numbers.
92local function dumpactions(out)
93 out:write("DynASM encoding engine action codes:\n")
94 for n,name in ipairs(action_names) do
95 local num = map_action[name]
96 out:write(format(" %-10s %02X %d\n", name, num, num))
97 end
98 out:write("\n")
99end
100
101-- Write action list buffer as a huge static C array.
102local function writeactions(out, name)
103 local nn = #actlist
104 local last = actlist[nn] or 255
105 actlist[nn] = nil -- Remove last byte.
106 if nn == 0 then nn = 1 end
107 out:write("static const unsigned char ", name, "[", nn, "] = {\n")
108 local s = " "
109 for n,b in ipairs(actlist) do
110 s = s..b..","
111 if #s >= 75 then
112 assert(out:write(s, "\n"))
113 s = " "
114 end
115 end
116 out:write(s, last, "\n};\n\n") -- Add last byte back.
117end
118
119------------------------------------------------------------------------------
120
121-- Add byte to action list.
122local function wputxb(n)
123 assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
124 actlist[#actlist+1] = n
125end
126
127-- Add action to list with optional arg. Advance buffer pos, too.
128local function waction(action, a, num)
129 wputxb(assert(map_action[action], "bad action name `"..action.."'"))
130 if a then actargs[#actargs+1] = a end
131 if a or num then secpos = secpos + (num or 1) end
132end
133
134-- Add call to embedded DynASM C code.
135local function wcall(func, args)
136 wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
137end
138
139-- Delete duplicate action list chunks. A tad slow, but so what.
140local function dedupechunk(offset)
141 local al, as = actlist, actstr
142 local chunk = char(unpack(al, offset+1, #al))
143 local orig = find(as, chunk, 1, true)
144 if orig then
145 actargs[1] = orig-1 -- Replace with original offset.
146 for i=offset+1,#al do al[i] = nil end -- Kill dupe.
147 else
148 actstr = as..chunk
149 end
150end
151
152-- Flush action list (intervening C code or buffer pos overflow).
153local function wflush(term)
154 local offset = actargs[1]
155 if #actlist == offset then return end -- Nothing to flush.
156 if not term then waction("STOP") end -- Terminate action list.
157 dedupechunk(offset)
158 wcall("put", actargs) -- Add call to dasm_put().
159 actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
160 secpos = 1 -- The actionlist offset occupies a buffer position, too.
161end
162
163-- Put escaped byte.
164local function wputb(n)
165 if n >= actfirst then waction("ESC") end -- Need to escape byte.
166 wputxb(n)
167end
168
169------------------------------------------------------------------------------
170
171-- Global label name -> global label number. With auto assignment on 1st use.
172local next_global = 10
173local map_global = setmetatable({}, { __index = function(t, name)
174 if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
175 local n = next_global
176 if n > 246 then werror("too many global labels") end
177 next_global = n + 1
178 t[name] = n
179 return n
180end})
181
182-- Dump global labels.
183local function dumpglobals(out, lvl)
184 local t = {}
185 for name, n in pairs(map_global) do t[n] = name end
186 out:write("Global labels:\n")
187 for i=10,next_global-1 do
188 out:write(format(" %s\n", t[i]))
189 end
190 out:write("\n")
191end
192
193-- Write global label enum.
194local function writeglobals(out, prefix)
195 local t = {}
196 for name, n in pairs(map_global) do t[n] = name end
197 out:write("enum {\n")
198 for i=10,next_global-1 do
199 out:write(" ", prefix, t[i], ",\n")
200 end
201 out:write(" ", prefix, "_MAX\n};\n")
202end
203
204-- Write global label names.
205local function writeglobalnames(out, name)
206 local t = {}
207 for name, n in pairs(map_global) do t[n] = name end
208 out:write("static const char *const ", name, "[] = {\n")
209 for i=10,next_global-1 do
210 out:write(" \"", t[i], "\",\n")
211 end
212 out:write(" (const char *)0\n};\n")
213end
214
215------------------------------------------------------------------------------
216
217-- Extern label name -> extern label number. With auto assignment on 1st use.
218local next_extern = -1
219local map_extern = setmetatable({}, { __index = function(t, name)
220 -- No restrictions on the name for now.
221 local n = next_extern
222 if n < -256 then werror("too many extern labels") end
223 next_extern = n - 1
224 t[name] = n
225 return n
226end})
227
228-- Dump extern labels.
229local function dumpexterns(out, lvl)
230 local t = {}
231 for name, n in pairs(map_extern) do t[-n] = name end
232 out:write("Extern labels:\n")
233 for i=1,-next_extern-1 do
234 out:write(format(" %s\n", t[i]))
235 end
236 out:write("\n")
237end
238
239-- Write extern label names.
240local function writeexternnames(out, name)
241 local t = {}
242 for name, n in pairs(map_extern) do t[-n] = name end
243 out:write("static const char *const ", name, "[] = {\n")
244 for i=1,-next_extern-1 do
245 out:write(" \"", t[i], "\",\n")
246 end
247 out:write(" (const char *)0\n};\n")
248end
249
250------------------------------------------------------------------------------
251
252-- Arch-specific maps.
253local map_archdef = {} -- Ext. register name -> int. name.
254local map_reg_rev = {} -- Int. register name -> ext. name.
255local map_reg_num = {} -- Int. register name -> register number.
256local map_reg_opsize = {} -- Int. register name -> operand size.
257local map_reg_valid_base = {} -- Int. register name -> valid base register?
258local map_reg_valid_index = {} -- Int. register name -> valid index register?
259local reg_list = {} -- Canonical list of int. register names.
260
261local map_type = {} -- Type name -> { ctype, reg }
262local ctypenum = 0 -- Type number (for _PTx macros).
263
264local addrsize = "d" -- Size for address operands. !x64
265
266-- Helper function to fill register maps.
267local function mkrmap(sz, cl, names)
268 local cname = format("@%s", sz)
269 reg_list[#reg_list+1] = cname
270 map_archdef[cl] = cname
271 map_reg_rev[cname] = cl
272 map_reg_num[cname] = -1
273 map_reg_opsize[cname] = sz
274 if sz == addrsize then
275 map_reg_valid_base[cname] = true
276 map_reg_valid_index[cname] = true
277 end
278 for n,name in ipairs(names) do
279 local iname = format("@%s%x", sz, n-1)
280 reg_list[#reg_list+1] = iname
281 map_archdef[name] = iname
282 map_reg_rev[iname] = name
283 map_reg_num[iname] = n-1
284 map_reg_opsize[iname] = sz
285 if sz == addrsize then
286 map_reg_valid_base[iname] = true
287 map_reg_valid_index[iname] = true
288 end
289 end
290 reg_list[#reg_list+1] = ""
291end
292
293-- Integer registers (dword, word and byte sized).
294mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
295map_reg_valid_index[map_archdef.esp] = false
296mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
297mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
298map_archdef["Ra"] = "@"..addrsize
299
300-- FP registers (internally tword sized, but use "f" as operand size).
301mkrmap("f", "Rf", {"st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"})
302
303-- SSE registers (oword sized, but qword and dword accessible).
304mkrmap("o", "xmm", {"xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"})
305
306-- Operand size prefixes to codes.
307local map_opsize = {
308 byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t",
309 aword = addrsize,
310}
311
312-- Operand size code to number.
313local map_opsizenum = {
314 b = 1, w = 2, d = 4, q = 8, o = 16, t = 10,
315}
316
317-- Operand size code to name.
318local map_opsizename = {
319 b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword",
320 f = "fpword",
321}
322
323-- Valid index register scale factors.
324local map_xsc = {
325 ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
326}
327
328-- Condition codes.
329local map_cc = {
330 o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
331 s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
332 c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
333 pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15,
334}
335
336
337-- Reverse defines for registers.
338function _M.revdef(s)
339 return gsub(s, "@%w+", map_reg_rev)
340end
341
342-- Dump register names and numbers
343local function dumpregs(out)
344 out:write("Register names, sizes and internal numbers:\n")
345 for _,reg in ipairs(reg_list) do
346 if reg == "" then
347 out:write("\n")
348 else
349 local name = map_reg_rev[reg]
350 local num = map_reg_num[reg]
351 local opsize = map_opsizename[map_reg_opsize[reg]]
352 out:write(format(" %-5s %-8s %s\n", name, opsize,
353 num < 0 and "(variable)" or num))
354 end
355 end
356end
357
358------------------------------------------------------------------------------
359
360-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
361local function wputlabel(aprefix, imm, num)
362 if type(imm) == "number" then
363 if imm < 0 then
364 waction("EXTERN")
365 wputxb(aprefix == "IMM_" and 0 or 1)
366 imm = -imm-1
367 else
368 waction(aprefix.."LG", nil, num);
369 end
370 wputxb(imm)
371 else
372 waction(aprefix.."PC", imm, num)
373 end
374end
375
376-- Put signed byte or arg.
377local function wputsbarg(n)
378 if type(n) == "number" then
379 if n < -128 or n > 127 then
380 werror("signed immediate byte out of range")
381 end
382 if n < 0 then n = n + 256 end
383 wputb(n)
384 else waction("IMM_S", n) end
385end
386
387-- Put unsigned byte or arg.
388local function wputbarg(n)
389 if type(n) == "number" then
390 if n < 0 or n > 255 then
391 werror("unsigned immediate byte out of range")
392 end
393 wputb(n)
394 else waction("IMM_B", n) end
395end
396
397-- Put unsigned word or arg.
398local function wputwarg(n)
399 if type(n) == "number" then
400 if n < 0 or n > 65535 then
401 werror("unsigned immediate word out of range")
402 end
403 local r = n%256; n = (n-r)/256; wputb(r); wputb(n);
404 else waction("IMM_W", n) end
405end
406
407-- Put signed or unsigned dword or arg.
408local function wputdarg(n)
409 local tn = type(n)
410 if tn == "number" then
411 if n < 0 then n = n + 4294967296 end
412 local r = n%256; n = (n-r)/256; wputb(r);
413 r = n%256; n = (n-r)/256; wputb(r);
414 r = n%256; n = (n-r)/256; wputb(r); wputb(n);
415 elseif tn == "table" then
416 wputlabel("IMM_", n[1], 1)
417 else
418 waction("IMM_D", n)
419 end
420end
421
422-- Put operand-size dependent number or arg (defaults to dword).
423local function wputszarg(sz, n)
424 if not sz or sz == "d" then wputdarg(n)
425 elseif sz == "w" then wputwarg(n)
426 elseif sz == "b" then wputbarg(n)
427 elseif sz == "s" then wputsbarg(n)
428 else werror("bad operand size") end
429end
430
431-- Put multi-byte opcode with operand-size dependent modifications.
432local function wputop(sz, op)
433 local r
434 if sz == "w" then wputb(102) end
435 -- Needs >32 bit numbers, but only for crc32 eax, word [ebx]
436 if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end
437 if op >= 16777216 then r = op % 16777216 wputb((op-r) / 16777216) op = r end
438 if op >= 65536 then r = op % 65536 wputb((op-r) / 65536) op = r end
439 if op >= 256 then r = op % 256 wputb((op-r) / 256) op = r end
440 if sz == "b" then op = op - 1 end
441 wputb(op)
442end
443
444-- Put ModRM or SIB formatted byte.
445local function wputmodrm(m, s, rm, vs, vrm)
446 assert(m < 4 and s < 8 and rm < 8, "bad modrm operands")
447 wputb(64*m + 8*s + rm)
448end
449
450-- Put ModRM/SIB plus optional displacement.
451local function wputmrmsib(t, imark, s, vsreg)
452 local vreg, vxreg
453 local reg, xreg = t.reg, t.xreg
454 if reg and reg < 0 then reg = 0; vreg = t.vreg end
455 if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end
456 if s < 0 then s = 0 end
457
458 -- Register mode.
459 if sub(t.mode, 1, 1) == "r" then
460 wputmodrm(3, s, reg)
461 if vsreg then waction("VREG", vsreg); wputxb(2) end
462 if vreg then waction("VREG", vreg); wputxb(0) end
463 return
464 end
465
466 local disp = t.disp
467 local tdisp = type(disp)
468 -- No base register?
469 if not reg then
470 if xreg then
471 -- Indexed mode with index register only.
472 -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
473 wputmodrm(0, s, 4)
474 if imark then waction("MARK") end
475 if vsreg then waction("VREG", vsreg); wputxb(2) end
476 wputmodrm(t.xsc, xreg, 5)
477 if vxreg then waction("VREG", vxreg); wputxb(3) end
478 else
479 -- Pure displacement.
480 wputmodrm(0, s, 5) -- [disp] -> (0, s, ebp)
481 if imark then waction("MARK") end
482 if vsreg then waction("VREG", vsreg); wputxb(2) end
483 end
484 wputdarg(disp)
485 return
486 end
487
488 local m
489 if tdisp == "number" then -- Check displacement size at assembly time.
490 if disp == 0 and reg ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too)
491 if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0]
492 elseif disp >= -128 and disp <= 127 then m = 1
493 else m = 2 end
494 elseif tdisp == "table" then
495 m = 2
496 end
497
498 -- Index register present or esp as base register: need SIB encoding.
499 if xreg or reg == 4 then
500 wputmodrm(m or 2, s, 4) -- ModRM.
501 if m == nil or imark then waction("MARK") end
502 if vsreg then waction("VREG", vsreg); wputxb(2) end
503 wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB.
504 if vxreg then waction("VREG", vxreg); wputxb(3) end
505 if vreg then waction("VREG", vreg); wputxb(1) end
506 else
507 wputmodrm(m or 2, s, reg) -- ModRM.
508 if (imark and (m == 1 or m == 2)) or
509 (m == nil and (vsreg or vreg)) then waction("MARK") end
510 if vsreg then waction("VREG", vsreg); wputxb(2) end
511 if vreg then waction("VREG", vreg); wputxb(1) end
512 end
513
514 -- Put displacement.
515 if m == 1 then wputsbarg(disp)
516 elseif m == 2 then wputdarg(disp)
517 elseif m == nil then waction("DISP", disp) end
518end
519
520------------------------------------------------------------------------------
521
522-- Return human-readable operand mode string.
523local function opmodestr(op, args)
524 local m = {}
525 for i=1,#args do
526 local a = args[i]
527 m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
528 end
529 return op.." "..concat(m, ",")
530end
531
532-- Convert number to valid integer or nil.
533local function toint(expr)
534 local n = tonumber(expr)
535 if n then
536 if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
537 werror("bad integer number `"..expr.."'")
538 end
539 return n
540 end
541end
542
543-- Parse immediate expression.
544local function immexpr(expr)
545 -- &expr (pointer)
546 if sub(expr, 1, 1) == "&" then
547 return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
548 end
549
550 local prefix = sub(expr, 1, 2)
551 -- =>expr (pc label reference)
552 if prefix == "=>" then
553 return "iJ", sub(expr, 3)
554 end
555 -- ->name (global label reference)
556 if prefix == "->" then
557 return "iJ", map_global[sub(expr, 3)]
558 end
559
560 -- [<>][1-9] (local label reference)
561 local dir, lnum = match(expr, "^([<>])([1-9])$")
562 if dir then -- Fwd: 247-255, Bkwd: 1-9.
563 return "iJ", lnum + (dir == ">" and 246 or 0)
564 end
565
566 local extname = match(expr, "^extern%s+(%S+)$")
567 if extname then
568 return "iJ", map_extern[extname]
569 end
570
571 -- expr (interpreted as immediate)
572 return "iI", expr
573end
574
575-- Parse displacement expression: +-num, +-expr, +-opsize*num
576local function dispexpr(expr)
577 local disp = expr == "" and 0 or toint(expr)
578 if disp then return disp end
579 local c, dispt = match(expr, "^([+-])%s*(.+)$")
580 if c == "+" then
581 expr = dispt
582 elseif not c then
583 werror("bad displacement expression `"..expr.."'")
584 end
585 local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
586 local ops, imm = map_opsize[opsize], toint(tailops)
587 if ops and imm then
588 if c == "-" then imm = -imm end
589 return imm*map_opsizenum[ops]
590 end
591 local mode, iexpr = immexpr(dispt)
592 if mode == "iJ" then
593 if c == "-" then werror("cannot invert label reference") end
594 return { iexpr }
595 end
596 return expr -- Need to return original signed expression.
597end
598
599-- Parse register or type expression.
600local function rtexpr(expr)
601 if not expr then return end
602 local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
603 local tp = map_type[tname or expr]
604 if tp then
605 local reg = ovreg or tp.reg
606 local rnum = map_reg_num[reg]
607 if not rnum then
608 werror("type `"..(tname or expr).."' needs a register override")
609 end
610 if not map_reg_valid_base[reg] then
611 werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
612 end
613 return reg, rnum, tp
614 end
615 return expr, map_reg_num[expr]
616end
617
618-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
619local function parseoperand(param)
620 local t = {}
621
622 local expr = param
623 local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
624 if opsize then
625 t.opsize = map_opsize[opsize]
626 if t.opsize then expr = tailops end
627 end
628
629 local br = match(expr, "^%[%s*(.-)%s*%]$")
630 repeat
631 if br then
632 t.mode = "xm"
633
634 -- [disp]
635 t.disp = toint(br)
636 if t.disp then
637 t.mode = "xmO"
638 break
639 end
640
641 -- [reg...]
642 local tp
643 local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
644 reg, t.reg, tp = rtexpr(reg)
645 if not t.reg then
646 -- [expr]
647 t.mode = "xmO"
648 t.disp = dispexpr("+"..br)
649 break
650 end
651
652 if t.reg == -1 then
653 t.vreg, tailr = match(tailr, "^(%b())(.*)$")
654 if not t.vreg then werror("bad variable register expression") end
655 end
656
657 -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
658 local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
659 if xsc then
660 if not map_reg_valid_index[reg] then
661 werror("bad index register `"..map_reg_rev[reg].."'")
662 end
663 t.xsc = map_xsc[xsc]
664 t.xreg = t.reg
665 t.vxreg = t.vreg
666 t.reg = nil
667 t.vreg = nil
668 t.disp = dispexpr(tailsc)
669 break
670 end
671 if not map_reg_valid_base[reg] then
672 werror("bad base register `"..map_reg_rev[reg].."'")
673 end
674
675 -- [reg] or [reg+-disp]
676 t.disp = toint(tailr) or (tailr == "" and 0)
677 if t.disp then break end
678
679 -- [reg+xreg...]
680 local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
681 xreg, t.xreg, tp = rtexpr(xreg)
682 if not t.xreg then
683 -- [reg+-expr]
684 t.disp = dispexpr(tailr)
685 break
686 end
687 if not map_reg_valid_index[xreg] then
688 werror("bad index register `"..map_reg_rev[xreg].."'")
689 end
690
691 if t.xreg == -1 then
692 t.vxreg, tailx = match(tailx, "^(%b())(.*)$")
693 if not t.vxreg then werror("bad variable register expression") end
694 end
695
696 -- [reg+xreg*xsc...]
697 local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
698 if xsc then
699 t.xsc = map_xsc[xsc]
700 tailx = tailsc
701 end
702
703 -- [...] or [...+-disp] or [...+-expr]
704 t.disp = dispexpr(tailx)
705 else
706 -- imm or opsize*imm
707 local imm = toint(expr)
708 if not imm and sub(expr, 1, 1) == "*" and t.opsize then
709 imm = toint(sub(expr, 2))
710 if imm then
711 imm = imm * map_opsizenum[t.opsize]
712 t.opsize = nil
713 end
714 end
715 if imm then
716 if t.opsize then werror("bad operand size override") end
717 local m = "i"
718 if imm == 1 then m = m.."1" end
719 if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
720 if imm >= -128 and imm <= 127 then m = m.."S" end
721 t.imm = imm
722 t.mode = m
723 break
724 end
725
726 local tp
727 local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
728 reg, t.reg, tp = rtexpr(reg)
729 if t.reg then
730 if t.reg == -1 then
731 t.vreg, tailr = match(tailr, "^(%b())(.*)$")
732 if not t.vreg then werror("bad variable register expression") end
733 end
734 -- reg
735 if tailr == "" then
736 if t.opsize then werror("bad operand size override") end
737 t.opsize = map_reg_opsize[reg]
738 if t.opsize == "f" then
739 t.mode = t.reg == 0 and "fF" or "f"
740 else
741 if reg == "@w4" then wwarn("bad idea, try again with `esp'") end
742 t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
743 end
744 break
745 end
746
747 -- type[idx], type[idx].field, type->field -> [reg+offset_expr]
748 if not tp then werror("bad operand `"..param.."'") end
749 t.mode = "xm"
750 t.disp = format(tp.ctypefmt, tailr)
751 else
752 t.mode, t.imm = immexpr(expr)
753 if sub(t.mode, -1) == "J" then
754 if t.opsize and t.opsize ~= addrsize then
755 werror("bad operand size override")
756 end
757 t.opsize = addrsize
758 end
759 end
760 end
761 until true
762 return t
763end
764
765------------------------------------------------------------------------------
766-- x86 Template String Description
767-- ===============================
768--
769-- Each template string is a list of [match:]pattern pairs,
770-- separated by "|". The first match wins. No match means a
771-- bad or unsupported combination of operand modes or sizes.
772--
773-- The match part and the ":" is omitted if the operation has
774-- no operands. Otherwise the first N characters are matched
775-- against the mode strings of each of the N operands.
776--
777-- The mode string for each operand type is (see parseoperand()):
778-- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
779-- FP register: "f", +"F" for st0
780-- Index operand: "xm", +"O" for [disp] (pure offset)
781-- Immediate: "i", +"S" for signed 8 bit, +"1" for 1,
782-- +"I" for arg, +"P" for pointer
783-- Any: +"J" for valid jump targets
784--
785-- So a match character "m" (mixed) matches both an integer register
786-- and an index operand (to be encoded with the ModRM/SIB scheme).
787-- But "r" matches only a register and "x" only an index operand
788-- (e.g. for FP memory access operations).
789--
790-- The operand size match string starts right after the mode match
791-- characters and ends before the ":". "dwb" is assumed, if empty.
792-- The effective data size of the operation is matched against this list.
793--
794-- If only the regular "b", "w", "d", "q", "t" operand sizes are
795-- present, then all operands must be the same size. Unspecified sizes
796-- are ignored, but at least one operand must have a size or the pattern
797-- won't match (use the "byte", "word", "dword", "qword", "tword"
798-- operand size overrides. E.g.: mov dword [eax], 1).
799--
800-- If the list has a "1" or "2" prefix, the operand size is taken
801-- from the respective operand and any other operand sizes are ignored.
802-- If the list contains only ".", all operand sizes are ignored.
803-- If the list has a "/" prefix, the concatenated (mixed) operand sizes
804-- are compared to the match.
805--
806-- E.g. "rrdw" matches for either two dword registers or two word
807-- registers. "Fx2dq" matches an st0 operand plus an index operand
808-- pointing to a dword (float) or qword (double).
809--
810-- Every character after the ":" is part of the pattern string:
811-- Hex chars are accumulated to form the opcode (left to right).
812-- "n" disables the standard opcode mods
813-- (otherwise: -1 for "b", o16 prefix for "w")
814-- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode.
815-- "m"/"M" generates ModRM/SIB from the 1st/2nd operand.
816-- The spare 3 bits are either filled with the last hex digit or
817-- the result from a previous "r"/"R". The opcode is restored.
818--
819-- All of the following characters force a flush of the opcode:
820-- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand.
821-- "S" stores a signed 8 bit immediate from the last operand.
822-- "U" stores an unsigned 8 bit immediate from the last operand.
823-- "W" stores an unsigned 16 bit immediate from the last operand.
824-- "i" stores an operand sized immediate from the last operand.
825-- "I" dito, but generates an action code to optionally modify
826-- the opcode (+2) for a signed 8 bit immediate.
827-- "J" generates one of the REL action codes from the last operand.
828--
829------------------------------------------------------------------------------
830
831-- Template strings for x86 instructions. Ordered by first opcode byte.
832-- Unimplemented opcodes (deliberate omissions) are marked with *.
833local map_op = {
834 -- 00-05: add...
835 -- 06: *push es
836 -- 07: *pop es
837 -- 08-0D: or...
838 -- 0E: *push cs
839 -- 0F: two byte opcode prefix
840 -- 10-15: adc...
841 -- 16: *push ss
842 -- 17: *pop ss
843 -- 18-1D: sbb...
844 -- 1E: *push ds
845 -- 1F: *pop ds
846 -- 20-25: and...
847 es_0 = "26",
848 -- 27: *daa
849 -- 28-2D: sub...
850 cs_0 = "2E",
851 -- 2F: *das
852 -- 30-35: xor...
853 ss_0 = "36",
854 -- 37: *aaa
855 -- 38-3D: cmp...
856 ds_0 = "3E",
857 -- 3F: *aas
858 inc_1 = "rdw:40r|m:FF0m",
859 dec_1 = "rdw:48r|m:FF1m",
860 push_1 = "rdw:50r|mdw:FF6m|S.:6AS|ib:n6Ai|i.:68i",
861 pop_1 = "rdw:58r|mdw:8F0m",
862 -- 60: *pusha, *pushad, *pushaw
863 -- 61: *popa, *popad, *popaw
864 -- 62: *bound rdw,x
865 -- 63: *arpl mw,rw
866 fs_0 = "64",
867 gs_0 = "65",
868 o16_0 = "66",
869 a16_0 = "67",
870 -- 68: push idw
871 -- 69: imul rdw,mdw,idw
872 -- 6A: push ib
873 -- 6B: imul rdw,mdw,S
874 -- 6C: *insb
875 -- 6D: *insd, *insw
876 -- 6E: *outsb
877 -- 6F: *outsd, *outsw
878 -- 70-7F: jcc lb
879 -- 80: add... mb,i
880 -- 81: add... mdw,i
881 -- 82: *undefined
882 -- 83: add... mdw,S
883 test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi",
884 -- 86: xchg rb,mb
885 -- 87: xchg rdw,mdw
886 -- 88: mov mb,r
887 -- 89: mov mdw,r
888 -- 8A: mov r,mb
889 -- 8B: mov r,mdw
890 -- 8C: *mov mdw,seg
891 lea_2 = "rxd:8DrM",
892 -- 8E: *mov seg,mdw
893 -- 8F: pop mdw
894 nop_0 = "90",
895 xchg_2 = "Rrdw:90R|rRdw:90r|rm:87rM|mr:87Rm",
896 cbw_0 = "6698",
897 cwde_0 = "98",
898 cwd_0 = "6699",
899 cdq_0 = "99",
900 -- 9A: *call iw:idw
901 wait_0 = "9B",
902 fwait_0 = "9B",
903 pushf_0 = "9C",
904 pushfw_0 = "669C",
905 pushfd_0 = "9C",
906 popf_0 = "9D",
907 popfw_0 = "669D",
908 popfd_0 = "9D",
909 sahf_0 = "9E",
910 lahf_0 = "9F",
911 mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
912 movsb_0 = "A4",
913 movsw_0 = "66A5",
914 movsd_0 = "A5",
915 cmpsb_0 = "A6",
916 cmpsw_0 = "66A7",
917 cmpsd_0 = "A7",
918 -- A8: test Rb,i
919 -- A9: test Rdw,i
920 stosb_0 = "AA",
921 stosw_0 = "66AB",
922 stosd_0 = "AB",
923 lodsb_0 = "AC",
924 lodsw_0 = "66AD",
925 lodsd_0 = "AD",
926 scasb_0 = "AE",
927 scasw_0 = "66AF",
928 scasd_0 = "AF",
929 -- B0-B7: mov rb,i
930 -- B8-BF: mov rdw,i
931 -- C0: rol... mb,i
932 -- C1: rol... mdw,i
933 ret_1 = "i.:nC2W",
934 ret_0 = "C3",
935 -- C4: *les rdw,mq
936 -- C5: *lds rdw,mq
937 -- C6: mov mb,i
938 -- C7: mov mdw,i
939 -- C8: *enter iw,ib
940 leave_0 = "C9",
941 -- CA: *retf iw
942 -- CB: *retf
943 int3_0 = "CC",
944 int_1 = "i.:nCDU",
945 into_0 = "CE",
946 -- CF: *iret
947 -- D0: rol... mb,1
948 -- D1: rol... mdw,1
949 -- D2: rol... mb,cl
950 -- D3: rol... mb,cl
951 -- D4: *aam ib
952 -- D5: *aad ib
953 -- D6: *salc
954 -- D7: *xlat
955 -- D8-DF: floating point ops
956 -- E0: *loopne
957 -- E1: *loope
958 -- E2: *loop
959 -- E3: *jcxz, *jecxz
960 -- E4: *in Rb,ib
961 -- E5: *in Rdw,ib
962 -- E6: *out ib,Rb
963 -- E7: *out ib,Rdw
964 call_1 = "md:FF2m|J.:E8J",
965 jmp_1 = "md:FF4m|J.:E9J", -- short: EB
966 -- EA: *jmp iw:idw
967 -- EB: jmp ib
968 -- EC: *in Rb,dx
969 -- ED: *in Rdw,dx
970 -- EE: *out dx,Rb
971 -- EF: *out dx,Rdw
972 -- F0: *lock
973 int1_0 = "F1",
974 repne_0 = "F2",
975 repnz_0 = "F2",
976 rep_0 = "F3",
977 repe_0 = "F3",
978 repz_0 = "F3",
979 -- F4: *hlt
980 cmc_0 = "F5",
981 -- F6: test... mb,i; div... mb
982 -- F7: test... mdw,i; div... mdw
983 clc_0 = "F8",
984 stc_0 = "F9",
985 -- FA: *cli
986 cld_0 = "FC",
987 std_0 = "FD",
988 -- FE: inc... mb
989 -- FF: inc... mdw
990
991 -- misc ops
992 not_1 = "m:F72m",
993 neg_1 = "m:F73m",
994 mul_1 = "m:F74m",
995 imul_1 = "m:F75m",
996 div_1 = "m:F76m",
997 idiv_1 = "m:F77m",
998
999 imul_2 = "rmdw:0FAFrM|rIdw:69rmI|rSdw:6BrmS|ridw:69rmi",
1000 imul_3 = "rmIdw:69rMI|rmSdw:6BrMS|rmidw:69rMi",
1001
1002 movzx_2 = "rm/db:0FB6rM|rm/wb:0FB6rM|rm/dw:0FB7rM",
1003 movsx_2 = "rm/db:0FBErM|rm/wb:0FBErM|rm/dw:0FBFrM",
1004
1005 bswap_1 = "rd:0FC8r",
1006 bsf_2 = "rmdw:0FBCrM",
1007 bsr_2 = "rmdw:0FBDrM",
1008 bt_2 = "mrdw:0FA3Rm|midw:0FBA4mU",
1009 btc_2 = "mrdw:0FBBRm|midw:0FBA7mU",
1010 btr_2 = "mrdw:0FB3Rm|midw:0FBA6mU",
1011 bts_2 = "mrdw:0FABRm|midw:0FBA5mU",
1012
1013 rdtsc_0 = "0F31", -- P1+
1014 cpuid_0 = "0FA2", -- P1+
1015
1016 -- floating point ops
1017 fst_1 = "ff:DDD0r|xd:D92m|xq:DD2m",
1018 fstp_1 = "ff:DDD8r|xd:D93m|xq:DD3m|xt:DB7m",
1019 fld_1 = "ff:D9C0r|xd:D90m|xq:DD0m|xt:DB5m",
1020
1021 fpop_0 = "DDD8", -- Alias for fstp st0.
1022
1023 fist_1 = "xw:nDF2m|xd:DB2m",
1024 fistp_1 = "xw:nDF3m|xd:DB3m|xq:DF7m",
1025 fild_1 = "xw:nDF0m|xd:DB0m|xq:DF5m",
1026
1027 fxch_0 = "D9C9",
1028 fxch_1 = "ff:D9C8r",
1029 fxch_2 = "fFf:D9C8r|Fff:D9C8R",
1030
1031 fucom_1 = "ff:DDE0r",
1032 fucom_2 = "Fff:DDE0R",
1033 fucomp_1 = "ff:DDE8r",
1034 fucomp_2 = "Fff:DDE8R",
1035 fucomi_1 = "ff:DBE8r", -- P6+
1036 fucomi_2 = "Fff:DBE8R", -- P6+
1037 fucomip_1 = "ff:DFE8r", -- P6+
1038 fucomip_2 = "Fff:DFE8R", -- P6+
1039 fcomi_1 = "ff:DBF0r", -- P6+
1040 fcomi_2 = "Fff:DBF0R", -- P6+
1041 fcomip_1 = "ff:DFF0r", -- P6+
1042 fcomip_2 = "Fff:DFF0R", -- P6+
1043 fucompp_0 = "DAE9",
1044 fcompp_0 = "DED9",
1045
1046 fldcw_1 = "xw:nD95m",
1047 fstcw_1 = "xw:n9BD97m",
1048 fnstcw_1 = "xw:nD97m",
1049 fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m",
1050 fnstsw_1 = "Rw:nDFE0|xw:nDD7m",
1051 fclex_0 = "9BDBE2",
1052 fnclex_0 = "DBE2",
1053
1054 fnop_0 = "D9D0",
1055 -- D9D1-D9DF: unassigned
1056
1057 fchs_0 = "D9E0",
1058 fabs_0 = "D9E1",
1059 -- D9E2: unassigned
1060 -- D9E3: unassigned
1061 ftst_0 = "D9E4",
1062 fxam_0 = "D9E5",
1063 -- D9E6: unassigned
1064 -- D9E7: unassigned
1065 fld1_0 = "D9E8",
1066 fldl2t_0 = "D9E9",
1067 fldl2e_0 = "D9EA",
1068 fldpi_0 = "D9EB",
1069 fldlg2_0 = "D9EC",
1070 fldln2_0 = "D9ED",
1071 fldz_0 = "D9EE",
1072 -- D9EF: unassigned
1073
1074 f2xm1_0 = "D9F0",
1075 fyl2x_0 = "D9F1",
1076 fptan_0 = "D9F2",
1077 fpatan_0 = "D9F3",
1078 fxtract_0 = "D9F4",
1079 fprem1_0 = "D9F5",
1080 fdecstp_0 = "D9F6",
1081 fincstp_0 = "D9F7",
1082 fprem_0 = "D9F8",
1083 fyl2xp1_0 = "D9F9",
1084 fsqrt_0 = "D9FA",
1085 fsincos_0 = "D9FB",
1086 frndint_0 = "D9FC",
1087 fscale_0 = "D9FD",
1088 fsin_0 = "D9FE",
1089 fcos_0 = "D9FF",
1090
1091 -- SSE, SSE2
1092 andnpd_2 = "rmo:660F55rM",
1093 andnps_2 = "rmo:0F55rM",
1094 andpd_2 = "rmo:660F54rM",
1095 andps_2 = "rmo:0F54rM",
1096 clflush_1 = "x.:0FAE7m",
1097 cmppd_3 = "rmio:660FC2rMU",
1098 cmpps_3 = "rmio:0FC2rMU",
1099 cmpsd_3 = "rmio:F20FC2rMU",
1100 cmpss_3 = "rmio:F30FC2rMU",
1101 comisd_2 = "rmo:660F2FrM",
1102 comiss_2 = "rmo:0F2FrM",
1103 cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:",
1104 cvtdq2ps_2 = "rmo:0F5BrM",
1105 cvtpd2dq_2 = "rmo:F20FE6rM",
1106 cvtpd2ps_2 = "rmo:660F5ArM",
1107 cvtpi2pd_2 = "rx/oq:660F2ArM",
1108 cvtpi2ps_2 = "rx/oq:0F2ArM",
1109 cvtps2dq_2 = "rmo:660F5BrM",
1110 cvtps2pd_2 = "rro:0F5ArM|rx/oq:",
1111 cvtsd2si_2 = "rr/do:F20F2DrM|rx/dq:",
1112 cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:",
1113 cvtsi2sd_2 = "rm/od:F20F2ArM",
1114 cvtsi2ss_2 = "rm/od:F30F2ArM",
1115 cvtss2sd_2 = "rro:F30F5ArM|rx/od:",
1116 cvtss2si_2 = "rr/do:F20F2CrM|rx/dd:",
1117 cvttpd2dq_2 = "rmo:660FE6rM",
1118 cvttps2dq_2 = "rmo:F30F5BrM",
1119 cvttsd2si_2 = "rr/do:F20F2CrM|rx/dq:",
1120 cvttss2si_2 = "rr/do:F30F2CrM|rx/dd:",
1121 ldmxcsr_1 = "xd:0FAE2m",
1122 lfence_0 = "0FAEE8",
1123 maskmovdqu_2 = "rro:660FF7rM",
1124 mfence_0 = "0FAEF0",
1125 movapd_2 = "rmo:660F28rM|mro:660F29Rm",
1126 movaps_2 = "rmo:0F28rM|mro:0F29Rm",
1127 movd_2 = "rm/od:660F6ErM|mr/do:660F7ERm",
1128 movdqa_2 = "rmo:660F6FrM|mro:660F7FRm",
1129 movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm",
1130 movhlps_2 = "rro:0F12rM",
1131 movhpd_2 = "rx/oq:660F16rM|xr/qo:660F17Rm",
1132 movhps_2 = "rx/oq:0F16rM|xr/qo:0F17Rm",
1133 movlhps_2 = "rro:0F16rM",
1134 movlpd_2 = "rx/oq:660F12rM|xr/qo:660F13Rm",
1135 movlps_2 = "rx/oq:0F12rM|xr/qo:0F13Rm",
1136 movmskpd_2 = "rr/do:660F50rM",
1137 movmskps_2 = "rr/do:0F50rM",
1138 movntdq_2 = "xro:660FE7Rm",
1139 movnti_2 = "xrd:0FC3Rm",
1140 movntpd_2 = "xro:660F2BRm",
1141 movntps_2 = "xro:0F2BRm",
1142 movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:660FD6Rm",
1143 movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:F20F11Rm",
1144 movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
1145 movupd_2 = "rmo:660F10rM|mro:660F11Rm",
1146 movups_2 = "rmo:0F10rM|mro:0F11Rm",
1147 orpd_2 = "rmo:660F56rM",
1148 orps_2 = "rmo:0F56rM",
1149 packssdw_2 = "rmo:660F6BrM",
1150 packsswb_2 = "rmo:660F63rM",
1151 packuswb_2 = "rmo:660F67rM",
1152 paddb_2 = "rmo:660FFCrM",
1153 paddd_2 = "rmo:660FFErM",
1154 paddq_2 = "rmo:660FD4rM",
1155 paddsb_2 = "rmo:660FECrM",
1156 paddsw_2 = "rmo:660FEDrM",
1157 paddusb_2 = "rmo:660FDCrM",
1158 paddusw_2 = "rmo:660FDDrM",
1159 paddw_2 = "rmo:660FFDrM",
1160 pand_2 = "rmo:660FDBrM",
1161 pandn_2 = "rmo:660FDFrM",
1162 pause_0 = "F390",
1163 pavgb_2 = "rmo:660FE0rM",
1164 pavgw_2 = "rmo:660FE3rM",
1165 pcmpeqb_2 = "rmo:660F74rM",
1166 pcmpeqd_2 = "rmo:660F76rM",
1167 pcmpeqw_2 = "rmo:660F75rM",
1168 pcmpgtb_2 = "rmo:660F64rM",
1169 pcmpgtd_2 = "rmo:660F66rM",
1170 pcmpgtw_2 = "rmo:660F65rM",
1171 pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nrMU", -- Mem op: SSE4.1 only.
1172 pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:",
1173 pmaddwd_2 = "rmo:660FF5rM",
1174 pmaxsw_2 = "rmo:660FEErM",
1175 pmaxub_2 = "rmo:660FDErM",
1176 pminsw_2 = "rmo:660FEArM",
1177 pminub_2 = "rmo:660FDArM",
1178 pmovmskb_2 = "rr/do:660FD7rM",
1179 pmulhuw_2 = "rmo:660FE4rM",
1180 pmulhw_2 = "rmo:660FE5rM",
1181 pmullw_2 = "rmo:660FD5rM",
1182 pmuludq_2 = "rmo:660FF4rM",
1183 por_2 = "rmo:660FEBrM",
1184 prefetchnta_1 = "xb:n0F180m",
1185 prefetcht0_1 = "xb:n0F181m",
1186 prefetcht1_1 = "xb:n0F182m",
1187 prefetcht2_1 = "xb:n0F183m",
1188 psadbw_2 = "rmo:660FF6rM",
1189 pshufd_3 = "rmio:660F70rMU",
1190 pshufhw_3 = "rmio:F30F70rMU",
1191 pshuflw_3 = "rmio:F20F70rMU",
1192 pslld_2 = "rmo:660FF2rM|rio:660F726mU",
1193 pslldq_2 = "rio:660F737mU",
1194 psllq_2 = "rmo:660FF3rM|rio:660F736mU",
1195 psllw_2 = "rmo:660FF1rM|rio:660F716mU",
1196 psrad_2 = "rmo:660FE2rM|rio:660F724mU",
1197 psraw_2 = "rmo:660FE1rM|rio:660F714mU",
1198 psrld_2 = "rmo:660FD2rM|rio:660F722mU",
1199 psrldq_2 = "rio:660F733mU",
1200 psrlq_2 = "rmo:660FD3rM|rio:660F732mU",
1201 psrlw_2 = "rmo:660FD1rM|rio:660F712mU",
1202 psubb_2 = "rmo:660FF8rM",
1203 psubd_2 = "rmo:660FFArM",
1204 psubq_2 = "rmo:660FFBrM",
1205 psubsb_2 = "rmo:660FE8rM",
1206 psubsw_2 = "rmo:660FE9rM",
1207 psubusb_2 = "rmo:660FD8rM",
1208 psubusw_2 = "rmo:660FD9rM",
1209 psubw_2 = "rmo:660FF9rM",
1210 punpckhbw_2 = "rmo:660F68rM",
1211 punpckhdq_2 = "rmo:660F6ArM",
1212 punpckhqdq_2 = "rmo:660F6DrM",
1213 punpckhwd_2 = "rmo:660F69rM",
1214 punpcklbw_2 = "rmo:660F60rM",
1215 punpckldq_2 = "rmo:660F62rM",
1216 punpcklqdq_2 = "rmo:660F6CrM",
1217 punpcklwd_2 = "rmo:660F61rM",
1218 pxor_2 = "rmo:660FEFrM",
1219 rcpps_2 = "rmo:0F53rM",
1220 rcpss_2 = "rmo:F30F53rM",
1221 rsqrtps_2 = "rmo:0F52rM",
1222 rsqrtss_2 = "rmo:F30F52rM",
1223 sfence_0 = "0FAEF8",
1224 shufpd_3 = "rmio:660FC6rMU",
1225 shufps_3 = "rmio:0FC6rMU",
1226 stmxcsr_1 = "xd:0FAE3m",
1227 ucomisd_2 = "rmo:660F2ErM",
1228 ucomiss_2 = "rmo:0F2ErM",
1229 unpckhpd_2 = "rmo:660F15rM",
1230 unpckhps_2 = "rmo:0F15rM",
1231 unpcklpd_2 = "rmo:660F14rM",
1232 unpcklps_2 = "rmo:0F14rM",
1233 xorpd_2 = "rmo:660F57rM",
1234 xorps_2 = "rmo:0F57rM",
1235
1236 -- SSE3 ops
1237 fisttp_1 = "xw:nDF1m|xd:DB1m|xq:DD1m",
1238 addsubpd_2 = "rmo:660FD0rM",
1239 addsubps_2 = "rmo:F20FD0rM",
1240 haddpd_2 = "rmo:660F7CrM",
1241 haddps_2 = "rmo:F20F7CrM",
1242 hsubpd_2 = "rmo:660F7DrM",
1243 hsubps_2 = "rmo:F20F7DrM",
1244 lddqu_2 = "rxo:F20FF0rM",
1245 movddup_2 = "rmo:F20F12rM",
1246 movshdup_2 = "rmo:F30F16rM",
1247 movsldup_2 = "rmo:F30F12rM",
1248
1249 -- SSSE3 ops
1250 pabsb_2 = "rmo:660F381CrM",
1251 pabsd_2 = "rmo:660F381ErM",
1252 pabsw_2 = "rmo:660F381DrM",
1253 palignr_3 = "rmio:660F3A0FrMU",
1254 phaddd_2 = "rmo:660F3802rM",
1255 phaddsw_2 = "rmo:660F3803rM",
1256 phaddw_2 = "rmo:660F3801rM",
1257 phsubd_2 = "rmo:660F3806rM",
1258 phsubsw_2 = "rmo:660F3807rM",
1259 phsubw_2 = "rmo:660F3805rM",
1260 pmaddubsw_2 = "rmo:660F3804rM",
1261 pmulhrsw_2 = "rmo:660F380BrM",
1262 pshufb_2 = "rmo:660F3800rM",
1263 psignb_2 = "rmo:660F3808rM",
1264 psignd_2 = "rmo:660F380ArM",
1265 psignw_2 = "rmo:660F3809rM",
1266
1267 -- SSE4.1 ops
1268 blendpd_3 = "rmio:660F3A0DrMU",
1269 blendps_3 = "rmio:660F3A0CrMU",
1270 blendvpd_3 = "rmRo:660F3815rM",
1271 blendvps_3 = "rmRo:660F3814rM",
1272 dppd_3 = "rmio:660F3A41rMU",
1273 dpps_3 = "rmio:660F3A40rMU",
1274 extractps_3 = "mri/do:660F3A17RmU",
1275 insertps_3 = "rrio:660F3A41rMU|rxi/od:",
1276 movntdqa_2 = "rmo:660F382ArM",
1277 mpsadbw_3 = "rmio:660F3A42rMU",
1278 packusdw_2 = "rmo:660F382BrM",
1279 pblendvb_3 = "rmRo:660F3810rM",
1280 pblendw_3 = "rmio:660F3A0ErMU",
1281 pcmpeqq_2 = "rmo:660F3829rM",
1282 pextrb_3 = "rri/do:660F3A14nRmU|xri/bo:",
1283 pextrd_3 = "mri/do:660F3A16RmU",
1284 -- x64: pextrq
1285 -- pextrw is SSE2, mem operand is SSE4.1 only
1286 phminposuw_2 = "rmo:660F3841rM",
1287 pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:",
1288 pinsrd_3 = "rmi/od:660F3A22rMU",
1289 -- x64: pinsrq
1290 pmaxsb_2 = "rmo:660F383CrM",
1291 pmaxsd_2 = "rmo:660F383DrM",
1292 pmaxud_2 = "rmo:660F383FrM",
1293 pmaxuw_2 = "rmo:660F383ErM",
1294 pminsb_2 = "rmo:660F3838rM",
1295 pminsd_2 = "rmo:660F3839rM",
1296 pminud_2 = "rmo:660F383BrM",
1297 pminuw_2 = "rmo:660F383ArM",
1298 pmovsxbd_2 = "rro:660F3821rM|rx/od:",
1299 pmovsxbq_2 = "rro:660F3822rM|rx/ow:",
1300 pmovsxbw_2 = "rro:660F3820rM|rx/oq:",
1301 pmovsxdq_2 = "rro:660F3825rM|rx/oq:",
1302 pmovsxwd_2 = "rro:660F3823rM|rx/oq:",
1303 pmovsxwq_2 = "rro:660F3824rM|rx/od:",
1304 pmovzxbd_2 = "rro:660F3831rM|rx/od:",
1305 pmovzxbq_2 = "rro:660F3832rM|rx/ow:",
1306 pmovzxbw_2 = "rro:660F3830rM|rx/oq:",
1307 pmovzxdq_2 = "rro:660F3835rM|rx/oq:",
1308 pmovzxwd_2 = "rro:660F3833rM|rx/oq:",
1309 pmovzxwq_2 = "rro:660F3834rM|rx/od:",
1310 pmuldq_2 = "rmo:660F3828rM",
1311 pmulld_2 = "rmo:660F3840rM",
1312 ptest_2 = "rmo:660F3817rM",
1313 roundpd_3 = "rmio:660F3A09rMU",
1314 roundps_3 = "rmio:660F3A08rMU",
1315 roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:",
1316 roundss_3 = "rrio:660F3A0ArMU|rxi/od:",
1317
1318 -- SSE4.2 ops
1319 crc32_2 = "rmd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0nrM",
1320 pcmpestri_3 = "rmio:660F3A61rMU",
1321 pcmpestrm_3 = "rmio:660F3A60rMU",
1322 pcmpgtq_2 = "rmo:660F3837rM",
1323 pcmpistri_3 = "rmio:660F3A63rMU",
1324 pcmpistrm_3 = "rmio:660F3A62rMU",
1325 popcnt_2 = "rmdw:F30FB8rM",
1326
1327 -- SSE4a
1328 extrq_2 = "rro:660F79rM",
1329 extrq_3 = "riio:660F780mUU",
1330 insertq_2 = "rro:F20F79rM",
1331 insertq_4 = "rriio:F20F78rMUU",
1332 lzcnt_2 = "rmdw:F30FBDrM",
1333 movntsd_2 = "xr/qo:F20F2BRm",
1334 movntss_2 = "xr/do:F30F2BRm",
1335 -- popcnt is also in SSE4.2
1336}
1337
1338------------------------------------------------------------------------------
1339
1340-- Arithmetic ops.
1341for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
1342 ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
1343 local n8 = n * 8
1344 map_op[name.."_2"] = format(
1345 "mr:%02XRm|rm:%02XrM|mI1dw:81%XmI|mS1dw:83%XmS|Ri1dwb:%02Xri|mi1dwb:81%Xmi",
1346 1+n8, 3+n8, n, n, 5+n8, n)
1347end
1348
1349-- Shift ops.
1350for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
1351 shl = 4, shr = 5, sar = 7, sal = 4 } do
1352 map_op[name.."_2"] = format("m1:D1%Xm|mC1dwb:D3%Xm|mi:C1%XmU", n, n, n)
1353end
1354
1355-- Conditional ops.
1356for cc,n in pairs(map_cc) do
1357 map_op["j"..cc.."_1"] = format("J.:0F8%XJ", n) -- short: 7%X
1358 map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
1359 map_op["cmov"..cc.."_2"] = format("rmdw:0F4%XrM", n) -- P6+
1360end
1361
1362-- FP arithmetic ops.
1363for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
1364 sub = 4, subr = 5, div = 6, divr = 7 } do
1365 local nc = 192 + n * 8
1366 local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
1367 local fn = "f"..name
1368 map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:DC%Xm", nc, n, n)
1369 if n == 2 or n == 3 then
1370 map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:DC%XM", nc, n, n)
1371 else
1372 map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:DC%XM", nc, nr, n, n)
1373 map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
1374 map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
1375 end
1376 map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
1377end
1378
1379-- FP conditional moves.
1380for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
1381 local n4 = n % 4
1382 local nc = 56000 + n4 * 8 + (n-n4) * 64
1383 map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
1384 map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
1385end
1386
1387-- SSE FP arithmetic ops.
1388for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
1389 sub = 12, min = 13, div = 14, max = 15 } do
1390 map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
1391 map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
1392 map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
1393 map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
1394end
1395
1396------------------------------------------------------------------------------
1397
1398-- Process pattern string.
1399local function dopattern(pat, args, sz, op)
1400 local digit, addin
1401 local opcode = 0
1402 local szov = sz
1403 local narg = 1
1404
1405 -- Limit number of section buffer positions used by a single dasm_put().
1406 -- A single opcode needs a maximum of 2 positions. !x64
1407 if secpos+2 > maxsecpos then wflush() end
1408
1409 -- Process each character.
1410 for c in gmatch(pat.."|", ".") do
1411 if match(c, "%x") then -- Hex digit.
1412 digit = byte(c) - 48
1413 if digit > 48 then digit = digit - 39
1414 elseif digit > 16 then digit = digit - 7 end
1415 opcode = opcode*16 + digit
1416 addin = nil
1417 elseif c == "n" then -- Disable operand size mods for opcode.
1418 szov = nil
1419 elseif c == "r" then -- Merge 1st operand regno. into opcode.
1420 addin = args[1]; opcode = opcode + addin.reg
1421 if narg < 2 then narg = 2 end
1422 elseif c == "R" then -- Merge 2nd operand regno. into opcode.
1423 addin = args[2]; opcode = opcode + addin.reg
1424 narg = 3
1425 elseif c == "m" or c == "M" then -- Encode ModRM/SIB.
1426 local s
1427 if addin then
1428 s = addin.reg
1429 opcode = opcode - s -- Undo regno opcode merge.
1430 else
1431 s = opcode % 16 -- Undo last digit.
1432 opcode = (opcode - s) / 16
1433 end
1434 wputop(szov, opcode); opcode = nil
1435 local imark = (sub(pat, -1) == "I") -- Force a mark (ugly).
1436 -- Put ModRM/SIB with regno/last digit as spare.
1437 local nn = c == "m" and 1 or 2
1438 wputmrmsib(args[nn], imark, s, addin and addin.vreg)
1439 if narg <= nn then narg = nn + 1 end
1440 addin = nil
1441 else
1442 if opcode then -- Flush opcode.
1443 if addin and addin.reg == -1 then
1444 wputop(szov, opcode + 1)
1445 waction("VREG", addin.vreg); wputxb(0)
1446 else
1447 wputop(szov, opcode)
1448 end
1449 opcode = nil
1450 end
1451 if c == "|" then break end
1452 if c == "o" then -- Offset (pure 32 bit displacement).
1453 wputdarg(args[1].disp); if narg < 2 then narg = 2 end
1454 elseif c == "O" then
1455 wputdarg(args[2].disp); narg = 3
1456 else
1457 -- Anything else is an immediate operand.
1458 local a = args[narg]
1459 narg = narg + 1
1460 local mode, imm = a.mode, a.imm
1461 if mode == "iJ" and not match("iIJ", c) then
1462 werror("bad operand size for label")
1463 end
1464 if c == "S" then
1465 wputsbarg(imm)
1466 elseif c == "U" then
1467 wputbarg(imm)
1468 elseif c == "W" then
1469 wputwarg(imm)
1470 elseif c == "i" or c == "I" then
1471 if mode == "iJ" then
1472 wputlabel("IMM_", imm, 1)
1473 elseif mode == "iI" and c == "I" then
1474 waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
1475 else
1476 wputszarg(sz, imm)
1477 end
1478 elseif c == "J" then
1479 if mode == "iPJ" then
1480 waction("REL_A", imm) -- !x64 (secpos)
1481 else
1482 wputlabel("REL_", imm, 2)
1483 end
1484 else
1485 werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
1486 end
1487 end
1488 end
1489 end
1490end
1491
1492------------------------------------------------------------------------------
1493
1494-- Mapping of operand modes to short names. Suppress output with '#'.
1495local map_modename = {
1496 r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
1497 f = "stx", F = "st0", J = "lbl", ["1"] = "1",
1498 I = "#", S = "#", O = "#",
1499}
1500
1501-- Return a table/string showing all possible operand modes.
1502local function templatehelp(template, nparams)
1503 if nparams == 0 then return "" end
1504 local t = {}
1505 for tm in gmatch(template, "[^%|]+") do
1506 local s = map_modename[sub(tm, 1, 1)]
1507 s = s..gsub(sub(tm, 2, nparams), ".", function(c)
1508 return ", "..map_modename[c]
1509 end)
1510 if not match(s, "#") then t[#t+1] = s end
1511 end
1512 return t
1513end
1514
1515-- Match operand modes against mode match part of template.
1516local function matchtm(tm, args)
1517 for i=1,#args do
1518 if not match(args[i].mode, sub(tm, i, i)) then return end
1519 end
1520 return true
1521end
1522
1523-- Handle opcodes defined with template strings.
1524map_op[".template__"] = function(params, template, nparams)
1525 if not params then return templatehelp(template, nparams) end
1526 local args = {}
1527
1528 -- Zero-operand opcodes have no match part.
1529 if #params == 0 then
1530 dopattern(template, args, "d", params.op)
1531 return
1532 end
1533
1534 -- Determine common operand size (coerce undefined size) or flag as mixed.
1535 local sz, szmix
1536 for i,p in ipairs(params) do
1537 args[i] = parseoperand(p)
1538 local nsz = args[i].opsize
1539 if nsz then
1540 if sz and sz ~= nsz then szmix = true else sz = nsz end
1541 end
1542 end
1543
1544 -- Try all match:pattern pairs (separated by '|').
1545 local gotmatch, lastpat
1546 for tm in gmatch(template, "[^%|]+") do
1547 -- Split off size match (starts after mode match) and pattern string.
1548 local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
1549 if pat == "" then pat = lastpat else lastpat = pat end
1550 if matchtm(tm, args) then
1551 local prefix = sub(szm, 1, 1)
1552 if prefix == "/" then -- Match both operand sizes.
1553 if args[1].opsize == sub(szm, 2, 2) and
1554 args[2].opsize == sub(szm, 3, 3) then
1555 dopattern(pat, args, sz, params.op) -- Process pattern string.
1556 return
1557 end
1558 else -- Match common operand size.
1559 local szp = sz
1560 if szm == "" then szm = "dwb" end -- Default size match.
1561 if prefix == "1" then szp = args[1].opsize; szmix = nil
1562 elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
1563 if not szmix and (prefix == "." or match(szm, szp or "#")) then
1564 dopattern(pat, args, szp, params.op) -- Process pattern string.
1565 return
1566 end
1567 end
1568 gotmatch = true
1569 end
1570 end
1571
1572 local msg = "bad operand mode"
1573 if gotmatch then
1574 if szmix then
1575 msg = "mixed operand size"
1576 else
1577 msg = sz and "bad operand size" or "missing operand size"
1578 end
1579 end
1580
1581 werror(msg.." in `"..opmodestr(params.op, args).."'")
1582end
1583
1584------------------------------------------------------------------------------
1585
1586-- Pseudo-opcodes for data storage.
1587local function op_data(params)
1588 if not params then return "imm..." end
1589 local sz = sub(params.op, 2, 2)
1590 if sz == "a" then sz = addrsize end
1591 for _,p in ipairs(params) do
1592 local a = parseoperand(p)
1593 if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
1594 werror("bad mode or size in `"..p.."'")
1595 end
1596 if a.mode == "iJ" then
1597 wputlabel("IMM_", a.imm, 1)
1598 else
1599 wputszarg(sz, a.imm)
1600 end
1601 end
1602end
1603
1604map_op[".byte_*"] = op_data
1605map_op[".sbyte_*"] = op_data
1606map_op[".word_*"] = op_data
1607map_op[".dword_*"] = op_data
1608map_op[".aword_*"] = op_data
1609
1610------------------------------------------------------------------------------
1611
1612-- Pseudo-opcode to mark the position where the action list is to be emitted.
1613map_op[".actionlist_1"] = function(params)
1614 if not params then return "cvar" end
1615 local name = params[1] -- No syntax check. You get to keep the pieces.
1616 wline(function(out) writeactions(out, name) end)
1617end
1618
1619-- Pseudo-opcode to mark the position where the global enum is to be emitted.
1620map_op[".globals_1"] = function(params)
1621 if not params then return "prefix" end
1622 local prefix = params[1] -- No syntax check. You get to keep the pieces.
1623 wline(function(out) writeglobals(out, prefix) end)
1624end
1625
1626-- Pseudo-opcode to mark the position where the global names are to be emitted.
1627map_op[".globalnames_1"] = function(params)
1628 if not params then return "cvar" end
1629 local name = params[1] -- No syntax check. You get to keep the pieces.
1630 wline(function(out) writeglobalnames(out, name) end)
1631end
1632
1633-- Pseudo-opcode to mark the position where the extern names are to be emitted.
1634map_op[".externnames_1"] = function(params)
1635 if not params then return "cvar" end
1636 local name = params[1] -- No syntax check. You get to keep the pieces.
1637 wline(function(out) writeexternnames(out, name) end)
1638end
1639
1640------------------------------------------------------------------------------
1641
1642-- Label pseudo-opcode (converted from trailing colon form).
1643map_op[".label_2"] = function(params)
1644 if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end
1645 local a = parseoperand(params[1])
1646 local mode, imm = a.mode, a.imm
1647 if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
1648 -- Local label (1: ... 9:) or global label (->global:).
1649 waction("LABEL_LG", nil, 1)
1650 wputxb(imm)
1651 elseif mode == "iJ" then
1652 -- PC label (=>pcexpr:).
1653 waction("LABEL_PC", imm)
1654 else
1655 werror("bad label definition")
1656 end
1657 -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
1658 local addr = params[2]
1659 if addr then
1660 local a = parseoperand(params[2])
1661 if a.mode == "iPJ" then
1662 waction("SETLABEL", a.imm) -- !x64 (secpos)
1663 else
1664 werror("bad label assignment")
1665 end
1666 end
1667end
1668map_op[".label_1"] = map_op[".label_2"]
1669
1670------------------------------------------------------------------------------
1671
1672-- Alignment pseudo-opcode.
1673map_op[".align_1"] = function(params)
1674 if not params then return "numpow2" end
1675 local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
1676 if align then
1677 local x = align
1678 -- Must be a power of 2 in the range (2 ... 256).
1679 for i=1,8 do
1680 x = x / 2
1681 if x == 1 then
1682 waction("ALIGN", nil, 1)
1683 wputxb(align-1) -- Action byte is 2**n-1.
1684 return
1685 end
1686 end
1687 end
1688 werror("bad alignment")
1689end
1690
1691-- Spacing pseudo-opcode.
1692map_op[".space_2"] = function(params)
1693 if not params then return "num [, filler]" end
1694 waction("SPACE", params[1])
1695 local fill = params[2]
1696 if fill then
1697 fill = tonumber(fill)
1698 if not fill or fill < 0 or fill > 255 then werror("bad filler") end
1699 end
1700 wputxb(fill or 0)
1701end
1702map_op[".space_1"] = map_op[".space_2"]
1703
1704------------------------------------------------------------------------------
1705
1706-- Pseudo-opcode for (primitive) type definitions (map to C types).
1707map_op[".type_3"] = function(params, nparams)
1708 if not params then
1709 return nparams == 2 and "name, ctype" or "name, ctype, reg"
1710 end
1711 local name, ctype, reg = params[1], params[2], params[3]
1712 if not match(name, "^[%a_][%w_]*$") then
1713 werror("bad type name `"..name.."'")
1714 end
1715 local tp = map_type[name]
1716 if tp then
1717 werror("duplicate type `"..name.."'")
1718 end
1719 if reg and not map_reg_valid_base[reg] then
1720 werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
1721 end
1722 -- Add #type to defines. A bit unclean to put it in map_archdef.
1723 map_archdef["#"..name] = "sizeof("..ctype..")"
1724 -- Add new type and emit shortcut define.
1725 local num = ctypenum + 1
1726 map_type[name] = {
1727 ctype = ctype,
1728 ctypefmt = format("Dt%X(%%s)", num),
1729 reg = reg,
1730 }
1731 wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
1732 ctypenum = num
1733end
1734map_op[".type_2"] = map_op[".type_3"]
1735
1736-- Dump type definitions.
1737local function dumptypes(out, lvl)
1738 local t = {}
1739 for name in pairs(map_type) do t[#t+1] = name end
1740 sort(t)
1741 out:write("Type definitions:\n")
1742 for _,name in ipairs(t) do
1743 local tp = map_type[name]
1744 local reg = tp.reg and map_reg_rev[tp.reg] or ""
1745 out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
1746 end
1747 out:write("\n")
1748end
1749
1750------------------------------------------------------------------------------
1751
1752-- Set the current section.
1753function _M.section(num)
1754 waction("SECTION")
1755 wputxb(num)
1756 wflush(true) -- SECTION is a terminal action.
1757end
1758
1759------------------------------------------------------------------------------
1760
1761-- Dump architecture description.
1762function _M.dumparch(out)
1763 out:write(format("DynASM %s version %s, released %s\n\n",
1764 _info.arch, _info.version, _info.release))
1765 dumpregs(out)
1766 dumpactions(out)
1767end
1768
1769-- Dump all user defined elements.
1770function _M.dumpdef(out, lvl)
1771 dumptypes(out, lvl)
1772 dumpglobals(out, lvl)
1773 dumpexterns(out, lvl)
1774end
1775
1776------------------------------------------------------------------------------
1777
1778-- Pass callbacks from/to the DynASM core.
1779function _M.passcb(wl, we, wf, ww)
1780 wline, werror, wfatal, wwarn = wl, we, wf, ww
1781 return wflush
1782end
1783
1784-- Setup the arch-specific module.
1785function _M.setup(arch, opt)
1786 g_arch, g_opt = arch, opt
1787end
1788
1789-- Merge the core maps and the arch-specific maps.
1790function _M.mergemaps(map_coreop, map_def)
1791 setmetatable(map_op, { __index = map_coreop })
1792 setmetatable(map_def, { __index = map_archdef })
1793 return map_op, map_def
1794end
1795
1796return _M
1797
1798------------------------------------------------------------------------------
1799
diff --git a/dynasm/dynasm.lua b/dynasm/dynasm.lua
new file mode 100644
index 00000000..20ff9cf5
--- /dev/null
+++ b/dynasm/dynasm.lua
@@ -0,0 +1,1070 @@
1------------------------------------------------------------------------------
2-- DynASM. A dynamic assembler for code generation engines.
3-- Originally designed and implemented for LuaJIT.
4--
5-- Copyright (C) 2005-2009 Mike Pall. All rights reserved.
6-- See below for full copyright notice.
7------------------------------------------------------------------------------
8
9-- Application information.
10local _info = {
11 name = "DynASM",
12 description = "A dynamic assembler for code generation engines",
13 version = "1.2.1",
14 vernum = 10201,
15 release = "2009-04-16",
16 author = "Mike Pall",
17 url = "http://luajit.org/dynasm.html",
18 license = "MIT",
19 copyright = [[
20Copyright (C) 2005-2009 Mike Pall. All rights reserved.
21
22Permission is hereby granted, free of charge, to any person obtaining
23a copy of this software and associated documentation files (the
24"Software"), to deal in the Software without restriction, including
25without limitation the rights to use, copy, modify, merge, publish,
26distribute, sublicense, and/or sell copies of the Software, and to
27permit persons to whom the Software is furnished to do so, subject to
28the following conditions:
29
30The above copyright notice and this permission notice shall be
31included in all copies or substantial portions of the Software.
32
33THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
38TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
41[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
42]],
43}
44
45-- Cache library functions.
46local type, pairs, ipairs = type, pairs, ipairs
47local pcall, error, assert = pcall, error, assert
48local _s = string
49local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
50local format, rep, upper = _s.format, _s.rep, _s.upper
51local _t = table
52local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
53local exit = os.exit
54local io = io
55local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
56
57------------------------------------------------------------------------------
58
59-- Program options.
60local g_opt = {}
61
62-- Global state for current file.
63local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
64local g_errcount = 0
65
66-- Write buffer for output file.
67local g_wbuffer, g_capbuffer
68
69------------------------------------------------------------------------------
70
71-- Write an output line (or callback function) to the buffer.
72local function wline(line, needindent)
73 local buf = g_capbuffer or g_wbuffer
74 buf[#buf+1] = needindent and g_indent..line or line
75 g_synclineno = g_synclineno + 1
76end
77
78-- Write assembler line as a comment, if requestd.
79local function wcomment(aline)
80 if g_opt.comment then
81 wline(g_opt.comment..aline..g_opt.endcomment, true)
82 end
83end
84
85-- Resync CPP line numbers.
86local function wsync()
87 if g_synclineno ~= g_lineno and g_opt.cpp then
88 wline("# "..g_lineno..' "'..g_fname..'"')
89 g_synclineno = g_lineno
90 end
91end
92
93-- Dummy action flush function. Replaced with arch-specific function later.
94local function wflush(term)
95end
96
97-- Dump all buffered output lines.
98local function wdumplines(out, buf)
99 for _,line in ipairs(buf) do
100 if type(line) == "string" then
101 assert(out:write(line, "\n"))
102 else
103 -- Special callback to dynamically insert lines after end of processing.
104 line(out)
105 end
106 end
107end
108
109------------------------------------------------------------------------------
110
111-- Emit an error. Processing continues with next statement.
112local function werror(msg)
113 error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
114end
115
116-- Emit a fatal error. Processing stops.
117local function wfatal(msg)
118 g_errcount = "fatal"
119 werror(msg)
120end
121
122-- Print a warning. Processing continues.
123local function wwarn(msg)
124 stderr:write(format("%s:%s: warning: %s:\n%s\n",
125 g_fname, g_lineno, msg, g_curline))
126end
127
128-- Print caught error message. But suppress excessive errors.
129local function wprinterr(...)
130 if type(g_errcount) == "number" then
131 -- Regular error.
132 g_errcount = g_errcount + 1
133 if g_errcount < 21 then -- Seems to be a reasonable limit.
134 stderr:write(...)
135 elseif g_errcount == 21 then
136 stderr:write(g_fname,
137 ":*: warning: too many errors (suppressed further messages).\n")
138 end
139 else
140 -- Fatal error.
141 stderr:write(...)
142 return true -- Stop processing.
143 end
144end
145
146------------------------------------------------------------------------------
147
148-- Map holding all option handlers.
149local opt_map = {}
150local opt_current
151
152-- Print error and exit with error status.
153local function opterror(...)
154 stderr:write("dynasm.lua: ERROR: ", ...)
155 stderr:write("\n")
156 exit(1)
157end
158
159-- Get option parameter.
160local function optparam(args)
161 local argn = args.argn
162 local p = args[argn]
163 if not p then
164 opterror("missing parameter for option `", opt_current, "'.")
165 end
166 args.argn = argn + 1
167 return p
168end
169
170------------------------------------------------------------------------------
171
172-- Core pseudo-opcodes.
173local map_coreop = {}
174-- Dummy opcode map. Replaced by arch-specific map.
175local map_op = {}
176
177-- Forward declarations.
178local dostmt
179local readfile
180
181------------------------------------------------------------------------------
182
183-- Map for defines (initially empty, chains to arch-specific map).
184local map_def = {}
185
186-- Pseudo-opcode to define a substitution.
187map_coreop[".define_2"] = function(params, nparams)
188 if not params then return nparams == 1 and "name" or "name, subst" end
189 local name, def = params[1], params[2] or "1"
190 if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end
191 map_def[name] = def
192end
193map_coreop[".define_1"] = map_coreop[".define_2"]
194
195-- Define a substitution on the command line.
196function opt_map.D(args)
197 local namesubst = optparam(args)
198 local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$")
199 if name then
200 map_def[name] = subst
201 elseif match(namesubst, "^[%a_][%w_]*$") then
202 map_def[namesubst] = "1"
203 else
204 opterror("bad define")
205 end
206end
207
208-- Undefine a substitution on the command line.
209function opt_map.U(args)
210 local name = optparam(args)
211 if match(name, "^[%a_][%w_]*$") then
212 map_def[name] = nil
213 else
214 opterror("bad define")
215 end
216end
217
218-- Helper for definesubst.
219local gotsubst
220
221local function definesubst_one(word)
222 local subst = map_def[word]
223 if subst then gotsubst = word; return subst else return word end
224end
225
226-- Iteratively substitute defines.
227local function definesubst(stmt)
228 -- Limit number of iterations.
229 for i=1,100 do
230 gotsubst = false
231 stmt = gsub(stmt, "#?[%w_]+", definesubst_one)
232 if not gotsubst then break end
233 end
234 if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
235 return stmt
236end
237
238-- Dump all defines.
239local function dumpdefines(out, lvl)
240 local t = {}
241 for name in pairs(map_def) do
242 t[#t+1] = name
243 end
244 sort(t)
245 out:write("Defines:\n")
246 for _,name in ipairs(t) do
247 local subst = map_def[name]
248 if g_arch then subst = g_arch.revdef(subst) end
249 out:write(format(" %-20s %s\n", name, subst))
250 end
251 out:write("\n")
252end
253
254------------------------------------------------------------------------------
255
256-- Support variables for conditional assembly.
257local condlevel = 0
258local condstack = {}
259
260-- Evaluate condition with a Lua expression. Substitutions already performed.
261local function cond_eval(cond)
262 local func, err = loadstring("return "..cond)
263 if func then
264 setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil.
265 local ok, res = pcall(func)
266 if ok then
267 if res == 0 then return false end -- Oh well.
268 return not not res
269 end
270 err = res
271 end
272 wfatal("bad condition: "..err)
273end
274
275-- Skip statements until next conditional pseudo-opcode at the same level.
276local function stmtskip()
277 local dostmt_save = dostmt
278 local lvl = 0
279 dostmt = function(stmt)
280 local op = match(stmt, "^%s*(%S+)")
281 if op == ".if" then
282 lvl = lvl + 1
283 elseif lvl ~= 0 then
284 if op == ".endif" then lvl = lvl - 1 end
285 elseif op == ".elif" or op == ".else" or op == ".endif" then
286 dostmt = dostmt_save
287 dostmt(stmt)
288 end
289 end
290end
291
292-- Pseudo-opcodes for conditional assembly.
293map_coreop[".if_1"] = function(params)
294 if not params then return "condition" end
295 local lvl = condlevel + 1
296 local res = cond_eval(params[1])
297 condlevel = lvl
298 condstack[lvl] = res
299 if not res then stmtskip() end
300end
301
302map_coreop[".elif_1"] = function(params)
303 if not params then return "condition" end
304 if condlevel == 0 then wfatal(".elif without .if") end
305 local lvl = condlevel
306 local res = condstack[lvl]
307 if res then
308 if res == "else" then wfatal(".elif after .else") end
309 else
310 res = cond_eval(params[1])
311 if res then
312 condstack[lvl] = res
313 return
314 end
315 end
316 stmtskip()
317end
318
319map_coreop[".else_0"] = function(params)
320 if condlevel == 0 then wfatal(".else without .if") end
321 local lvl = condlevel
322 local res = condstack[lvl]
323 condstack[lvl] = "else"
324 if res then
325 if res == "else" then wfatal(".else after .else") end
326 stmtskip()
327 end
328end
329
330map_coreop[".endif_0"] = function(params)
331 local lvl = condlevel
332 if lvl == 0 then wfatal(".endif without .if") end
333 condlevel = lvl - 1
334end
335
336-- Check for unfinished conditionals.
337local function checkconds()
338 if g_errcount ~= "fatal" and condlevel ~= 0 then
339 wprinterr(g_fname, ":*: error: unbalanced conditional\n")
340 end
341end
342
343------------------------------------------------------------------------------
344
345-- Search for a file in the given path and open it for reading.
346local function pathopen(path, name)
347 local dirsep = match(package.path, "\\") and "\\" or "/"
348 for _,p in ipairs(path) do
349 local fullname = p == "" and name or p..dirsep..name
350 local fin = io.open(fullname, "r")
351 if fin then
352 g_fname = fullname
353 return fin
354 end
355 end
356end
357
358-- Include a file.
359map_coreop[".include_1"] = function(params)
360 if not params then return "filename" end
361 local name = params[1]
362 -- Save state. Ugly, I know. but upvalues are fast.
363 local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent
364 -- Read the included file.
365 local fatal = readfile(pathopen(g_opt.include, name) or
366 wfatal("include file `"..name.."' not found"))
367 -- Restore state.
368 g_synclineno = -1
369 g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi
370 if fatal then wfatal("in include file") end
371end
372
373-- Make .include initially available, too.
374map_op[".include_1"] = map_coreop[".include_1"]
375
376------------------------------------------------------------------------------
377
378-- Support variables for macros.
379local mac_capture, mac_lineno, mac_name
380local mac_active = {}
381local mac_list = {}
382
383-- Pseudo-opcode to define a macro.
384map_coreop[".macro_*"] = function(mparams)
385 if not mparams then return "name [, params...]" end
386 -- Split off and validate macro name.
387 local name = remove(mparams, 1)
388 if not name then werror("missing macro name") end
389 if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]+$")) then
390 wfatal("bad macro name `"..name.."'")
391 end
392 -- Validate macro parameter names.
393 local mdup = {}
394 for _,mp in ipairs(mparams) do
395 if not match(mp, "^[%a_][%w_]*$") then
396 wfatal("bad macro parameter name `"..mp.."'")
397 end
398 if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
399 mdup[mp] = true
400 end
401 -- Check for duplicate or recursive macro definitions.
402 local opname = name.."_"..#mparams
403 if map_op[opname] or map_op[name.."_*"] then
404 wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
405 end
406 if mac_capture then wfatal("recursive macro definition") end
407
408 -- Enable statement capture.
409 local lines = {}
410 mac_lineno = g_lineno
411 mac_name = name
412 mac_capture = function(stmt) -- Statement capture function.
413 -- Stop macro definition with .endmacro pseudo-opcode.
414 if not match(stmt, "^%s*.endmacro%s*$") then
415 lines[#lines+1] = stmt
416 return
417 end
418 mac_capture = nil
419 mac_lineno = nil
420 mac_name = nil
421 mac_list[#mac_list+1] = opname
422 -- Add macro-op definition.
423 map_op[opname] = function(params)
424 if not params then return mparams, lines end
425 -- Protect against recursive macro invocation.
426 if mac_active[opname] then wfatal("recursive macro invocation") end
427 mac_active[opname] = true
428 -- Setup substitution map.
429 local subst = {}
430 for i,mp in ipairs(mparams) do subst[mp] = params[i] end
431 local mcom
432 if g_opt.maccomment and g_opt.comment then
433 mcom = " MACRO "..name.." ("..#mparams..")"
434 wcomment("{"..mcom)
435 end
436 -- Loop through all captured statements
437 for _,stmt in ipairs(lines) do
438 -- Substitute macro parameters.
439 local st = gsub(stmt, "[%w_]+", subst)
440 st = definesubst(st)
441 st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
442 if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
443 -- Emit statement. Use a protected call for better diagnostics.
444 local ok, err = pcall(dostmt, st)
445 if not ok then
446 -- Add the captured statement to the error.
447 wprinterr(err, "\n", g_indent, "| ", stmt,
448 "\t[MACRO ", name, " (", #mparams, ")]\n")
449 end
450 end
451 if mcom then wcomment("}"..mcom) end
452 mac_active[opname] = nil
453 end
454 end
455end
456
457-- An .endmacro pseudo-opcode outside of a macro definition is an error.
458map_coreop[".endmacro_0"] = function(params)
459 wfatal(".endmacro without .macro")
460end
461
462-- Dump all macros and their contents (with -PP only).
463local function dumpmacros(out, lvl)
464 sort(mac_list)
465 out:write("Macros:\n")
466 for _,opname in ipairs(mac_list) do
467 local name = sub(opname, 1, -3)
468 local params, lines = map_op[opname]()
469 out:write(format(" %-20s %s\n", name, concat(params, ", ")))
470 if lvl > 1 then
471 for _,line in ipairs(lines) do
472 out:write(" |", line, "\n")
473 end
474 out:write("\n")
475 end
476 end
477 out:write("\n")
478end
479
480-- Check for unfinished macro definitions.
481local function checkmacros()
482 if mac_capture then
483 wprinterr(g_fname, ":", mac_lineno,
484 ": error: unfinished .macro `", mac_name ,"'\n")
485 end
486end
487
488------------------------------------------------------------------------------
489
490-- Support variables for captures.
491local cap_lineno, cap_name
492local cap_buffers = {}
493local cap_used = {}
494
495-- Start a capture.
496map_coreop[".capture_1"] = function(params)
497 if not params then return "name" end
498 wflush()
499 local name = params[1]
500 if not match(name, "^[%a_][%w_]*$") then
501 wfatal("bad capture name `"..name.."'")
502 end
503 if cap_name then
504 wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
505 end
506 cap_name = name
507 cap_lineno = g_lineno
508 -- Create or continue a capture buffer and start the output line capture.
509 local buf = cap_buffers[name]
510 if not buf then buf = {}; cap_buffers[name] = buf end
511 g_capbuffer = buf
512 g_synclineno = 0
513end
514
515-- Stop a capture.
516map_coreop[".endcapture_0"] = function(params)
517 wflush()
518 if not cap_name then wfatal(".endcapture without a valid .capture") end
519 cap_name = nil
520 cap_lineno = nil
521 g_capbuffer = nil
522 g_synclineno = 0
523end
524
525-- Dump a capture buffer.
526map_coreop[".dumpcapture_1"] = function(params)
527 if not params then return "name" end
528 wflush()
529 local name = params[1]
530 if not match(name, "^[%a_][%w_]*$") then
531 wfatal("bad capture name `"..name.."'")
532 end
533 cap_used[name] = true
534 wline(function(out)
535 local buf = cap_buffers[name]
536 if buf then wdumplines(out, buf) end
537 end)
538 g_synclineno = 0
539end
540
541-- Dump all captures and their buffers (with -PP only).
542local function dumpcaptures(out, lvl)
543 out:write("Captures:\n")
544 for name,buf in pairs(cap_buffers) do
545 out:write(format(" %-20s %4s)\n", name, "("..#buf))
546 if lvl > 1 then
547 local bar = rep("=", 76)
548 out:write(" ", bar, "\n")
549 for _,line in ipairs(buf) do
550 out:write(" ", line, "\n")
551 end
552 out:write(" ", bar, "\n\n")
553 end
554 end
555 out:write("\n")
556end
557
558-- Check for unfinished or unused captures.
559local function checkcaptures()
560 if cap_name then
561 wprinterr(g_fname, ":", cap_lineno,
562 ": error: unfinished .capture `", cap_name,"'\n")
563 return
564 end
565 for name in pairs(cap_buffers) do
566 if not cap_used[name] then
567 wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
568 end
569 end
570end
571
572------------------------------------------------------------------------------
573
574-- Sections names.
575local map_sections = {}
576
577-- Pseudo-opcode to define code sections.
578-- TODO: Data sections, BSS sections. Needs extra C code and API.
579map_coreop[".section_*"] = function(params)
580 if not params then return "name..." end
581 if #map_sections > 0 then werror("duplicate section definition") end
582 wflush()
583 for sn,name in ipairs(params) do
584 local opname = "."..name.."_0"
585 if not match(name, "^[%a][%w_]*$") or
586 map_op[opname] or map_op["."..name.."_*"] then
587 werror("bad section name `"..name.."'")
588 end
589 map_sections[#map_sections+1] = name
590 wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
591 map_op[opname] = function(params) g_arch.section(sn-1) end
592 end
593 wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
594end
595
596-- Dump all sections.
597local function dumpsections(out, lvl)
598 out:write("Sections:\n")
599 for _,name in ipairs(map_sections) do
600 out:write(format(" %s\n", name))
601 end
602 out:write("\n")
603end
604
605------------------------------------------------------------------------------
606
607-- Load architecture-specific module.
608local function loadarch(arch)
609 if not match(arch, "^[%w_]+$") then return "bad arch name" end
610 local ok, m_arch = pcall(require, "dasm_"..arch)
611 if not ok then return "cannot load module: "..m_arch end
612 g_arch = m_arch
613 wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
614 m_arch.setup(arch, g_opt)
615 map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
616end
617
618-- Dump architecture description.
619function opt_map.dumparch(args)
620 local name = optparam(args)
621 if not g_arch then
622 local err = loadarch(name)
623 if err then opterror(err) end
624 end
625
626 local t = {}
627 for name in pairs(map_coreop) do t[#t+1] = name end
628 for name in pairs(map_op) do t[#t+1] = name end
629 sort(t)
630
631 local out = stdout
632 local _arch = g_arch._info
633 out:write(format("%s version %s, released %s, %s\n",
634 _info.name, _info.version, _info.release, _info.url))
635 g_arch.dumparch(out)
636
637 local pseudo = true
638 out:write("Pseudo-Opcodes:\n")
639 for _,sname in ipairs(t) do
640 local name, nparam = match(sname, "^(.+)_([0-9%*])$")
641 if name then
642 if pseudo and sub(name, 1, 1) ~= "." then
643 out:write("\nOpcodes:\n")
644 pseudo = false
645 end
646 local f = map_op[sname]
647 local s
648 if nparam ~= "*" then nparam = nparam + 0 end
649 if nparam == 0 then
650 s = ""
651 elseif type(f) == "string" then
652 s = map_op[".template__"](nil, f, nparam)
653 else
654 s = f(nil, nparam)
655 end
656 if type(s) == "table" then
657 for _,s2 in ipairs(s) do
658 out:write(format(" %-12s %s\n", name, s2))
659 end
660 else
661 out:write(format(" %-12s %s\n", name, s))
662 end
663 end
664 end
665 out:write("\n")
666 exit(0)
667end
668
669-- Pseudo-opcode to set the architecture.
670-- Only initially available (map_op is replaced when called).
671map_op[".arch_1"] = function(params)
672 if not params then return "name" end
673 local err = loadarch(params[1])
674 if err then wfatal(err) end
675end
676
677-- Dummy .arch pseudo-opcode to improve the error report.
678map_coreop[".arch_1"] = function(params)
679 if not params then return "name" end
680 wfatal("duplicate .arch statement")
681end
682
683------------------------------------------------------------------------------
684
685-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
686map_coreop[".nop_*"] = function(params)
687 if not params then return "[ignored...]" end
688end
689
690-- Pseudo-opcodes to raise errors.
691map_coreop[".error_1"] = function(params)
692 if not params then return "message" end
693 werror(params[1])
694end
695
696map_coreop[".fatal_1"] = function(params)
697 if not params then return "message" end
698 wfatal(params[1])
699end
700
701-- Dump all user defined elements.
702local function dumpdef(out)
703 local lvl = g_opt.dumpdef
704 if lvl == 0 then return end
705 dumpsections(out, lvl)
706 dumpdefines(out, lvl)
707 if g_arch then g_arch.dumpdef(out, lvl) end
708 dumpmacros(out, lvl)
709 dumpcaptures(out, lvl)
710end
711
712------------------------------------------------------------------------------
713
714-- Helper for splitstmt.
715local splitlvl
716
717local function splitstmt_one(c)
718 if c == "(" then
719 splitlvl = ")"..splitlvl
720 elseif c == "[" then
721 splitlvl = "]"..splitlvl
722 elseif c == ")" or c == "]" then
723 if sub(splitlvl, 1, 1) ~= c then werror("unbalanced () or []") end
724 splitlvl = sub(splitlvl, 2)
725 elseif splitlvl == "" then
726 return " \0 "
727 end
728 return c
729end
730
731-- Split statement into (pseudo-)opcode and params.
732local function splitstmt(stmt)
733 -- Convert label with trailing-colon into .label statement.
734 local label = match(stmt, "^%s*(.+):%s*$")
735 if label then return ".label", {label} end
736
737 -- Split at commas and equal signs, but obey parentheses and brackets.
738 splitlvl = ""
739 stmt = gsub(stmt, "[,%(%)%[%]]", splitstmt_one)
740 if splitlvl ~= "" then werror("unbalanced () or []") end
741
742 -- Split off opcode.
743 local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
744 if not op then werror("bad statement syntax") end
745
746 -- Split parameters.
747 local params = {}
748 for p in gmatch(other, "%s*(%Z+)%z?") do
749 params[#params+1] = gsub(p, "%s+$", "")
750 end
751 if #params > 16 then werror("too many parameters") end
752
753 params.op = op
754 return op, params
755end
756
757-- Process a single statement.
758dostmt = function(stmt)
759 -- Ignore empty statements.
760 if match(stmt, "^%s*$") then return end
761
762 -- Capture macro defs before substitution.
763 if mac_capture then return mac_capture(stmt) end
764 stmt = definesubst(stmt)
765
766 -- Emit C code without parsing the line.
767 if sub(stmt, 1, 1) == "|" then
768 local tail = sub(stmt, 2)
769 wflush()
770 if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
771 return
772 end
773
774 -- Split into (pseudo-)opcode and params.
775 local op, params = splitstmt(stmt)
776
777 -- Get opcode handler (matching # of parameters or generic handler).
778 local f = map_op[op.."_"..#params] or map_op[op.."_*"]
779 if not f then
780 if not g_arch then wfatal("first statement must be .arch") end
781 -- Improve error report.
782 for i=0,16 do
783 if map_op[op.."_"..i] then
784 werror("wrong number of parameters for `"..op.."'")
785 end
786 end
787 werror("unknown statement `"..op.."'")
788 end
789
790 -- Call opcode handler or special handler for template strings.
791 if type(f) == "string" then
792 map_op[".template__"](params, f)
793 else
794 f(params)
795 end
796end
797
798-- Process a single line.
799local function doline(line)
800 if g_opt.flushline then wflush() end
801
802 -- Assembler line?
803 local indent, aline = match(line, "^(%s*)%|(.*)$")
804 if not aline then
805 -- No, plain C code line, need to flush first.
806 wflush()
807 wsync()
808 wline(line, false)
809 return
810 end
811
812 g_indent = indent -- Remember current line indentation.
813
814 -- Emit C code (even from macros). Avoids echo and line parsing.
815 if sub(aline, 1, 1) == "|" then
816 if not mac_capture then
817 wsync()
818 elseif g_opt.comment then
819 wsync()
820 wcomment(aline)
821 end
822 dostmt(aline)
823 return
824 end
825
826 -- Echo assembler line as a comment.
827 if g_opt.comment then
828 wsync()
829 wcomment(aline)
830 end
831
832 -- Strip assembler comments.
833 aline = gsub(aline, "//.*$", "")
834
835 -- Split line into statements at semicolons.
836 if match(aline, ";") then
837 for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
838 else
839 dostmt(aline)
840 end
841end
842
843------------------------------------------------------------------------------
844
845-- Write DynASM header.
846local function dasmhead(out)
847 out:write(format([[
848/*
849** This file has been pre-processed with DynASM.
850** %s
851** DynASM version %s, DynASM %s version %s
852** DO NOT EDIT! The original file is in "%s".
853*/
854
855#if DASM_VERSION != %d
856#error "Version mismatch between DynASM and included encoding engine"
857#endif
858
859]], _info.url,
860 _info.version, g_arch._info.arch, g_arch._info.version,
861 g_fname, _info.vernum))
862end
863
864-- Read input file.
865readfile = function(fin)
866 g_indent = ""
867 g_lineno = 0
868 g_synclineno = -1
869
870 -- Process all lines.
871 for line in fin:lines() do
872 g_lineno = g_lineno + 1
873 g_curline = line
874 local ok, err = pcall(doline, line)
875 if not ok and wprinterr(err, "\n") then return true end
876 end
877 wflush()
878
879 -- Close input file.
880 assert(fin == stdin or fin:close())
881end
882
883-- Write output file.
884local function writefile(outfile)
885 local fout
886
887 -- Open output file.
888 if outfile == nil or outfile == "-" then
889 fout = stdout
890 else
891 fout = assert(io.open(outfile, "w"))
892 end
893
894 -- Write all buffered lines
895 wdumplines(fout, g_wbuffer)
896
897 -- Close output file.
898 assert(fout == stdout or fout:close())
899
900 -- Optionally dump definitions.
901 dumpdef(fout == stdout and stderr or stdout)
902end
903
904-- Translate an input file to an output file.
905local function translate(infile, outfile)
906 g_wbuffer = {}
907 g_indent = ""
908 g_lineno = 0
909 g_synclineno = -1
910
911 -- Put header.
912 wline(dasmhead)
913
914 -- Read input file.
915 local fin
916 if infile == "-" then
917 g_fname = "(stdin)"
918 fin = stdin
919 else
920 g_fname = infile
921 fin = assert(io.open(infile, "r"))
922 end
923 readfile(fin)
924
925 -- Check for errors.
926 if not g_arch then
927 wprinterr(g_fname, ":*: error: missing .arch directive\n")
928 end
929 checkconds()
930 checkmacros()
931 checkcaptures()
932
933 if g_errcount ~= 0 then
934 stderr:write(g_fname, ":*: info: ", g_errcount, " error",
935 (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
936 " in input file -- no output file generated.\n")
937 dumpdef(stderr)
938 exit(1)
939 end
940
941 -- Write output file.
942 writefile(outfile)
943end
944
945------------------------------------------------------------------------------
946
947-- Print help text.
948function opt_map.help()
949 stdout:write("DynASM -- ", _info.description, ".\n")
950 stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n")
951 stdout:write[[
952
953Usage: dynasm [OPTION]... INFILE.dasc|-
954
955 -h, --help Display this help text.
956 -V, --version Display version and copyright information.
957
958 -o, --outfile FILE Output file name (default is stdout).
959 -I, --include DIR Add directory to the include search path.
960
961 -c, --ccomment Use /* */ comments for assembler lines.
962 -C, --cppcomment Use // comments for assembler lines (default).
963 -N, --nocomment Suppress assembler lines in output.
964 -M, --maccomment Show macro expansions as comments (default off).
965
966 -L, --nolineno Suppress CPP line number information in output.
967 -F, --flushline Flush action list for every line.
968
969 -D NAME[=SUBST] Define a substitution.
970 -U NAME Undefine a substitution.
971
972 -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
973 -A, --dumparch ARCH Load architecture ARCH and dump description.
974]]
975 exit(0)
976end
977
978-- Print version information.
979function opt_map.version()
980 stdout:write(format("%s version %s, released %s\n%s\n\n%s",
981 _info.name, _info.version, _info.release, _info.url, _info.copyright))
982 exit(0)
983end
984
985-- Misc. options.
986function opt_map.outfile(args) g_opt.outfile = optparam(args) end
987function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
988function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
989function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
990function opt_map.nocomment() g_opt.comment = false end
991function opt_map.maccomment() g_opt.maccomment = true end
992function opt_map.nolineno() g_opt.cpp = false end
993function opt_map.flushline() g_opt.flushline = true end
994function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
995
996------------------------------------------------------------------------------
997
998-- Short aliases for long options.
999local opt_alias = {
1000 h = "help", ["?"] = "help", V = "version",
1001 o = "outfile", I = "include",
1002 c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
1003 L = "nolineno", F = "flushline",
1004 P = "dumpdef", A = "dumparch",
1005}
1006
1007-- Parse single option.
1008local function parseopt(opt, args)
1009 opt_current = #opt == 1 and "-"..opt or "--"..opt
1010 local f = opt_map[opt] or opt_map[opt_alias[opt]]
1011 if not f then
1012 opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
1013 end
1014 f(args)
1015end
1016
1017-- Parse arguments.
1018local function parseargs(args)
1019 -- Default options.
1020 g_opt.comment = "//|"
1021 g_opt.endcomment = ""
1022 g_opt.cpp = true
1023 g_opt.dumpdef = 0
1024 g_opt.include = { "" }
1025
1026 -- Process all option arguments.
1027 args.argn = 1
1028 repeat
1029 local a = args[args.argn]
1030 if not a then break end
1031 local lopt, opt = match(a, "^%-(%-?)(.+)")
1032 if not opt then break end
1033 args.argn = args.argn + 1
1034 if lopt == "" then
1035 -- Loop through short options.
1036 for o in gmatch(opt, ".") do parseopt(o, args) end
1037 else
1038 -- Long option.
1039 parseopt(opt, args)
1040 end
1041 until false
1042
1043 -- Check for proper number of arguments.
1044 local nargs = #args - args.argn + 1
1045 if nargs ~= 1 then
1046 if nargs == 0 then
1047 if g_opt.dumpdef > 0 then return dumpdef(stdout) end
1048 end
1049 opt_map.help()
1050 end
1051
1052 -- Translate a single input file to a single output file
1053 -- TODO: Handle multiple files?
1054 translate(args[args.argn], g_opt.outfile)
1055end
1056
1057------------------------------------------------------------------------------
1058
1059-- Add the directory dynasm.lua resides in to the Lua module search path.
1060local arg = arg
1061if arg and arg[0] then
1062 local prefix = match(arg[0], "^(.*[/\\])")
1063 if prefix then package.path = prefix.."?.lua;"..package.path end
1064end
1065
1066-- Start DynASM.
1067parseargs{...}
1068
1069------------------------------------------------------------------------------
1070