diff options
| -rw-r--r-- | asm.peg | 236 | ||||
| -rw-r--r-- | main.c | 133 | ||||
| -rw-r--r-- | minias.h | 54 | ||||
| -rw-r--r-- | test/test.sh | 44 | ||||
| -rw-r--r-- | util.c | 14 |
5 files changed, 339 insertions, 142 deletions
@@ -1,8 +1,11 @@ -line = - ws? s:stmt (eol | !. ) { yy->v = s; } - | eol { yy->v.kind = ASM_BLANK; } - | . { yy->v.kind = ASM_SYNTAX_ERROR; } +line = + ws? s:stmt eol { yy->v = s; } + | eol { yy->v.kind = ASM_BLANK; } + | . { yy->v.kind = ASM_SYNTAX_ERROR; } + +ws = [ \t]+ +eol = ws? "\n" stmt = d:directive {$$ = d;} @@ -10,7 +13,7 @@ stmt = | l:label { $$ = l; } directive = - ".glob" "o"? "l" ws i:ident + ".glob" 'o'? 'l' ws i:ident { $$.globl = (Globl){.kind = ASM_DIR_GLOBL, .name = i.ident.name }; } | ".data" { $$.kind = ASM_DIR_DATA; } @@ -31,93 +34,195 @@ instr = | "ret" { $$.kind = ASM_RET; } | i:jmp { $$ = i; } | i:lea { $$ = i; } + | i:movzx { $$ = i; } | i:mod-rm-binop { $$ = i; } jmp = "jmp" ws i:ident { $$.jmp = (Jmp){.kind = ASM_JMP, .target = i.ident.name}; } +movzx = + "movzx" + ( + ( + 'b' ws s:m ws? ',' ws? d:r16 + | 'b' ws s:m ws? ',' ws? d:r32 + | 'b' ws s:m ws? ',' ws? d:r64 + | 'b'? ws s:r8 ws? ',' ws? d:r16 + | 'b'? ws s:r8 ws? ',' ws? d:r32 + | 'b'? ws s:r8 ws? ',' ws? d:r64 + ) { $$.movzx.type = 'b'; } + | + ( + 'w' ws s:m ws? ',' ws? d:r32 + | 'w' ws s:m ws? ',' ws? d:r64 + | 'w'? ws s:r16 ws? ',' ws? d:r32 + | 'w'? ws s:r16 ws? ',' ws? d:r64 + ) { $$.movzx.type = 'w'; } + ) { $$.movzx.kind = ASM_MOVZX; + $$.movzx.src = dupv(&s); + $$.movzx.dst = dupv(&d); } + lea = "lea" ( - "q"? ws s:m ws? ',' ws? d:r64 - { $$.lea.type = 'q'; } - | "l"? ws s:m ws? ',' ws? d:r32 - { $$.lea.type = 'l'; } + 'w'? ws s:m ws? ',' ws? d:r16 + { $$.lea.type = 'w'; } + | 'l'? ws s:m ws? ',' ws? d:r32 + { $$.lea.type = 'l'; } + | 'q'? ws s:m ws? ',' ws? d:r64 + { $$.lea.type = 'q'; } + ) { $$.lea.kind = ASM_LEA; $$.lea.src = dupv(&s); $$.lea.dst = dupv(&d); } mod-rm-binop = - "add" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_ADD; } - | "and" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_AND;} - | "mov" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_MOV;} - | "or" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_OR;} - | "sub" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_SUB;} - | "xor" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_XOR;} + "add" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_ADD; } + | "and" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_AND; } + | "mov" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_MOV; } + | "or" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_OR; } + | "sub" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_SUB; } + | "xchg" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_XCHG; } + | "xor" a:mod-rm-binop-args { $$ = a; $$.kind = ASM_XOR; } + mod-rm-binop-args = ( - "q" ws s:r-m64 ws? ',' ws? d:r64 - | "q" ws s:r64 ws? ',' ws? d:r-m64 - | "q" ws s:imm ws? ',' ws? d:r-m64 + 'b' ws s:r-m8 ws? ',' ws? d:r8 + | 'b' ws s:r8 ws? ',' ws? d:r-m8 + | 'b' ws s:imm ws? ',' ws? d:r-m8 + | ws s:r8 ws? ',' ws? d:r8 + | ws s:m ws? ',' ws? d:r8 + | ws s:imm ws? ',' ws? d:r8 + ) + { $$.modrmbinop = (ModRMBinop){ .type = 'b', .src = dupv(&s), .dst = dupv(&d) }; } + | + ( + 'w' ws s:r-m16 ws? ',' ws? d:r16 + | 'w' ws s:r16 ws? ',' ws? d:r-m16 + | 'w' ws s:imm ws? ',' ws? d:r-m16 + | ws s:r16 ws? ',' ws? d:r16 + | ws s:m ws? ',' ws? d:r16 + | ws s:imm ws? ',' ws? d:r16 + ) + { $$.modrmbinop = (ModRMBinop){ .type = 'w', .src = dupv(&s), .dst = dupv(&d) }; } + | + ( + 'l' ws s:r-m32 ws? ',' ws? d:r32 + | 'l' ws s:r32 ws? ',' ws? d:r-m32 + | 'l' ws s:imm ws? ',' ws? d:r-m32 + | ws s:r32 ws? ',' ws? d:r32 + | ws s:m ws? ',' ws? d:r32 + | ws s:imm ws? ',' ws? d:r32 + ) + { $$.modrmbinop = (ModRMBinop){ .type = 'l', .src = dupv(&s), .dst = dupv(&d) }; } + | + ( + 'q' ws s:r-m64 ws? ',' ws? d:r64 + | 'q' ws s:r64 ws? ',' ws? d:r-m64 + | 'q' ws s:imm ws? ',' ws? d:r-m64 | ws s:r64 ws? ',' ws? d:r64 | ws s:m ws? ',' ws? d:r64 | ws s:imm ws? ',' ws? d:r64 - ) { $$.modrmbinop = (ModRMBinop){ .type = 'q', .src = dupv(&s), .dst = dupv(&d) } } - | ( - "l" ws s:r-m32 ws? ',' ws? d:r32 - | "l" ws s:r32 ws? ',' ws? d:r-m32 - | "l" ws s:imm ws? ',' ws? d:r-m32 - | ws s:r32 ws? ',' ws? d:r32 - | ws s:m ws? ',' ws? d:r32 - | ws s:imm ws? ',' ws? d:r32 - ) - { $$.modrmbinop = (ModRMBinop){ .type = 'l', .src = dupv(&s), .dst = dupv(&d) } } + ) { $$.modrmbinop = (ModRMBinop){ .type = 'q', .src = dupv(&s), .dst = dupv(&d) }; } -r-m64 = - r:r64 { $$ = r; } - | m:m { $$ = m; } + +r-m8 = + r:r8 { $$ = r; } + | m:m { $$ = m; } + +r-m16 = + r:r16 { $$ = r; } + | m:m { $$ = m; } r-m32 = r:r32 { $$ = r; } | m:m { $$ = m; } +r-m64 = + r:r64 { $$ = r; } + | m:m { $$ = m; } + m = '(' ws? r:r64 ws? ')' - { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = NULL, .reg = r.kind } } + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = NULL, .reg = r.kind }; } | <'-'?[0-9]+> ws? '(' ws? r:r64 ws? ')' - { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = strtoll(yytext, NULL, 10), .l = NULL, .reg = r.kind } } + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = strtoll(yytext, NULL, 10), .l = NULL, .reg = r.kind }; } | i:ident ws? '(' ws? r:r64 ws? ')' - { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = i.ident.name, .reg = r.kind } } - -r64 = - "%rax" { $$.kind = ASM_RAX } - | "%rcx" { $$.kind = ASM_RCX } - | "%rdx" { $$.kind = ASM_RDX } - | "%rbx" { $$.kind = ASM_RBX } - | "%rsp" { $$.kind = ASM_RSP } - | "%rbp" { $$.kind = ASM_RBP } - | "%rsi" { $$.kind = ASM_RSI } - | "%rdi" { $$.kind = ASM_RDI } - | "%r8" { $$.kind = ASM_R8 } - | "%r9" { $$.kind = ASM_R9 } - | "%r10" { $$.kind = ASM_R10 } - | "%r11" { $$.kind = ASM_R11 } - | "%r12" { $$.kind = ASM_R12 } - | "%r13" { $$.kind = ASM_R13 } - | "%r14" { $$.kind = ASM_R14 } - | "%r15" { $$.kind = ASM_R15 } - -r32 = - "%eax" { $$.kind = ASM_EAX } - | "%ecx" { $$.kind = ASM_ECX } - | "%edx" { $$.kind = ASM_EDX } - | "%ebx" { $$.kind = ASM_EBX } - | "%esp" { $$.kind = ASM_ESP } - | "%ebp" { $$.kind = ASM_EBP } - | "%esi" { $$.kind = ASM_ESI } - | "%edi" { $$.kind = ASM_EDI } - + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = i.ident.name, .reg = r.kind }; } + +r8 = + "%al" { $$.kind = ASM_AL; } + | "%cl" { $$.kind = ASM_CL; } + | "%dl" { $$.kind = ASM_DL; } + | "%bl" { $$.kind = ASM_BL; } + | "%spl" { $$.kind = ASM_SPL; } + | "%bpl" { $$.kind = ASM_BPL; } + | "%sil" { $$.kind = ASM_SIL; } + | "%dil" { $$.kind = ASM_DIL; } + | "%r8b" { $$.kind = ASM_R8B; } + | "%r9b" { $$.kind = ASM_R9B; } + | "%r10b" { $$.kind = ASM_R10B; } + | "%r11b" { $$.kind = ASM_R11B; } + | "%r12b" { $$.kind = ASM_R12B; } + | "%r13b" { $$.kind = ASM_R13B; } + | "%r14b" { $$.kind = ASM_R14B; } + | "%r15b" { $$.kind = ASM_R15B; } + +r16 = + "%ax" { $$.kind = ASM_AX; } + | "%cx" { $$.kind = ASM_CX; } + | "%dx" { $$.kind = ASM_DX; } + | "%bx" { $$.kind = ASM_BX; } + | "%sp" { $$.kind = ASM_SP; } + | "%bp" { $$.kind = ASM_BP; } + | "%si" { $$.kind = ASM_SI; } + | "%di" { $$.kind = ASM_DI; } + | "%r8w" { $$.kind = ASM_R8W; } + | "%r9w" { $$.kind = ASM_R9W; } + | "%r10w" { $$.kind = ASM_R10W; } + | "%r11w" { $$.kind = ASM_R11W; } + | "%r12w" { $$.kind = ASM_R12W; } + | "%r13w" { $$.kind = ASM_R13W; } + | "%r14w" { $$.kind = ASM_R14W; } + | "%r15w" { $$.kind = ASM_R15W; } + +r32 = + "%eax" { $$.kind = ASM_EAX; } + | "%ecx" { $$.kind = ASM_ECX; } + | "%edx" { $$.kind = ASM_EDX; } + | "%ebx" { $$.kind = ASM_EBX; } + | "%esp" { $$.kind = ASM_ESP; } + | "%ebp" { $$.kind = ASM_EBP; } + | "%esi" { $$.kind = ASM_ESI; } + | "%edi" { $$.kind = ASM_EDI; } + | "%r8d" { $$.kind = ASM_R8D; } + | "%r9d" { $$.kind = ASM_R9D; } + | "%r10d" { $$.kind = ASM_R10D; } + | "%r11d" { $$.kind = ASM_R11D; } + | "%r12d" { $$.kind = ASM_R12D; } + | "%r13d" { $$.kind = ASM_R13D; } + | "%r14d" { $$.kind = ASM_R14D; } + | "%r15d" { $$.kind = ASM_R15D; } + +r64 = ( + "%rax" { $$.kind = ASM_RAX; } + | "%rcx" { $$.kind = ASM_RCX; } + | "%rdx" { $$.kind = ASM_RDX; } + | "%rbx" { $$.kind = ASM_RBX; } + | "%rsp" { $$.kind = ASM_RSP; } + | "%rbp" { $$.kind = ASM_RBP; } + | "%rsi" { $$.kind = ASM_RSI; } + | "%rdi" { $$.kind = ASM_RDI; } + | "%r8" ![lwb] { $$.kind = ASM_R8; } + | "%r9" ![lwb] { $$.kind = ASM_R9; } + | "%r10" ![lwb] { $$.kind = ASM_R10; } + | "%r11" ![lwb] { $$.kind = ASM_R11; } + | "%r12" ![lwb] { $$.kind = ASM_R12; } + | "%r13" ![lwb] { $$.kind = ASM_R13; } + | "%r14" ![lwb] { $$.kind = ASM_R14; } + | "%r15" ![lwb] { $$.kind = ASM_R15; } +) imm = '$' i:ident @@ -132,8 +237,3 @@ ident = number = <'-'?[0-9]+> { $$.number = (Number){ .kind = ASM_NUMBER, .v = strtoll(yytext, NULL, 10) }; } - -ws = [ \t]+ - -eol = ws? "\n" - @@ -19,6 +19,8 @@ static Section *bss = NULL; static Section *text = NULL; static Section *data = NULL; +size_t curlineno = 0; + static Symbol *getsym(const char *name) { Symbol **ps, *s; struct hashtablekey htk; @@ -126,25 +128,23 @@ static Parsev *dupv(Parsev *p) { #include "asm.peg.inc" void parse(void) { - uint64_t lineno; AsmLine *l, *prevl; yycontext ctx; memset(&ctx, 0, sizeof(yycontext)); prevl = NULL; - lineno = 0; + curlineno = 0; while (yyparse(&ctx)) { - lineno += 1; + curlineno += 1; if (ctx.v.kind == ASM_SYNTAX_ERROR) { - fprintf(stderr, "<stdin>:%lu: syntax error\n", lineno); - exit(1); + lfatal("syntax error\n"); } if (ctx.v.kind == ASM_BLANK) continue; l = zalloc(sizeof(AsmLine)); l->v = ctx.v; - l->lineno = lineno; + l->lineno = curlineno; if (prevl) prevl->next = l; else @@ -180,29 +180,40 @@ static void sw(uint32_t w) { static int isregkind(AsmKind k) { return k > ASM_REG_BEGIN && k < ASM_REG_END; } -/* Is one of the r$n style registers. */ -static int isextr64(AsmKind k) { return k >= ASM_R8 && k <= ASM_R15; } +/* Convert an AsmKind to register bits in reg/rm style. */ +static uint8_t modrmregbits(AsmKind k) { + return (k - (ASM_REG_BEGIN+1)) % 16; +} -static uint8_t r64bits(AsmKind k) { - if (isextr64(k)) { - return (1 << 4) | ((k - ASM_R8) & 0xff); - } else { - return (k - ASM_RAX) & 0xff; - } +static uint8_t modrmregopcode(AsmKind k, char t) { + uint8_t opcode; + if (k == ASM_ADD) { + opcode = 0x00; + } else if (k == ASM_AND) { + opcode = 0x20; + } else if (k == ASM_MOV) { + opcode = 0x88; + } else if (k == ASM_OR) { + opcode = 0x08; + } else if (k == ASM_SUB) { + opcode = 0x28; + } else if (k == ASM_XCHG) { + opcode = 0x86; + } else if (k == ASM_XOR) { + opcode = 0x30; + } else { + unreachable(); + } + if (t != 'b') + opcode += 1; + return opcode; } -static uint8_t r32bits(AsmKind k) { return (k - ASM_EAX) & 0xff; } -/* Convert an ASM_KIND to register bits */ -static uint8_t rbits(AsmKind k) { - if (k >= ASM_RAX && k <= ASM_R15) { - return r64bits(k); - } else if (k >= ASM_EAX && k <= ASM_EDI) { - return r32bits(k); - } else { - fatal("BUG: kind not a register"); - } - return 0; +static uint8_t modrmmemopcode(AsmKind k, char t) { + if (k == ASM_LEA) + return 0x8d; + return modrmregopcode(k, t) + 2; } #define REX(W, R, X, B) \ @@ -217,6 +228,7 @@ static void assemble() { cursection = text; for (l = allasm; l; l = l->next) { + curlineno = l->lineno; v = &l->v; switch (l->v.kind) { case ASM_DIR_GLOBL: @@ -258,13 +270,19 @@ static void assemble() { case ASM_RET: sb(0xc3); break; + case ASM_MOVZX: + case ASM_MOVSX: { + fatal("TODO"); + } case ASM_ADD: case ASM_AND: case ASM_LEA: case ASM_MOV: case ASM_OR: case ASM_SUB: + case ASM_XCHG: case ASM_XOR: { + ModRMBinop *op; Memarg *memarg; uint8_t opcode; @@ -290,11 +308,11 @@ static void assemble() { } if (memarg) { - rm = rbits(memarg->reg); + rm = modrmregbits(memarg->reg); /* We cannot address ESP/RSP/... */ if ((rm & 7) == 4) - fatal("addressing mode unrepresentable"); + lfatal("addressing mode unrepresentable"); if (memarg->c == 0 && memarg->l == NULL) { if ((rm & 7) == 5) { // BP style registers need displacement @@ -307,66 +325,35 @@ static void assemble() { mod = 0x00; } } else { - fatal("unreachable"); + unreachable(); } } if (isregkind(op->dst->kind)) { - rm = rbits(op->dst->kind); + rm = modrmregbits(op->dst->kind); } if (isregkind(op->src->kind)) { - - if (op->kind == ASM_ADD) { - opcode = 0x01; - } else if (op->kind == ASM_AND) { - opcode = 0x21; - } else if (op->kind == ASM_MOV) { - opcode = 0x89; - } else if (op->kind == ASM_OR) { - opcode = 0x09; - } else if (op->kind == ASM_SUB) { - opcode = 0x29; - } else if (op->kind == ASM_XOR) { - opcode = 0x31; - } else { - fatal("unreachable"); - } - - reg = rbits(op->src->kind); + opcode = modrmregopcode(op->kind, op->type); + reg = modrmregbits(op->src->kind); } else if (op->src->kind == ASM_MEMARG) { - - if (op->kind == ASM_ADD) { - opcode = 0x03; - } else if (op->kind == ASM_AND) { - opcode = 0x23; - } else if (op->kind == ASM_LEA) { - opcode = 0x8d; - } else if (op->kind == ASM_MOV) { - opcode = 0x8b; - } else if (op->kind == ASM_OR) { - opcode = 0x0b; - } else if (op->kind == ASM_SUB) { - opcode = 0x2b; - } else if (op->kind == ASM_XOR) { - opcode = 0x33; - } else { - fatal("unreachable"); - } - reg = rbits(op->dst->kind); + opcode = modrmmemopcode(op->kind, op->type); + reg = modrmregbits(op->dst->kind); } else if (op->src->kind == ASM_IMM) { - opcode = 0x81; reg = 0x00; if (memarg) { - rm = rbits(memarg->reg); + rm = modrmregbits(memarg->reg); } else { - rm = rbits(op->dst->kind); + rm = modrmregbits(op->dst->kind); } + } + if (op->type == 'w') { + sb(0x66); } - rex = REX(op->type == 'q', reg & (1 << 4), 0, rm & (1 << 4)); + rex = REX(op->type == 'q', reg & (1 << 3), 0, rm & (1 << 3)); if (rex != REX(0, 0, 0, 0)) { sb(rex); @@ -388,7 +375,7 @@ static void assemble() { sw((uint32_t)disp); break; default: - fatal("unreachable"); + unreachable(); } switch (immsz) { @@ -401,7 +388,7 @@ static void assemble() { sw((uint32_t)imm); break; default: - fatal("unreachable"); + unreachable(); } break; @@ -424,7 +411,7 @@ static void assemble() { break; } default: - fatal("assemble: unexpected kind: %d", l->v.kind); + lfatal("assemble: unexpected kind: %d", l->v.kind); } } } @@ -51,11 +51,49 @@ typedef enum { ASM_AND, ASM_LEA, ASM_MOV, + ASM_MOVSX, + ASM_MOVZX, ASM_OR, ASM_SUB, + ASM_XCHG, ASM_XOR, // Registers, order matters. ASM_REG_BEGIN, + + ASM_AL, + ASM_CL, + ASM_DL, + ASM_BL, + ASM_SPL, + ASM_BPL, + ASM_SIL, + ASM_DIL, + ASM_R8B, + ASM_R9B, + ASM_R10B, + ASM_R11B, + ASM_R12B, + ASM_R13B, + ASM_R14B, + ASM_R15B, + + ASM_AX, + ASM_CX, + ASM_DX, + ASM_BX, + ASM_SP, + ASM_BP, + ASM_SI, + ASM_DI, + ASM_R8W, + ASM_R9W, + ASM_R10W, + ASM_R11W, + ASM_R12W, + ASM_R13W, + ASM_R14W, + ASM_R15W, + ASM_EAX, ASM_ECX, ASM_EDX, @@ -64,6 +102,15 @@ typedef enum { ASM_EBP, ASM_ESI, ASM_EDI, + ASM_R8D, + ASM_R9D, + ASM_R10D, + ASM_R11D, + ASM_R12D, + ASM_R13D, + ASM_R14D, + ASM_R15D, + ASM_RAX, ASM_RCX, ASM_RDX, @@ -80,6 +127,7 @@ typedef enum { ASM_R13, ASM_R14, ASM_R15, + ASM_REG_END, } AsmKind; @@ -144,6 +192,7 @@ typedef ModRMBinop Add; typedef ModRMBinop And; typedef ModRMBinop Lea; typedef ModRMBinop Mov; +typedef ModRMBinop Movzx; typedef ModRMBinop Or; typedef ModRMBinop Sub; typedef ModRMBinop Xor; @@ -159,6 +208,7 @@ union Parsev { And and; Lea lea; Mov mov; + Movzx movzx; Or or; Xor xor; Sub sub; @@ -176,9 +226,13 @@ struct AsmLine { AsmLine *next; }; +extern size_t curlineno; + /* util.c */ +void lfatal(const char *fmt, ...); void fatal(const char *fmt, ...); +void unreachable(void); void *xmalloc(size_t); void *xrealloc(void *, size_t); diff --git a/test/test.sh b/test/test.sh index be5a91f..0d92e4a 100644 --- a/test/test.sh +++ b/test/test.sh @@ -26,12 +26,56 @@ t () { } # TODO Tidy and be more systematic, we could just loop + +t "xchg %rax, %rax" +t "xchg %eax, %eax" +t "xchg %ax, %ax" +t "xchg %al, %al" +t "xchg %rax, (%rax)" +t "xchg %eax, (%rax)" +t "xchg %ax, (%rax)" +t "xchg %al, (%rax)" +t "xchg (%rax), %rax" +t "xchg (%rax), %eax" +t "xchg (%rax), %ax" +t "xchg (%rax), %al" + +exit 0 + +t "addb %al, %al" +t "addb (%rax), %al" +t "addb %al, (%rax)" + +t "subb %al, %al" +t "subb (%rax), %al" +t "subb %al, (%rax)" + +t "xorb %al, %al" +t "xorb (%rax), %al" +t "xorb %al, (%rax)" + +t "orb %al, %al" +t "orb (%rax), %al" +t "orb %al, (%rax)" + +t "andb %al, %al" +t "andb (%rax), %al" +t "andb %al, (%rax)" + +t "movb %al, %al" +t "movb (%rax), %al" +t "movb %al, (%rax)" + +t "movw %ax, %r9w" +t "movw %ax, %ax" +t "addw %ax, %ax" t "movq %rax, %rax" t "movq (%rax), %rax" t "movq %rax, (%rax)" t "movl %eax, %eax" t "movl (%rax), %eax" t "movl %eax, (%rax)" +t "leaw (%rax), %ax" t "leaq (%rax), %rax" t "leal (%rax), %eax" t "addq (%rax), %rax" @@ -10,15 +10,27 @@ static void vwarn(const char *fmt, va_list ap) { } } -void fatal(const char *fmt, ...) { +void lfatal(const char *fmt, ...) { va_list ap; + fprintf(stderr, "%ld: ", curlineno); + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); + exit(1); +} +void fatal(const char *fmt, ...) { + va_list ap; va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); exit(1); } +void unreachable(void) { + lfatal("BUG: unexpected internal condition"); +} + void *xmalloc(size_t n) { void *p; |
