summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2019-10-06 23:29:40 +1100
committerDamien George <damien.p.george@gmail.com>2019-12-12 20:15:28 +1100
commitb47e155bd07e5765b804c404411825b15378c0b6 (patch)
tree48e7c57050d5164e5482c5d9b1b2c2e921729031 /py
parentb310930dba3a35dbe4d790f461caf27d78b4c7b9 (diff)
py/persistentcode: Add ability to relocate loaded native code.
Implements text, rodata and bss generalised relocations, as well as generic qstr-object linking. This allows importing dynamic native modules on all supported architectures in a unified way.
Diffstat (limited to 'py')
-rw-r--r--py/asmbase.h2
-rw-r--r--py/bc.h2
-rw-r--r--py/persistentcode.c80
-rw-r--r--py/persistentcode.h2
-rw-r--r--py/runtime0.h6
5 files changed, 87 insertions, 5 deletions
diff --git a/py/asmbase.h b/py/asmbase.h
index d2b403893..b5e259358 100644
--- a/py/asmbase.h
+++ b/py/asmbase.h
@@ -60,7 +60,7 @@ static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) {
static inline void *mp_asm_base_get_code(mp_asm_base_t *as) {
#if defined(MP_PLAT_COMMIT_EXEC)
- return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size);
+ return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size, NULL);
#else
return as->code_base;
#endif
diff --git a/py/bc.h b/py/bc.h
index fd52571fd..a96d17a0d 100644
--- a/py/bc.h
+++ b/py/bc.h
@@ -74,7 +74,7 @@
#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \
do { \
/*// Get values to store in prelude */ \
- size_t F = scope->scope_flags & 0x0f; /* only need to store lower 4 flag bits */ \
+ size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG; \
size_t A = scope->num_pos_args; \
size_t K = scope->num_kwonly_args; \
size_t D = scope->num_def_pos_args; \
diff --git a/py/persistentcode.c b/py/persistentcode.c
index 84385c171..353fa268e 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -33,6 +33,7 @@
#include "py/emitglue.h"
#include "py/persistentcode.h"
#include "py/bc0.h"
+#include "py/objstr.h"
#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
@@ -145,8 +146,16 @@ STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) {
#include "py/parsenum.h"
+STATIC int read_byte(mp_reader_t *reader);
+STATIC size_t read_uint(mp_reader_t *reader, byte **out);
+
#if MICROPY_EMIT_MACHINE_CODE
+typedef struct _reloc_info_t {
+ mp_reader_t *reader;
+ mp_uint_t *const_table;
+} reloc_info_t;
+
#if MICROPY_EMIT_THUMB
STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) {
// high part
@@ -179,6 +188,52 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) {
#endif
}
+void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) {
+ // Relocate native code
+ reloc_info_t *ri = ri_in;
+ uint8_t op;
+ uintptr_t *addr_to_adjust = NULL;
+ while ((op = read_byte(ri->reader)) != 0xff) {
+ if (op & 1) {
+ // Point to new location to make adjustments
+ size_t addr = read_uint(ri->reader, NULL);
+ if ((addr & 1) == 0) {
+ // Point to somewhere in text
+ addr_to_adjust = &((uintptr_t*)text)[addr >> 1];
+ } else {
+ // Point to somewhere in rodata
+ addr_to_adjust = &((uintptr_t*)ri->const_table[1])[addr >> 1];
+ }
+ }
+ op >>= 1;
+ uintptr_t dest;
+ size_t n = 1;
+ if (op <= 5) {
+ if (op & 1) {
+ // Read in number of adjustments to make
+ n = read_uint(ri->reader, NULL);
+ }
+ op >>= 1;
+ if (op == 0) {
+ // Destination is text
+ dest = reloc_text;
+ } else {
+ // Destination is rodata (op=1) or bss (op=1 if no rodata, else op=2)
+ dest = ri->const_table[op];
+ }
+ } else if (op == 6) {
+ // Destination is mp_fun_table itself
+ dest = (uintptr_t)&mp_fun_table;
+ } else {
+ // Destination is an entry in mp_fun_table
+ dest = ((uintptr_t*)&mp_fun_table)[op - 7];
+ }
+ while (n--) {
+ *addr_to_adjust++ += dest;
+ }
+ }
+}
+
#endif
STATIC int read_byte(mp_reader_t *reader) {
@@ -340,6 +395,9 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
// Generic 16-bit link
dest[0] = qst & 0xff;
dest[1] = (qst >> 8) & 0xff;
+ } else if ((off & 3) == 3) {
+ // Generic, aligned qstr-object link
+ *(mp_obj_t*)dest = MP_OBJ_NEW_QSTR(qst);
} else {
// Architecture-specific link
arch_link_qstr(dest, (off & 3) == 2, qst);
@@ -423,8 +481,26 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
#if MICROPY_EMIT_MACHINE_CODE
} else {
+ mp_uint_t *ct = &const_table[1];
+ if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
+ size_t size = read_uint(reader, NULL);
+ uint8_t *rodata = m_new(uint8_t, size);
+ read_bytes(reader, rodata, size);
+ *ct++ = (uintptr_t)rodata;
+ }
+ if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) {
+ size_t size = read_uint(reader, NULL);
+ uint8_t *bss = m_new0(uint8_t, size);
+ *ct++ = (uintptr_t)bss;
+ }
+ reloc_info_t ri = {reader, const_table};
#if defined(MP_PLAT_COMMIT_EXEC)
- fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len);
+ void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL;
+ fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri);
+ #else
+ if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) {
+ mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data);
+ }
#endif
mp_emit_glue_assign_native(rc, kind,
@@ -624,7 +700,7 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q
save_prelude_qstrs(print, qstr_window, ip_info);
} else {
// Save basic scope info for viper and asm
- mp_print_uint(print, rc->scope_flags);
+ mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG);
prelude.n_pos_args = 0;
prelude.n_kwonly_args = 0;
if (rc->kind == MP_CODE_NATIVE_ASM) {
diff --git a/py/persistentcode.h b/py/persistentcode.h
index 07e018f8a..fde7a4625 100644
--- a/py/persistentcode.h
+++ b/py/persistentcode.h
@@ -95,4 +95,6 @@ mp_raw_code_t *mp_raw_code_load_file(const char *filename);
void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print);
void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename);
+void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text);
+
#endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H
diff --git a/py/runtime0.h b/py/runtime0.h
index f588110c0..b433c716f 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -28,13 +28,17 @@
// The first four must fit in 8 bits, see emitbc.c
// The remaining must fit in 16 bits, see scope.h
+#define MP_SCOPE_FLAG_ALL_SIG (0x0f)
#define MP_SCOPE_FLAG_GENERATOR (0x01)
#define MP_SCOPE_FLAG_VARKEYWORDS (0x02)
#define MP_SCOPE_FLAG_VARARGS (0x04)
#define MP_SCOPE_FLAG_DEFKWARGS (0x08)
#define MP_SCOPE_FLAG_REFGLOBALS (0x10) // used only if native emitter enabled
#define MP_SCOPE_FLAG_HASCONSTS (0x20) // used only if native emitter enabled
-#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type
+#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type, to pass from compiler to native emitter
+#define MP_SCOPE_FLAG_VIPERRELOC (0x10) // used only when loading viper from .mpy
+#define MP_SCOPE_FLAG_VIPERRODATA (0x20) // used only when loading viper from .mpy
+#define MP_SCOPE_FLAG_VIPERBSS (0x40) // used only when loading viper from .mpy
// types for native (viper) function signature
#define MP_NATIVE_TYPE_OBJ (0x00)