Есть программа на паскале, написанная изначально не мной.
Перевожу ее на C#. В одной из части программы идет весьма своеобразный расчет контрольной суммы файлов. Контрольная сумма хранится в базе в формате bigint
и функция расчета контрольной суммы выглядит так:
function GetCheckSum(FileName: string): DWORD;
var
F: file of DWORD;
P: Pointer;
Fsize: DWORD;
Buffer: array[0..500] of DWORD;
begin
FileMode := 0;
AssignFile(F, FileName);
Reset(F);
Seek(F, FileSize(F) div 2);
Fsize := FileSize(F) - 1 - FilePos(F);
if Fsize > 500 then
Fsize := 500;
BlockRead(F, Buffer, Fsize);
Close(F);
P := @Buffer;
asm
XOR eax, eax
XOR ecx, ecx
mov edi, P
@again:
add eax, [edi + 4 * ecx]
inc ecx
cmp ecx, Fsize
jl @again
mov @result, eax
end;
end;
Подскажите, что происходит в Ассемблере и как бы могла выглядеть данная конструкция в C#?
Воспользовался следующим:
private long GetCheckSum(string FilePath)
{
byte[] FBytes = File.ReadAllBytes(FilePath);
int FSize = FBytes.Length / 2;
int FToRead = FSize + 500 > FBytes.Length ? FBytes.Length : FSize + 500;
long FSum = 0;
for (int i = FSize; i < FToRead; i++)
{
FSum += FBytes[i];
}
return FSum;
}
На мой взгляд получилось идентично. Поправьте, если я не прав.
Просто сумма 32-разрядных беззнаковых чисел (по модулю 2^32, если возникнет переполнение).
UInt32 buffer[500];
sum = 0;
for (i = 0; i < fsize; i++)
sum += buffer[i];
Файл читается как бинарный, суммирование осуществляется для чисел из второй половины файла (благодаря Seek
), их количество не превышает 500. Т.о. для размера файла 8000 байт (2000 чисел) прочитаны будут числа с номерами от 1000 по 1499. Для размера файла 800 байт (200 чисел) прочитаны будут числа с номерами от 100 по 199.
Пояснения на c-подобном псевдокоде
XOR eax, eax // DWORD eax = 0; // здесь будет храниться результат
XOR ecx, ecx // int ecx = 0; // будет работать как индекс
mov edi, P // DWORD * edi = buffer;
@again:
add eax, [edi + 4 * ecx] // eax += edi[ecx]; // На ассемблере *4 потому что размер элемента 4 байта
inc ecx // ecx++;
// if(ecx<Fsize) goto again;
cmp ecx, Fsize
jl @again
mov @result, eax // result = eax;
Сделал так:
private long GetCheckSum(string FilePath)
{
byte[] FBytes = File.ReadAllBytes(FilePath);
int FSize = FBytes.Length / 2;
int FToRead = FSize + 500 * 4 > FBytes.Length ? FBytes.Length : FSize + 500 * 4;
long FSum = 0;
for (int i = FSize; i < FToRead; i += 4)
{
FSum += BitConverter.ToUInt32(FBytes, i);
}
return FSum;
}
Вроде как, возвращает то, что надо. BitConverter.ToUInt32
конвертирует 4 байта в массиве с указанной позиции в 32-битное беззнаковое число. Сама функция GetCheckSum
читает последовательность байтов из файла. Узнает где середина файла и начиная с нее перебегает через максимум 2000 элементов (если столько есть) с шагом 4. То есть по факту максимум 500 шагов. С помощью функции BitConverter.ToUInt32
получает сумму беззнаковых чисел и возвращает ее.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Всем привет! Нужно, чтобы cmdexe открывался по пути "{Системный диск}\Windows\System32"
Не выходит исправить ошибку 2 errors were found during analysis