Skip to content

Commit 81dee3e

Browse files
committed
unix: Add example of dynamic loadable native C code.
Build with: $ ./mk_native.sh Execute with: $ ./micropython import native_ex native_ex.foo()
1 parent 1e23a29 commit 81dee3e

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

ports/unix/mk_native.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
3+
# x64
4+
CFLAGS=-fno-stack-protector
5+
6+
# thumb
7+
#CROSS=arm-none-eabi-
8+
#CFLAGS=-mthumb
9+
10+
# xtensa
11+
#CROSS=xtensa-lx106-elf-
12+
#CFLAGS=-mforce-l32
13+
14+
${CROSS}gcc -fPIC -fPIE $CFLAGS -std=c99 -Os -c native_ex.c -o native_ex.o
15+
${CROSS}ld -T native_ex.ld native_ex.o -o native_ex.elf
16+
${CROSS}objcopy -O binary -j .header -j .text -j .trailer native_ex.elf native_ex.mpy

ports/unix/native_ex.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include <stdint.h>
2+
#include <stddef.h>
3+
4+
#define HEADER_SIZE (48)
5+
#define CODE_SIZE (256 - HEADER_SIZE)
6+
7+
#define UINT_HI(x) (0x80 | ((x) >> 7))
8+
#define UINT_LO(x) ((x) & 0x7f)
9+
10+
#define MP_BC_LOAD_CONST_NONE (0x11)
11+
#define MP_BC_STORE_GLOBAL (0x25) // qstr
12+
#define MP_BC_RETURN_VALUE (0x5b)
13+
#define MP_BC_MAKE_FUNCTION (0x60) // uint
14+
15+
#define MP_OBJ_NEW_SMALL_INT(x) ((x) << 1 | 1)
16+
17+
typedef enum {
18+
MP_CODE_BYTECODE = 2,
19+
MP_CODE_NATIVE_PY,
20+
MP_CODE_NATIVE_VIPER,
21+
MP_CODE_NATIVE_ASM,
22+
} mp_raw_code_kind_t;
23+
24+
struct _mp_f_table_t {
25+
uintptr_t none_obj;
26+
uintptr_t false_obj;
27+
uintptr_t true_obj;
28+
uintptr_t pad0[2];
29+
uintptr_t (*swap_globals)(uintptr_t new_globals);
30+
uintptr_t (*load_name)(uint16_t qst);
31+
uintptr_t pad1[13];
32+
uintptr_t (*new_list)(size_t n, uintptr_t *items);
33+
uintptr_t pad2[6];
34+
uintptr_t (*call_function_n_kw)(uintptr_t fun_in, size_t n_args_kw, const uintptr_t *args);
35+
};
36+
37+
typedef struct _mp_obj_fun_bc_t {
38+
uintptr_t base;
39+
uintptr_t globals;
40+
const void *fun_data;
41+
const void **const_table;
42+
} mp_obj_fun_bc_t;
43+
44+
const uint8_t header[HEADER_SIZE] __attribute__((section(".header"))) = {
45+
'M', 4, 3 | 2 << 2, 31, 32, // x64
46+
//'M', 4, 2 | 5 << 2, 31, 32, // thumb
47+
//'M', 4, 2 | 9 << 2, 31, 32, // xtensa
48+
49+
((12 + 10) << 2) | (MP_CODE_BYTECODE - MP_CODE_BYTECODE), // n bytes
50+
51+
// prelude
52+
1, // n_state
53+
0, // n_exc_stack
54+
0, // scope_flags
55+
0, // n_pos_args
56+
0, // n_kwonly_args
57+
0, // n_def_pos_args
58+
5, // code_info_size (incl this member)
59+
0, 0, // simple_name
60+
0, 0, // source_file
61+
255, // end of list sentinel
62+
63+
// bytecode
64+
MP_BC_MAKE_FUNCTION, 0,
65+
MP_BC_STORE_GLOBAL, 3 << 1, 'f', 'o', 'o',
66+
MP_BC_LOAD_CONST_NONE,
67+
MP_BC_RETURN_VALUE,
68+
0, 0, 0, // padding
69+
70+
6 << 1, 'n', 'a', 't', 'i', 'v', 'e', // simple_name
71+
6 << 1, 'n', 'a', 't', 'i', 'v', 'e', // source_file
72+
0, // n_obj
73+
1, // n_raw_code
74+
75+
// raw_code
76+
UINT_HI(((CODE_SIZE + 2) << 2) | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE)),
77+
UINT_LO(((CODE_SIZE + 2) << 2) | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE)),
78+
};
79+
80+
const uint8_t trailer[] __attribute__((section(".trailer"))) = {
81+
0, 0, // qstr0
82+
1, // n_qstr
83+
UINT_HI(CODE_SIZE << 2), UINT_LO(CODE_SIZE << 2), 5 << 1, 'p', 'r', 'i', 'n', 't', // qstr0
84+
0, // scope_flags
85+
0, // n_obj
86+
0, // n_raw_code
87+
};
88+
89+
uintptr_t foo(mp_obj_fun_bc_t *self, uintptr_t n_args, uintptr_t n_kw, uintptr_t *args) {
90+
uint16_t *qstr_table = (uint16_t*)(self->fun_data + CODE_SIZE);
91+
const struct _mp_f_table_t *f = (const void*)self->const_table[0];
92+
93+
uintptr_t old_globals = f->swap_globals(self->globals);
94+
95+
uintptr_t print = f->load_name(qstr_table[0]);
96+
97+
for (int i = 0; i < 10; ++i) {
98+
uintptr_t args[2] = {MP_OBJ_NEW_SMALL_INT(i), (i & 1) ? f->true_obj : f->false_obj};
99+
f->call_function_n_kw(print, 2, &args[0]);
100+
}
101+
102+
f->swap_globals(old_globals);
103+
104+
uintptr_t list[2] = {MP_OBJ_NEW_SMALL_INT(42), MP_OBJ_NEW_SMALL_INT(n_args)};
105+
return f->new_list(2, list);
106+
}

ports/unix/native_ex.ld

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
MEMORY
2+
{
3+
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
4+
}
5+
6+
SECTIONS
7+
{
8+
.header :
9+
{
10+
KEEP(header*(.rodata*))
11+
} >FLASH
12+
13+
.text :
14+
{
15+
KEEP(*(.text*))
16+
KEEP(*(.rodata*))
17+
} >FLASH
18+
19+
.trailer :
20+
{
21+
. = ALIGN(256);
22+
KEEP(trailer*(.rodata*))
23+
} >FLASH
24+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy