diff options
| author | Andrew Chambers <[email protected]> | 2021-10-14 14:37:37 +1300 |
|---|---|---|
| committer | Andrew Chambers <[email protected]> | 2021-10-14 14:37:37 +1300 |
| commit | 1de295e1499d2fa5fc4bfa80b5edc6d3dbed7350 (patch) | |
| tree | 691f8ed3b784287cce6de1ad400aaba122420387 | |
| parent | 819bbdd85a9950d428db00934849ee5a900c347b (diff) | |
Handle 64 bit immediates.
| -rw-r--r-- | asm.peg | 2 | ||||
| -rw-r--r-- | main.c | 33 | ||||
| -rw-r--r-- | test/test.sh | 2 |
3 files changed, 30 insertions, 7 deletions
@@ -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" ( @@ -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" |
