source: trunk/minix/commands/i386/asmconv/emit_gnu.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 15.4 KB
Line 
1/* emit_gnu.c - emit GNU assembly Author: Kees J. Bot
2 * 28 Dec 1993
3 */
4#define nil 0
5#include <stdio.h>
6#include <stdlib.h>
7#include <stdarg.h>
8#include <string.h>
9#include <assert.h>
10#include "asmconv.h"
11#include "token.h"
12#include "asm86.h"
13#include "languages.h"
14
15typedef struct mnemonic { /* GNU as386 mnemonics translation table. */
16 opcode_t opcode;
17 char *name;
18} mnemonic_t;
19
20static mnemonic_t mnemtab[] = {
21 { AAA, "aaa" },
22 { AAD, "aad" },
23 { AAM, "aam" },
24 { AAS, "aas" },
25 { ADC, "adc%" },
26 { ADD, "add%" },
27 { AND, "and%" },
28 { ARPL, "arpl" },
29 { BOUND, "bound%" },
30 { BSF, "bsf%" },
31 { BSR, "bsr%" },
32 { BSWAP, "bswap" },
33 { BT, "bt%" },
34 { BTC, "btc%" },
35 { BTR, "btr%" },
36 { BTS, "bts%" },
37 { CALL, "call" },
38 { CALLF, "lcall" },
39 { CBW, "cbtw" },
40 { CLC, "clc" },
41 { CLD, "cld" },
42 { CLI, "cli" },
43 { CLTS, "clts" },
44 { CMC, "cmc" },
45 { CMP, "cmp%" },
46 { CMPS, "cmps%" },
47 { CMPXCHG, "cmpxchg" },
48 { CWD, "cwtd" },
49 { DAA, "daa" },
50 { DAS, "das" },
51 { DEC, "dec%" },
52 { DIV, "div%" },
53 { DOT_ALIGN, ".align" },
54 { DOT_ASCII, ".ascii" },
55 { DOT_ASCIZ, ".asciz" },
56 { DOT_ASSERT, ".assert" },
57 { DOT_BASE, ".base" },
58 { DOT_BSS, ".bss" },
59 { DOT_COMM, ".comm" },
60 { DOT_DATA, ".data" },
61 { DOT_DATA1, ".byte" },
62 { DOT_DATA2, ".short" },
63 { DOT_DATA4, ".long" },
64 { DOT_DEFINE, ".globl" },
65 { DOT_EXTERN, ".globl" },
66 { DOT_FILE, ".file" },
67 { DOT_LCOMM, ".lcomm" },
68 { DOT_LINE, ".line" },
69 { DOT_LIST, ".list" },
70 { DOT_NOLIST, ".nolist" },
71 { DOT_ROM, ".data" }, /* Minix -- separate I&D. */
72 { DOT_SPACE, ".space" },
73 { DOT_SYMB, ".symb" },
74 { DOT_TEXT, ".text" },
75 { DOT_USE16, ".use16" },
76 { DOT_USE32, ".use32" },
77 { ENTER, "enter" },
78 { F2XM1, "f2xm1" },
79 { FABS, "fabs" },
80 { FADD, "fadd" },
81 { FADDD, "faddl" },
82 { FADDP, "faddp" },
83 { FADDS, "fadds" },
84 { FBLD, "fbld" },
85 { FBSTP, "fbstp" },
86 { FCHS, "fchs" },
87 { FCLEX, "fnclex" },
88 { FCOMD, "fcoml" },
89 { FCOMPD, "fcompl" },
90 { FCOMPP, "fcompp" },
91 { FCOMPS, "fcomps" },
92 { FCOMS, "fcoms" },
93 { FCOS, "fcos" },
94 { FDECSTP, "fdecstp" },
95 { FDIVD, "fdivl" },
96 { FDIVP, "fdivp" },
97 { FDIVRD, "fdivrl" },
98 { FDIVRP, "fdivrp" },
99 { FDIVRS, "fdivrs" },
100 { FDIVS, "fdivs" },
101 { FFREE, "ffree" },
102 { FIADDL, "fiaddl" },
103 { FIADDS, "fiadds" },
104 { FICOM, "ficom" },
105 { FICOMP, "ficomp" },
106 { FIDIVL, "fidivl" },
107 { FIDIVRL, "fidivrl" },
108 { FIDIVRS, "fidivrs" },
109 { FIDIVS, "fidivs" },
110 { FILDL, "fildl" },
111 { FILDQ, "fildq" },
112 { FILDS, "filds" },
113 { FIMULL, "fimull" },
114 { FIMULS, "fimuls" },
115 { FINCSTP, "fincstp" },
116 { FINIT, "fninit" },
117 { FISTL, "fistl" },
118 { FISTP, "fistp" },
119 { FISTS, "fists" },
120 { FISUBL, "fisubl" },
121 { FISUBRL, "fisubrl" },
122 { FISUBRS, "fisubrs" },
123 { FISUBS, "fisubs" },
124 { FLD1, "fld1" },
125 { FLDCW, "fldcw" },
126 { FLDD, "fldl" },
127 { FLDENV, "fldenv" },
128 { FLDL2E, "fldl2e" },
129 { FLDL2T, "fldl2t" },
130 { FLDLG2, "fldlg2" },
131 { FLDLN2, "fldln2" },
132 { FLDPI, "fldpi" },
133 { FLDS, "flds" },
134 { FLDX, "fldt" },
135 { FLDZ, "fldz" },
136 { FMULD, "fmull" },
137 { FMULP, "fmulp" },
138 { FMULS, "fmuls" },
139 { FNOP, "fnop" },
140 { FPATAN, "fpatan" },
141 { FPREM, "fprem" },
142 { FPREM1, "fprem1" },
143 { FPTAN, "fptan" },
144 { FRNDINT, "frndint" },
145 { FRSTOR, "frstor" },
146 { FSAVE, "fnsave" },
147 { FSCALE, "fscale" },
148 { FSIN, "fsin" },
149 { FSINCOS, "fsincos" },
150 { FSQRT, "fsqrt" },
151 { FSTCW, "fnstcw" },
152 { FSTD, "fstl" },
153 { FSTENV, "fnstenv" },
154 { FSTPD, "fstpl" },
155 { FSTPS, "fstps" },
156 { FSTPX, "fstpt" },
157 { FSTS, "fsts" },
158 { FSTSW, "fstsw" },
159 { FSUBD, "fsubl" },
160 { FSUBP, "fsubp" },
161 { FSUBPR, "fsubpr" },
162 { FSUBRD, "fsubrl" },
163 { FSUBRS, "fsubrs" },
164 { FSUBS, "fsubs" },
165 { FTST, "ftst" },
166 { FUCOM, "fucom" },
167 { FUCOMP, "fucomp" },
168 { FUCOMPP, "fucompp" },
169 { FXAM, "fxam" },
170 { FXCH, "fxch" },
171 { FXTRACT, "fxtract" },
172 { FYL2X, "fyl2x" },
173 { FYL2XP1, "fyl2xp1" },
174 { HLT, "hlt" },
175 { IDIV, "idiv%" },
176 { IMUL, "imul%" },
177 { IN, "in%" },
178 { INC, "inc%" },
179 { INS, "ins%" },
180 { INT, "int" },
181 { INTO, "into" },
182 { INVD, "invd" },
183 { INVLPG, "invlpg" },
184 { IRET, "iret" },
185 { IRETD, "iret" },
186 { JA, "ja" },
187 { JAE, "jae" },
188 { JB, "jb" },
189 { JBE, "jbe" },
190 { JCXZ, "jcxz" },
191 { JE, "je" },
192 { JG, "jg" },
193 { JGE, "jge" },
194 { JL, "jl" },
195 { JLE, "jle" },
196 { JMP, "jmp" },
197 { JMPF, "ljmp" },
198 { JNE, "jne" },
199 { JNO, "jno" },
200 { JNP, "jnp" },
201 { JNS, "jns" },
202 { JO, "jo" },
203 { JP, "jp" },
204 { JS, "js" },
205 { LAHF, "lahf" },
206 { LAR, "lar" },
207 { LDS, "lds" },
208 { LEA, "lea%" },
209 { LEAVE, "leave" },
210 { LES, "les" },
211 { LFS, "lfs" },
212 { LGDT, "lgdt" },
213 { LGS, "lgs" },
214 { LIDT, "lidt" },
215 { LLDT, "lldt" },
216 { LMSW, "lmsw" },
217 { LOCK, "lock" },
218 { LODS, "lods%" },
219 { LOOP, "loop" },
220 { LOOPE, "loope" },
221 { LOOPNE, "loopne" },
222 { LSL, "lsl" },
223 { LSS, "lss" },
224 { LTR, "ltr" },
225 { MOV, "mov%" },
226 { MOVS, "movs%" },
227 { MOVSX, "movswl" },
228 { MOVSXB, "movsb%" },
229 { MOVZX, "movzwl" },
230 { MOVZXB, "movzb%" },
231 { MUL, "mul%" },
232 { NEG, "neg%" },
233 { NOP, "nop" },
234 { NOT, "not%" },
235 { OR, "or%" },
236 { OUT, "out%" },
237 { OUTS, "outs%" },
238 { POP, "pop%" },
239 { POPA, "popa%" },
240 { POPF, "popf%" },
241 { PUSH, "push%" },
242 { PUSHA, "pusha%" },
243 { PUSHF, "pushf%" },
244 { RCL, "rcl%" },
245 { RCR, "rcr%" },
246 { RET, "ret" },
247 { RETF, "lret" },
248 { ROL, "rol%" },
249 { ROR, "ror%" },
250 { SAHF, "sahf" },
251 { SAL, "sal%" },
252 { SAR, "sar%" },
253 { SBB, "sbb%" },
254 { SCAS, "scas%" },
255 { SETA, "setab" },
256 { SETAE, "setaeb" },
257 { SETB, "setbb" },
258 { SETBE, "setbeb" },
259 { SETE, "seteb" },
260 { SETG, "setgb" },
261 { SETGE, "setgeb" },
262 { SETL, "setlb" },
263 { SETLE, "setleb" },
264 { SETNE, "setneb" },
265 { SETNO, "setnob" },
266 { SETNP, "setnpb" },
267 { SETNS, "setnsb" },
268 { SETO, "setob" },
269 { SETP, "setpb" },
270 { SETS, "setsb" },
271 { SGDT, "sgdt" },
272 { SHL, "shl%" },
273 { SHLD, "shld%" },
274 { SHR, "shr%" },
275 { SHRD, "shrd%" },
276 { SIDT, "sidt" },
277 { SLDT, "sldt" },
278 { SMSW, "smsw" },
279 { STC, "stc" },
280 { STD, "std" },
281 { STI, "sti" },
282 { STOS, "stos%" },
283 { STR, "str" },
284 { SUB, "sub%" },
285 { TEST, "test%" },
286 { VERR, "verr" },
287 { VERW, "verw" },
288 { WAIT, "wait" },
289 { WBINVD, "wbinvd" },
290 { XADD, "xadd" },
291 { XCHG, "xchg%" },
292 { XLAT, "xlat" },
293 { XOR, "xor%" },
294};
295
296static FILE *ef;
297static long eline= 1;
298static char *efile;
299static char *orig_efile;
300static char *opcode2name_tab[N_OPCODES];
301
302static void gnu_putchar(int c)
303/* LOOK, this programmer checks the return code of putc! What an idiot, noone
304 * does that!
305 */
306{
307 if (putc(c, ef) == EOF) fatal(orig_efile);
308}
309
310static void gnu_printf(const char *fmt, ...)
311{
312 va_list ap;
313
314 va_start(ap, fmt);
315 if (vfprintf(ef, fmt, ap) == EOF) fatal(orig_efile);
316 va_end(ap);
317}
318
319void gnu_emit_init(char *file, const char *banner)
320/* Prepare producing a GNU assembly file. */
321{
322 mnemonic_t *mp;
323
324 if (file == nil) {
325 file= "stdout";
326 ef= stdout;
327 } else {
328 if ((ef= fopen(file, "w")) == nil) fatal(file);
329 }
330 orig_efile= file;
331 efile= file;
332 gnu_printf("/ %s", banner);
333
334 /* Initialize the opcode to mnemonic translation table. */
335 for (mp= mnemtab; mp < arraylimit(mnemtab); mp++) {
336 assert(opcode2name_tab[mp->opcode] == nil);
337 opcode2name_tab[mp->opcode]= mp->name;
338 }
339}
340
341#define opcode2name(op) (opcode2name_tab[op] + 0)
342
343static void gnu_put_string(const char *s, size_t n)
344/* Emit a string with weird characters quoted. */
345{
346 while (n > 0) {
347 int c= *s;
348
349 if (c < ' ' || c > 0177) {
350 gnu_printf("\\%03o", c);
351 } else
352 if (c == '"' || c == '\\') {
353 gnu_printf("\\%c", c & 0xFF);
354 } else {
355 gnu_putchar(c);
356 }
357 s++;
358 n--;
359 }
360}
361
362static void gnu_put_expression(asm86_t *a, expression_t *e, int deref)
363/* Send an expression, i.e. instruction operands, to the output file. Deref
364 * is true when the rewrite of "x" -> "#x" or "(x)" -> "x" may be made.
365 */
366{
367 assert(e != nil);
368
369 switch (e->operator) {
370 case ',':
371 if (is_pseudo(a->opcode)) {
372 /* Pseudo's are normal. */
373 gnu_put_expression(a, e->left, deref);
374 gnu_printf(", ");
375 gnu_put_expression(a, e->right, deref);
376 } else {
377 /* He who invented GNU assembly has seen one VAX too
378 * many, operands are given in the wrong order. This
379 * makes coding from an Intel databook a real delight.
380 * A good thing this program allows us to write the
381 * more normal ACK assembly.
382 */
383 gnu_put_expression(a, e->right, deref);
384 gnu_printf(", ");
385 gnu_put_expression(a, e->left, deref);
386 }
387 break;
388 case 'O':
389 if (deref && a->optype == JUMP) gnu_putchar('*');
390 if (e->left != nil) gnu_put_expression(a, e->left, 0);
391 gnu_putchar('(');
392 if (e->middle != nil) gnu_put_expression(a, e->middle, 0);
393 if (e->right != nil) {
394 gnu_putchar(',');
395 gnu_put_expression(a, e->right, 0);
396 }
397 gnu_putchar(')');
398 break;
399 case '(':
400 if (!deref) gnu_putchar('(');
401 if (deref && a->optype == JUMP) gnu_putchar('*');
402 gnu_put_expression(a, e->middle, 0);
403 if (!deref) gnu_putchar(')');
404 break;
405 case 'B':
406 gnu_printf("%%%s", e->name);
407 break;
408 case '1':
409 case '2':
410 case '4':
411 case '8':
412 gnu_printf("%%%s,%c", e->name, e->operator);
413 break;
414 case '+':
415 case '-':
416 case '~':
417 if (e->middle != nil) {
418 if (deref && a->optype >= BYTE) gnu_putchar('$');
419 gnu_putchar(e->operator);
420 gnu_put_expression(a, e->middle, 0);
421 break;
422 }
423 /*FALL THROUGH*/
424 case '*':
425 case '/':
426 case '%':
427 case '&':
428 case '|':
429 case '^':
430 case S_LEFTSHIFT:
431 case S_RIGHTSHIFT:
432 if (deref && a->optype >= BYTE) gnu_putchar('$');
433 gnu_put_expression(a, e->left, 0);
434 if (e->operator == S_LEFTSHIFT) {
435 gnu_printf("<<");
436 } else
437 if (e->operator == S_RIGHTSHIFT) {
438 gnu_printf(">>");
439 } else {
440 gnu_putchar(e->operator);
441 }
442 gnu_put_expression(a, e->right, 0);
443 break;
444 case '[':
445 if (deref && a->optype >= BYTE) gnu_putchar('$');
446 gnu_putchar('(');
447 gnu_put_expression(a, e->middle, 0);
448 gnu_putchar(')');
449 break;
450 case 'W':
451 if (isregister(e->name)) {
452 if (a->optype == JUMP) gnu_putchar('*');
453 gnu_printf("%%%s", e->name);
454 } else {
455 if (deref && a->optype >= BYTE) gnu_putchar('$');
456 gnu_printf("%s", e->name);
457 }
458 break;
459 case 'S':
460 gnu_putchar('"');
461 gnu_put_string(e->name, e->len);
462 gnu_putchar('"');
463 break;
464 default:
465 fprintf(stderr,
466 "asmconv: internal error, unknown expression operator '%d'\n",
467 e->operator);
468 exit(EXIT_FAILURE);
469 }
470}
471
472void gnu_emit_instruction(asm86_t *a)
473/* Output one instruction and its operands. */
474{
475 int same= 0;
476 char *p;
477
478 if (a == nil) {
479 /* Last call */
480 gnu_putchar('\n');
481 return;
482 }
483
484 if (use16()) {
485 fprintf(stderr,
486 "asmconv: the GNU assembler can't translate 8086 code\n");
487 exit(EXIT_FAILURE);
488 }
489
490 /* Make sure the line number of the line to be emitted is ok. */
491 if ((a->file != efile && strcmp(a->file, efile) != 0)
492 || a->line < eline || a->line > eline+10) {
493 gnu_putchar('\n');
494 gnu_printf("# %ld \"%s\"\n", a->line, a->file);
495 efile= a->file;
496 eline= a->line;
497 } else {
498 if (a->line == eline) {
499 gnu_printf("; ");
500 same= 1;
501 }
502 while (eline < a->line) {
503 gnu_putchar('\n');
504 eline++;
505 }
506 }
507
508 if (a->opcode == DOT_LABEL) {
509 assert(a->args->operator == ':');
510 gnu_printf("%s:", a->args->name);
511 } else
512 if (a->opcode == DOT_EQU) {
513 assert(a->args->operator == '=');
514 gnu_printf("\t%s = ", a->args->name);
515 gnu_put_expression(a, a->args->middle, 0);
516 } else
517 if (a->opcode == DOT_ALIGN) {
518 /* GNU .align thinks in powers of two. */
519 unsigned long n;
520 unsigned s;
521
522 assert(a->args->operator == 'W' && isanumber(a->args->name));
523 n= strtoul(a->args->name, nil, 0);
524 for (s= 0; s <= 4 && (1 << s) < n; s++) {}
525 gnu_printf(".align\t%u", s);
526 } else
527 if ((p= opcode2name(a->opcode)) != nil) {
528 if (!is_pseudo(a->opcode) && !same) gnu_putchar('\t');
529
530 switch (a->rep) {
531 case ONCE: break;
532 case REP: gnu_printf("rep; "); break;
533 case REPE: gnu_printf("repe; "); break;
534 case REPNE: gnu_printf("repne; "); break;
535 default: assert(0);
536 }
537 switch (a->seg) {
538 /* Kludge to avoid knowing where to put the "%es:" */
539 case DEFSEG: break;
540 case CSEG: gnu_printf(".byte 0x2e; "); break;
541 case DSEG: gnu_printf(".byte 0x3e; "); break;
542 case ESEG: gnu_printf(".byte 0x26; "); break;
543 case FSEG: gnu_printf(".byte 0x64; "); break;
544 case GSEG: gnu_printf(".byte 0x65; "); break;
545 case SSEG: gnu_printf(".byte 0x36; "); break;
546 default: assert(0);
547 }
548
549 /* Exceptions, exceptions... */
550 if (a->opcode == CBW) {
551 if (!(a->oaz & OPZ)) p= "cwtl";
552 a->oaz&= ~OPZ;
553 }
554 if (a->opcode == CWD) {
555 if (!(a->oaz & OPZ)) p= "cltd";
556 a->oaz&= ~OPZ;
557 }
558
559 if (a->opcode == RET || a->opcode == RETF) {
560 /* Argument of RET needs a '$'. */
561 a->optype= WORD;
562 }
563
564 if (a->opcode == MUL && a->args != nil
565 && a->args->operator == ',') {
566 /* Two operand MUL is an IMUL? */
567 p="imul%";
568 }
569
570 /* GAS doesn't understand the interesting combinations. */
571 if (a->oaz & ADZ) gnu_printf(".byte 0x67; ");
572 if (a->oaz & OPZ && strchr(p, '%') == nil)
573 gnu_printf(".byte 0x66; ");
574
575 /* Unsupported instructions that Minix code needs. */
576 if (a->opcode == JMPF && a->args != nil
577 && a->args->operator == ',') {
578 /* JMPF seg:off. */
579 gnu_printf(".byte 0xEA; .long ");
580 gnu_put_expression(a, a->args->right, 0);
581 gnu_printf("; .short ");
582 gnu_put_expression(a, a->args->left, 0);
583 return;
584 }
585 if (a->opcode == JMPF && a->args != nil
586 && a->args->operator == 'O'
587 && a->args->left != nil
588 && a->args->right == nil
589 && a->args->middle != nil
590 && a->args->middle->operator == 'B'
591 && strcmp(a->args->middle->name, "esp") == 0
592 ) {
593 /* JMPF offset(ESP). */
594 gnu_printf(".byte 0xFF,0x6C,0x24,");
595 gnu_put_expression(a, a->args->left, 0);
596 return;
597 }
598 if (a->opcode == MOV && a->args != nil
599 && a->args->operator == ','
600 && a->args->left != nil
601 && a->args->left->operator == 'W'
602 && (strcmp(a->args->left->name, "ds") == 0
603 || strcmp(a->args->left->name, "es") == 0)
604 && a->args->right->operator == 'O'
605 && a->args->right->left != nil
606 && a->args->right->right == nil
607 && a->args->right->middle != nil
608 && a->args->right->middle->operator == 'B'
609 && strcmp(a->args->right->middle->name, "esp") == 0
610 ) {
611 /* MOV DS, offset(ESP); MOV ES, offset(ESP) */
612 gnu_printf(".byte 0x8E,0x%02X,0x24,",
613 a->args->left->name[0] == 'd' ? 0x5C : 0x44);
614 gnu_put_expression(a, a->args->right->left, 0);
615 return;
616 }
617 if (a->opcode == MOV && a->args != nil
618 && a->args->operator == ','
619 && a->args->left != nil
620 && a->args->left->operator == 'W'
621 && (strcmp(a->args->left->name, "ds") == 0
622 || strcmp(a->args->left->name, "es") == 0)
623 && a->args->right->operator == '('
624 && a->args->right->middle != nil
625 ) {
626 /* MOV DS, (memory); MOV ES, (memory) */
627 gnu_printf(".byte 0x8E,0x%02X; .long ",
628 a->args->left->name[0] == 'd' ? 0x1D : 0x05);
629 gnu_put_expression(a, a->args->right->middle, 0);
630 return;
631 }
632
633 while (*p != 0) {
634 if (*p == '%') {
635 if (a->optype == BYTE) {
636 gnu_putchar('b');
637 } else
638 if (a->optype == WORD) {
639 gnu_putchar((a->oaz & OPZ) ? 'w' : 'l');
640 } else {
641 assert(0);
642 }
643 } else {
644 gnu_putchar(*p);
645 }
646 p++;
647 }
648
649 if (a->args != nil) {
650 static char *aregs[] = { "al", "ax", "eax" };
651
652 gnu_putchar('\t');
653 switch (a->opcode) {
654 case IN:
655 gnu_put_expression(a, a->args, 1);
656 gnu_printf(", %%%s", aregs[a->optype - BYTE]);
657 break;
658 case OUT:
659 gnu_printf("%%%s, ", aregs[a->optype - BYTE]);
660 gnu_put_expression(a, a->args, 1);
661 break;
662 default:
663 gnu_put_expression(a, a->args, 1);
664 }
665 }
666 if (a->opcode == DOT_USE16) set_use16();
667 if (a->opcode == DOT_USE32) set_use32();
668 } else {
669 fprintf(stderr,
670 "asmconv: internal error, unknown opcode '%d'\n",
671 a->opcode);
672 exit(EXIT_FAILURE);
673 }
674}
Note: See TracBrowser for help on using the repository browser.