为什么我的 asm 校验和宏的 Dart 实现不起作用?

Why my Dart implementation of an asm checksum macro does not work?

我正在尝试为 Dart 语言实现一个用 masm32 编写的 32 位校验和宏。 这是我的理解:校验和函数将字符串作为输入,returns 校验和为 4 字节整数。 但我没有得到相同的结果。 请问有人看到我的错误吗?

; ecx : length of String variable
; esi : pointer to String variable
; eax : 'return' value of calculated checksum
CHECKSUM32_MACRO MACRO 
   LOCAL Checksum32Loop, Checksum32Done       
        xor     eax,eax
        cmp     ecx,4
        jb      Checksum32Done
    align 16
    Checksum32Loop:
        mov     ebx,dword ptr [esi]
        add     eax,ebx
        shl     ebx,1
        adc     ebx,1
        xor     eax,ebx
        add     esi,4
        sub     ecx,4
        jz      Checksum32Done
        cmp     ecx,4
        jae     Checksum32Loop       
        mov     edx,4        
        sub     edx,ecx        
        sub     esi,edx
        mov     ecx,4
        jmp     Checksum32Loop
   Checksum32Done:     
ENDM
int checksum(String src){
  int i = src.length-1;
  int res = 0;
  do{
    int c  = src.codeUnitAt(i);
    res += c;
    String cBits = c.toRadixString(2);
    int bitFort = int.parse(cBits[0]);
    
    int transform = c << 1;
    transform = transform + 1 + bitFort;
    res = res ^ transform;   
    i--;
  }while(i>=0);  
  return res;
}

我按照提示修改了代码,假设一个ASCII字符串总是4的倍数,有时间看懂问题了。 不过还是不行。

String deComp = File(CHEMIN_FICHIER_DECOMP).readAsStringSync();

List<int> encoded = [];
for (int i =0; i<deComp.length; i++){
    List<int> cUtf8 = utf8.encode(deComp[i]);
    encoded.addAll(cUtf8);
}
print(checksum_stack(encoded));

_______

int checksum_stack(List<int> src){
  int i = 0;
  int res = 0;
  do{
    int c  = fusion(src.sublist(i, i+4));
    res += c;
    String cBits = c.toRadixString(2).padLeft(8, '0');
    int bitFort = int.parse(cBits[0]);

    int transform = c << 1;
    transform = transform + 1 +bitFort;
    res = res ^ transform;
    i+=4;
  }while(i < src.length-4);
  return res;
}

int fusion(List<int> str){
  if (str.length != 4) {
    throw "need multiple of 4!";
  }
  String hexStr = "";
  str.forEach((c) {
    hexStr += c.toRadixString(16).padLeft(2, '0');
  });  
  return int.parse(hexStr,radix: 16);
}

校验和算法的转录有误。
以下是我的做法:

import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';

int checksum(String string, {Encoding encoder = utf8, Endian endian = Endian.little})
{
    final ByteData bytes = ByteData.sublistView(Uint8List.fromList(encoder.encode(string)));
    int checksum = 0;
    
    
    if (bytes.lengthInBytes >= 4)   
  {
        for (int i = 0; i < bytes.lengthInBytes; i += 4)
        {
            int chunk = bytes.getUint32(min(i + 4, bytes.lengthInBytes) - 4, endian);
            checksum = (checksum + chunk) ^ ((chunk << 1) + 1 + (chunk >> 31)); 
        }
  }
  
    return checksum & 0xffffffff;
    
}

你完全错过了:

  • 代码使用 DWORD(32 位整数)。
  • 少于 4 个字节的字符串的校验和为零。
  • 代码通过读取最后四个字节(必然与前一个 DWORD 重叠)来处理长度不是四的倍数的字符串。

这是评论的程序集:

CHECKSUM32_MACRO MACRO 
   LOCAL Checksum32Loop, Checksum32Done       
        xor     eax,eax                   ;Checksum = 0
        cmp     ecx,4
        jb      Checksum32Done            ;If len < 4 Then Return
    align 16
    Checksum32Loop:
        mov     ebx,dword ptr [esi]       ;c = DWORD from string (**FOUR** bytes)
        add     eax,ebx                   ;Checksum += c
        shl     ebx,1                     ;CF = c[31], c = c << 1
        adc     ebx,1                     ;c += (1 + CF)
        xor     eax,ebx                   ;Checksum ^= c
        add     esi,4                     ;Point to next DWORD
        sub     ecx,4                     ;Len -= 4
        jz      Checksum32Done            ;If Len == 0 Then Return
        cmp     ecx,4                     
        jae     Checksum32Loop            ;If Len >= 4 Then Cycle back
        mov     edx,4                     
        sub     edx,ecx                   ;edx = 4 - Len (left, so it's 4 - Len % 4 in absolute terms)
        sub     esi,edx                   ;Point to last DWORD (Len-4 in absolute terms, go back 4-Len in relative terms)
        mov     ecx,4                     ;Set Len=4 to cycle one more time
        jmp     Checksum32Loop
   Checksum32Done:     
ENDM

另请注意,将数字转换为字符串以提取数字或位通常是一种不好的做法。使用 >> 移位运算符,最后使用 AND。