summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2020-10-23 10:59:22 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2021-10-20 18:19:25 -0400
commitb761f5c96ff1635aeeb26bb7ba6cb2b30adcddaf (patch)
tree126c76c04bfca852b8369d2992bfc1821069790a
parent498fe0fb52c4b3f7c8a4abdc9da1fffb2aa8c69b (diff)
Implemented mechanism for rel32 call
-rw-r--r--ujit_asm.c36
-rw-r--r--ujit_asm.h1
-rw-r--r--ujit_compile.c3
3 files changed, 37 insertions, 3 deletions
diff --git a/ujit_asm.c b/ujit_asm.c
index c99ad37d66..0b833445b2 100644
--- a/ujit_asm.c
+++ b/ujit_asm.c
@@ -758,7 +758,7 @@ void cb_write_jcc_ptr(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op
cb_write_byte(cb, op0);
cb_write_byte(cb, op1);
- // Pointer to the end of this jump
+ // Pointer to the end of this jump instruction
uint8_t* end_ptr = &cb->mem_block[cb->write_pos] + 4;
// Compute the jump offset
@@ -822,6 +822,40 @@ void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
);
}
+// call - Call to a pointer with a 32-bit displacement offset
+void call_rel32(codeblock_t* cb, int32_t rel32)
+{
+ //cb.writeASM("call", rel32);
+
+ // Write the opcode
+ cb_write_byte(cb, 0xE8);
+
+ // Write the relative 32-bit jump offset
+ cb_write_int(cb, (int32_t)rel32, 32);
+}
+
+// call - Call a pointer, encode with a 32-bit offset if possible
+void call_ptr(codeblock_t* cb, x86opnd_t scratch_reg, uint8_t* dst_ptr)
+{
+ assert (scratch_reg.type == OPND_REG);
+
+ // Pointer to the end of this call instruction
+ uint8_t* end_ptr = &cb->mem_block[cb->write_pos] + 5;
+
+ // Compute the jump offset
+ int64_t rel64 = (int64_t)(dst_ptr - end_ptr);
+
+ // If the offset fits in 32-bit
+ if (rel64 >= -2147483648 && rel64 <= 2147483647)
+ {
+ return call_rel32(cb, (int32_t)rel64);
+ }
+
+ // Move the pointer into the scratch register and call
+ mov(cb, scratch_reg, const_ptr_opnd(dst_ptr));
+ call(cb, scratch_reg);
+}
+
/// call - Call to label with 32-bit offset
void call_label(codeblock_t* cb, size_t label_idx)
{
diff --git a/ujit_asm.h b/ujit_asm.h
index 6d6b18b0a9..ca5e8884ce 100644
--- a/ujit_asm.h
+++ b/ujit_asm.h
@@ -254,6 +254,7 @@ void cb_link_labels(codeblock_t* cb);
// Encode individual instructions into a code block
void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
+void call_ptr(codeblock_t* cb, x86opnd_t scratch_reg, uint8_t* dst_ptr);
void call_label(codeblock_t* cb, size_t label_idx);
void call(codeblock_t* cb, x86opnd_t opnd);
void cmova(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
diff --git a/ujit_compile.c b/ujit_compile.c
index dcf4b672c9..678f84c977 100644
--- a/ujit_compile.c
+++ b/ujit_compile.c
@@ -668,8 +668,7 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
// Call the C function
// VALUE ret = (cfunc->func)(recv, argv[0], argv[1]);
- mov(cb, REG0, const_ptr_opnd(cfunc->func));
- call(cb, REG0);
+ call_ptr(cb, REG0, cfunc->func);
//print_str(cb, "after C call");