Hi to everybody
I'm trying (unsuccessfully) to convert in MASM some Pascal code. It's a routine that calculates the CRC32.
There are some methods of casting in Pascal, namely the Byte() and the LongInt(), that drive me insane.
The Byte() is suppose to catch the high-order byte of a Long Integer. I assume then it should be the leftmost
byte of a register (ie say eax holds 12345678h should be the byte holding 12h).
The LongInt() thing, that i ignore, according to the Byte() logic could be i guess something like
movzx eax,a_byte
shl eax,24
or not?!??
Will appreciate any hints
The following are the original Pascal source (coded by SWAG SUPPORT TEAM)
Unit CRC32c;
Interface
Const
CRCSeed = $ffffffff;
CRC32tab : Array[0..255] of LongInt = (
$00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f,
$e963a535, $9e6495a3, $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988,
............. );
Function CRC32(value: Byte; crc: LongInt) : LongInt;
Function CRCend( crc : LongInt ) : LongInt ;
Implementation
Function CRC32(value: Byte; crc: LongInt) : LongInt;
begin
CRC32 := CRC32tab[Byte(crc xor LongInt(value))] xor
((crc shr 8) and $00ffffff);
end;
end.
Function CRCend( crc : LongInt ): LongInt;
begin
CRCend := (crc xor CRCSeed);
end;
{ With a LongInt Variable, say vCRC32, first seed it }
vCRC32 := CRCSeed;
{ Then go Byte-by-Byte thorugh to calculate: }
For P := 1 to Size DO
vCRC32 := CRC32(Bytes[P], vCRC32);
{ Then finish it off With CRCend }
vCRC32 := CRCend(vCRC32);
...and my miserable attempt :D
CRC32 PROC
LOCAL idx:DWORD
mov vCRC32,0FFFFFFFFh ; seed it
push ebx
push esi
push edi
xor ecx,ecx
mov idx,0
mov esi,hFileMem ; the pointer to the source buffer
mov edi,offset CRC32tab ; the pointer to the doubleword array
.WHILE TRUE
xor eax,eax
mov cl,BYTE PTR[esi]
mov al,cl
shl eax,24
PrintHex eax, " LongInt(value)"
push vCRC32
push vCRC32
pop ebx
xor ebx,eax
PrintHex ebx, " crc xor LongInt(value)"
shr ebx,24
PrintHex ebx, " Byte(...)"
mov eax,[edi+ebx]
PrintHex eax, " CRC32tab[...]"
pop ecx
shr ecx,8
and ecx,00ffffffh
xor eax,ecx
mov vCRC32,eax
PrintHex eax, " (crc shr 8) and 00ffffffh"
inc idx
mov ebx,hFlen
inc esi
.BREAK .IF (idx > ebx)
.ENDW
mov edx, crcseed
xor eax,edx
mov vCRC32,eax
pop edi
pop esi
pop ebx
ret
CRC32 ENDP
my quick guess would be that you are hitting a big-endian vs. little-endian problem. Have a look at this: http://www.webopedia.com/TERM/b/big_endian.html
The byte function, type conversion, gets the lowest order byte of the conversion.
crc := $12345678; a longint 32 bit signed integer
b := byte(crc); a byte 8 bit unsigned integer
after the conversion b is $78
mov eax,012345678h
mov bl,al
Thank you for the hint!
In your reply you specified the type Longint as a 32 bit signed integer.
For me to cast a byte to a doubleword as with the LongInt() does it means that I have to
mov al,10h
movsx ebx,al
rather than
mov al,10h
movzx ebx,al
???
You want the movzx
the pascal code should have used longword or cardinal (both 32 bit unsigned integers, equivalent to a dword)
but it lets longint work for some reason (maybe it exploits a feature/bug in the compiler).
This is a very simple (unoptimized) translation of the pascal code
using some of your assembly code. I haven't tested it though.
mov eax,0FFFFFFFFh
mov crcseed,eax
mov vCRC32,eax ; seed it
CRC32 PROC
LOCAL idx:DWORD
push ebx
push esi
push edi
mov idx,0
mov esi,hFileMem ; the pointer to the source buffer
mov edi,offset CRC32tab ; the pointer to the doubleword array
.WHILE TRUE
mov ecx,vCRC32
shr ecx,8
and ecx,0FFFFFFh
mov eax,vCRC32
movzx edx,BYTE PTR[esi]
xor eax,edx
and eax,0FFh
xor ecx,[edi + eax*4]
mov vCRC32,ecx
inc idx
mov eax,hFlen
.BREAK .IF (idx > eax)
inc esi
.ENDW
mov eax, vCRC32
xor eax, crcseed
mov vCRC32,eax
pop edi
pop esi
pop ebx
ret
CRC32 ENDP
Thanks a lot for your support
mAX