Files
Interpreter/Doc/isa/stb文件格式.md
T
Admin 0ebf193ff9 阶段 D 步骤 11:文档同步 + 提交(指令配置全流程收尾)。
- 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 全绿
2026-08-21 22:35:20 +08:00

6.7 KiB
Raw Permalink Blame History

.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_datav1 为空)│
├──────────────────────────────────────────────────┤
│ 数据段    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 1MAIN
28 4 全局槽数 n_globals 4
32 4 I 槽数 n_i 0v1 不拆)
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 1040x68
56 4 offset_funcs 104
60 4 offset_code 1280x80
64 4 offset_fb 2000xC8
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]tag0=BOOL、1=INT、2=TIME。

line1 无字面量常量 → 段为空(offset_const == offset_funcs)。

函数表段(offset_funcs 起)

一行 12 字节:[nregs:u32][code_offset:u32][code_len:u32]

  • 行下标即 fn_idcode_offset 相对字节码段起点(字节);code_len指令条数
  • 入口 = 头的 entry_fn_id 指向的行

line12 行):

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
  • CALLfn_id = 函数表行下标
  • 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起

line1 MAIN 前 5 条(0x84 起;0x80fn 0 的占位 RETslot 为 8 字节定宽槽号):

偏移 字节 反汇编 含义
0x84 12 08 01 00 LOAD_I r8, 1 I0_0io.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 EmergencyStopBOOL,初值 0
1 0xD0 I0_0BOOL
2 0xD8 I0_1BOOL
3 0xE0 Q0_0BOOL
4 0xE8 starter.startBOOL
5 0xF0 starter.stopBOOL
6 0xF8 starter.qBOOL

SHA-256 文件尾(32 字节)

数据段之后追加 32 字节 SHA-256:对文件尾之前全部内容计算0x100..0x11F)。执行器必须校验通过才运行;任一字节被篡改 → 直接拒绝。compiler 写侧与 vm 读侧各自实现一份 SHA-256。

用工具验证

  • ctestcodegen_slice1(写侧 model/sha 自检)、vm_cycles(读侧型号/SHA 拒绝)、machine_config
  • STCompiler 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.tomlvar → 槽号 → channel/bit)。