aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-10 15:10:47 +1300
committerAndrew Chambers <[email protected]>2021-10-10 15:10:47 +1300
commit54da6cf3b5a2ee14705857bb988af67378d4be2c (patch)
tree9448e6599416f62cd5d1d207795858af34bfc8a2
parent0c15252bb0ca5a1f2f38ad2bd33c025d79590716 (diff)
Implement shift instructions.
-rw-r--r--asm.peg53
-rw-r--r--main.c60
-rw-r--r--minias.h4
-rw-r--r--test/test.sh16
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)"