diff options
| -rw-r--r-- | asm.peg | 24 | ||||
| -rw-r--r-- | main.c | 60 | ||||
| -rw-r--r-- | test/test.sh | 12 |
3 files changed, 76 insertions, 20 deletions
@@ -36,6 +36,7 @@ instr = | i:add { $$ = i; } | i:and { $$ = i; } | i:lea { $$ = i; } + | i:mov { $$ = i; } | i:or { $$ = i; } | i:sub { $$ = i; } | i:xor { $$ = i; } @@ -47,6 +48,29 @@ lea = | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(2, s, d); } ) { $$.instr.kind = ASM_LEA; } +mov = "mov" ( + 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR(0, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR(1, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR(2, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR(3, s, d); } + | 'b' ws s:imm8 ws? ',' ws? d:m { $$ = INSTR(4, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:m { $$ = INSTR(5, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR(6, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR(7, s, d); } + | 'b'? ws s:m ws? ',' ws? d:r8 { $$ = INSTR(8, s, d); } + | 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR(9, s, d); } + | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR(10, s, d); } + | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(11, s, d); } + | 'b'? ws s:r8 ws? ',' ws? d:m { $$ = INSTR(12, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:m { $$ = INSTR(13, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:m { $$ = INSTR(14, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:m { $$ = INSTR(15, s, d); } + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR(16, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR(17, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR(18, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR(19, s, d); } +) { $$.instr.kind = ASM_MOV; } + xchg = 'xchg' ( 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); } @@ -190,7 +190,7 @@ static void sl(uint32_t l) { l & 0xff, (l & 0xff00) >> 8, (l & 0xff0000) >> 16, - (l & 0xff0000) >> 24, + (l & 0xff000000) >> 24, }; secaddbytes(cursection, buf, sizeof(buf)); } @@ -224,7 +224,7 @@ static uint8_t modregrm(uint8_t mod, uint8_t reg, uint8_t rm) { } /* Assemble op +rw | op + rd. */ -static void assembleplusr(Instr *i, uint8_t opcode, AsmKind reg) { +static void assembleplusr(uint8_t opcode, AsmKind reg) { uint8_t bits = regbits(reg); uint8_t rex = rexbyte(isreg64(reg), 0, 0, bits & (1 << 3)); if (isreg16(reg)) @@ -347,6 +347,46 @@ static void assemblebasicop(Instr *instr, uint8_t opcode) { } } +static void assemblexchg(Instr *xchg) { + static uint8_t variant2op[14] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x86, + 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87}; + uint8_t opcode = variant2op[xchg->variant]; + if (xchg->variant <= 5) { + assembleplusr(opcode, + (xchg->variant % 2) ? xchg->src->kind : xchg->dst->kind); + } else { + assemblerrm(xchg, opcode); + } +} + +static void assemblemov(Instr *mov) { + uint8_t opcode, rex, mod, rm; + + static uint8_t variant2op[20] = { + 0xb0, 0xb8, 0xb8, 0xc7, 0xc6, 0xc7, 0xc7, 0xc7, 0x8a, 0x8b, + 0x8b, 0x8b, 0x88, 0x89, 0x89, 0x89, 0x88, 0x89, 0x89, 0x89, + }; + + opcode = variant2op[mov->variant]; + if (mov->variant >= 8) { + assemblerrm(mov, opcode); + } else if (mov->variant >= 3) { + // c7 /0 i[bwd] encoding. + // dest in rm. + rm = regbits(mov->dst->kind); + rex = rexbyte(isreg64(mov->dst->kind), 0, 0, rm & (1 << 3)); + if (isreg16(mov->dst->kind)) + sb(0x66); + if (rex != rexbyte(0, 0, 0, 0)) + sb(rex); + sb2(opcode, modregrm(3, 0, rm)); + assembleimm(&mov->src->imm); + } else { + assembleplusr(opcode, mov->dst->kind); + assembleimm(&mov->src->imm); + } +} + static void assemble() { Symbol *sym; Parsev *v; @@ -401,6 +441,10 @@ static void assemble() { case ASM_LEA: assemblerrm(&v->instr, 0x8d); break; + case ASM_MOV: { + assemblemov(&v->instr); + break; + } case ASM_ADD: { static uint8_t variant2op[24] = { 0x04, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, @@ -447,17 +491,7 @@ static void assemble() { break; } case ASM_XCHG: { - Instr *xchg = &v->instr; - static uint8_t variant2op[14] = {0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x86, 0x86, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87}; - uint8_t opcode = variant2op[xchg->variant]; - if (xchg->variant <= 5) { - assembleplusr(xchg, opcode, - (xchg->variant % 2) ? xchg->src->kind : xchg->dst->kind); - } else { - assemblerrm(xchg, opcode); - } + assemblexchg(&v->instr); break; } case ASM_JMP: { diff --git a/test/test.sh b/test/test.sh index 8d0255a..8d790d8 100644 --- a/test/test.sh +++ b/test/test.sh @@ -30,14 +30,12 @@ t () { echo -n "." } - - -for op in add and or sub xor +for op in mov add and or sub xor do - t "${op}b \$1, %al" - #t "${op}w \$1, %ax" # clang disagrees - #t "${op}l \$1, %eax" # clang disagrees - #t "${op}q \$1, %rax" # clang disagrees + t "${op}b \$127, %al" + t "${op}w \$32767, %ax" # clang disagrees + t "${op}l \$2147483647, %eax" # clang disagrees + t "${op}q \$2147483647, %rax" # clang disagrees t "${op}b (%rax), %al" t "${op}w (%rax), %ax" t "${op}l (%rax), %eax" |
