diff options
| -rw-r--r-- | asm.peg | 48 | ||||
| -rw-r--r-- | main.c | 125 | ||||
| -rw-r--r-- | minias.h | 18 | ||||
| -rw-r--r-- | test/test.sh | 7 |
4 files changed, 117 insertions, 81 deletions
@@ -61,6 +61,8 @@ instr = | i:div { $$ = i; } | i:idiv { $$ = i; } | i:lea { $$ = i; } + | i:mul { $$ = i; } + | i:imul { $$ = i; } | i:mov { $$ = i; } | i:or { $$ = i; } | i:sub { $$ = i; } @@ -71,13 +73,13 @@ push = "push" ( 'q'? ws s:r64 { $$ = INSTR1(0, s); } | 'q' ws s:m { $$ = INSTR1(1, s); } - ) { $$.instr2.kind = ASM_PUSH; } + ) { $$.instr.kind = ASM_PUSH; } pop = "pop" ( 'q'? ws d:r64 { $$ = INSTR1(0, d); } | 'q' ws d:m { $$ = INSTR1(1, d); } - ) { $$.instr2.kind = ASM_POP; } + ) { $$.instr.kind = ASM_POP; } call = "call" 'q'? ws t:ident @@ -92,17 +94,25 @@ lea = 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } - ) { $$.instr2.kind = ASM_LEA; } + ) { $$.instr.kind = ASM_LEA; } div = "div" ( - args:div-opargs { $$ = args; } -) { $$.instr2.kind = ASM_DIV; } + args:divmul-opargs { $$ = args; } +) { $$.instr.kind = ASM_DIV; } idiv = "idiv" ( - args:div-opargs { $$ = args; } -) { $$.instr2.kind = ASM_IDIV; } + args:divmul-opargs { $$ = args; } +) { $$.instr.kind = ASM_IDIV; } -div-opargs = +mul = "mul" ( + args:divmul-opargs { $$ = args; } +) { $$.instr.kind = ASM_MUL; } + +imul = "imul" ( + args:divmul-opargs { $$ = args; } +) { $$.instr.kind = ASM_IMUL; } + +divmul-opargs = 'b' ws a:m { $$ = INSTR1(0, a); } | 'w' ws a:m { $$ = INSTR1(1, a); } | 'l' ws a:m { $$ = INSTR1(2, a); } @@ -138,8 +148,8 @@ r-rm-opargs = mov = "mov" ( args:imm-rm-opargs { $$ = args; } - | args:r-rm-opargs { args.instr2.variant += 8; $$ = args; } -) { $$.instr2.kind = ASM_MOV; } + | args:r-rm-opargs { args.instr.variant += 8; $$ = args; } +) { $$.instr.kind = ASM_MOV; } xchg = 'xchg' ( @@ -149,22 +159,22 @@ xchg = | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR2(3, s, d); } | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR2(5, s, d); } - | args:r-rm-opargs { args.instr2.variant += 6; $$ = args; } - ) { $$.instr2.kind = ASM_XCHG; } + | args:r-rm-opargs { args.instr.variant += 6; $$ = args; } + ) { $$.instr.kind = ASM_XCHG; } -add = "add" a:basic-op-args { a.instr2.kind = ASM_ADD; $$ = a; } -and = "and" a:basic-op-args { a.instr2.kind = ASM_AND; $$ = a; } -or = "or" a:basic-op-args { a.instr2.kind = ASM_OR; $$ = a; } -sub = "sub" a:basic-op-args { a.instr2.kind = ASM_SUB; $$ = a; } -xor = "xor" a:basic-op-args { a.instr2.kind = ASM_XOR; $$ = a; } +add = "add" a:basic-op-args { a.instr.kind = ASM_ADD; $$ = a; } +and = "and" a:basic-op-args { a.instr.kind = ASM_AND; $$ = a; } +or = "or" a:basic-op-args { a.instr.kind = ASM_OR; $$ = a; } +sub = "sub" a:basic-op-args { a.instr.kind = ASM_SUB; $$ = a; } +xor = "xor" a:basic-op-args { a.instr.kind = ASM_XOR; $$ = a; } basic-op-args = 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = INSTR2(0, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR2(2, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR2(3, s, d); } - | args:imm-rm-opargs { args.instr2.variant += 4; $$ = args; } - | args:r-rm-opargs { args.instr2.variant += 12; $$ = args; } + | args:imm-rm-opargs { args.instr.variant += 4; $$ = args; } + | args:r-rm-opargs { args.instr.variant += 12; $$ = args; } r64-or-rip = ( r:r64 @@ -203,17 +203,27 @@ static Parsev *dupv(Parsev *p) { return r; } -#define INSTR1(V, A) \ +#define INSTR1(V, A1) \ (Parsev) { \ - .instr1 = (Instr1) { .kind = 0, .variant = V, .arg = dupv(&A), } \ + .instr = (Instr) { \ + .kind = 0, .variant = V, .arg1 = dupv(&A1), .arg2 = NULL, .arg3 = NULL \ + } \ } - -#define INSTR2(V, S, D) \ +#define INSTR2(V, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = 0, .variant = V, .arg1 = dupv(&A1), .arg2 = dupv(&A2), \ + .arg3 = NULL \ + } \ + } +#define INSTR3(V, A1, A2, A3) \ (Parsev) { \ - .instr2 = (Instr2) { \ - .kind = 0, .variant = V, .src = dupv(&S), .dst = dupv(&D) \ + .instr = (Instr) { \ + .kind = 0, .variant = V, .arg1 = dupv(&A1), .arg2 = dupv(&A2), \ + .arg3 = dupv(&A3) \ } \ } + #define REG(K) \ (Parsev) { .kind = K } @@ -247,7 +257,7 @@ void parse(void) { } } -/* Shorthand helpers to write section bytes. */ +/* Shorthand helpers to write section data. */ static void sb(uint8_t b) { secaddbyte(cursection, b); } @@ -289,6 +299,7 @@ static uint8_t regbits(AsmKind k) { return (k - (ASM_REG_BEGIN + 1)) % 16; } static uint8_t isreg(AsmKind k) { return k > ASM_REG_BEGIN && k < ASM_REG_END; } static uint8_t isreg8(AsmKind k) { return k >= ASM_AL && k <= ASM_R15B; } static uint8_t isreg16(AsmKind k) { return k >= ASM_AX && k <= ASM_R15W; } +static uint8_t isreg32(AsmKind k) { return k >= ASM_EAX && k <= ASM_R15D; } static uint8_t isreg64(AsmKind k) { return k >= ASM_RAX && k <= ASM_R15; } /* Is an r$n style register variant. */ @@ -420,54 +431,54 @@ static void assemblemem(Memarg *memarg, uint8_t rexw, uint8_t opcode, } /* Assemble op + imm -> r/m. */ -static void assembleimmrm(Instr2 *instr, uint8_t opcode, uint8_t immreg, +static void assembleimmrm(Instr *instr, uint8_t opcode, uint8_t immreg, uint8_t opsz) { Imm *imm; - imm = &instr->src->imm; + imm = &instr->arg1->imm; - if (instr->dst->kind == ASM_MEMARG) { - assemblemem(&instr->dst->memarg, opsz == 8, opcode, immreg, opsz); + if (instr->arg2->kind == ASM_MEMARG) { + assemblemem(&instr->arg2->memarg, opsz == 8, opcode, immreg, opsz); assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); } else { - assemblemodregrm(isreg64(instr->dst->kind), opcode, 0x03, immreg, - regbits(instr->dst->kind), opsz); + assemblemodregrm(isreg64(instr->arg2->kind), opcode, 0x03, immreg, + regbits(instr->arg2->kind), opsz); assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); } } /* Assemble op + r <-> r/m. */ -static void assemblerrm(Instr2 *instr, uint8_t opcode, uint8_t opsz) { +static void assemblerrm(Instr *instr, uint8_t opcode, uint8_t opsz) { Memarg *memarg; AsmKind regarg; - if (instr->src->kind == ASM_MEMARG) { - memarg = &instr->src->memarg; - regarg = instr->dst->kind; + if (instr->arg1->kind == ASM_MEMARG) { + memarg = &instr->arg1->memarg; + regarg = instr->arg2->kind; assemblemem(memarg, isreg64(regarg), opcode, regbits(regarg), opsz); - } else if (instr->dst->kind == ASM_MEMARG) { - memarg = &instr->dst->memarg; - regarg = instr->src->kind; + } else if (instr->arg2->kind == ASM_MEMARG) { + memarg = &instr->arg2->memarg; + regarg = instr->arg1->kind; assemblemem(memarg, isreg64(regarg), opcode, regbits(regarg), opsz); } else { - assemblemodregrm(isreg64(instr->src->kind), opcode, 0x03, - regbits(instr->src->kind), regbits(instr->dst->kind), + assemblemodregrm(isreg64(instr->arg1->kind), opcode, 0x03, + regbits(instr->arg1->kind), regbits(instr->arg2->kind), opsz); } } /* Assemble a 'basic op' which is just a repeated op pattern we have named. */ -static void assemblebasicop(Instr2 *instr, uint8_t opcode, uint8_t immreg) { +static void assemblebasicop(Instr *instr, uint8_t opcode, uint8_t immreg) { Imm *imm; uint8_t opsz = 1 << (instr->variant % 4); if (instr->variant < 4) { if (opsz == 2) sb(0x66); - if (instr->dst->kind == ASM_RAX) + if (instr->arg2->kind == ASM_RAX) sb(rexbyte(1, 0, 0, 0)); sb(opcode); - imm = &instr->src->imm; + imm = &instr->arg1->imm; assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); } else if (instr->variant < 12) { assembleimmrm(instr, opcode, immreg, opsz); @@ -476,13 +487,13 @@ static void assemblebasicop(Instr2 *instr, uint8_t opcode, uint8_t immreg) { } } -static void assemblexchg(Instr2 *xchg) { +static void assemblexchg(Instr *xchg) { static uint8_t variant2op[18] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x86, 0x87, 0x87, 0x87, 0x86, 0x87, 0x87, 0x87, 0x86, 0x87, 0x87, 0x87}; uint8_t opcode = variant2op[xchg->variant]; if (xchg->variant < 6) { - AsmKind reg = (xchg->variant % 2) ? xchg->src->kind : xchg->dst->kind; + AsmKind reg = (xchg->variant % 2) ? xchg->arg1->kind : xchg->arg2->kind; assembleplusr(opcode, isreg64(reg), reg); } else { uint8_t opsz = 1 << ((xchg->variant - 6) % 4); @@ -490,7 +501,7 @@ static void assemblexchg(Instr2 *xchg) { } } -static void assemblemov(Instr2 *mov) { +static void assemblemov(Instr *mov) { Imm *imm; uint8_t opcode, rex, mod, rm; @@ -501,8 +512,8 @@ static void assemblemov(Instr2 *mov) { opcode = variant2op[mov->variant]; if (mov->variant >= 4 && mov->variant <= 6) { - imm = &mov->src->imm; - assembleplusr(opcode, isreg64(mov->dst->kind), mov->dst->kind); + imm = &mov->arg1->imm; + assembleplusr(opcode, isreg64(mov->arg2->kind), mov->arg2->kind); assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); } else if (mov->variant == 7 || mov->variant < 4) { uint8_t opsz = 1 << (mov->variant % 4); @@ -513,17 +524,17 @@ static void assemblemov(Instr2 *mov) { } } -static void assemblediv(Instr1 *div, uint8_t reg) { +static void assembledivmul(Instr *div, uint8_t reg) { uint8_t opcode, opsz, rex, mod, rm; opsz = 1 << (div->variant % 4); opcode = opsz == 1 ? 0xf6 : 0xf7; if (div->variant < 4) { - assemblemem(&div->arg->memarg, opsz == 8, opcode, reg, opsz); + assemblemem(&div->arg1->memarg, opsz == 8, opcode, reg, opsz); } else { - assemblemodregrm(isreg64(div->arg->kind), opcode, 0x03, reg, - regbits(div->arg->kind), opsz); + assemblemodregrm(isreg64(div->arg1->kind), opcode, 0x03, reg, + regbits(div->arg1->kind), opsz); } } @@ -620,17 +631,17 @@ static void assemble(void) { break; } case ASM_PUSH: - if (v->instr1.arg->kind == ASM_MEMARG) { - assemblemem(&v->instr1.arg->memarg, 0, 0xff, 0x06, 8); + if (v->instr.arg1->kind == ASM_MEMARG) { + assemblemem(&v->instr.arg1->memarg, 0, 0xff, 0x06, 8); } else { - assembleplusr(0x50, 0, v->instr1.arg->kind); + assembleplusr(0x50, 0, v->instr.arg1->kind); } break; case ASM_POP: - if (v->instr1.arg->kind == ASM_MEMARG) { - assemblemem(&v->instr1.arg->memarg, 0, 0x8f, 0x00, 8); + if (v->instr.arg1->kind == ASM_MEMARG) { + assemblemem(&v->instr.arg1->memarg, 0, 0x8f, 0x00, 8); } else { - assembleplusr(0x58, 0, v->instr1.arg->kind); + assembleplusr(0x58, 0, v->instr.arg1->kind); } break; case ASM_NOP: @@ -643,12 +654,12 @@ static void assemble(void) { sb(0xc3); break; case ASM_LEA: { - uint8_t opsz = 1 << (v->instr2.variant + 1); - assemblerrm(&v->instr2, 0x8d, opsz); + uint8_t opsz = 1 << (v->instr.variant + 1); + assemblerrm(&v->instr, 0x8d, opsz); break; } case ASM_MOV: - assemblemov(&v->instr2); + assemblemov(&v->instr); break; case ASM_ADD: { static uint8_t variant2op[24] = { @@ -656,7 +667,7 @@ static void assemble(void) { 0x80, 0x81, 0x81, 0x81, 0x02, 0x03, 0x03, 0x03, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, }; - assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x00); + assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x00); break; } case ASM_AND: { @@ -665,15 +676,27 @@ static void assemble(void) { 0x80, 0x81, 0x81, 0x81, 0x22, 0x23, 0x23, 0x23, 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, }; - assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x04); + assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x04); break; } case ASM_DIV: { - assemblediv(&v->instr1, 0x06); + assembledivmul(&v->instr, 0x06); break; } case ASM_IDIV: { - assemblediv(&v->instr1, 0x07); + assembledivmul(&v->instr, 0x07); + break; + } + case ASM_MUL: { + assembledivmul(&v->instr, 0x04); + break; + } + case ASM_IMUL: { + if (v->instr.variant < 8) { + assembledivmul(&v->instr, 0x05); + } else { + fatal("TODO..."); + } break; } case ASM_OR: { @@ -682,7 +705,7 @@ static void assemble(void) { 0x80, 0x81, 0x81, 0x81, 0x0a, 0x0b, 0x0b, 0x0b, 0x08, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, }; - assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x01); + assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x01); break; } case ASM_SUB: { @@ -691,7 +714,7 @@ static void assemble(void) { 0x80, 0x81, 0x81, 0x81, 0x2a, 0x2b, 0x2b, 0x2b, 0x28, 0x29, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, }; - assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x05); + assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x05); break; } case ASM_XOR: { @@ -700,11 +723,11 @@ static void assemble(void) { 0x80, 0x81, 0x81, 0x81, 0x32, 0x33, 0x33, 0x33, 0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, }; - assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x06); + assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x06); break; } case ASM_XCHG: { - assemblexchg(&v->instr2); + assemblexchg(&v->instr); break; } default: @@ -67,6 +67,8 @@ typedef enum { ASM_DIV, ASM_IDIV, ASM_LEA, + ASM_MUL, + ASM_IMUL, ASM_MOV, ASM_MOVSX, ASM_MOVZX, @@ -215,15 +217,10 @@ typedef struct { typedef struct { AsmKind kind; uint8_t variant; - Parsev *arg; -} Instr1; - -typedef struct { - AsmKind kind; - uint8_t variant; - Parsev *src; - Parsev *dst; -} Instr2; + Parsev *arg1; + Parsev *arg2; + Parsev *arg3; +} Instr; union Parsev { AsmKind kind; @@ -234,8 +231,7 @@ union Parsev { Ascii ascii; Asciiz asciiz; Memarg memarg; - Instr1 instr1; - Instr2 instr2; + Instr instr; Call call; Jmp jmp; Byte byte; diff --git a/test/test.sh b/test/test.sh index 05d40bf..71e13b5 100644 --- a/test/test.sh +++ b/test/test.sh @@ -36,6 +36,13 @@ t "divq (%rip)" t "idiv %rax" t "idivq (%rax)" t "idivq (%rip)" +t "mul %rax" +t "mulq (%rax)" +t "mulq (%rip)" +t "imul %rax" +t "imulq (%rax)" +t "imulq (%rip)" + t "pushq (%r9)" t "pushq %r9" |
