diff options
author | Damien George <damien.p.george@gmail.com> | 2019-10-06 23:29:40 +1100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2019-12-12 20:15:28 +1100 |
commit | b47e155bd07e5765b804c404411825b15378c0b6 (patch) | |
tree | 48e7c57050d5164e5482c5d9b1b2c2e921729031 /py/persistentcode.c | |
parent | b310930dba3a35dbe4d790f461caf27d78b4c7b9 (diff) | |
download | micropython-b47e155bd07e5765b804c404411825b15378c0b6.tar.gz micropython-b47e155bd07e5765b804c404411825b15378c0b6.zip |
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/persistentcode.c')
-rw-r--r-- | py/persistentcode.c | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/py/persistentcode.c b/py/persistentcode.c index 84385c1713..353fa268e5 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) { |