aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c765
1 files changed, 189 insertions, 576 deletions
diff --git a/main.c b/main.c
index c444cc8..3c8f6ee 100644
--- a/main.c
+++ b/main.c
@@ -3,10 +3,10 @@
/* Parsed assembly */
static AsmLine *allasm = NULL;
-/* Number of assembly the relaxation passes. */
+/* Number of assembly relaxation passes. */
static int nrelax = 1;
-/* Symbol table. */
+/* Symbols before writing to symtab section. */
static struct hashtable *symbols = NULL;
/* Array of all relocations before adding to the rel section. */
@@ -213,15 +213,6 @@ static uint8_t regbits(AsmKind k) { return (k - (ASM_REG_BEGIN + 1)) % 16; }
static uint8_t isreg64(AsmKind k) { return k >= ASM_RAX && k <= ASM_R15; }
-/* Rex opcode prefix. */
-typedef struct Rex {
- uint8_t required : 1;
- uint8_t w : 1;
- uint8_t r : 1;
- uint8_t x : 1;
- uint8_t b : 1;
-} Rex;
-
/* Register that requires the use of a rex prefix. */
static uint8_t isrexreg(AsmKind k) {
return k > ASM_REG_BEGIN && k < ASM_REG_END &&
@@ -289,14 +280,6 @@ static void assemblerex(Rex rex) {
sb(rexbyte(rex));
}
-/* Assemble op +rw | op + rd. */
-static void assembleplusr(Rex rex, VarBytes prefix, VarBytes opcode,
- uint8_t reg) {
- assemblevbytes(prefix);
- assemblerex(rex);
- assemblevbytes(opcode | (reg & 7));
-}
-
static void assemblemodregrm(Rex rex, VarBytes prefix, VarBytes opcode,
uint8_t mod, uint8_t reg, uint8_t rm) {
assemblevbytes(prefix);
@@ -449,301 +432,6 @@ static void assemblemem(const Memarg *memarg, Rex rex, VarBytes prefix,
}
}
-/* Assemble op + imm -> r/m. */
-static void assembleimmrm(const Instr *instr, Rex rex, VarBytes prefix,
- VarBytes opcode, uint8_t immreg) {
- uint8_t rm;
- const Memarg *memarg;
- const Imm *imm;
-
- imm = &instr->arg1->imm;
-
- if (instr->arg2->kind == ASM_MEMARG) {
- memarg = &instr->arg2->memarg;
-
- if (memarg->base == ASM_RIP) {
- assembleriprel(memarg, rex, prefix, opcode, immreg, -imm->nbytes);
- } else {
- assemblemem(memarg, rex, prefix, opcode, immreg);
- }
-
- } else {
- rm = regbits(instr->arg2->kind);
- rex.required = isrexreg(instr->arg2->kind);
- rex.b = !!(rm & (1 << 3));
- assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm);
- }
- assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
-}
-
-/* Assemble op + r <-> r/m. */
-static void assemblerrm(const Instr *instr, VarBytes prefix, VarBytes opcode,
- int invert) {
- Rex rex;
- AsmKind regarg;
- uint8_t reg1bits, reg2bits;
- const Memarg *memarg;
- const Parsev *arg1, *arg2;
-
- if (invert) {
- arg1 = instr->arg2;
- arg2 = instr->arg1;
- } else {
- arg1 = instr->arg1;
- arg2 = instr->arg2;
- }
-
- if (arg1->kind == ASM_MEMARG) {
- memarg = &arg1->memarg;
- regarg = arg2->kind;
- reg1bits = regbits(regarg);
- rex = (Rex){.required = isrexreg(regarg),
- .w = isreg64(regarg),
- .r = !!(reg1bits & (1 << 3))};
- assemblemem(memarg, rex, prefix, opcode, reg1bits);
- } else if (arg2->kind == ASM_MEMARG) {
- memarg = &arg2->memarg;
- regarg = arg1->kind;
- reg1bits = regbits(regarg);
- rex = (Rex){.required = isrexreg(regarg),
- .w = isreg64(regarg),
- .r = !!(reg1bits & (1 << 3))};
- assemblemem(memarg, rex, prefix, opcode, reg1bits);
- } else {
- reg1bits = regbits(arg1->kind);
- reg2bits = regbits(arg2->kind);
- rex = (Rex){.required = isrexreg(arg1->kind) || isrexreg(arg2->kind),
- .w = isreg64(arg1->kind) || isreg64(arg2->kind),
- .r = !!(reg1bits & (1 << 3)),
- .b = !!(reg2bits & (1 << 3))};
- assemblemodregrm(rex, prefix, opcode, 0x03, reg1bits, reg2bits);
- }
-}
-
-/* Assemble a 'basic op' which is just a repeated op pattern we have named. */
-static void assemblebasicop(const Instr *instr, VarBytes opcode,
- uint8_t immreg) {
- VarBytes prefix;
- const Imm *imm;
- Rex rex;
-
- prefix = ((instr->variant % 4) == 1) ? 0x66 : -1;
-
- if (instr->variant < 4) {
- imm = &instr->arg1->imm;
- rex = (Rex){
- .w = instr->variant == 3,
- };
- assemblevbytes(prefix);
- assemblerex(rex);
- assemblevbytes(opcode);
- assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
- } else if (instr->variant < 12) {
- rex = (Rex){
- .w = (instr->variant % 4) == 3,
- };
- assembleimmrm(instr, rex, prefix, opcode, immreg);
- } else {
- assemblerrm(instr, prefix, opcode, 0);
- }
-}
-
-static void assemblexchg(const Instr *xchg) {
- Rex rex;
- AsmKind reg;
- VarBytes prefix, opcode;
- static uint8_t variant2op[18] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
- 0x86, 0x87, 0x87, 0x87, 0x86, 0x87,
- 0x87, 0x87, 0x86, 0x87, 0x87, 0x87};
-
- opcode = variant2op[xchg->variant];
- if (xchg->variant < 6) {
- reg = (xchg->variant % 2) ? xchg->arg1->kind : xchg->arg2->kind;
- prefix = (xchg->variant < 2) ? 0x66 : -1;
- rex = (Rex){
- .required = isrexreg(xchg->arg1->kind) || isrexreg(xchg->arg2->kind),
- .w = isreg64(xchg->arg1->kind) || isreg64(xchg->arg2->kind),
- .b = !!(regbits(reg) & (1 << 3)),
- };
- assembleplusr(rex, prefix, opcode, regbits(reg));
- } else {
- prefix = (((xchg->variant - 6) % 4) == 1) ? 0x66 : -1;
- assemblerrm(xchg, prefix, opcode, 0);
- }
-}
-
-static void assemblemov(const Instr *mov) {
- Rex rex;
- int8_t reg;
- const Imm *imm;
- VarBytes prefix, opcode;
-
- static uint8_t variant2op[20] = {0x88, 0x89, 0x89, 0x89, 0x88, 0x89, 0x89,
- 0x89, 0x8a, 0x8b, 0x8b, 0x8b, 0xc6, 0xc7,
- 0xc7, 0xc7, 0xb0, 0xb8, 0xb8, 0xc7};
-
- prefix = ((mov->variant % 4) == 1) ? 0x66 : -1;
- opcode = variant2op[mov->variant];
-
- if (mov->variant < 12) {
- assemblerrm(mov, prefix, opcode, 0);
- } else if (mov->variant < 16) {
- rex = (Rex){.w = (mov->variant % 4) == 3};
- assembleimmrm(mov, rex, prefix, opcode, 0x00);
- } else if (mov->variant == 19) {
- uint64_t mask, maskedc;
-
- imm = &mov->arg1->imm;
- mask = 0xffffffff80000000;
- maskedc = ((uint64_t)imm->v.c) & mask;
-
- if ((maskedc == mask || maskedc == 0) && imm->v.l == NULL) {
- /* Sign extension works for this value, regular mov */
- reg = regbits(mov->arg2->kind);
- rex = (Rex){
- .required = isrexreg(mov->arg2->kind),
- .w = 1,
- .b = !!(reg & (1 << 3)),
- };
- assemblemodregrm(rex, prefix, opcode, 0x03, 0x00, reg);
- assemblereloc(imm->v.l, imm->v.c, 4, R_X86_64_32);
- } else {
- /* 64 bit immediate required. */
- reg = regbits(mov->arg2->kind);
- rex = (Rex){
- .required = isrexreg(mov->arg2->kind),
- .w = 1,
- .b = !!(reg & (1 << 3)),
- };
- assemblerex(rex);
- sb(0xb8 | (reg & 7));
- assemblereloc(imm->v.l, imm->v.c, 8, R_X86_64_64);
- }
- } else {
- imm = &mov->arg1->imm;
- reg = regbits(mov->arg2->kind);
- rex = (Rex){
- .required = isrexreg(mov->arg2->kind),
- .w = isreg64(mov->arg2->kind),
- .b = !!(reg & (1 << 3)),
- };
- assembleplusr(rex, prefix, opcode, reg);
- assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
- }
-}
-
-static void assemblemovextend(const Instr *mov, VarBytes opcode) {
- VarBytes prefix;
- if (mov->variant == 0 || mov->variant == 5)
- prefix = 0x66;
- else
- prefix = -1;
- assemblerrm(mov, prefix, opcode, 1);
-}
-
-static void assembledivmulneg(const Instr *instr, uint8_t reg) {
- Rex rex;
- VarBytes prefix, opcode;
- uint8_t rm;
-
- rex = (Rex){
- .w = (instr->variant % 4) == 3,
- };
- prefix = (instr->variant % 4) == 1 ? 0x66 : -1;
- opcode = (instr->variant % 4) == 1 ? 0xf6 : 0xf7;
-
- if (instr->arg1->kind == ASM_MEMARG) {
- assemblemem(&instr->arg1->memarg, rex, prefix, opcode, reg);
- } else {
- rm = regbits(instr->arg1->kind);
- rex.w = isreg64(instr->arg1->kind);
- rex.r = !!(reg & (1 << 3));
- rex.b = !!(rm & (1 << 3));
- assemblemodregrm(rex, prefix, opcode, 0x03, reg, rm);
- }
-}
-
-static void assembleshift(const Instr *instr, uint8_t immreg) {
- Rex rex;
- VarBytes prefix, opcode;
- uint8_t rm;
-
- opcode = (instr->variant < 6) ? 0xd3 : 0xc1;
- rex = (Rex){.w = (instr->variant % 3) == 2};
- prefix = ((instr->variant % 3) == 0) ? 0x66 : -1;
-
- if (instr->arg1->kind == ASM_IMM) {
- assembleimmrm(instr, rex, prefix, opcode, immreg);
- } else if (instr->arg2->kind == ASM_MEMARG) {
- assemblemem(&instr->arg2->memarg, rex, prefix, opcode, immreg);
- } else {
- rm = regbits(instr->arg2->kind);
- rex.r = !!(immreg & (1 << 3));
- rex.b = !!(rm & (1 << 3));
- assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm);
- }
-}
-
-static void assemblemovsmmx(const Instr *instr, VarBytes prefix) {
- VarBytes opcode;
- if (instr->variant == 2) {
- opcode = 0x01000f11;
- assemblerrm(instr, prefix, opcode, 0);
- } else {
- opcode = 0x01000f10;
- assemblerrm(instr, prefix, opcode, 1);
- }
-}
-
-static void assembletest(const Instr *instr) {
- const Imm *imm;
- Rex rex;
- VarBytes prefix;
- uint8_t byteop;
-
- byteop = ((instr->variant % 4) == 0);
- prefix = ((instr->variant % 4) == 1) ? 0x66 : -1;
-
- if (instr->variant < 4) {
- rex = (Rex){.w = instr->variant == 3};
- assemblevbytes(prefix);
- assemblerex(rex);
- assemblevbytes(byteop ? 0xa8 : 0xa9);
- imm = &instr->arg1->imm;
- assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
- } else if (instr->variant < 12) {
- rex = (Rex){.w = (instr->variant % 4) == 3};
- assembleimmrm(instr, rex, prefix, byteop ? 0xf6 : 0xf7, 0);
- } else {
- assemblerrm(instr, prefix, byteop ? 0x84 : 0x85, 0);
- }
-}
-
-static void assembleset(const Instr *instr) {
- Rex rex;
- VarBytes prefix, opcode;
- uint8_t 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,
- 0x9e, 0x9c, 0x9d, 0x9f, 0x94, 0x92, 0x96, 0x92, 0x93, 0x97,
- };
- opcode = 0x01000f00 | variant2op[instr->variant % 31];
- prefix = -1;
- if (instr->arg1->kind == ASM_MEMARG) {
- rex = (Rex){0};
- assemblemem(&instr->arg1->memarg, rex, prefix, opcode, 0);
- } else {
- rm = regbits(instr->arg1->kind);
- rex = (Rex){
- .required = isrexreg(instr->arg1->kind),
- .w = isreg64(instr->arg1->kind),
- .b = !!(rm & (1 << 3)),
- };
- assemblemodregrm(rex, prefix, opcode, 0x03, 0, rm);
- }
-}
-
static void assemblecall(const Call *call) {
Rex rex;
uint8_t rm;
@@ -751,7 +439,8 @@ static void assemblecall(const Call *call) {
if (call->indirect) {
if (call->target.indirect->kind == ASM_MEMARG) {
rex = (Rex){0};
- assemblemem(&call->target.indirect->memarg, rex, -1, 0xff, 0x02);
+ abort(); // assemblemem(&call->target.indirect->memarg, rex, -1, 0xff,
+ // 0x02);
} else {
rm = regbits(call->target.indirect->kind);
rex = (Rex){.b = !!(rm & (1 << 3))};
@@ -764,25 +453,6 @@ static void assemblecall(const Call *call) {
}
}
-static void assembleimul(const Instr *instr) {
- VarBytes prefix, opcode;
-
- if (instr->variant < 8) {
- assembledivmulneg(instr, 0x05);
- } else if (instr->variant < 14) {
- opcode = 0x01000faf;
- prefix = ((instr->variant - 8) % 3) == 0 ? 0x66 : -1;
- assemblerrm(instr, prefix, opcode, 1);
- } else {
- const Imm *imm;
- imm = &instr->arg3->imm;
- opcode = 0x69;
- prefix = ((instr->variant - 14) % 3) == 0 ? 0x66 : -1;
- assemblerrm(instr, prefix, opcode, 1);
- assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
- }
-}
-
static void assemblejmp(const Jmp *j) {
int jmpsize;
int64_t distance;
@@ -927,262 +597,205 @@ static void assemble(void) {
lfatal("%s already defined", sym->name);
sym->defined = 1;
break;
- case ASM_CALL:
- assemblecall(&v->call);
- break;
- case ASM_JMP:
- assemblejmp(&v->jmp);
- break;
- case ASM_PUSH: {
+ case ASM_INSTR: {
Rex rex;
- uint8_t reg;
+ const Instr *instr;
+ const Memarg *memarg;
+ const Imm *imm;
+ uint8_t mod, reg, rm;
- if (v->instr.arg1->kind == ASM_MEMARG) {
- rex = (Rex){0};
- assemblemem(&v->instr.arg1->memarg, rex, -1, 0xff, 0x06);
- } else {
- reg = regbits(v->instr.arg1->kind);
- rex = (Rex){.b = !!(reg & (1 << 3))};
- assembleplusr(rex, -1, 0x50, reg);
- }
- break;
- }
- case ASM_POP: {
- Rex rex;
- uint8_t reg;
+ instr = &v->instr;
- if (v->instr.arg1->kind == ASM_MEMARG) {
- rex = (Rex){0};
- assemblemem(&v->instr.arg1->memarg, rex, -1, 0x8f, 0x00);
- } else {
- reg = regbits(v->instr.arg1->kind);
- rex = (Rex){.b = !!(reg & (1 << 3))};
- assembleplusr(rex, -1, 0x58, reg);
- }
- break;
- }
- case ASM_NOP:
- sb(0x90);
- break;
- case ASM_LEAVE:
- sb(0xc9);
- break;
- case ASM_CLTD:
- sb(0x99);
- break;
- case ASM_CQTO:
- sb2(0x48, 0x99);
- break;
- case ASM_CVTSI2SD:
- assemblerrm(&v->instr, 0xf2, 0x01000f2a, 1);
- break;
- case ASM_CVTSI2SS:
- assemblerrm(&v->instr, 0xf3, 0x01000f2a, 1);
- break;
- case ASM_CVTSS2SD:
- assemblerrm(&v->instr, 0xf3, 0x01000f5a, 1);
- break;
- case ASM_CVTSD2SS:
- assemblerrm(&v->instr, 0xf2, 0x01000f5a, 1);
- break;
- case ASM_CVTTSD2SI:
- assemblerrm(&v->instr, 0xf2, 0x01000f2c, 1);
- break;
- case ASM_CVTTSS2SI:
- assemblerrm(&v->instr, 0xf3, 0x01000f2c, 1);
- break;
- case ASM_RET:
- sb(0xc3);
- break;
- case ASM_LEA: {
- VarBytes prefix;
- prefix = v->instr.variant == 0 ? 0x66 : -1;
- assemblerrm(&v->instr, prefix, 0x8d, 0);
- break;
- }
- case ASM_MOVAPS: {
- VarBytes prefix, opcode;
- prefix = -1;
- opcode = v->instr.variant == 2 ? 0x01000f29 : 0x01000f28;
- assemblerrm(&v->instr, prefix, opcode, 1);
- break;
- }
- case ASM_MOV:
- assemblemov(&v->instr);
- break;
- case ASM_MOVQ:
- switch (v->instr.variant) {
- case 0:
- assemblerrm(&v->instr, 0x66, 0x01000f7e, 0);
+ switch (instr->encoder) {
+ case ENCODER_OP:
+ assemblevbytes(instr->opcode);
+ break;
+ case ENCODER_OPREG:
+ rm = regbits(instr->arg1->kind);
+ rex = instr->rex;
+ rex.required = isrexreg(instr->arg1->kind);
+ rex.b = !!(rm & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ sb(modregrmbyte(0x03, instr->fixedreg, rm));
+ break;
+ case ENCODER_OPMEM:
+ memarg = &instr->arg1->memarg;
+ rex = instr->rex;
+ assemblemem(memarg, rex, instr->prefix, instr->opcode, instr->fixedreg);
break;
- case 1:
- assemblerrm(&v->instr, 0x66, 0x01000f6e, 1);
+ case ENCODER_R:
+ reg = regbits(instr->arg1->kind);
+ rex = instr->rex;
+ rex.required = isrexreg(instr->arg1->kind);
+ rex.b = !!(reg & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode | (reg & 7));
break;
- case 2:
- assemblerrm(&v->instr, 0x66, 0x01000fd6, 0);
+ case ENCODER_RIMM:
+ imm = &instr->arg1->imm;
+ reg = regbits(instr->arg2->kind);
+ rex = instr->rex;
+ rex.required = isrexreg(instr->arg2->kind);
+ rex.b = !!(reg & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode | (reg & 7));
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else if (imm->nbytes == 8)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_64);
+ else
+ unreachable();
+ break;
+ case ENCODER_IMM:
+ imm = &instr->arg1->imm;
+ rex = instr->rex;
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else
+ unreachable();
break;
- case 3:
- assemblerrm(&v->instr, 0xf3, 0x01000f7e, 1);
+ case ENCODER_IMMREG:
+ imm = &instr->arg1->imm;
+ reg = instr->fixedreg;
+ rm = regbits(instr->arg2->kind);
+ rex = instr->rex;
+ rex.required = isrexreg(instr->arg2->kind);
+ rex.b = !!(rm & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ sb(modregrmbyte(0x03, reg, rm));
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else
+ unreachable();
+ break;
+ case ENCODER_IMMMEM:
+ imm = &instr->arg1->imm;
+ memarg = &instr->arg2->memarg;
+ reg = instr->fixedreg;
+ rex = instr->rex;
+ if (memarg->base == ASM_RIP) {
+ assembleriprel(memarg, rex, instr->prefix, instr->opcode,
+ instr->fixedreg, -imm->nbytes);
+ } else {
+ assemblemem(memarg, rex, instr->prefix, instr->opcode,
+ instr->fixedreg);
+ }
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else
+ unreachable();
+ break;
+ case ENCODER_REGMEM:
+ case ENCODER_MEMREG:
+ if (instr->encoder == ENCODER_MEMREG) {
+ memarg = &instr->arg1->memarg;
+ reg = regbits(instr->arg2->kind);
+ } else {
+ memarg = &instr->arg2->memarg;
+ reg = regbits(instr->arg1->kind);
+ }
+ rex = instr->rex;
+ rex.required =
+ isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind);
+ rex.r = !!(reg & (1 << 3));
+ assemblemem(memarg, rex, instr->prefix, instr->opcode, reg);
+ break;
+ case ENCODER_REGREG:
+ case ENCODER_REGREG2:
+ if (instr->encoder == ENCODER_REGREG) {
+ reg = regbits(instr->arg1->kind);
+ rm = regbits(instr->arg2->kind);
+ } else {
+ reg = regbits(instr->arg2->kind);
+ rm = regbits(instr->arg1->kind);
+ }
+ rex = instr->rex;
+ rex.required =
+ isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind);
+ rex.r = !!(reg & (1 << 3));
+ rex.b = !!(rm & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ sb(modregrmbyte(0x03, reg, rm));
+ break;
+ case ENCODER_IMMREGREG2:
+ imm = &instr->arg1->imm;
+ reg = regbits(instr->arg3->kind);
+ rm = regbits(instr->arg2->kind);
+ rex = instr->rex;
+ rex.required =
+ isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind);
+ rex.r = !!(reg & (1 << 3));
+ rex.b = !!(rm & (1 << 3));
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ sb(modregrmbyte(0x03, reg, rm));
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else
+ unreachable();
+ break;
+ case ENCODER_IMMMEMREG:
+ imm = &instr->arg1->imm;
+ memarg = &instr->arg2->memarg;
+ reg = regbits(instr->arg3->kind);
+ rex = instr->rex;
+ rex.required =
+ isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind);
+ rex.r = !!(reg & (1 << 3));
+ assemblemem(memarg, rex, instr->prefix, instr->opcode, reg);
+ if (imm->nbytes == 1)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8);
+ else if (imm->nbytes == 2)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16);
+ else if (imm->nbytes == 4)
+ assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32);
+ else
+ unreachable();
break;
default:
unreachable();
}
- break;
- case ASM_MOVSD:
- assemblemovsmmx(&v->instr, 0xf2);
- break;
- case ASM_MOVSS:
- assemblemovsmmx(&v->instr, 0xf3);
- break;
- case ASM_MOVSX: {
- VarBytes opcode;
- if (v->instr.variant >= 10) {
- opcode = 0x63; // movsxd
- } else {
- static uint8_t variant2op[10] = {0xbe, 0xbe, 0xbe, 0xbf, 0xbf,
- 0xbe, 0xbe, 0xbe, 0xbf, 0xbf};
- opcode = 0x01000f00 | variant2op[v->instr.variant];
- }
- assemblemovextend(&v->instr, opcode);
- break;
- }
- case ASM_MOVZX: {
- VarBytes opcode;
- static uint8_t variant2op[10] = {0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
- 0xb6, 0xb6, 0xb6, 0xb7, 0xb7};
- opcode = 0x01000f00 | variant2op[v->instr.variant];
- assemblemovextend(&v->instr, opcode);
- break;
- }
- case ASM_ADD: {
- static uint8_t variant2op[24] = {
- 0x04, 0x05, 0x05, 0x05, 0x80, 0x81, 0x81, 0x81,
- 0x80, 0x81, 0x81, 0x81, 0x02, 0x03, 0x03, 0x03,
- 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x00);
- break;
- }
- case ASM_AND: {
- static uint8_t variant2op[24] = {
- 0x24, 0x25, 0x25, 0x25, 0x80, 0x81, 0x81, 0x81,
- 0x80, 0x81, 0x81, 0x81, 0x22, 0x23, 0x23, 0x23,
- 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x04);
- break;
- }
- case ASM_CMP: {
- static uint8_t variant2op[24] = {
- 0x3c, 0x3d, 0x3d, 0x3d, 0x80, 0x81, 0x81, 0x81,
- 0x80, 0x81, 0x81, 0x81, 0x3a, 0x3b, 0x3b, 0x3b,
- 0x38, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, 0x39,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x07);
- break;
- }
- case ASM_ADDSS:
- assemblerrm(&v->instr, 0xf3, 0x01000f58, 1);
- break;
- case ASM_ADDSD:
- assemblerrm(&v->instr, 0xf2, 0x01000f58, 1);
- break;
- case ASM_DIV:
- assembledivmulneg(&v->instr, 0x06);
- break;
- case ASM_IDIV:
- assembledivmulneg(&v->instr, 0x07);
- break;
- case ASM_DIVSD:
- assemblerrm(&v->instr, 0xf2, 0x01000f5e, 1);
- break;
- case ASM_DIVSS:
- assemblerrm(&v->instr, 0xf3, 0x01000f5e, 1);
- break;
- case ASM_MUL:
- assembledivmulneg(&v->instr, 0x04);
- break;
- case ASM_MULSD:
- assemblerrm(&v->instr, 0xf2, 0x01000f59, 1);
- break;
- case ASM_MULSS:
- assemblerrm(&v->instr, 0xf3, 0x01000f59, 1);
- break;
- case ASM_IMUL:
- assembleimul(&v->instr);
- break;
- case ASM_NEG:
- assembledivmulneg(&v->instr, 0x03);
- break;
- case ASM_OR: {
- static uint8_t variant2op[24] = {
- 0x0c, 0x0d, 0x0d, 0x0d, 0x80, 0x81, 0x81, 0x81,
- 0x80, 0x81, 0x81, 0x81, 0x0a, 0x0b, 0x0b, 0x0b,
- 0x08, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x01);
- break;
- }
- case ASM_PXOR:
- assemblerrm(&v->instr, 0x66, 0x01000fef, 1);
- break;
- case ASM_SET:
- assembleset(&v->instr);
- break;
- case ASM_SAL:
- /* fallthrough */
- 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,
- 0x80, 0x81, 0x81, 0x81, 0x2a, 0x2b, 0x2b, 0x2b,
- 0x28, 0x29, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x05);
+
break;
}
- case ASM_SUBSS:
- assemblerrm(&v->instr, 0xf3, 0x01000f5c, 1);
- break;
- case ASM_SUBSD:
- assemblerrm(&v->instr, 0xf2, 0x01000f5c, 1);
- break;
- case ASM_TEST:
- assembletest(&v->instr);
- break;
- case ASM_UCOMISD:
- assemblerrm(&v->instr, 0x66, 0x01000f2e, 1);
- break;
- case ASM_UCOMISS:
- assemblerrm(&v->instr, -1, 0x01000f2e, 1);
- break;
- case ASM_XORPD:
- assemblerrm(&v->instr, 0x66, 0x01000f57, 1);
- break;
- case ASM_XORPS:
- assemblerrm(&v->instr, -1, 0x01000f57, 1);
- break;
- case ASM_XOR: {
- static uint8_t variant2op[24] = {
- 0x34, 0x35, 0x35, 0x35, 0x80, 0x81, 0x81, 0x81,
- 0x80, 0x81, 0x81, 0x81, 0x32, 0x33, 0x33, 0x33,
- 0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31,
- };
- assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x06);
+ case ASM_CALL:
+ assemblecall(&v->call);
break;
- }
- case ASM_XCHG: {
- assemblexchg(&v->instr);
+ case ASM_JMP:
+ assemblejmp(&v->jmp);
break;
- }
default:
lfatal("assemble: unexpected kind: %d", v->kind);
}