aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-12 14:23:15 +1300
committerAndrew Chambers <[email protected]>2021-10-12 14:23:15 +1300
commitdc55c00a34a9c5b0d2374d31e00daeb502863626 (patch)
tree5b9366efa4fd3a798be5d073e74dcbce09e32340
parent814daf68e4e3c91b8f8102140ed5202a58835575 (diff)
Minor refactor.
-rw-r--r--main.c145
1 files changed, 74 insertions, 71 deletions
diff --git a/main.c b/main.c
index dccefd1..6944694 100644
--- a/main.c
+++ b/main.c
@@ -380,7 +380,7 @@ static void assemblevbytes(VarBytes bytes) {
}
/* Assemble op +rw | op + rd. */
-static void assembleplusr(VarBytes prefix, VarBytes opcode, uint8_t rexw,
+static void assembleplusr(uint8_t rexw, VarBytes prefix, VarBytes opcode,
AsmKind reg) {
uint8_t bits;
uint8_t rex;
@@ -393,12 +393,9 @@ static void assembleplusr(VarBytes prefix, VarBytes opcode, uint8_t rexw,
assemblevbytes(opcode | (bits & 7));
}
-static void assemblemodregrm(uint8_t rexw, VarBytes prefix, VarBytes opcode,
+static void assemblemodregrm(uint8_t rex, VarBytes prefix, VarBytes opcode,
uint8_t mod, uint8_t reg, uint8_t rm) {
- uint8_t rex;
-
assemblevbytes(prefix);
- rex = rexbyte(rexw, reg & (1 << 3), 0, rm & (1 << 3));
if (rex != rexbyte(0, 0, 0, 0))
sb(rex);
assemblevbytes(opcode);
@@ -423,30 +420,27 @@ static void assemblereloc(const char *l, int64_t c, int nbytes, int type) {
assembleconstant(c, nbytes);
}
-/* Assemble a r <-> (%rip) operation. */
-static void assembleriprel(Memarg *memarg, uint8_t rexw, VarBytes prefix,
- VarBytes opcode, uint8_t reg) {
- assemblemodregrm(rexw, prefix, opcode, 0x00, reg, 0x05);
- if (memarg->l) {
- assemblereloc(memarg->l, memarg->c - 4, 4, R_X86_64_PC32);
- } else {
- assembleconstant(memarg->c, 4);
- }
-}
-
/* Assemble a r <-> mem operation. */
static void assemblemem(Memarg *memarg, uint8_t rexw, VarBytes prefix,
VarBytes opcode, uint8_t reg) {
uint8_t rex, mod, rm, scale, index, base, sib;
- rm = regbits(memarg->base);
-
+ /* rip relative addressing. */
if (memarg->base == ASM_RIP) {
- assembleriprel(memarg, rexw, prefix, opcode, reg);
+ rm = 0x05;
+ rex = rexbyte(rexw, reg & (1 << 3), 0, rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x00, reg, rm);
+ if (memarg->l) {
+ assemblereloc(memarg->l, memarg->c - 4, 4, R_X86_64_PC32);
+ } else {
+ assembleconstant(memarg->c, 4);
+ }
return;
}
+ rm = regbits(memarg->base);
+
/* Case when we don't need sib */
if (memarg->index == ASM_NO_REG && memarg->scale == 0 && ((rm & 7) != 4)) {
@@ -460,12 +454,8 @@ static void assemblemem(Memarg *memarg, uint8_t rexw, VarBytes prefix,
mod = 2;
}
- assemblevbytes(prefix);
rex = rexbyte(rexw, reg & (1 << 3), 0, rm & (1 << 3));
- if (rex != rexbyte(0, 0, 0, 0))
- sb(rex);
- assemblevbytes(opcode);
- sb(modregrmbyte(mod, reg, rm));
+ assemblemodregrm(rex, prefix, opcode, mod, reg, rm);
if (mod == 1) {
assemblereloc(memarg->l, memarg->c, 1, R_X86_64_32);
@@ -521,14 +511,10 @@ static void assemblemem(Memarg *memarg, uint8_t rexw, VarBytes prefix,
lfatal("invalid addressing scale");
}
- assemblevbytes(prefix);
rex = rexbyte(rexw, reg & (1 << 3), index & (1 << 3), base & (1 << 3));
- if (rex != rexbyte(0, 0, 0, 0))
- sb(rex);
- assemblevbytes(opcode);
- sb2(modregrmbyte(mod, reg, rm), sibbyte(scale, index, base));
+ assemblemodregrm(rex, prefix, opcode, mod, reg, rm);
+ sb(sibbyte(scale, index, base));
- /* If mod is set, or we are indexing bp we must output a displacement. */
if (mod)
assemblereloc(memarg->l, memarg->c, (mod == 2) ? 4 : 1, R_X86_64_32);
}
@@ -536,6 +522,7 @@ static void assemblemem(Memarg *memarg, uint8_t rexw, VarBytes prefix,
/* Assemble op + imm -> r/m. */
static void assembleimmrm(Instr *instr, uint8_t rexw, VarBytes prefix,
VarBytes opcode, uint8_t immreg) {
+ uint8_t rex, rm;
Imm *imm;
imm = &instr->arg1->imm;
@@ -543,14 +530,16 @@ static void assembleimmrm(Instr *instr, uint8_t rexw, VarBytes prefix,
if (instr->arg2->kind == ASM_MEMARG) {
assemblemem(&instr->arg2->memarg, rexw, prefix, opcode, immreg);
} else {
- assemblemodregrm(rexw, prefix, opcode, 0x03, immreg,
- regbits(instr->arg2->kind));
+ rm = regbits(instr->arg2->kind);
+ rex = rexbyte(rexw, immreg & (1 << 3), 0, rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm);
}
assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32);
}
/* Assemble op + r <-> r/m. */
static void assemblerrm(Instr *instr, VarBytes prefix, VarBytes opcode) {
+ uint8_t rexw, rex, reg1, reg2, rm;
Memarg *memarg;
AsmKind regarg;
@@ -563,8 +552,11 @@ static void assemblerrm(Instr *instr, VarBytes prefix, VarBytes opcode) {
regarg = instr->arg1->kind;
assemblemem(memarg, isreg64(regarg), prefix, opcode, regbits(regarg));
} else {
- assemblemodregrm(isreg64(instr->arg2->kind), prefix, opcode, 0x03,
- regbits(instr->arg1->kind), regbits(instr->arg2->kind));
+ rexw = isreg64(instr->arg2->kind);
+ reg1 = regbits(instr->arg1->kind);
+ reg2 = regbits(instr->arg2->kind);
+ rex = rexbyte(rexw, reg1 & (1 << 3), 0, reg2 & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, reg1, reg2);
}
}
@@ -600,7 +592,7 @@ static void assemblexchg(Instr *xchg) {
if (xchg->variant < 6) {
AsmKind reg = (xchg->variant % 2) ? xchg->arg1->kind : xchg->arg2->kind;
prefix = (xchg->variant < 2) ? 0x66 : EMPTY_VBYTES;
- assembleplusr(prefix, opcode, isreg64(reg), reg);
+ assembleplusr(isreg64(reg), prefix, opcode, reg);
} else {
prefix = (((xchg->variant - 6) % 4) == 1) ? 0x66 : EMPTY_VBYTES;
assemblerrm(xchg, prefix, opcode);
@@ -622,13 +614,12 @@ static void assemblemov(Instr *mov) {
if (mov->variant >= 4 && mov->variant <= 6) {
imm = &mov->arg1->imm;
- assembleplusr(prefix, opcode, isreg64(mov->arg2->kind), mov->arg2->kind);
+ assembleplusr(isreg64(mov->arg2->kind), prefix, opcode, mov->arg2->kind);
assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32);
} else if (mov->variant == 7 || mov->variant < 4) {
rexw = ((mov->variant % 4) == 3);
assembleimmrm(mov, rexw, prefix, opcode, 0x00);
} else {
- rexw = ((mov->variant % 4) == 3);
assemblerrm(mov, prefix, opcode);
}
}
@@ -646,7 +637,7 @@ static void assemblemovextend(Instr *mov, VarBytes opcode) {
static void assembledivmulneg(Instr *instr, uint8_t reg) {
VarBytes prefix, opcode;
- uint8_t rexw, mod, rm, opsz;
+ uint8_t rexw, rex, mod, rm, opsz;
rexw = (instr->variant % 4) == 3;
prefix = (instr->variant % 4) == 1 ? 0x66 : EMPTY_VBYTES;
@@ -655,8 +646,9 @@ static void assembledivmulneg(Instr *instr, uint8_t reg) {
if (instr->arg1->kind == ASM_MEMARG) {
assemblemem(&instr->arg1->memarg, rexw, prefix, opcode, reg);
} else {
+ rex = rexbyte(rexw, reg & (1 << 3), 0, rm & (1 << 3));
rm = regbits(instr->arg1->kind);
- assemblemodregrm(rexw, prefix, opcode, 0x03, reg, rm);
+ assemblemodregrm(rex, prefix, opcode, 0x03, reg, rm);
}
}
@@ -674,18 +666,23 @@ static void assembleshift(Instr *instr, uint8_t immreg) {
assemblemem(&instr->arg2->memarg, rexw, prefix, opcode, immreg);
} else {
rexw = isreg64(instr->arg2->kind);
- assemblemodregrm(rexw, prefix, opcode, 0x03, immreg,
- regbits(instr->arg2->kind));
+ rm = regbits(instr->arg2->kind);
+ rex = rexbyte(rexw, immreg & (1 << 3), 0, rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm);
}
}
static void assemblexmmbasicop(Instr *instr, VarBytes prefix, VarBytes opcode) {
+ uint8_t rex, reg, rm;
+
if (instr->arg1->kind == ASM_MEMARG) {
assemblemem(&instr->arg1->memarg, 0, prefix, opcode,
regbits(instr->arg2->kind));
} else {
- assemblemodregrm(0, prefix, opcode, 3, regbits(instr->arg2->kind),
- regbits(instr->arg1->kind));
+ reg = regbits(instr->arg2->kind);
+ rm = regbits(instr->arg1->kind);
+ rex = rexbyte(0, reg & (1 << 3), 0, rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, reg, rm);
}
}
@@ -700,6 +697,29 @@ static void assemblemovsmmx(Instr *instr, VarBytes prefix) {
}
}
+static void assembletest(Instr *instr) {
+ VarBytes prefix;
+ uint8_t rexw, byteop;
+
+ byteop = ((instr->variant % 4) == 0);
+ prefix = ((instr->variant % 4) == 1) ? 0x66 : EMPTY_VBYTES;
+ rexw = ((instr->variant % 4) == 3);
+
+ if (instr->variant < 4) {
+ Imm *imm;
+ assemblevbytes(prefix);
+ if (rexw)
+ sb(rexbyte(1, 0, 0, 0));
+ assemblevbytes(byteop ? 0xa8 : 0xa9);
+ imm = &instr->arg1->imm;
+ assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32);
+ } else if (instr->variant < 12) {
+ assembleimmrm(instr, rexw, prefix, byteop ? 0xf6 : 0xf7, 0);
+ } else {
+ assemblerrm(instr, prefix, byteop ? 0x84 : 0x85);
+ }
+}
+
static void assemble(void) {
Symbol *sym;
Parsev *v;
@@ -810,14 +830,14 @@ static void assemble(void) {
if (v->instr.arg1->kind == ASM_MEMARG) {
assemblemem(&v->instr.arg1->memarg, 0, EMPTY_VBYTES, 0xff, 0x06);
} else {
- assembleplusr(EMPTY_VBYTES, 0x50, 0, v->instr.arg1->kind);
+ assembleplusr(0, EMPTY_VBYTES, 0x50, v->instr.arg1->kind);
}
break;
case ASM_POP:
if (v->instr.arg1->kind == ASM_MEMARG) {
assemblemem(&v->instr.arg1->memarg, 0, EMPTY_VBYTES, 0x8f, 0x00);
} else {
- assembleplusr(EMPTY_VBYTES, 0x58, 0, v->instr.arg1->kind);
+ assembleplusr(0, EMPTY_VBYTES, 0x58, v->instr.arg1->kind);
}
break;
case ASM_NOP:
@@ -924,7 +944,7 @@ static void assemble(void) {
if (v->instr.variant < 8) {
assembledivmulneg(&v->instr, 0x05);
} else if (v->instr.variant < 14) {
- opcode = 0x01000faf; // 0f af variable length opcode.
+ opcode = 0x01000faf;
prefix = ((v->instr.variant - 8) % 3) == 0 ? 0x66 : EMPTY_VBYTES;
assemblerrm(&v->instr, prefix, opcode);
} else {
@@ -951,6 +971,7 @@ static void assemble(void) {
}
case ASM_SET: {
VarBytes prefix, opcode;
+ uint8_t rex, reg, rm;
static uint8_t variant2op[30] = {
0x94, 0x98, 0x9b, 0x9a, 0x9a, 0x90, 0x95, 0x99, 0x9b, 0x91,
0x9f, 0x9d, 0x9c, 0x9e, 0x95, 0x93, 0x97, 0x93, 0x92, 0x96,
@@ -961,8 +982,11 @@ static void assemble(void) {
if (v->instr.arg1->kind == ASM_MEMARG) {
assemblemem(&v->instr.arg1->memarg, 0, prefix, opcode, 0);
} else {
- assemblemodregrm(isreg64(v->instr.arg1->kind), prefix, opcode, 0x03,
- 0x00, regbits(v->instr.arg1->kind));
+ reg = 0;
+ rm = regbits(v->instr.arg1->kind);
+ rex = rexbyte(isreg64(v->instr.arg1->kind), reg & (1 << 3), 0,
+ rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, reg, rm);
}
break;
}
@@ -985,30 +1009,9 @@ static void assemble(void) {
assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x05);
break;
}
- case ASM_TEST: {
-
- VarBytes prefix;
- uint8_t rexw, byteop;
-
- byteop = ((v->instr.variant % 4) == 0);
- prefix = ((v->instr.variant % 4) == 1) ? 0x66 : EMPTY_VBYTES;
- rexw = ((v->instr.variant % 4) == 3);
-
- if (v->instr.variant < 4) {
- Imm *imm;
- assemblevbytes(prefix);
- if (rexw)
- sb(rexbyte(1, 0, 0, 0));
- assemblevbytes(byteop ? 0xa8 : 0xa9);
- imm = &v->instr.arg1->imm;
- assemblereloc(imm->l, imm->c, imm->nbytes, R_X86_64_32);
- } else if (v->instr.variant < 12) {
- assembleimmrm(&v->instr, rexw, prefix, byteop ? 0xf6 : 0xf7, 0);
- } else {
- assemblerrm(&v->instr, prefix, byteop ? 0x84 : 0x85);
- }
+ case ASM_TEST:
+ assembletest(&v->instr);
break;
- }
case ASM_UCOMISD:
assemblexmmbasicop(&v->instr, 0x66, 0x01000f2e);
break;