FFI 调用链路

从 VML 程序到原生动态库的完整调用路径

1
VML 程序CALL gl_setup
↓ VML 库函数执行 ↓
2
SYSCALL #370dl_open("libglhelper.dylib")
↓ 加载动态库,返回 handle ↓
3
SYSCALL #371dl_sym(handle, "glh_init")
↓ 查找函数指针,存入 func_id ↓
4
SYSCALL #373 native_call / #375 native_call_f
↓ 调用原生函数 (int 参数用 #373, float 参数用 #375) ↓
5
原生 .dylib / .so / .dll

FFI 相关 SYSCALL 参考

SYSCALL编号功能参数返回
dl_open#370加载动态库R0 = 库路径字符串地址R0 = handle (非0成功)
dl_sym#371查找函数符号R0 = handle, R1 = 函数名字符串地址R0 = func_ptr_id
dl_close#372卸载动态库R0 = handle—
native_call#373调用原生函数 (int 参数)R0 = func_id, R1 = args_addr, R2 = arg_count, R3 = flagsR0 = int 返回值
native_call_0#374调用无参原生函数R0 = func_idR0 = 返回值
native_call_f#375调用原生函数 (float 参数)R0 = func_id, R1 = args_addr, R2 = arg_count, R3 = flagsR0 = float 的 int32 位模式

native_call (#373) — 整数参数原生调用

支持 int/指针 参数传递,最多 8 个参数

寄存器约定

寄存器含义说明
R0func_ptr_id通过 dl_sym 获取的函数指针 ID
R1args_addrVML 内存中参数数组地址(每个参数 4 字节)
R2arg_count参数数量(最大 8)
R3flags0 = int 返回, 1 = void 返回

使用示例:调用 glh_init(640, 480, title)

; 1. 准备参数数组 (每个参数 4 字节)
MOVE R0, #640
STORE [R12-4], R0       ; arg[0] = 640 (宽度)
MOVE R0, #480
STORE [R12-8], R0       ; arg[1] = 480 (高度)
LOAD R0, title_str
STORE [R12-12], R0      ; arg[2] = title 指针

; 2. 调用 native_call
LOAD R0, [R12+glh_init_id]  ; func_ptr_id
LOAD R1, R12
SUB R1, #12                 ; args_addr = R12-12
MOVE R2, #3                 ; 3 个参数
MOVE R3, #1                 ; void 返回
SYSCALL #373                 ; native_call

native_call_f (#375) — Float 参数原生调用

为 OpenGL 函数 (glRotatef, glVertex3f 等) 设计的 float 参数调用接口

寄存器约定

寄存器含义说明
R0func_ptr_id通过 dl_sym 获取的函数指针 ID
R1args_addrVML 内存中参数数组地址(每个参数 4 字节 float 位模式)
R2arg_count参数数量(最大 8)
R3flags0 = float 返回, 1 = void 返回

使用示例:调用 glh_rotatef(angle, x, y, z)

; 1. 准备 float 参数 (使用 FSTORE 或手动构造位模式)
FLOAD F0, #0.5              ; angle = 0.5 弧度
FSTORE [R12-4], F0
FLOAD F0, #1.0
FSTORE [R12-8], F0          ; x = 1.0
FLOAD F0, #0.0
FSTORE [R12-12], F0         ; y = 0.0
FLOAD F0, #0.0
FSTORE [R12-16], F0         ; z = 0.0

; 2. 调用 native_call_f
LOAD R0, [R12+glh_rotatef_id]
LOAD R1, R12
SUB R1, #16                 ; args_addr
MOVE R2, #4                 ; 4 个 float 参数
MOVE R3, #1                 ; void 返回
SYSCALL #375                 ; native_call_f

实现细节

  • 从 VML 内存读取 int32 → BitConverter.Int32BitsToSingle → float
  • 调用 float 委托(CLR 正确将 float 放入 SSE/V 寄存器)
  • float 返回值 → BitConverter.SingleToInt32Bits → 存入 R0
  • 仅 OS 模式可用

OpenGL 旋转立方体 — 完整示例

22 种语言调用同一个 VML FFI 封装库,实现 OpenGL 旋转立方体

架构:原生库 → VML 封装 → 22 语言

原生层
libglhelper.c → libglhelper.dylib
导出: glh_init / glh_clear / glh_begin / glh_color3f / glh_vertex3f / glh_rotatef / glh_end / glh_swap / glh_should_close / glh_get_time / glh_destroy / glh_draw_cube
↓ dl_open + dl_sym + native_call/native_call_f ↓
VML 封装
opengl_lib.vml
导出标签别名: gl_setup / func_gl_setup / sub_gl_setup / word_gl_setup / method_gl_setup / LADDER_GL_SETUP
↓ CALL gl_setup / CALL gl_frame / CALL gl_teardown ↓
22 语言
.c.bas.pas .py.lua.fth .rs.go.ld .java.js.cs .swift.cpp.kt .scm.rb.dart .m.r.d.f90

各语言调用代码(零 asm,纯原生语法)

C
BASIC
Pascal
Rust
Python
Go
void gl_setup();
int  gl_should_close();
void gl_frame();
void gl_teardown();

int main() {
    gl_setup();
    while (!gl_should_close())
        gl_frame();
    gl_teardown();
}
DECLARE SUB gl_setup
DECLARE FUNCTION gl_should_close
DECLARE SUB gl_frame
DECLARE SUB gl_teardown

CALL gl_setup
WHILE gl_should_close() = 0
    CALL gl_frame
WEND
CALL gl_teardown
program CubeDemo;
procedure gl_setup; forward;
function gl_should_close: integer; forward;
procedure gl_frame; forward;
procedure gl_teardown; forward;

begin
    gl_setup;
    while gl_should_close = 0 do
        gl_frame;
    gl_teardown;
end.
fn main() {
    gl_setup();
    while gl_should_close() == 0 {
        gl_frame();
    }
    gl_teardown();
}
def gl_setup():
    asm("CALL gl_setup_impl")
def gl_frame():
    asm("CALL gl_frame_impl")
def gl_teardown():
    asm("CALL gl_teardown_impl")

gl_setup()
for _ in range(2000):
    gl_frame()
gl_teardown()

Python 编译器限制: def 内需要 asm 桥接到库标签,主代码调用正常

package main
func main() {
    gl_setup()
    for {
        if gl_should_close() != 0 {
            break
        }
        gl_frame()
    }
    gl_teardown()
}

跨语言兼容性表

语言零 asm 调用标签别名说明
C / C++ / Rust / Go / BASIC / Swift / Kotlin / JS / Scheme✅gl_setup 或 func_gl_setup直接调用,无需声明
Pascal / C# / Java✅gl_setup / method_gl_setup需要 forward/extern 声明
Lua✅func_gl_setup编译器自动添加 func_ 前缀
Python⚠️gl_setup_impldef 内需 asm 桥接,主代码正常
Forth✅word_gl_setup编译器自动添加 word_ 前缀
Ladder⚠️LADDER_GL_SETUP需 ASM 块,梯形图语言限制

编译原生辅助库

如何编写和编译供 VML FFI 调用的原生 C 库

libglhelper.c 核心 API

// 纯 float/int 参数,无结构体,便于 FFI 调用
void* glh_init(int w, int h, const char* title);
void  glh_clear(float r, float g, float b, float a);
void  glh_begin(int mode);
void  glh_color3f(float r, float g, float b);
void  glh_vertex3f(float x, float y, float z);
void  glh_rotatef(float angle, float x, float y, float z);
void  glh_translatef(float x, float y, float z);
void  glh_end();
void  glh_swap();
int   glh_should_close();
float glh_get_time();
void  glh_destroy();
void  glh_draw_cube(float time);

编译命令

# macOS — 编译为动态库
cc -shared -o Lib/opengl/libglhelper.dylib Lib/opengl/libglhelper.c \
   -framework OpenGL -framework GLFW \
   -I/opt/homebrew/include -L/opt/homebrew/lib

# Linux
cc -shared -fPIC -o Lib/opengl/libglhelper.so Lib/opengl/libglhelper.c \
   -lGL -lglfw

# 然后编译 VML 程序并运行
vmltool Examples/OpenGL/cube_c.c -o cube_c.vml --mode os
consoleemulator -r cube_c.vml --mode os