aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-07 01:53:34 +1300
committerAndrew Chambers <[email protected]>2021-10-07 01:53:34 +1300
commitf4a9a52d001a54ca1142110b70142a8ef8df53bc (patch)
tree95226e04b60c43b1143b7d27d7fe6905ae0b3dd4
parent78aa469080b95f41fabc0f428bd4e5b1bbdaa04b (diff)
Work.
-rw-r--r--asm.peg236
-rw-r--r--main.c133
-rw-r--r--minias.h54
-rw-r--r--test/test.sh44
-rw-r--r--util.c14
5 files changed, 339 insertions, 142 deletions
diff --git a/asm.peg b/asm.peg
index f163271..1a834cc 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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"
-
diff --git a/main.c b/main.c
index 81e6220..e469bcd 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
}
}
diff --git a/minias.h b/minias.h
index 5e456fa..bf0b857 100644
--- a/minias.h
+++ b/minias.h
@@ -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"
diff --git a/util.c b/util.c
index 5ab9c48..43c3d8b 100644
--- a/util.c
+++ b/util.c
@@ -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;