【问题标题】:Calculation of exFAT checksumexFAT校验和的计算
【发布时间】:2016-10-08 12:34:23
【问题描述】:

我目前正在尝试使用微控制器将磁盘格式化为 exFAT。我的问题是我需要计算一个校验和,该校验和使用 VBR(卷引导区域)的扇区 1 到 11 的字节将其存储到扇区 12,但我的结果不正确。当校验和不正确时,磁盘不能被 Windows 或任何其他识别 exFAT 的操作系统使用,因为校验和已被验证,如果不正确,则会发生致命错误。

这是计算 32 位校验和的函数:

uint32_t BootChecksum(char * data, long bytes){
    uint32_t checksum = 0; 
    for (uint32_t i = 0 ; i < bytes ; i++){
        if (i == 106 || i == 107 || i == 112)
            continue;
        checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
        if(checksum == 0xF1924082){
            printf("%02X | i = %d", checksum, i);
        }
    }
    return checksum;
}

据我所知,该函数是正确的,所以我的猜测是我使用的数据不正确。我只是取了所需的 11 个扇区,因此每个扇区 512 个字节会产生一个 5632 个字节的数组。

我使用了类似的函数来计算条目集的校验和(16 位校验和),结果是正确的,它确实必须是数据,但我不明白我在那里缺少什么!

任何了解 exFAT 的人可以帮助我吗?谢谢!

【问题讨论】:

    标签: c++ c++11 checksum fat


    【解决方案1】:

    我怀疑这是运算符优先级的问题。

    this page我看到crc定义checksum是这样修改的

    checksum = (checksum<<31) | (checksum>> 1) + data[i];
    

    也就是说,如果我没记错的话,相当于

    checksum = (checksum<<31) | ((checksum>> 1) + data[i]);
    

    因为(如果我没记错的话)加号运算符 (+) 的优先级高于位或运算符 (|)。

    相反,你的代码是

    checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
    

    这是完全不同的代码,因为您首先应用按位或,然后再应用加号。

    我想可以使用

    checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
    

    p.s.:对不起我的英语不好

    ---编辑 2016.06.09---

    另一个问题应该是data的签名。

    你将data定义为char的指针; ntfs.com 将data 定义为const unsigned char 的数组。

    指针/数组的区别不是问题; const 部分并不重要(但我建议您也将data 定义为const);问题(我想)是转换为charuint32_t,如果char 用负值而不是unsigned char 签名。

    举个例子:假设你的data[i] 的值为-1;使用(uint32_t) data[i],如果我没记错的话,首先将data[i] 转换为int(-1),然后再转换为uint32_t(-1)。所以你得到 4294967295。

    如果您的data[i]unsigned char,而不是-1 data[i] 值是255;所以(uint32_t) data[i]首先将255转换为int(255),也就是255,在uint32_t(255)旁边,剩下的就是255。

    简单来说,我的建议是:改变

    checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
    

    checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) (unsigned char) data[i]);
    

    或者干脆

    checksum = (checksum << 31) | ((checksum >> 1) + (unsigned char) data[i]);
    

    【讨论】:

    • 你确实是对的,我用你的括号试过了,没有任何括号,我得到了相同的结果,所以我似乎误解了运算符的优先级!但是,结果仍然不正确。我得到 0x95672D57 而我应该得到 0xF1924082。感谢您的帮助!
    • @ArthurPenguin - 解决了一个问题,让我们看看能否解决另一个问题;我已经编辑了我的分析器,建议对您的代码进行另一项更改以解决签名问题
    • 算法的至少一部分似乎/曾经有些混乱。 ((checksum &lt;&lt; 31) | (checksum &gt;&gt; 1)) 是“C”等效于单个“原子”汇编语言指令ror DWORD [checksum], 1,即将变量向右旋转一。通常在汇编语言中会使用一个寄存器。
    猜你喜欢
    • 2010-12-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2021-05-08
    相关资源
    最近更新 更多