windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/amd64/chksum.asm
2020-09-26 16:20:57 +08:00

202 lines
7.7 KiB
NASM

title "Compute Checksum"
;/*++
;
; Copyright (c) 2001 Microsoft Corporation
;
; Module Name:
;
; chksum.asm
;
; Abstract:
;
; This module implements a fucntion to compute the checksum of a buffer.
;
; Author:
;
; David N. Cutler (davec) 25-Jan-2001
;
; Environment:
;
; Any mode.
;
; Revision History:
;
;--*/
include ksamd64.inc
subttl "Checksum"
;++
;
; USHORT
; ChkSum(
; IN ULONG cksum,
; IN PUSHORT buf,
; IN ULONG len
; )
;
; Routine Description:
;
; This function computes the checksum of the specified buffer.
;
; Arguments:
;
; cksum (ecx) - Suppiles the initial checksum value.
;
; buf (rdx) - Supplies a pointer to the buffer that is checksumed.
;
; len (r8d) - Supplies the of the buffer in words.
;
; Return Value:
;
; The computed checksum is returned as the function value.
;
;--
LEAF_ENTRY ChkSum, _TEXT$00
mov eax, ecx ; set initial checksum value
mov ecx, r8d ; set length of buffer in words
shl ecx, 1 ; convert to length in bytes
jz cks80 ; if z, 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-byte blocks.
;
test rdx, 02h ; check if source dword aligned
jz short cks10 ; if z, source is dword aligned
xor r8, r8 ; get initial word for alignment
mov r8w, [rdx] ;
add eax, r8d ; update partial checkcum
adc eax, 0 ; add carry
add rdx, 2 ; update source address
sub ecx, 2 ; reduce length in bytes
cks10: mov r8d, ecx ; isolate residual bytes
and r8d, 07h ;
sub ecx, r8d ; subtract residual bytes
jz cks60 ; if z, no 8-byte blocks
test ecx, 08h ; test if initial 8-byte block
jz short cks20 ; if z, no initial 8-byte block
add eax, [rdx] ; compute 8-byte checksum
adc eax, 4[rdx] ;
adc eax, 0 ; add carry
add rdx, 8 ; update source address
sub ecx, 8 ; reduce length of checksum
jz cks60 ; if z, end of 8-byte blocks
cks20: test ecx, 010h ; test if initial 16-byte block
jz short cks30 ; if z, no initial 16-byte block
add eax, [rdx] ; compute 16-byte checksum
adc eax, 4[rdx] ;
adc eax, 8[rdx] ;
adc eax, 12[rdx] ;
adc eax, 0 ; add carry
add rdx, 16 ; update source address
sub ecx, 16 ; reduce length of checksum
jz cks60 ; if z, 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, [rdx] ; compute 32-byte checksum
adc eax, 4[rdx] ;
adc eax, 8[rdx] ;
adc eax, 12[rdx] ;
adc eax, 16[rdx] ;
adc eax, 20[rdx] ;
adc eax, 24[rdx] ;
adc eax, 28[rdx] ;
adc eax, 0 ; add carry
add rdx, 32 ; update source address
sub ecx, 32 ; reduce length of checksum
jz cks60 ; if z, end of 8-byte blocks
cks40: test ecx, 040h ; test if initial 64-byte block
jz cks50 ; if z, no initial 64-byte block
add eax, [rdx] ; compute 64-byte checksum
adc eax, 4[rdx] ;
adc eax, 8[rdx] ;
adc eax, 12[rdx] ;
adc eax, 16[rdx] ;
adc eax, 20[rdx] ;
adc eax, 24[rdx] ;
adc eax, 28[rdx] ;
adc eax, 32[rdx] ;
adc eax, 36[rdx] ;
adc eax, 40[rdx] ;
adc eax, 44[rdx] ;
adc eax, 48[rdx] ;
adc eax, 52[rdx] ;
adc eax, 56[rdx] ;
adc eax, 60[rdx] ;
adc eax, 0 ; add carry
add rdx, 64 ; update source address
sub ecx, 64 ; reduce length of checksum
jz cks60 ; if z, end of 8-byte blocks
cks50: add eax, [rdx] ; compute 128-byte checksum
adc eax, 4[rdx] ;
adc eax, 8[rdx] ;
adc eax, 12[rdx] ;
adc eax, 16[rdx] ;
adc eax, 20[rdx] ;
adc eax, 24[rdx] ;
adc eax, 28[rdx] ;
adc eax, 32[rdx] ;
adc eax, 36[rdx] ;
adc eax, 40[rdx] ;
adc eax, 44[rdx] ;
adc eax, 48[rdx] ;
adc eax, 52[rdx] ;
adc eax, 56[rdx] ;
adc eax, 60[rdx] ;
adc eax, 64[rdx] ;
adc eax, 68[rdx] ;
adc eax, 72[rdx] ;
adc eax, 76[rdx] ;
adc eax, 80[rdx] ;
adc eax, 84[rdx] ;
adc eax, 88[rdx] ;
adc eax, 92[rdx] ;
adc eax, 96[rdx] ;
adc eax, 100[rdx] ;
adc eax, 104[rdx] ;
adc eax, 108[rdx] ;
adc eax, 112[rdx] ;
adc eax, 116[rdx] ;
adc eax, 120[rdx] ;
adc eax, 124[rdx] ;
adc eax, 0 ; add carry
add rdx, 128 ; update source address
sub ecx, 128 ; reduce length of checksum
jnz short cks50 ; if nz, not end of 8-byte blocks
;
; Compute checksum on 2-byte blocks.
;
cks60: test r8d, r8d ; check if any 2-byte blocks
jz short cks80 ; if z, no 2-byte blocks
xor ecx, ecx ; clear entire register
cks70: mov cx, [rdx] ; load 2-byte block
add eax, ecx ; compute 2-byte checksum
adc eax, 0 ;
add rdx, 2 ; update source address
sub r8d, 2 ; reduce length of checksum
jnz short cks70 ; if nz, 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
ret ;
LEAF_END ChkSum, _TEXT$00
end