diff --git a/compiler/include/compiler/Stb.h b/compiler/include/compiler/Stb.h index 0143493..42c3bc6 100644 --- a/compiler/include/compiler/Stb.h +++ b/compiler/include/compiler/Stb.h @@ -40,6 +40,42 @@ namespace compiler { /// FNV-1a 64 哈希素数。 static const uint64_t kFnvPrime = 0x100000001b3ull; + // ---- 头字段偏移(与 Doc/isa/指令与映像.md 字段表一致;vm 侧另有同值一份)---- + inline constexpr size_t kOffMagic = 0; ///< 魔数 "STSC" + inline constexpr size_t kOffVersion = 4; ///< 格式版本 + inline constexpr size_t kOffCycleLimit = 8; ///< 每周期指令数上限 + inline constexpr size_t kOffDtMs = 12; ///< 周期时长(毫秒) + inline constexpr size_t kOffProjectHash = 16; ///< 工程哈希(8 字节) + inline constexpr size_t kOffEntryFnId = 24; ///< 入口函数 fn_id + inline constexpr size_t kOffNGlobals = 28; ///< 全局槽数 + inline constexpr size_t kOffNI = 32; ///< 输入(I)槽数 + inline constexpr size_t kOffNQ = 36; ///< 输出(Q)槽数 + inline constexpr size_t kOffNM = 40; ///< 中间(M)槽数 + inline constexpr size_t kOffNConsts = 44; ///< 常量表条目数 + inline constexpr size_t kOffNFuncs = 48; ///< 函数表行数 + inline constexpr size_t kOffConst = 52; ///< 常量表段偏移 + inline constexpr size_t kOffFuncs = 56; ///< 函数表段偏移 + inline constexpr size_t kOffCode = 60; ///< 字节码段偏移 + inline constexpr size_t kOffFb = 64; ///< FB 表段偏移 + inline constexpr size_t kOffData = 68; ///< 数据段偏移 + inline constexpr size_t kOffModelId = 72; ///< 型号标识[32](12.13 修订) + + // ---- 段内行偏移 ---- + inline constexpr size_t kConstTagOff = 0; ///< 常量表行内:tag + inline constexpr size_t kConstValueOff = 4; ///< 常量表行内:value(8 字节) + inline constexpr size_t kFuncNregsOff = 0; ///< 函数表行内:nregs + inline constexpr size_t kFuncCodeOff = 4; ///< 函数表行内:code_offset(字节) + inline constexpr size_t kFuncLenOff = 8; ///< 函数表行内:code_len(指令条数) + + // 防漂移:头布局自洽性(与 Doc/isa/指令与映像.md 冻结表核对) + static_assert(kHeaderSize == kOffModelId + kModelIdSize, "header size = 72 + model id[32]"); + static_assert(kOffData > kOffFb && kOffFb > kOffCode && kOffCode > kOffFuncs && + kOffFuncs > kOffConst, + "header field offsets monotonic"); + static_assert(kOffModelId == kOffData + 4, "model id follows data offset field"); + static_assert(kConstEntrySize == kConstValueOff + 8, "const row: tag + value:8"); + static_assert(kFuncRowSize == kFuncLenOff + 4, "func row: nregs/code_offset/code_len"); + /** * @brief 常量表一行。 * @details tag 契约:0=BOOL、1=INT、2=TIME。 diff --git a/compiler/src/Codegen.cpp b/compiler/src/Codegen.cpp index 721a6d2..620a7a3 100644 --- a/compiler/src/Codegen.cpp +++ b/compiler/src/Codegen.cpp @@ -847,16 +847,16 @@ namespace { std::vector& b = *image_; b.assign(off_end, 0); - put_le32(b, 0, kMagic); - put_le32(b, 4, kVersion); - put_le32(b, 8, proj_.cycle_limit); - put_le32(b, 12, proj_.dt_ms); + put_le32(b, kOffMagic, kMagic); + put_le32(b, kOffVersion, kVersion); + put_le32(b, kOffCycleLimit, proj_.cycle_limit); + put_le32(b, kOffDtMs, proj_.dt_ms); uint64_t hash = kFnvBasis; if (!compute_project_hash(proj_, &hash, err_)) { return false; } - put_le64(b, 16, hash); + put_le64(b, kOffProjectHash, hash); uint32_t entry = 0; for (size_t i = 0; i < funcs_.size(); ++i) { @@ -864,38 +864,38 @@ namespace { entry = static_cast(i); } } - put_le32(b, 24, entry); - put_le32(b, 28, static_cast(link_.globals.size())); - put_le32(b, 32, 0); - put_le32(b, 36, 0); - put_le32(b, 40, 0); - put_le32(b, 44, static_cast(consts_.size())); - put_le32(b, 48, static_cast(funcs_.size())); - put_le32(b, 52, off_const); - put_le32(b, 56, off_funcs); - put_le32(b, 60, off_code); - put_le32(b, 64, off_data); - put_le32(b, 68, off_data); + put_le32(b, kOffEntryFnId, entry); + put_le32(b, kOffNGlobals, static_cast(link_.globals.size())); + put_le32(b, kOffNI, 0); + put_le32(b, kOffNQ, 0); + put_le32(b, kOffNM, 0); + put_le32(b, kOffNConsts, static_cast(consts_.size())); + put_le32(b, kOffNFuncs, static_cast(funcs_.size())); + put_le32(b, kOffConst, off_const); + put_le32(b, kOffFuncs, off_funcs); + put_le32(b, kOffCode, off_code); + put_le32(b, kOffFb, off_data); + put_le32(b, kOffData, off_data); // 型号标识[32](偏移 72;12.13 修订) char mid[kModelIdSize]; fill_model_id(cfg_.model_name(), cfg_.version(), mid); for (size_t i = 0; i < kModelIdSize; ++i) { - b[72 + i] = static_cast(mid[i]); + b[kOffModelId + i] = static_cast(mid[i]); } for (size_t i = 0; i < consts_.size(); ++i) { const size_t o = off_const + i * kConstEntrySize; - put_le32(b, o, consts_[i].tag); - put_le64(b, o + 4, consts_[i].value); + put_le32(b, o + kConstTagOff, consts_[i].tag); + put_le64(b, o + kConstValueOff, consts_[i].value); } uint32_t c = off_code; for (size_t i = 0; i < funcs_.size(); ++i) { const FuncCtx& f = funcs_[i]; const size_t o = off_funcs + i * kFuncRowSize; - put_le32(b, o, f.nregs); - put_le32(b, o + 8, static_cast(f.code.size())); + put_le32(b, o + kFuncNregsOff, f.nregs); + put_le32(b, o + kFuncLenOff, static_cast(f.code.size())); for (const Instr in : f.code) { put_le32(b, c, in); c += 4; @@ -904,7 +904,7 @@ namespace { uint32_t acc = 0; for (size_t i = 0; i < funcs_.size(); ++i) { const size_t o = off_funcs + i * kFuncRowSize; - put_le32(b, o + 4, acc); + put_le32(b, o + kFuncCodeOff, acc); acc += static_cast(funcs_[i].code.size()) * 4; } diff --git a/compiler/src/Stb.cpp b/compiler/src/Stb.cpp index 75a85e2..2dd8923 100644 --- a/compiler/src/Stb.cpp +++ b/compiler/src/Stb.cpp @@ -243,31 +243,31 @@ StbView StbView::from(const uint8_t* buf, size_t len) { v.err_ = "image too short"; return v; } - if (get_le32(buf + 0) != kMagic) { + if (get_le32(buf + kOffMagic) != kMagic) { v.err_ = "bad magic"; return v; } - if (get_le32(buf + 4) != kVersion) { + if (get_le32(buf + kOffVersion) != kVersion) { v.err_ = "bad version"; return v; } - v.cycle_limit_ = get_le32(buf + 8); - v.dt_ms_ = get_le32(buf + 12); - v.project_hash_ = get_le64(buf + 16); - v.entry_fn_id_ = get_le32(buf + 24); - v.n_globals_ = get_le32(buf + 28); - v.n_consts_ = get_le32(buf + 44); - v.n_funcs_ = get_le32(buf + 48); - v.offset_code_ = get_le32(buf + 60); - v.offset_fb_ = get_le32(buf + 64); - v.offset_data_ = get_le32(buf + 68); + v.cycle_limit_ = get_le32(buf + kOffCycleLimit); + v.dt_ms_ = get_le32(buf + kOffDtMs); + v.project_hash_ = get_le64(buf + kOffProjectHash); + v.entry_fn_id_ = get_le32(buf + kOffEntryFnId); + v.n_globals_ = get_le32(buf + kOffNGlobals); + v.n_consts_ = get_le32(buf + kOffNConsts); + v.n_funcs_ = get_le32(buf + kOffNFuncs); + v.offset_code_ = get_le32(buf + kOffCode); + v.offset_fb_ = get_le32(buf + kOffFb); + v.offset_data_ = get_le32(buf + kOffData); // 段校验(12.13:文件尾 SHA-256[32] 在数据段之后) if (len < static_cast(v.offset_data_) + kSha256Size) { v.err_ = "missing sha256 tail"; return v; } - const uint64_t offs[5] = {get_le32(buf + 52), get_le32(buf + 56), v.offset_code_, + const uint64_t offs[5] = {get_le32(buf + kOffConst), get_le32(buf + kOffFuncs), v.offset_code_, v.offset_fb_, v.offset_data_}; for (int i = 0; i < 5; ++i) { if (offs[i] < kHeaderSize || offs[i] > len - kSha256Size) { @@ -311,7 +311,7 @@ ConstEntry StbView::const_entry(size_t i) const { if (ok_ && i < n_consts_) { const uint8_t* p = buf_ + offs_of_const() + i * kConstEntrySize; e.tag = get_le32(p); - e.value = get_le64(p + 4); + e.value = get_le64(p + kConstValueOff); } return e; } @@ -327,9 +327,9 @@ StbView::FuncRow StbView::func_row(size_t i) const { FuncRow r; if (ok_ && i < n_funcs_) { const uint8_t* p = buf_ + get_le32(buf_ + 56) + i * kFuncRowSize; - r.nregs = get_le32(p + 0); - r.code_offset = get_le32(p + 4); - r.code_len = get_le32(p + 8); + r.nregs = get_le32(p + kFuncNregsOff); + r.code_offset = get_le32(p + kFuncCodeOff); + r.code_len = get_le32(p + kFuncLenOff); } return r; } @@ -359,7 +359,7 @@ std::string StbView::model_id() const { if (!ok_) { return ""; } - std::string s(reinterpret_cast(buf_ + 72), kModelIdSize); + std::string s(reinterpret_cast(buf_ + kOffModelId), kModelIdSize); const size_t z = s.find('\0'); if (z != std::string::npos) { s.resize(z); @@ -371,7 +371,7 @@ std::string StbView::model_id() const { bool StbView::model_matches(const std::string& name, uint32_t version) const { char want[kModelIdSize]; fill_model_id(name, version, want); - return std::memcmp(buf_ + 72, want, kModelIdSize) == 0; + return std::memcmp(buf_ + kOffModelId, want, kModelIdSize) == 0; } /// 文件尾 32 字节 SHA-256 校验(对文件尾之前全部内容重算;未 ok() 时返回 false)。 diff --git a/vm/src/Image.cpp b/vm/src/Image.cpp index 66bb53f..3bc49a9 100644 --- a/vm/src/Image.cpp +++ b/vm/src/Image.cpp @@ -29,6 +29,42 @@ namespace { /// 型号标识长度(头内 @72,不足补 '\0')。 const size_t kModelIdSize = 32; + // ---- 头字段偏移(与 Doc/isa/指令与映像.md 字段表一致;compiler 侧另有同值一份)---- + constexpr size_t kOffMagic = 0; ///< 魔数 "STSC" + constexpr size_t kOffVersion = 4; ///< 格式版本 + constexpr size_t kOffCycleLimit = 8; ///< 每周期指令数上限 + constexpr size_t kOffDtMs = 12; ///< 周期时长(毫秒) + constexpr size_t kOffProjectHash = 16; ///< 工程哈希(8 字节) + constexpr size_t kOffEntryFnId = 24; ///< 入口函数 fn_id + constexpr size_t kOffNGlobals = 28; ///< 全局槽数 + constexpr size_t kOffNI = 32; ///< 输入(I)槽数 + constexpr size_t kOffNQ = 36; ///< 输出(Q)槽数 + constexpr size_t kOffNM = 40; ///< 中间(M)槽数 + constexpr size_t kOffNConsts = 44; ///< 常量表条目数 + constexpr size_t kOffNFuncs = 48; ///< 函数表行数 + constexpr size_t kOffConst = 52; ///< 常量表段偏移 + constexpr size_t kOffFuncs = 56; ///< 函数表段偏移 + constexpr size_t kOffCode = 60; ///< 字节码段偏移 + constexpr size_t kOffFb = 64; ///< FB 表段偏移 + constexpr size_t kOffData = 68; ///< 数据段偏移 + constexpr size_t kOffModelId = 72; ///< 型号标识[32](12.13 修订) + + // ---- 段内行偏移 ---- + constexpr size_t kConstTagOff = 0; ///< 常量表行内:tag + constexpr size_t kConstValueOff = 4; ///< 常量表行内:value(8 字节) + constexpr size_t kFuncNregsOff = 0; ///< 函数表行内:nregs + constexpr size_t kFuncCodeOff = 4; ///< 函数表行内:code_offset(字节) + constexpr size_t kFuncLenOff = 8; ///< 函数表行内:code_len(指令条数) + + // 防漂移:头布局自洽性(与 Doc/isa/指令与映像.md 冻结表核对) + static_assert(kHeaderSize == kOffModelId + kModelIdSize, "header size = 72 + model id[32]"); + static_assert(kOffData > kOffFb && kOffFb > kOffCode && kOffCode > kOffFuncs && + kOffFuncs > kOffConst, + "header field offsets monotonic"); + static_assert(kOffModelId == kOffData + 4, "model id follows data offset field"); + static_assert(kConstEntrySize == kConstValueOff + 8, "const row: tag + value:8"); + static_assert(kFuncRowSize == kFuncLenOff + 4, "func row: nregs/code_offset/code_len"); + /// 小端读 32 位。 uint32_t get_le32(const uint8_t* p) { return static_cast(p[0]) @@ -214,30 +250,30 @@ Image Image::from(const uint8_t* buf, size_t len) { v.err_ = "image too short"; return v; } - if (get_le32(buf + 0) != kMagic) { + if (get_le32(buf + kOffMagic) != kMagic) { v.err_ = "bad magic"; return v; } - if (get_le32(buf + 4) != kVersion) { + if (get_le32(buf + kOffVersion) != kVersion) { v.err_ = "bad version"; return v; } ImageHeader& h = v.hdr_; - h.cycle_limit = get_le32(buf + 8); - h.dt_ms = get_le32(buf + 12); - h.project_hash = get_le64(buf + 16); - h.entry_fn_id = get_le32(buf + 24); - h.n_globals = get_le32(buf + 28); - h.n_i = get_le32(buf + 32); - h.n_q = get_le32(buf + 36); - h.n_m = get_le32(buf + 40); - h.n_consts = get_le32(buf + 44); - h.n_funcs = get_le32(buf + 48); - h.offset_const = get_le32(buf + 52); - h.offset_funcs = get_le32(buf + 56); - h.offset_code = get_le32(buf + 60); - h.offset_fb = get_le32(buf + 64); - h.offset_data = get_le32(buf + 68); + h.cycle_limit = get_le32(buf + kOffCycleLimit); + h.dt_ms = get_le32(buf + kOffDtMs); + h.project_hash = get_le64(buf + kOffProjectHash); + h.entry_fn_id = get_le32(buf + kOffEntryFnId); + h.n_globals = get_le32(buf + kOffNGlobals); + h.n_i = get_le32(buf + kOffNI); + h.n_q = get_le32(buf + kOffNQ); + h.n_m = get_le32(buf + kOffNM); + h.n_consts = get_le32(buf + kOffNConsts); + h.n_funcs = get_le32(buf + kOffNFuncs); + h.offset_const = get_le32(buf + kOffConst); + h.offset_funcs = get_le32(buf + kOffFuncs); + h.offset_code = get_le32(buf + kOffCode); + h.offset_fb = get_le32(buf + kOffFb); + h.offset_data = get_le32(buf + kOffData); // 段校验(数据段之后是 SHA-256 文件尾;这里仅保证有尾,sha_ok() 做完整性校验) if (len < static_cast(h.offset_data) + kSha256Size) { @@ -295,9 +331,9 @@ FuncRow Image::func_row(size_t i) const { FuncRow r; if (ok_ && i < hdr_.n_funcs) { const uint8_t* p = buf_ + hdr_.offset_funcs + i * kFuncRowSize; - r.nregs = get_le32(p + 0); - r.code_offset = get_le32(p + 4); - r.code_len = get_le32(p + 8); + r.nregs = get_le32(p + kFuncNregsOff); + r.code_offset = get_le32(p + kFuncCodeOff); + r.code_len = get_le32(p + kFuncLenOff); } return r; } @@ -311,8 +347,8 @@ ConstEntry Image::const_entry(size_t i) const { ConstEntry e; if (ok_ && i < hdr_.n_consts) { const uint8_t* p = buf_ + hdr_.offset_const + i * kConstEntrySize; - e.tag = get_le32(p); - e.value = get_le64(p + 4); + e.tag = get_le32(p + kConstTagOff); + e.value = get_le64(p + kConstValueOff); } return e; } @@ -349,7 +385,7 @@ std::string Image::model_id() const { if (!ok_) { return ""; } - std::string s(reinterpret_cast(buf_ + 72), kModelIdSize); + std::string s(reinterpret_cast(buf_ + kOffModelId), kModelIdSize); const size_t z = s.find('\0'); if (z != std::string::npos) { s.resize(z); @@ -366,7 +402,7 @@ std::string Image::model_id() const { bool Image::model_matches(const std::string& name, uint32_t version) const { char want[kModelIdSize]; fill_model_id(name, version, want); - return std::memcmp(buf_ + 72, want, kModelIdSize) == 0; + return std::memcmp(buf_ + kOffModelId, want, kModelIdSize) == 0; } /**