- stb文件格式.md:288 字节真实拆解(头 104 含型号标识 STATOR1@0x48、函数表 0x68、 代码 0x80 fn0 RET=0x21、数据段 0xC8 7 槽、SHA-256 尾 0x100);工具验证与执行器关系更新 - STCompiler使用说明.md:--machine 参数(编译/disasm 必填、打印模式不需要)、 .stb 加固说明、288 字节示例、当前状态(可编译+可执行+配置驱动) - 执行器入口.md:读取时型号/SHA 校验拒绝 - ctest 14/14 全绿
6.7 KiB
.stb 映像文件结构
编译产物 .stb 的面向使用者的结构说明。规范以 指令与映像.md 为准,本文用 line1.stb(288 字节,12.13 修订后)做真实拆解。
概览
- 魔数
STSC,版本1,全部整数小端 - 文件 = 头 + 五个段,段序:常量表 → 函数表 → 字节码 → FB 布局 → 数据
- 段偏移记在头里;
offset_const ≤ offset_funcs ≤ offset_code ≤ offset_fb ≤ offset_data ≤ 文件长度
┌──────────────────────────────────────────────────┐
│ 头(104 字节,偏移 0,含型号标识[32]) │
├──────────────────────────────────────────────────┤
│ 常量表段 offset_const .. offset_funcs │
├──────────────────────────────────────────────────┤
│ 函数表段 offset_funcs .. offset_code │
├──────────────────────────────────────────────────┤
│ 字节码段 offset_code .. offset_fb │
├──────────────────────────────────────────────────┤
│ FB 布局段 offset_fb .. offset_data(v1 为空)│
├──────────────────────────────────────────────────┤
│ 数据段 offset_data .. offset_data+len │
├──────────────────────────────────────────────────┤
│ SHA-256 文件尾(32 字节,对文件尾之前全部内容) │
└──────────────────────────────────────────────────┘
头(104 字节)
| 偏移 | 宽 | 字段 | line1 实际值 |
|---|---|---|---|
| 0 | 4 | 魔数 STSC |
53 53 54 43 |
| 4 | 4 | 版本 1 |
1 |
| 8 | 4 | cycle_limit(每周期指令上限) |
100000 |
| 12 | 4 | dt_ms(本周期 Δt) |
10 |
| 16 | 8 | 工程哈希(FNV-1a 64) | 0xc3fe4ae74ad45900 |
| 24 | 4 | 入口 entry_fn_id |
1(MAIN) |
| 28 | 4 | 全局槽数 n_globals |
4 |
| 32 | 4 | I 槽数 n_i |
0(v1 不拆) |
| 36 | 4 | Q 槽数 n_q |
0 |
| 40 | 4 | M 槽数 n_m |
0 |
| 44 | 4 | 常量数 n_consts |
0 |
| 48 | 4 | 函数数 n_funcs |
2 |
| 52 | 4 | offset_const |
104(0x68) |
| 56 | 4 | offset_funcs |
104 |
| 60 | 4 | offset_code |
128(0x80) |
| 64 | 4 | offset_fb |
200(0xC8) |
| 68 | 4 | offset_data |
200 |
| 72 | 32 | 型号标识(定长 ASCII 含版本,补 '\0') |
"STATOR1"(0x48..0x67) |
12.13 修订:型号标识由
machine.toml [meta] name + version拼成(如STATOR + 1→"STATOR1"); 执行器读取时型号不匹配 → 直接报错。
常量表段(offset_const 起)
一行 12 字节:[tag:u32][value:u64];tag:0=BOOL、1=INT、2=TIME。
line1 无字面量常量 → 段为空(offset_const == offset_funcs)。
函数表段(offset_funcs 起)
一行 12 字节:[nregs:u32][code_offset:u32][code_len:u32]
- 行下标即
fn_id;code_offset相对字节码段起点(字节);code_len为指令条数 - 入口 = 头的
entry_fn_id指向的行
line1(2 行):
| fn_id | nregs | code_offset | code_len | 内容 |
|---|---|---|---|---|
| 0 | 8 | 0 | 1 | MotorStarter 占位(内联展开,仅 RET) |
| 1 | 13 | 4 | 17 | MAIN |
字节码段(offset_code 起)
指令 4 字节一条:[op:8 | rd:8 | a:8 | b:8](小端 u32)。
rd目的寄存器;a|b视操作码为寄存器、槽号(u16)或跳转偏移(有符号 int16,相对下一条指令:目标 = 当前 + 1 + off)CALL的fn_id= 函数表行下标- 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起
line1 MAIN 前 5 条(0x84 起;0x80 是 fn 0 的占位 RET,slot 为 8 字节定宽槽号):
| 偏移 | 字节 | 反汇编 | 含义 |
|---|---|---|---|
| 0x84 | 12 08 01 00 |
LOAD_I r8, 1 |
I0_0(io.input 绑定 → LOAD_I,槽 1) |
| 0x88 | 17 08 04 00 |
STORE_GLOBAL r8, 4 |
starter.start(槽 4)← I0_0 |
| 0x8C | 16 09 02 00 |
LOAD_GLOBAL r9, 2 |
I0_1(槽 2) |
| 0x90 | 17 09 05 00 |
STORE_GLOBAL r9, 5 |
starter.stop(槽 5)← I0_1 |
| 0x94 | 16 08 04 00 |
LOAD_GLOBAL r8, 4 |
内联体:读 starter.start(槽 4) |
FB 布局段(offset_fb 起)
v1 为空(用户 FB 内联展开,字段偏移已算进数据段;内建 8 个 FB 布局冻结在编译器中(12.11 扩充))。行格式约定:[field_count:u32][field_count × (tag:u32, offset:u32)],offset 相对实例基址。
数据段(offset_data 起)
每槽 8 字节定宽(12.9 方案 a):BOOL 用低 1 字节、INT 用低 2 字节(小端)、TIME 全 8 字节。指令 slot 操作数即槽号,数据偏移 = 槽号 × 8。
槽序:全局块(n_globals 个,声明序)→ FB 实例块(POU 收集序、实例声明序,每字段一槽)。
line1 数据段(56 字节 = 7 槽 × 8B,0xC8 起):
| 槽号 | 偏移 | 内容 |
|---|---|---|
| 0 | 0xC8 | EmergencyStop(BOOL,初值 0) |
| 1 | 0xD0 | I0_0(BOOL) |
| 2 | 0xD8 | I0_1(BOOL) |
| 3 | 0xE0 | Q0_0(BOOL) |
| 4 | 0xE8 | starter.start(BOOL) |
| 5 | 0xF0 | starter.stop(BOOL) |
| 6 | 0xF8 | starter.q(BOOL) |
SHA-256 文件尾(32 字节)
数据段之后追加 32 字节 SHA-256:对文件尾之前全部内容计算(0x100..0x11F)。执行器必须校验通过才运行;任一字节被篡改 → 直接拒绝。compiler 写侧与 vm 读侧各自实现一份 SHA-256。
用工具验证
ctest:codegen_slice1(写侧 model/sha 自检)、vm_cycles(读侧型号/SHA 拒绝)、machine_configSTCompiler x.stb --disasm --machine machine.toml:显示model=与sha=ok|BAD- 手工检查:
xxd line1.stb对照上表逐段核对
与执行器的关系
BytecodeExecutor 只读本格式:头(cycle_limit/dt_ms/型号标识)、函数表(帧 nregs + 代码定位)、数据段(全局 + FB 实例状态)。读取时型号匹配 + SHA-256 校验,任一不符 → 报错拒绝。I/O 绑定不在映像里,在 sidecar <name>.runtime.toml(var → 槽号 → channel/bit)。