aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm.peg24
-rw-r--r--main.c60
-rw-r--r--test/test.sh12
3 files changed, 76 insertions, 20 deletions
diff --git a/asm.peg b/asm.peg
index 76918fd..a49dfe7 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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); }
diff --git a/main.c b/main.c
index 51272cc..75efa72 100644
--- a/main.c
+++ b/main.c
@@ -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"