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

220 lines
8.2 KiB
NASM

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