aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-12 19:42:01 +1300
committerAndrew Chambers <[email protected]>2021-10-12 19:42:01 +1300
commit25fa3f8e631f26b09303b1263d9bf5cf4e564c64 (patch)
treef3abf4d65645c5f1327dd81a9af8249f95dcc1bb
parentb4e630f77661aae9e030e9dabead9ba5b0370368 (diff)
More types of call.
-rw-r--r--asm.peg33
-rw-r--r--main.c36
-rw-r--r--minias.h6
-rw-r--r--test/test.sh3
4 files changed, 59 insertions, 19 deletions
diff --git a/asm.peg b/asm.peg
index 8a36802..c00abec 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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; }
diff --git a/main.c b/main.c
index ffd925f..8ba72e2 100644
--- a/main.c
+++ b/main.c
@@ -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: {
diff --git a/minias.h b/minias.h
index 38f1f1d..b5eb779 100644
--- a/minias.h
+++ b/minias.h
@@ -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"