aboutsummaryrefslogtreecommitdiff
path: root/py/asmx86.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-08-16 13:45:24 +1000
committerDamien George <damien.p.george@gmail.com>2018-08-16 13:45:24 +1000
commit2964b41c282917bfb3f6e3a1d6e3fd7a078abed6 (patch)
tree82e8039004d9a19790878c9cff77413d87cf2f81 /py/asmx86.c
parentf7d6108d1ad83f26598e73d3b163f3de411c902b (diff)
py/asm*: Support assembling code to jump to a register, and get PC+off.
Useful for position independent code, and implementing state machines.
Diffstat (limited to 'py/asmx86.c')
-rw-r--r--py/asmx86.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/py/asmx86.c b/py/asmx86.c
index 821fc7a19..a330c69ec 100644
--- a/py/asmx86.c
+++ b/py/asmx86.c
@@ -76,6 +76,7 @@
#define OPCODE_TEST_R32_WITH_RM32 (0x85) /* /r */
#define OPCODE_JMP_REL8 (0xeb)
#define OPCODE_JMP_REL32 (0xe9)
+#define OPCODE_JMP_RM32 (0xff) /* /4 */
#define OPCODE_JCC_REL8 (0x70) /* | jcc type */
#define OPCODE_JCC_REL32_A (0x0f)
#define OPCODE_JCC_REL32_B (0x80) /* | jcc type */
@@ -343,6 +344,10 @@ void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) {
asm_x86_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r8));
}
+void asm_x86_jmp_reg(asm_x86_t *as, int src_r32) {
+ asm_x86_write_byte_2(as, OPCODE_JMP_RM32, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(src_r32));
+}
+
STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) {
assert(label < as->base.max_num_labels);
return as->base.label_offsets[label];
@@ -462,6 +467,17 @@ void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) {
}
}
+void asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r32, mp_uint_t label) {
+ asm_x86_write_byte_1(as, OPCODE_CALL_REL32);
+ asm_x86_write_word32(as, 0);
+ mp_uint_t dest = get_label_dest(as, label);
+ mp_int_t rel = dest - as->base.code_offset;
+ asm_x86_pop_r32(as, dest_r32);
+ // PC rel is usually a forward reference, so need to assume it's large
+ asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
+ asm_x86_write_word32(as, rel);
+}
+
#if 0
void asm_x86_push_local(asm_x86_t *as, int local_num) {
asm_x86_push_disp(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, local_num));