aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c370
-rw-r--r--test/test.sh4
2 files changed, 161 insertions, 213 deletions
diff --git a/main.c b/main.c
index 3c8f6ee..2dc6990 100644
--- a/main.c
+++ b/main.c
@@ -306,29 +306,22 @@ static void assemblereloc(const char *l, int64_t c, int nbytes, int type) {
assembleconstant(c, nbytes);
}
-/* Rip relative addressing. */
-static void assembleriprel(const Memarg *memarg, Rex rex, VarBytes prefix,
- VarBytes opcode, uint8_t reg, int32_t adjust) {
- uint8_t rm;
-
- rm = 0x05;
- assemblemodregrm(rex, prefix, opcode, 0x00, reg, rm);
- if (memarg->disp.l) {
- assemblereloc(memarg->disp.l, memarg->disp.c - 4 + adjust, 4,
- R_X86_64_PC32);
- } else {
- assembleconstant(memarg->disp.c, 4);
- }
-}
-
/* Assemble a r <-> mem operation. */
static void assemblemem(const Memarg *memarg, Rex rex, VarBytes prefix,
- VarBytes opcode, uint8_t reg) {
+ VarBytes opcode, uint8_t reg, int32_t nexti) {
uint8_t mod, rm, scale, index, base;
+ /* Rip relative addressing. */
if (memarg->base == ASM_RIP) {
- assembleriprel(memarg, rex, prefix, opcode, reg, 0);
+ rm = 0x05;
+ assemblemodregrm(rex, prefix, opcode, 0x00, reg, rm);
+ if (memarg->disp.l) {
+ assemblereloc(memarg->disp.l, memarg->disp.c - 4 + nexti, 4,
+ R_X86_64_PC32);
+ } else {
+ assembleconstant(memarg->disp.c, 4);
+ }
return;
}
@@ -490,6 +483,155 @@ static void assemblejmp(const Jmp *j) {
}
}
+static void assembleabsimm(const Imm *imm) {
+ 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();
+}
+
+static void assembleinstr(const Instr *instr) {
+ Rex rex;
+ const Memarg *memarg;
+ const Imm *imm;
+ uint8_t mod, reg, rm;
+
+ 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, 0);
+ break;
+ 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 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));
+ assembleabsimm(imm);
+ break;
+ case ENCODER_IMM:
+ imm = &instr->arg1->imm;
+ rex = instr->rex;
+ assemblevbytes(instr->prefix);
+ assemblerex(rex);
+ assemblevbytes(instr->opcode);
+ assembleabsimm(imm);
+ break;
+ 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));
+ assembleabsimm(imm);
+ break;
+ case ENCODER_IMMMEM:
+ imm = &instr->arg1->imm;
+ memarg = &instr->arg2->memarg;
+ reg = instr->fixedreg;
+ rex = instr->rex;
+ assemblemem(memarg, rex, instr->prefix, instr->opcode, instr->fixedreg,
+ imm->nbytes);
+ assembleabsimm(imm);
+ 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, 0);
+ 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));
+ assembleabsimm(imm);
+ 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, imm->nbytes);
+ assembleabsimm(imm);
+ break;
+ default:
+ unreachable();
+ }
+}
+
static void assemble(void) {
Symbol *sym;
AsmLine *l;
@@ -597,199 +739,9 @@ static void assemble(void) {
lfatal("%s already defined", sym->name);
sym->defined = 1;
break;
- case ASM_INSTR: {
- Rex rex;
- const Instr *instr;
- const Memarg *memarg;
- const Imm *imm;
- uint8_t mod, reg, rm;
-
- instr = &v->instr;
-
- 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 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 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 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();
- }
-
+ case ASM_INSTR:
+ assembleinstr(&v->instr);
break;
- }
case ASM_CALL:
assemblecall(&v->call);
break;
diff --git a/test/test.sh b/test/test.sh
index abe404a..5ef1266 100644
--- a/test/test.sh
+++ b/test/test.sh
@@ -32,8 +32,6 @@ t () {
# Various regression tests first.
t "movss %xmm15,-0x128(%rbp)"
-t "movaps -0x38(%rbp),%xmm15"
-t "movsd -0x38(%rbp),%xmm15"
t "xchgq %r13, %rax"
t "movl \$1000, %r8d"
t "movb %sil, (%rdi)"
@@ -44,8 +42,6 @@ t "callq *%rax"
t "callq *%r10"
t "movb %r11b, (%rsi, %r12, 1)"
-
-
for r in rax r10
do
for x in xmm0 xmm13