aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm.peg2
-rw-r--r--main.c33
-rw-r--r--test/test.sh2
3 files changed, 30 insertions, 7 deletions
diff --git a/asm.peg b/asm.peg
index f0886c3..24d397f 100644
--- a/asm.peg
+++ b/asm.peg
@@ -382,7 +382,7 @@ mov = "mov" (
| 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR2(16, s, d); }
| 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR2(17, s, d); }
| 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR2(18, s, d); }
- | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR2(19, s, d); }
+ | 'q'? ws s:imm ws? ',' ws? d:r64 { $$ = INSTR2(19, s, d); }
) { $$.instr.kind = ASM_MOV; }
movsx = "movs" (
diff --git a/main.c b/main.c
index f7af5a3..7828a39 100644
--- a/main.c
+++ b/main.c
@@ -200,7 +200,7 @@ static void su32(uint32_t l) {
secaddbytes(cursection, buf, sizeof(buf));
}
-static void su64(uint32_t l) {
+static void su64(uint64_t l) {
uint8_t buf[8] = {
l & 0xff,
(l & 0xff00) >> 8,
@@ -516,19 +516,40 @@ static void assemblemov(const Instr *mov) {
VarBytes prefix, opcode;
uint8_t rexw;
- 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};
+ 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);
- } else if (mov->variant < 16 || mov->variant == 19) {
+ } else if (mov->variant < 16) {
rexw = ((mov->variant % 4) == 3);
assembleimmrm(mov, rexw, prefix, opcode, 0x00);
+ } else if (mov->variant == 19) {
+ uint8_t reg, rex, rm;
+ uint64_t mask, maskedc;
+
+ imm = &mov->arg1->imm;
+ rexw = 1;
+ 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 */
+ rm = regbits(mov->arg2->kind);
+ rex = rexbyte(rexw, 0, 0, rm & (1 << 3));
+ assemblemodregrm(rex, prefix, opcode, 0x03, 0x00, rm);
+ assemblereloc(imm->v.l, imm->v.c, 4, R_X86_64_32);
+ } else {
+ /* 64 bit immediate required. */
+ reg = regbits(mov->arg2->kind);
+ rex = rexbyte(rexw, 0, 0, rm & (1 << 3));
+ sb2(rex, 0xb8 | (reg & 7));
+ assemblereloc(imm->v.l, imm->v.c, 8, R_X86_64_64);
+ }
} else {
imm = &mov->arg1->imm;
assembleplusr(isreg64(mov->arg2->kind), prefix, opcode,
diff --git a/test/test.sh b/test/test.sh
index 0173742..6082ca6 100644
--- a/test/test.sh
+++ b/test/test.sh
@@ -30,6 +30,8 @@ t () {
echo -n "."
}
+t "mov \$17293822569102704639, %rax"
+
t "callq *%rax"
t "callq *%r10"