版本 5 Unix 使用什麼校驗和算法?
我不知道在 Unix V5 和 V6 中該
sum
命令使用了什麼算法。起初,我認為它是字節模數 2^16 的簡單總和。然而,對於重複 320 次的字元串“1111111111\n”,它計算的校驗和為28930(使用Julius Schmidt 的用於 JavaScript的 PDP-11 模擬器)。而它的簡單字節總和要小兩個字節:
$ python -c 'print(sum(bytearray(b"1111111111\n"*320)) & 0xFFFF)' 28928
後來,從MacOS 的手冊頁中,我發現
sum
andcksum
命令有很長的不一致歷史。然而,即使是 MacOS 上提供的“歷史”算法版本也不同意 Unix V5 的校驗和。最接近的匹配是 UNIX System V 的預設sum
命令(在 Mac 上呼叫,如cksum -o 2
),它為此字元串返回相同的校驗和,但不同意其他命令:$ python -c 'print("1111111111\n"*320, end="")' | cksum -o 2 28930 7
更具體地說,
cksum -o 2
和 Unix V5sum
對模擬器中的大多數二進製文件(例如,在文件夾中/bin
)產生不同的輸出,儘管它們在大多數文本文件上是一致的。這是模擬器中的真實行為還是錯誤?如果是正版,是什麼算法?
PS這是原始碼,如果有人可以閱讀1974年的彙編程式碼。
起初,我以為它是字節模數 2^16 的簡單總和
它是一個 sum mod 2^16,只是每次溢出時都會加一個 1。此外,字節將在添加到總和之前進行符號擴展。這是程序集中的“註釋”片段:
# r2 is the pointer into the data # r0 is the length of the data # r5 is the sum 2: movb (r2)+,r4 # r4 = sign_extend(*r2++) add r4,r5 # r5 += r4 adc r5 # if(r5 overflowed) r5++ sob r0,2b # if(--r0) goto 2 above
同樣放入一個小的 C 程序(用作
./v5sum < file
):#include <stdio.h> int main(void){ int c, s = 0; while((c = getchar()) != EOF){ s += c & 0x80 ? c | 0xff00 : c; // alternative: s += (unsigned short)(signed char)c if(s & 0x10000){ s++; s &= 0xffff; }; } printf("%d\n", s); return 0; }
更具體地說, cksum -o 2 和 Unix V5 的 sum 為模擬器中的大多數二進製文件(例如,在文件夾 /bin 中)產生不同的輸出,儘管它們在大多數文本文件上是一致的。
那是因為原始的 unix v5
sum
將對字元進行符號擴展,並且只有二進製文件包含 >= 0x80 的字節。否則,算法應該相似,並且僅與非常大的文件不同(其中字元的總和將溢出 32 位無符號整數)。