aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-08-04 21:16:34 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2023-08-04 21:16:34 +0300
commit09f8df9f7e1166be48cdd6b1caba0f6771dd753e (patch)
tree1cad6a2b118825e19432e2acf4e65c45e975ab60
parentc671d6612be0fb28eea498246c39bb5032afa872 (diff)
downloadcopyjit-09f8df9f7e1166be48cdd6b1caba0f6771dd753e.tar.gz
copyjit-09f8df9f7e1166be48cdd6b1caba0f6771dd753e.zip
add simple patching mechanism
-rw-r--r--src/copyjit.c17
-rw-r--r--src/copyjit.h12
-rwxr-xr-xtests/checkbin1261584 -> 1269672 bytes
-rw-r--r--tests/check.c41
4 files changed, 68 insertions, 2 deletions
diff --git a/src/copyjit.c b/src/copyjit.c
index 393c8e1..0de85d3 100644
--- a/src/copyjit.c
+++ b/src/copyjit.c
@@ -471,6 +471,23 @@ void compile_start(ctx_t *ctx)
ctx->pc = ctx->buf;
}
+reloc_t compile_placeholder(ctx_t *ctx, compile_callback_t call)
+{
+ reloc_t r = {0};
+ r.addr = call(ctx, 0);
+
+ /* the immediate is the last sizeof(uintptr_t) bytes of the generated
+ * instruction
+ * (at least we assume, the user could've passed anything to our callback) */
+ r.imm = ((uintptr_t *)ctx->pc) - 1;
+ return r;
+}
+
+void compile_patch(reloc_t reloc, void *addr)
+{
+ *reloc.imm = (uintptr_t)addr;
+}
+
void compile_finish(ctx_t *ctx)
{
__builtin___clear_cache(ctx->buf, ctx->buf + ctx->size);
diff --git a/src/copyjit.h b/src/copyjit.h
index d752144..8170204 100644
--- a/src/copyjit.h
+++ b/src/copyjit.h
@@ -3,12 +3,21 @@
#ifndef HMMJIT_H
#define HMMJIT_H
+#include <stdint.h>
+
typedef struct {
char *pc;
char *buf;
size_t size;
} ctx_t;
+typedef struct {
+ void *addr;
+ uintptr_t *imm;
+} reloc_t;
+
+typedef void *(*compile_callback_t)(ctx_t *, unsigned long);
+
#include "../lib/op_decls.h"
#include "../lib/imm_decls.h"
@@ -30,6 +39,9 @@ void *compile_sly(ctx_t *ctx, unsigned long i);
/** @todo add in placeholders (for example for load immediate but we don't know
* what the immediate is yet) */
+reloc_t compile_placeholder(ctx_t *ctx, compile_callback_t call);
+void compile_patch(reloc_t reloc, void *addr);
+
void compile_start(ctx_t *ctx);
void compile_finish(ctx_t *ctx);
unsigned long run(ctx_t *ctx);
diff --git a/tests/check b/tests/check
index b079a57..a904b37 100755
--- a/tests/check
+++ b/tests/check
Binary files differ
diff --git a/tests/check.c b/tests/check.c
index 8f4c6de..f6e775c 100644
--- a/tests/check.c
+++ b/tests/check.c
@@ -138,8 +138,45 @@ static void check_add()
static void check_branch()
{
- /* oh yeah, I don't support forward references (yet), so this is a bit
- * tricky */
+ for (size_t i = 0; i < 2; ++i) {
+ ctx_t ctx;
+ compile_start(&ctx);
+
+ compile_fast_lia(&ctx, i);
+ reloc_t r = compile_placeholder(&ctx, compile_lio);
+ compile_ban(&ctx);
+
+ compile_lix(&ctx, 0);
+ compile_end(&ctx);
+
+ void *skip = compile_lix(&ctx, 1);
+ compile_end(&ctx);
+ compile_patch(r, skip);
+
+ compile_finish(&ctx);
+
+ assert(run(&ctx) == (i != 0));
+ }
+
+ for (size_t i = 0; i < 2; ++i) {
+ ctx_t ctx;
+ compile_start(&ctx);
+
+ compile_fast_lia(&ctx, i);
+ reloc_t r = compile_placeholder(&ctx, compile_lio);
+ compile_baz(&ctx);
+
+ compile_lix(&ctx, 0);
+ compile_end(&ctx);
+
+ void *skip = compile_lix(&ctx, 1);
+ compile_end(&ctx);
+ compile_patch(r, skip);
+
+ compile_finish(&ctx);
+
+ assert(run(&ctx) == (i == 0));
+ }
}
int main()