为何我实现的MASM32 32位校验和宏的Dart版本运行结果不正确?
问题分析与修复方案
原始MASM32校验和逻辑拆解
原始宏的运算规则整理如下:
- 输入为字节流、字节长度,返回32位无符号整数校验和
- 初始化校验值为0,若输入长度小于4直接返回0
- 每次从输入流读取4字节小端序(x86默认)双字(DWORD)参与运算:
- 校验值 += 当前双字,结果按32位无符号截断
- 当前双字左移1位,移出的最高位作为进位,通过
adc指令把进位+1加到左移后的结果上 - 校验值异或上一步得到的变换结果,按32位无符号截断
- 若最终剩余不足4字节,将输入指针回退到「总长度-4」的位置,凑够4字节再执行一次上述运算后结束
现有代码核心错误
- 字节序完全错误:x86读取4字节双字是小端序,你写的
fusion函数按输入顺序从左到右拼接16进制字符串,得到的是大端序数值,和汇编逻辑完全相反 - 进位计算逻辑错误:
adc ebx,1的进位是双字左移1位时移出的第31位,不是你理解的单字节最高位,转字符串取首位的逻辑完全不对 - 循环条件错误:
while(i < src.length-4)会跳过长度恰好为4的输入的唯一一次循环,直接返回0 - 无32位截断处理:Dart的int默认是64位,所有位运算、加减运算后没有做32位无符号截断,结果会溢出预期范围
- 剩余字节处理缺失:没有实现汇编中不足4字节时凑4字节重算最后一次的逻辑
修复后的正确实现
import 'dart:convert'; import 'dart:io'; int checksum32(List<int> bytes) { int len = bytes.length; int checksum = 0; if (len < 4) return checksum & 0xFFFFFFFF; int i = 0; while (true) { // 取4字节小端序拼DWORD int dword = bytes[i] | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); dword &= 0xFFFFFFFF; // 对应汇编 add eax, ebx checksum = (checksum + dword) & 0xFFFFFFFF; // 对应shl ebx,1 + adc ebx,1 int carry = (dword >> 31) & 1; int transform = ((dword << 1) & 0xFFFFFFFF) + carry + 1; transform &= 0xFFFFFFFF; // 对应xor eax, ebx checksum = (checksum ^ transform) & 0xFFFFFFFF; i += 4; if (i >= len) break; // 剩余不足4字节,调整i到len-4,最后跑一次 if (len - i < 4) { i = len - 4; } } return checksum & 0xFFFFFFFF; } // 调用示例 void main() { String input = File("你的文件路径").readAsStringSync(); // 字符串转字节流,注意和汇编输入的编码一致,汇编如果是ASCII就用ascii.encode,是utf8就用utf8.encode List<int> bytes = utf8.encode(input); print(checksum32(bytes)); }
注意事项
- 输入字节流的编码要和汇编场景完全一致,汇编如果处理的是GBK等其他编码的字符串,Dart侧也要转成对应编码的字节流再计算,否则结果必然不一致
- 如果你的场景确定输入长度永远是4的倍数,可以删除剩余字节处理的分支,进一步简化代码
内容的提问来源于stack exchange,提问作者Gaiusfr
相关产品推荐
相关产品推荐

