OPTION DOTNAME
include includes\temphls.inc
include includes\win64.inc
include includes\user32.inc
includelib includes\user32.lib
OPTION PROLOGUE:none
OPTION EPILOGUE:none
.data
	AppName: ;DLL Skeleton
		dw 0044h,004ch,004ch,0020h,0053h,006bh,0065h,006ch,0065h,0074h,006fh,006eh,0000h 
	HelloMsg: ;Вызвана функция TestHello
		dw 0412h,044bh,0437h,0432h,0430h,043dh,0430h,0020h,0444h,0443h,043dh,043ah,0446h,0438h,044fh,0020h,0054h,0065h,0073h,0074h,0048h,0065h,006ch,006ch,006fh,0000h 
	LoadMsg: ;DLL Загружена
		dw 0044h,004ch,004ch,0020h,0417h,0430h,0433h,0440h,0443h,0436h,0435h,043dh,0430h,0000h 
	UnloadMsg: ;DLL выгружена
		dw 0044h,004ch,004ch,0020h,0432h,044bh,0433h,0440h,0443h,0436h,0435h,043dh,0430h,0000h 
	SHAMsg: ;"SHA256 Запущена!"
		dw 0053h,0048h,0041h,0032h,0035h,0036h,0020h,0417h,0430h,043fh,0443h,0449h,0435h,043dh,0430h,0021h,0000h 
	
	DllAtata: ;Неожиданно прилетел DLL_THREAD_ATTACH
	 	dw 041dh,0435h,043eh,0436h,0438h,0434h,0430h,043dh,043dh,043eh,0020h,043fh,0440h,0438h,043bh,0435h,0442h,0435h,043bh,0020h,0044h,004ch,004ch,005fh,0054h,0048h,0052h,0045h,0041h,0044h,005fh,0041h,0054h,0054h,0041h,0043h,0048h,0000h
	prime2nums: ;Простые числа от 2 до 311 
				dw 02h,03h,05h,07h,0Bh,0Dh,11h,13h,17h,1Dh,1Fh,25h,29h,2Bh,2Fh,35h,3Bh,3Dh,43h,47h,49h,4Fh,53h,59h
				dw 61h,65h,67h,6Bh,6Dh,71h,7Fh,83h,89h,8Bh,95h,97h,9Dh,0A3h,0A7h,0ADh,0B3h,0B5h,0BFh,0C1h,0C5h,0C7h,0D3h,0DFh
				dw 0E3h,0E5h,0E9h,0EFh,0F1h,0FBh,101h,107h,10Dh,10Fh,115h,119h,11Bh,125h,133h,137h
	
	DllDetata: ;Неожиданно прилетел DLL_PROCESS_DETACH
	 	dw 041dh,0435h,043eh,0436h,0438h,0434h,0430h,043dh,043dh,043eh,0020h,043fh,0440h,0438h,043bh,0435h,0442h,0435h,\
		 043bh,0020h,0044h,004ch,004ch,005fh,0050h,0052h,004fh,0043h,0045h,0053h,0053h,005fh,0044h,0045h,0054h,0041h,0043h,0048h,0000h
	
	prime_nums: ; 8 байт с простыми числами от 2 до 19
	 	db 0 dup (8)		
	align 16
	my3sqrt REAL8 0.3333333333333333333333333333
	;xmminst dq 12232434,13342342342
	xmmhash xmmword 0 dup (4); 4 Байта в которых хранится хэш
	k_konst dd 0 dup (64)	;64 32-битных значения инициированных первыми 32 битами дробной части кубических корней от 2 о 311
	myXMMSAVE xmmword 0 dup (10) 	;глобальная переменная для сохранения/восстановления регистров XMM6-XMM15 (неизменяемые)
	myRnSAVE dq 0 dup (4)			;глобальная переменная для сохранения/восстановления регистров R12-R15 (неизменяемые)

.code
DllMain proc hInstDLL:QWORD, reason:QWORD, unused:QWORD
	;push rbp
	;mov	rbp,rsp
	sub rsp,28h
	.if edx==DLL_PROCESS_ATTACH				;Обрабатываю событие вызова DLL
		call _isAvxSupported
		pshufd xmm0,xmm0,10010011b			;Перераспределяет 32-битные qword'ы в xmm согласно битовой маске: 2 бита, числа от 0-3 сообщают
		pshufd xmm0,xmm0,10010011b			;слева направо новое расположение qword'ов в регистре XMM. Например: 3-2-1-0 -> 2-1-0-3(10010011b)
		pshufd xmm0,xmm0,10010011b
		pshufd xmm0,xmm0,10010011b
		mov eax,001020304h					;вычисляю Σ0
		xor rcx,rcx
		ror eax,2
		xor ecx,eax
		ror eax,11
		xor ecx,eax
		ror eax,9
		xor ecx,eax
		;вычисляю ключ
		mov eax,001020304h
		xor eax,ecx
		mov edx,eax 	; в EDX - ключ
		mov eax,001020304h
		xor eax,edx
		;смотрю, подходит ли он для других чисел
		mov eax,005040304h					;вычисляю Σ0
		xor rcx,rcx
		ror eax,2
		xor ecx,eax
		ror eax,11
		xor ecx,eax
		ror eax,9
		xor ecx,eax
		;Подставляю ключ из первого примера
		mov eax,005040304h
		xor eax,edx
		lea rdx,LoadMsg						;Указатель на сообщение "DLL загружена"
	.elseif edx==DLL_PROCESS_DETACH			;Обрабатываю событие закрытия DLL
		lea rdx,UnloadMsg					;Указатель на сообщение "DLL выгружена"
	.elseif edx==DLL_THREAD_ATTACH			;Обрабатываю событие создания треда в вызывающем процессе
											;(ох и попило крови это событие: не обрабатывал, а по-умолчанию падало на другой обработчик)
		;lea rdx,DllAtata					;Указатель на сообщение "неожиданно прилетел DLL_THREAD_ATTACH"
		add rsp,28h							;восстанавливаю вершину стека
		xor rax,rax							;возвращаю ноль
		ret									;Выхожу
	.elseif edx==DLL_THREAD_DETACH			;Обрабатываю событие закрытия треда в вызывающем процессе 
		;lea rdx,DllDetata					;Указатель на сообщение "Неожиданно прилетел DLL_PROCESS_DETACH"
		add rsp,28h							;восстанавливаю вершину стека
		xor rax,rax							;возвращаю ноль
		ret									;Выхожу
	.endif 
	mov r9d,MB_OK							;
	jmp exit
DllMain Endp
TestHello proc 
	sub rsp,28h
	lea rdx,HelloMsg
	mov r9d,MB_OK + MB_ICONERROR
exit::	lea r8,AppName
	xor rcx,rcx
	call MessageBoxW
	;mov rsp,rbp
	;pop rbp
	add rsp,28h
	mov rax,TRUE
	ret
TestHello endp
;Sha256 - Функция, принимающая в качестве параметра 1-Адрес хешируемого объекта;2-его полный размер; 3-Размер отрезка; 4-последний ли он?. Возвращаемое значение: NULL в случае успеха 
Sha256 proc __fastcall
	enter 128,0
	
	leave
	xor rax,rax
	ret
Sha256 Endp
;Инициализация хэш функции, ввод исходных значений
Sha256Init proc __fastcall
	LOCAL myInt64:QWORD ;Число для преобразования
	LOCAL squareRoot:QWORD ;Корень
	LOCAL delitel:QWORD ;делитель (равен 1 для извлечения дробной части числа)
	LOCAL mnoz:QWORD;множитель для выведение целого числа
	LOCAL myxmmword:XMMWORD
	enter 8*8,0
	lea rdx,prime_nums ;в RDX массив простых чисел
	lea r8,xmmhash ;в R8 - адрес инициализированного хэша (его начальных значений)
	mov rcx,8 ;в RCX количество повторений цикла. Для процессора нет разницы, обращаться к DL или к RDX, поэтому снижаю расходы приводя всё к единому размеру
	mov rax,1373893702338282242
	mov QWORD PTR [rdx],rax ; инициализирую простые числа от 2 до 19
loop1:
	finit
	mov al, BYTE PTR [rdx]		;беру текущее простое число
	and rax,255
	mov myInt64,rax 	
	mov delitel,1				;делитель 1 нужен для отсечения целой части, при делениии на 1 по модулю
	mov rax,4294967296			;множитель 2^32, нужен...\
	mov QWORD PTR mnoz,rax		;...для сдвига дробной части на 32 бита
	fild QWORD PTR mnoz			; сохраняю всё в стек FPU
	fild QWORD PTR delitel	
	fild QWORD PTR myInt64
	fsqrt						;извлекаю корень
	fprem						;делю на 1 по модулю
	fmul ST,ST(2)				;сдвигаю на 32
	fisttp qword ptr squareRoot	;сохраняю для проверки
	mov eax,dword ptr squareRoot	;сохраняю результат в хеше
	mov dword ptr [r8],eax
	add r8,4;сдвигаю указатель на хэш
	inc rdx						;сдвигаю указатель на простое число 
	dec rcx
	jnz loop1					;цикл
; Далее, инициализирую константы (k) кубическим корнем ряда первых 64 простых числел от 2 до 311
	lea rdx,prime2nums ;в RDX адресс массива простых числел
forxmm0: ;Заполняю регистр XMM0 значениями 4-х корней
	mov r8,64	;счётчик цикла
	lea r9,k_konst ;указатель на буфер k_konst
loopxmm0:	
	mov cx, word ptr [rdx]; беру текущее простое число
	and rcx,65535	;обнуляю остальные биты
	call z3sqrt ;вызываю процедуру рассчёта дробной части от кубического корня от числа в rcx
	mov dword ptr [r9],eax ;сохраняю результат в буфер
	add rdx,2	;сдвигаю указатель на простое число
	add r9,4	;сдвигаю указатель на буфер k_konst
	dec r8	;уменьшаю счётчик
	jnz loopxmm0						;цикл
	leave
	ret
Sha256Init Endp
_isAvxSupported: ; extern "C" int isAvxSupported()
    xor eax, eax
    cpuid
    cmp eax, 1 ; Поддерживает ли CPUID параметр eax = 1?
    jb not_supported
    mov eax, 1
    cpuid
    and ecx, 018000000h ; Проверяем, что установлены биты 27 (ОС использует XSAVE/XRSTOR)
    cmp ecx, 018000000h ; и 28 (поддержка AVX процессором)
    jne not_supported
    xor ecx, ecx ; Номер регистра XFEATURE_ENABLED_MASK/XCR0 есть 0
    xgetbv ; Регистр XFEATURE_ENABLED_MASK теперь в edx:eax
    and eax, 110b
    cmp eax, 110b ; Убеждаемся, что ОС сохраняет AVX регистры при переключении контекста
    jne not_supported
    mov eax, 1
    ret
	not_supported:
    xor eax, eax
    ret
z3sqrt proc __fastcall ;вынес вычисление кубического корня в процедуру. На входе, в rcx - простое число, на выходе, в rax 32 бита остатка.
	LOCAL myInt64:QWORD	;локальная переменная для хранения простого числа
	LOCAL delitel:QWORD ;делитель (равен 1 для извлечения дробной части числа)
	LOCAL mnoz:QWORD;множитель для выведение целого числа
	LOCAL result:QWORD ;результат
	LOCAL regCR:word	;ячейка для сохренения регистра CR (FPU)
	enter 5*8,0	
	mov myInt64,rcx	;сохраняю в переменную
	mov delitel,1	;единица для деления по модулю
	mov rax,4294967296			;множитель 2^32, нужен...\
	mov QWORD PTR mnoz,rax		;...для сдвига дробной части на 32 бита
	finit
	fstcw regCR 	;сохраняю регистр CR (FPU), для изменения значения бита округления
	or word ptr regCR,3072	;включаю 10 и 11 биты, сообщающие, что нужно округлять до нуля (в сторону нуля)
	fldcw regCR	;записываю изменённые значения в регистра CR 
	fild QWORD PTR mnoz			; сохраняю всё в стек FPU
	fild QWORD PTR delitel
	fld QWORD PTR my3sqrt 	;загружаю 1/3
	fild QWORD PTR myInt64 			;текущее простое число
	FYL2X 					;получаю LN(x)
	fld ST(0)				;Создаем еще одну копию LN(x)
	frndint					;Округляем
	fsubr st(0),st(1)  		;ST(1)=z, ST(0)=z-trunc(z)
	f2xm1  ;ST(1)=z, ST(0)=2**(z-trunc(z))-1
  	fld1
  	faddp  ;ST(1)=z, ST(0)=2**(z-trunc(z))
  	fscale ;ST(1)=z, ST(0)=(2**trunc(z))*(2**(z-trunc(z)))=2**t
  	fxch st(1)
  	fstp st ;Результат остается на вершине стека ST(0)
	fprem						;делю на 1 по модулю
	fmul ST,ST(2)				;сдвигаю на 32
	fisttp qword ptr result	;сохраняю результат	
	mov rax,result
	leave
	ret
z3sqrt endp
end