From 54da6cf3b5a2ee14705857bb988af67378d4be2c Mon Sep 17 00:00:00 2001 From: Andrew Chambers Date: Sun, 10 Oct 2021 15:10:47 +1300 Subject: Implement shift instructions. --- asm.peg | 53 +++++++++++++++++++++++++++++++++++++++++------------ main.c | 60 ++++++++++++++++++++++++++++++++++++++---------------------- minias.h | 4 ++++ test/test.sh | 16 ++++++++++++++++ 4 files changed, 99 insertions(+), 34 deletions(-) diff --git a/asm.peg b/asm.peg index 8076cce..99a574b 100644 --- a/asm.peg +++ b/asm.peg @@ -66,6 +66,10 @@ instr = | i:mov { $$ = i; } | i:or { $$ = i; } | i:sub { $$ = i; } + | i:sal { $$ = i; } + | i:sar { $$ = i; } + | i:shl { $$ = i; } + | i:shr { $$ = i; } | i:xchg { $$ = i; } | i:xor { $$ = i; } @@ -148,18 +152,18 @@ imm-rm-opargs = | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR2(7, s, d); } r-rm-opargs = - 'b'? ws s:m ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } - | 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } - | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } - | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:m { $$ = INSTR2(4, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:m { $$ = INSTR2(5, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:m { $$ = INSTR2(6, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:m { $$ = INSTR2(7, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(8, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(9, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(10, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } + 'b'? ws s:m ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } + | 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } + | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } + | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } + | 'b'? ws s:r8 ws? ',' ws? d:m { $$ = INSTR2(4, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:m { $$ = INSTR2(5, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:m { $$ = INSTR2(6, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:m { $$ = INSTR2(7, s, d); } + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(8, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(9, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(10, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } mov = "mov" ( args:imm-rm-opargs { $$ = args; } @@ -191,6 +195,30 @@ basic-op-args = | args:imm-rm-opargs { args.instr.variant += 4; $$ = args; } | args:r-rm-opargs { args.instr.variant += 12; $$ = args; } +sal = + 'sal' args:shift-args {$$ = args; $$.instr.kind = ASM_SAL} +sar = + 'sar' args:shift-args {$$ = args; $$.instr.kind = ASM_SAR} +shl = + 'shl' args:shift-args {$$ = args; $$.instr.kind = ASM_SHL} +shr = + 'shr' args:shift-args {$$ = args; $$.instr.kind = ASM_SHR} + +shift-args = + 'w' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(0, c, d); } + | 'l' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(1, c, d); } + | 'q' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(2, c, d); } + | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = INSTR2(3, c, d); } + | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = INSTR2(4, c, d); } + | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = INSTR2(5, c, d); } + | 'w' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(6, i, d); } + | 'l' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(7, i, d); } + | 'q' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(8, i, d); } + | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = INSTR2(9, i, d); } + | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = INSTR2(10, i, d); } + | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = INSTR2(11, i, d); } + + r64-or-rip = ( r:r64 | r:rip @@ -213,6 +241,7 @@ imm = { $$.imm = (Imm){ .kind = ASM_IMM, .c = strtoll(yytext, NULL, 10), .l = NULL, .nbytes = 0}; } al = "%al" { $$ = REG(ASM_AL); } +cl = "%cl" { $$ = REG(ASM_CL); } ax = "%ax" { $$ = REG(ASM_AX); } eax = "%eax" { $$ = REG(ASM_EAX); } rax = "%rax" { $$ = REG(ASM_RAX); } diff --git a/main.c b/main.c index e422c42..4fec4fc 100644 --- a/main.c +++ b/main.c @@ -470,7 +470,6 @@ static void assembleimmrm(Instr *instr, Opcode opcode, uint8_t immreg, assemblemem(&instr->arg2->memarg, opsz == 8, opcode, immreg, opsz); assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); } else { - assemblemodregrm(isreg64(instr->arg2->kind), opcode, 0x03, immreg, regbits(instr->arg2->kind), opsz); assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32); @@ -554,13 +553,14 @@ static void assemblemov(Instr *mov) { } } -static void assembledivmul(Instr *instr, uint8_t reg, uint8_t opsz) { +static void assembledivmul(Instr *instr, uint8_t reg) { Opcode opcode; - uint8_t rex, mod, rm; + uint8_t rex, mod, rm, opsz; + opsz = 1 << (instr->variant % 4); opcode = opsz == 1 ? 0xf6 : 0xf7; - if (instr->variant < 4) { + if (instr->arg1->kind == ASM_MEMARG) { assemblemem(&instr->arg1->memarg, opsz == 8, opcode, reg, opsz); } else { assemblemodregrm(isreg64(instr->arg1->kind), opcode, 0x03, reg, @@ -568,6 +568,23 @@ static void assembledivmul(Instr *instr, uint8_t reg, uint8_t opsz) { } } +static void assembleshift(Instr *instr, uint8_t immreg) { + Opcode opcode; + uint8_t rex, mod, rm, opsz; + + opcode = (instr->variant < 6) ? 0xd3 : 0xc1; + opsz = 1 << (1 + (instr->variant % 3)); + + if (instr->arg1->kind == ASM_IMM) { + assembleimmrm(instr, opcode, immreg, opsz); + } else if (instr->arg2->kind == ASM_MEMARG) { + assemblemem(&instr->arg2->memarg, opsz == 8, opcode, immreg, opsz); + } else { + assemblemodregrm(isreg64(instr->arg2->kind), opcode, 0x03, immreg, + regbits(instr->arg2->kind), opsz); + } +} + static void assemble(void) { Symbol *sym; Parsev *v; @@ -709,32 +726,21 @@ static void assemble(void) { assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x04); break; } - case ASM_DIV: { - uint8_t opsz; - opsz = 1 << (v->instr.variant % 4); - assembledivmul(&v->instr, 0x06, opsz); + case ASM_DIV: + assembledivmul(&v->instr, 0x06); break; - } - case ASM_IDIV: { - uint8_t opsz; - opsz = 1 << (v->instr.variant % 4); - assembledivmul(&v->instr, 0x07, opsz); + case ASM_IDIV: + assembledivmul(&v->instr, 0x07); break; - } - case ASM_MUL: { - uint8_t opsz; - opsz = 1 << (v->instr.variant % 4); - assembledivmul(&v->instr, 0x04, opsz); + case ASM_MUL: + assembledivmul(&v->instr, 0x04); break; - } case ASM_IMUL: { Opcode opcode; uint8_t opsz; if (v->instr.variant < 8) { - uint8_t opsz; - opsz = 1 << (v->instr.variant % 4); - assembledivmul(&v->instr, 0x05, opsz); + assembledivmul(&v->instr, 0x05); } else if (v->instr.variant < 14) { opcode = 0x01000faf; // 0f af variable length opcode. opsz = 1 << (1 + ((v->instr.variant - 8) % 3)); @@ -758,6 +764,16 @@ static void assemble(void) { assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x01); break; } + case ASM_SAL: + case ASM_SHL: + assembleshift(&v->instr, 0x04); + break; + case ASM_SAR: + assembleshift(&v->instr, 0x07); + break; + case ASM_SHR: + assembleshift(&v->instr, 0x05); + break; case ASM_SUB: { static uint8_t variant2op[24] = { 0x2c, 0x2d, 0x2d, 0x2d, 0x80, 0x81, 0x81, 0x81, diff --git a/minias.h b/minias.h index 7c0036d..9becc49 100644 --- a/minias.h +++ b/minias.h @@ -73,6 +73,10 @@ typedef enum { ASM_MOVSX, ASM_MOVZX, ASM_OR, + ASM_SAL, + ASM_SAR, + ASM_SHL, + ASM_SHR, ASM_SUB, ASM_XCHG, ASM_XOR, diff --git a/test/test.sh b/test/test.sh index f908e4a..ecc4624 100644 --- a/test/test.sh +++ b/test/test.sh @@ -30,6 +30,22 @@ t () { echo -n "." } +for op in sal sar shl shr +do +t "${op} \$3, %rax" +t "${op} %cl, %rax" +t "${op} \$3, %eax" +t "${op} %cl, %eax" +t "${op} \$3, %ax" +t "${op} %cl, %ax" +t "${op}w \$3, (%rax)" +t "${op}w %cl, (%rax)" +t "${op}l \$3, (%rax)" +t "${op}l %cl, (%rax)" +t "${op}q \$3, (%rax)" +t "${op}q %cl, (%rax)" +done + t "div %rax" t "divq (%rax)" t "divq (%rip)" -- cgit v1.2.3