title "Compute Checksum" ;/*++ ; ; Copyright (c) 1992 Microsoft Corporation ; ; Module Name: ; ; chksum.asm ; ; Abstract: ; ; This module implements a fucntion to compute the checksum of a buffer. ; ; Author: ; ; David N. Cutler (davec) 27-Jan-1992 ; ; Environment: ; ; Any mode. ; ; Revision History: ; ;--*/ .386 .model small,c assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT assume fs:nothing,gs:nothing .xlist include callconv.inc include ks386.inc .list .code ;++ ; ; USHORT ; ChkSum( ; IN ULONG cksum, ; IN PUSHORT buf, ; IN ULONG len ; ) ; ; Routine Description: ; ; This function computes the checksum of the specified buffer. ; ; Arguments: ; ; cksum - Suppiles the initial checksum value. ; ; buf - Supplies a pointer to the buffer that is checksumed. ; ; len - Supplies the of the buffer in words. ; ; Return Value: ; ; The computed checksum is returned as the function value. ; ;-- cksum equ 8 ; stack offset to initial checksum buf equ 12 ; stack offset to source address len equ 16 ; stack offset to length in words cPublicProc ChkSum,3 push esi ; save nonvolatile register mov ecx,[esp + len] ; get length in words mov esi,[esp + buf] ; get source address mov eax,[esp + cksum] ; get initial checksum shl ecx,1 ; convert to length in bytes jz cks80 ; if z set, no words to checksum ; ; Compute checksum in cascading order of block size until 128 byte blocks ; are all that is left, then loop on 128-bute blocks. ; test esi,02h ; check if source dword aligned jz short cks10 ; if z set, source is dword aligned sub edx,edx ; get initial word for alignment mov dx,[esi + 0] ; add eax,edx ; update partial checkcum adc eax,0 ; add carry add esi,2 ; update source address sub ecx,2 ; reduce length in bytes cks10: mov edx,ecx ; isolate residual bytes and edx,07h ; sub ecx,edx ; subtract residual bytes jz cks60 ; if z set, no 8-byte blocks test ecx,08h ; test if initial 8-byte block jz short cks20 ; if z set, no initial 8-byte block add eax,[esi + 0] ; compute 8-byte checksum adc eax,[esi + 4] ; adc eax,0 ; add carry add esi,8 ; update source address sub ecx,8 ; reduce length of checksum jz cks60 ; if z set, end of 8-byte blocks cks20: test ecx,010h ; test if initial 16-byte block jz short cks30 ; if z set, no initial 16-byte block add eax,[esi + 0] ; compute 16-byte checksum adc eax,[esi + 4] ; adc eax,[esi + 8] ; adc eax,[esi + 12] ; adc eax,0 ; add carry add esi,16 ; update source address sub ecx,16 ; reduce length of checksum jz cks60 ; if z set, end of 8-byte blocks cks30: test ecx,020h ; test if initial 32-byte block jz short cks40 ; if z set, no initial 32-byte block add eax,[esi + 0] ; compute 32-byte checksum adc eax,[esi + 4] ; adc eax,[esi + 8] ; adc eax,[esi + 12] ; adc eax,[esi + 16] ; adc eax,[esi + 20] ; adc eax,[esi + 24] ; adc eax,[esi + 28] ; adc eax,0 ; add carry add esi,32 ; update source address sub ecx,32 ; reduce length of checksum jz cks60 ; if z set, end of 8-byte blocks cks40: test ecx,040h ; test if initial 64-byte block jz cks50 ; if z set, no initial 64-byte block add eax,[esi + 0] ; compute 64-byte checksum adc eax,[esi + 4] ; adc eax,[esi + 8] ; adc eax,[esi + 12] ; adc eax,[esi + 16] ; adc eax,[esi + 20] ; adc eax,[esi + 24] ; adc eax,[esi + 28] ; adc eax,[esi + 32] ; adc eax,[esi + 36] ; adc eax,[esi + 40] ; adc eax,[esi + 44] ; adc eax,[esi + 48] ; adc eax,[esi + 52] ; adc eax,[esi + 56] ; adc eax,[esi + 60] ; adc eax,0 ; add carry add esi,64 ; update source address sub ecx,64 ; reduce length of checksum jz short cks60 ; if z set, end of 8-byte blocks cks50: add eax,[esi + 0] ; compute 64-byte checksum adc eax,[esi + 4] ; adc eax,[esi + 8] ; adc eax,[esi + 12] ; adc eax,[esi + 16] ; adc eax,[esi + 20] ; adc eax,[esi + 24] ; adc eax,[esi + 28] ; adc eax,[esi + 32] ; adc eax,[esi + 36] ; adc eax,[esi + 40] ; adc eax,[esi + 44] ; adc eax,[esi + 48] ; adc eax,[esi + 52] ; adc eax,[esi + 56] ; adc eax,[esi + 60] ; adc eax,[esi + 64] ; adc eax,[esi + 68] ; adc eax,[esi + 72] ; adc eax,[esi + 76] ; adc eax,[esi + 80] ; adc eax,[esi + 84] ; adc eax,[esi + 88] ; adc eax,[esi + 92] ; adc eax,[esi + 96] ; adc eax,[esi + 100] ; adc eax,[esi + 104] ; adc eax,[esi + 108] ; adc eax,[esi + 112] ; adc eax,[esi + 116] ; adc eax,[esi + 120] ; adc eax,[esi + 124] ; adc eax,0 ; add carry add esi,128 ; update source address sub ecx,128 ; reduce length of checksum jnz short cks50 ; if z clear, not end of 8-byte blocks ; ; Compute checksum on 2-byte blocks. ; cks60: test edx,edx ; check if any 2-byte blocks jz short cks80 ; if z set, no 2-byte blocks cks70: sub ecx,ecx ; load 2-byte block mov cx,[esi + 0] ; add eax,ecx ; compue 2-byte checksum adc eax,0 ; add esi,2 ; update source address sub edx,2 ; reduce length of checksum jnz short cks70 ; if z clear, more 2-bytes blocks ; ; Fold 32-but checksum into 16-bits ; cks80: mov edx,eax ; copy checksum value shr edx,16 ; isolate high order bits and eax,0ffffh ; isolate low order bits add eax,edx ; sum high and low order bits mov edx,eax ; isolate possible carry shr edx,16 ; add eax,edx ; add carry and eax,0ffffh ; clear possible carry bit pop esi ; restore nonvolatile register stdRET ChkSum stdENDP ChkSum end