📄 emit_gnu.c
字号:
}#define opcode2name(op) (opcode2name_tab[op] + 0)static void gnu_put_string(const char *s, size_t n)/* Emit a string with weird characters quoted. */{ while (n > 0) { int c= *s; if (c < ' ' || c > 0177) { gnu_printf("\\%03o", c); } else if (c == '"' || c == '\\') { gnu_printf("\\%c", c & 0xFF); } else { gnu_putchar(c); } s++; n--; }}static void gnu_put_expression(asm86_t *a, expression_t *e, int deref)/* Send an expression, i.e. instruction operands, to the output file. Deref * is true when the rewrite of "x" -> "#x" or "(x)" -> "x" may be made. */{ assert(e != nil); switch (e->operator) { case ',': if (is_pseudo(a->opcode)) { /* Pseudo's are normal. */ gnu_put_expression(a, e->left, deref); gnu_printf(", "); gnu_put_expression(a, e->right, deref); } else { /* He who invented GNU assembly has seen one VAX too * many, operands are given in the wrong order. This * makes coding from an Intel databook a real delight. * A good thing this program allows us to write the * more normal ACK assembly. */ gnu_put_expression(a, e->right, deref); gnu_printf(", "); gnu_put_expression(a, e->left, deref); } break; case 'O': if (deref && a->optype == JUMP) gnu_putchar('*'); if (e->left != nil) gnu_put_expression(a, e->left, 0); gnu_putchar('('); if (e->middle != nil) gnu_put_expression(a, e->middle, 0); if (e->right != nil) { gnu_putchar(','); gnu_put_expression(a, e->right, 0); } gnu_putchar(')'); break; case '(': if (!deref) gnu_putchar('('); if (deref && a->optype == JUMP) gnu_putchar('*'); gnu_put_expression(a, e->middle, 0); if (!deref) gnu_putchar(')'); break; case 'B': gnu_printf("%%%s", e->name); break; case '1': case '2': case '4': case '8': gnu_printf("%%%s,%c", e->name, e->operator); break; case '+': case '-': case '~': if (e->middle != nil) { if (deref && a->optype >= BYTE) gnu_putchar('$'); gnu_putchar(e->operator); gnu_put_expression(a, e->middle, 0); break; } /*FALL THROUGH*/ case '*': case '/': case '%': case '&': case '|': case '^': case S_LEFTSHIFT: case S_RIGHTSHIFT: if (deref && a->optype >= BYTE) gnu_putchar('$'); gnu_put_expression(a, e->left, 0); if (e->operator == S_LEFTSHIFT) { gnu_printf("<<"); } else if (e->operator == S_RIGHTSHIFT) { gnu_printf(">>"); } else { gnu_putchar(e->operator); } gnu_put_expression(a, e->right, 0); break; case '[': if (deref && a->optype >= BYTE) gnu_putchar('$'); gnu_putchar('('); gnu_put_expression(a, e->middle, 0); gnu_putchar(')'); break; case 'W': if (isregister(e->name)) { if (a->optype == JUMP) gnu_putchar('*'); gnu_printf("%%%s", e->name); } else { if (deref && a->optype >= BYTE) gnu_putchar('$'); gnu_printf("%s", e->name); } break; case 'S': gnu_putchar('"'); gnu_put_string(e->name, e->len); gnu_putchar('"'); break; default: fprintf(stderr, "asmconv: internal error, unknown expression operator '%d'\n", e->operator); exit(1); }}void gnu_emit_instruction(asm86_t *a)/* Output one instruction and its operands. */{ int same= 0; char *p; if (a == nil) { /* Last call */ gnu_putchar('\n'); return; } if (use16()) { fprintf(stderr, "asmconv: the GNU assembler can't translate 8086 code\n"); exit(1); } /* Make sure the line number of the line to be emitted is ok. */ if ((a->file != efile && strcmp(a->file, efile) != 0) || a->line < eline || a->line > eline+10) { gnu_putchar('\n'); gnu_printf("# %ld \"%s\"\n", a->line, a->file); efile= a->file; eline= a->line; } else { if (a->line == eline) { gnu_printf("; "); same= 1; } while (eline < a->line) { gnu_putchar('\n'); eline++; } } if (a->opcode == DOT_LABEL) { assert(a->args->operator == ':'); gnu_printf("%s:", a->args->name); } else if (a->opcode == DOT_EQU) { assert(a->args->operator == '='); gnu_printf("\t%s = ", a->args->name); gnu_put_expression(a, a->args->middle, 0); } else if (a->opcode == DOT_ALIGN) { /* GNU .align thinks in powers of two. */ unsigned long n; unsigned s; assert(a->args->operator == 'W' && isanumber(a->args->name)); n= strtoul(a->args->name, nil, 0); for (s= 0; s <= 4 && (1 << s) < n; s++) {} gnu_printf(".align\t%u", s); } else if ((p= opcode2name(a->opcode)) != nil) { if (!is_pseudo(a->opcode) && !same) gnu_putchar('\t'); switch (a->rep) { case ONCE: break; case REP: gnu_printf("rep; "); break; case REPE: gnu_printf("repe; "); break; case REPNE: gnu_printf("repne; "); break; default: assert(0); } switch (a->seg) { /* Kludge to avoid knowing where to put the "%es:" */ case DEFSEG: break; case CSEG: gnu_printf(".byte 0x2e; "); break; case DSEG: gnu_printf(".byte 0x3e; "); break; case ESEG: gnu_printf(".byte 0x26; "); break; case FSEG: gnu_printf(".byte 0x64; "); break; case GSEG: gnu_printf(".byte 0x65; "); break; case SSEG: gnu_printf(".byte 0x36; "); break; default: assert(0); } /* Exceptions, exceptions... */ if (a->opcode == CBW) { if (!(a->oaz & OPZ)) p= "cwde"; a->oaz&= ~OPZ; } if (a->opcode == CWD) { if (!(a->oaz & OPZ)) p= "cdq"; a->oaz&= ~OPZ; } if (a->opcode == RET || a->opcode == RETF) { /* Argument of RET needs a '$'. */ a->optype= WORD; } if (a->opcode == MUL && a->args != nil && a->args->operator == ',') { /* Two operand MUL is an IMUL? */ p="imul%"; } /* GAS doesn't understand the interesting combinations. */ if (a->oaz & ADZ) gnu_printf(".byte 0x67; "); if (a->oaz & OPZ && strchr(p, '%') == nil) gnu_printf(".byte 0x66; "); /* Unsupported instructions that Minix code needs. */ if (a->opcode == JMPF && a->args != nil && a->args->operator == ',') { /* JMPF seg:off. */ gnu_printf(".byte 0xEA; .long "); gnu_put_expression(a, a->args->right, 0); gnu_printf("; .short "); gnu_put_expression(a, a->args->left, 0); return; } if (a->opcode == JMPF && a->args != nil && a->args->operator == 'O' && a->args->left != nil && a->args->right == nil && a->args->middle != nil && a->args->middle->operator == 'B' && strcmp(a->args->middle->name, "esp") == 0 ) { /* JMPF offset(ESP). */ gnu_printf(".byte 0xFF,0x6C,0x24,"); gnu_put_expression(a, a->args->left, 0); return; } if (a->opcode == MOV && a->args != nil && a->args->operator == ',' && a->args->left != nil && a->args->left->operator == 'W' && (strcmp(a->args->left->name, "ds") == 0 || strcmp(a->args->left->name, "es") == 0) && a->args->right->operator == 'O' && a->args->right->left != nil && a->args->right->right == nil && a->args->right->middle != nil && a->args->right->middle->operator == 'B' && strcmp(a->args->right->middle->name, "esp") == 0 ) { /* MOV DS, offset(ESP); MOV ES, offset(ESP) */ gnu_printf(".byte 0x8E,0x%02X,0x24,", a->args->left->name[0] == 'd' ? 0x5C : 0x44); gnu_put_expression(a, a->args->right->left, 0); return; } if (a->opcode == MOV && a->args != nil && a->args->operator == ',' && a->args->left != nil && a->args->left->operator == 'W' && (strcmp(a->args->left->name, "ds") == 0 || strcmp(a->args->left->name, "es") == 0) && a->args->right->operator == '(' && a->args->right->middle != nil ) { /* MOV DS, (memory); MOV ES, (memory) */ gnu_printf(".byte 0x8E,0x%02X; .long ", a->args->left->name[0] == 'd' ? 0x1D : 0x05); gnu_put_expression(a, a->args->right->middle, 0); return; } while (*p != 0) { if (*p == '%') { if (a->optype == BYTE) { gnu_putchar('b'); } else if (a->optype == WORD) { gnu_putchar((a->oaz & OPZ) ? 'w' : 'l'); } else { assert(0); } } else { gnu_putchar(*p); } p++; } if (a->args != nil) { static char *aregs[] = { "al", "ax", "eax" }; gnu_putchar('\t'); switch (a->opcode) { case IN: gnu_put_expression(a, a->args, 1); gnu_printf(", %%%s", aregs[a->optype - BYTE]); break; case OUT: gnu_printf("%%%s, ", aregs[a->optype - BYTE]); gnu_put_expression(a, a->args, 1); break; default: gnu_put_expression(a, a->args, 1); } } if (a->opcode == DOT_USE16) set_use16(); if (a->opcode == DOT_USE32) set_use32(); } else { fprintf(stderr, "asmconv: internal error, unknown opcode '%d'\n", a->opcode); exit(1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -