diff options
| author | Andrew Chambers <[email protected]> | 2021-10-12 19:42:01 +1300 |
|---|---|---|
| committer | Andrew Chambers <[email protected]> | 2021-10-12 19:42:01 +1300 |
| commit | 25fa3f8e631f26b09303b1263d9bf5cf4e564c64 (patch) | |
| tree | f3abf4d65645c5f1327dd81a9af8249f95dcc1bb | |
| parent | b4e630f77661aae9e030e9dabead9ba5b0370368 (diff) | |
More types of call.
| -rw-r--r-- | asm.peg | 33 | ||||
| -rw-r--r-- | main.c | 36 | ||||
| -rw-r--r-- | minias.h | 6 | ||||
| -rw-r--r-- | test/test.sh | 3 |
4 files changed, 59 insertions, 19 deletions
@@ -118,9 +118,14 @@ pop = | 'q' ws d:m { $$ = INSTR1(1, d); } ) { $$.instr.kind = ASM_POP; } -call = - "call" 'q'? ws t:ident - { $$.call = (Call){ .kind = ASM_CALL, .target=t.charptr } ; } +call = "call" 'q'? ws ( + '*' t:m + { $$.call = (Call){ .kind = ASM_CALL, .target.indirect=dupv(&t), .indirect=1 } ; } + | '*' t:r64 + { $$.call = (Call){ .kind = ASM_CALL, .target.indirect=dupv(&t), .indirect=1 } ; } + | t:value + { $$.call = (Call){ .kind = ASM_CALL, .target.direct=t.value, .indirect=0 } ; } +) jmp = 'j' v:jmp-variant ws t:ident { $$.jmp = (Jmp) {.kind = ASM_JMP, .variant=v.i64, .target=t.charptr}; } @@ -408,19 +413,21 @@ r64-or-rip = ( | r:rip ) { $$ = r; } -scale-index-base = +m = + d:value ws? sib:opt-scale-index-base { $$ = sib; $$.memarg.disp = d.value; } + | sib:scale-index-base { $$ = sib; } + +opt-scale-index-base = + sib:scale-index-base { $$ = sib; } + | { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = ASM_NO_REG, .disp = {0} }; } + +scale-index-base = '(' ws? b:r64 ws? ',' ws? i:r64 ws? ',' ws? s:number ws? ')' - { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = s.i64, .index=i.kind, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } + { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = s.i64, .index=i.kind, .base = b.kind, .disp = {0} }; } | '(' ws? b:r64 ws? ',' ws? i:r64 ')' - { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 1, .index=i.kind, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } + { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 1, .index=i.kind, .base = b.kind, .disp = {0} }; } | '(' ws? b:r64-or-rip ws? ')' - { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } - -m = - sib:scale-index-base - { $$ = sib; } - | d:value ws? sib:scale-index-base - { sib.memarg.disp = d.value; $$ = sib; } + { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = b.kind, .disp = {0} }; } imm8 = i:imm { i.imm.nbytes = 1; $$ = i; } imm16 = i:imm { i.imm.nbytes = 2; $$ = i; } @@ -426,6 +426,21 @@ static void assemblemem(Memarg *memarg, uint8_t rexw, VarBytes prefix, uint8_t rex, mod, rm, scale, index, base, sib; + /* Direct memory access */ + if (memarg->base == ASM_NO_REG) { + mod = 0; + rm = 4; + rex = rexbyte(rexw, reg & (1 << 3), 0, 0); + assemblemodregrm(rex, prefix, opcode, mod, reg, rm); + sb(sibbyte(0, 4, 5)); + if (memarg->disp.l) { + assemblereloc(memarg->disp.l, memarg->disp.c, 4, R_X86_64_PC32); + } else { + assembleconstant(memarg->disp.c, 4); + } + return; + } + /* rip relative addressing. */ if (memarg->base == ASM_RIP) { rm = 0x05; @@ -821,11 +836,22 @@ static void assemble(void) { sym->defined = 1; break; case ASM_CALL: { - Symbol *sym; - Relocation *reloc; - - sb(0xe8); - assemblereloc(v->call.target, -4, 4, R_X86_64_PC32); + uint8_t rm, rex; + + if (v->call.indirect) { + if (v->call.target.indirect->kind == ASM_MEMARG) { + assemblemem(&v->call.target.indirect->memarg, 0, EMPTY_VBYTES, 0xff, + 0x02); + } else { + rm = regbits(v->call.target.indirect->kind); + rex = rexbyte(0, 0, 0, rm & (1 << 3)); + assemblemodregrm(rex, EMPTY_VBYTES, 0xff, 0x03, 0x02, rm); + } + } else { + sb(0xe8); + assemblereloc(v->call.target.direct.l, v->call.target.direct.c - 4, 4, + R_X86_64_PC32); + } break; } case ASM_JMP: { @@ -270,7 +270,11 @@ typedef String Asciiz; typedef struct { AsmKind kind; - const char *target; + uint8_t indirect; + union { + Parsev *indirect; + Value direct; + } target; } Call; typedef struct { diff --git a/test/test.sh b/test/test.sh index 153821a..115be24 100644 --- a/test/test.sh +++ b/test/test.sh @@ -30,6 +30,9 @@ t () { echo -n "." } +t "callq *%rax" +t "callq *%r10" + t "cvtss2sd %xmm0, %xmm1" t "cvtss2sd %xmm10, %xmm1" t "cvtss2sd (%rax), %xmm0" |
