mirror of
https://github.com/ApfelTeeSaft/Perfectium.git
synced 2026-08-26 19:33:36 +00:00
utility math functions and native function pointer bootstrap
This commit is contained in:
@@ -0,0 +1,402 @@
|
||||
INCLUDE include\master.inc
|
||||
|
||||
EXTRN GetModuleHandleA :PROC
|
||||
EXTRN sinf :PROC
|
||||
EXTRN cosf :PROC
|
||||
EXTRN atan2f :PROC
|
||||
EXTRN rand :PROC
|
||||
EXTRN strtoul :PROC
|
||||
|
||||
.const
|
||||
|
||||
; DIVIDE_BY_2 = PI / 360.0f (used for Rotator.component * PI/360 in RotToQuat)
|
||||
fDivBy2 REAL4 0.00872664625r ; PI / (180 * 2)
|
||||
fRadToDeg REAL4 57.2957795r ; 180 / PI
|
||||
fRandMax REAL4 32767.0r ; RAND_MAX (MSVC)
|
||||
|
||||
.code
|
||||
|
||||
; Utils_FindPattern(RCX=pszPattern, EDX=bRelative, R8D=offset) -> RAX
|
||||
;
|
||||
; Frame: 7 callee-save pushes (rbp rbx rsi rdi r12 r13 r14) + sub 576 bytes.
|
||||
; After 7 pushes, RSP = 0 mod 16. 576 mod 16 = 0 -> RSP = 0 at every CALL.
|
||||
;
|
||||
; Frame layout (offsets from RSP after sub):
|
||||
; [rsp+ 0 .. 31] shadow space for callees
|
||||
; [rsp+ 32 .. 543] pat_ints[128] (512 bytes, int32 per element)
|
||||
; [rsp+544] pat_len DWORD
|
||||
; [rsp+548] bRelative saved DWORD
|
||||
; [rsp+552] offset_val saved DWORD
|
||||
; [rsp+556] SizeOfImage saved DWORD
|
||||
; [rsp+560..567] endptr QWORD (for strtoul)
|
||||
; [rsp+568..575] pad
|
||||
Utils_FindPattern PROC
|
||||
push rbp
|
||||
push rbx
|
||||
push rsi
|
||||
push rdi
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
sub rsp, 576
|
||||
|
||||
mov r12, rcx ; r12 = pszPattern (parse cursor)
|
||||
mov DWORD PTR [rsp + 548], edx ; bRelative
|
||||
mov DWORD PTR [rsp + 552], r8d ; offset
|
||||
|
||||
xor ecx, ecx
|
||||
call GetModuleHandleA ; RAX = module base
|
||||
mov r13, rax ; r13 = base address
|
||||
|
||||
; IMAGE_DOS_HEADER.e_lfanew is a DWORD at [base + 0x3C]
|
||||
movsx rbx, DWORD PTR [r13 + 3Ch] ; rbx = e_lfanew
|
||||
add rbx, r13 ; rbx = IMAGE_NT_HEADERS64*
|
||||
; IMAGE_NT_HEADERS64: Signature(4) + FileHeader(20) = 0x18 to OptionalHeader
|
||||
; IMAGE_OPTIONAL_HEADER64.SizeOfImage: DWORD at OptionalHeader+0x38 -> NtHdrs+0x50
|
||||
mov edi, DWORD PTR [rbx + 50h] ; edi = SizeOfImage
|
||||
mov DWORD PTR [rsp + 556], edi ; save SizeOfImage
|
||||
|
||||
; r12 = current char pointer into pszPattern
|
||||
; rsi = write index (0-based, < 128)
|
||||
xor esi, esi ; rsi = pattern element count
|
||||
|
||||
@@parse_top:
|
||||
movzx eax, BYTE PTR [r12]
|
||||
test al, al
|
||||
jz @@parse_done ; end of string
|
||||
|
||||
cmp al, ' ' ; skip spaces
|
||||
jne @@parse_not_space
|
||||
inc r12
|
||||
jmp @@parse_top
|
||||
|
||||
@@parse_not_space:
|
||||
cmp al, '?' ; wildcard?
|
||||
jne @@parse_hex
|
||||
|
||||
; Wildcard: store -1
|
||||
mov DWORD PTR [rsp + 32 + rsi*4], -1
|
||||
inc esi
|
||||
inc r12 ; skip first '?'
|
||||
cmp BYTE PTR [r12], '?'
|
||||
jne @@parse_top
|
||||
inc r12 ; skip optional second '?'
|
||||
jmp @@parse_top
|
||||
|
||||
@@parse_hex:
|
||||
; Parse two hex digits via strtoul(r12, &endptr, 16)
|
||||
; strtoul will consume "AB" and set *endptr to the char after
|
||||
mov rcx, r12 ; arg1: string ptr
|
||||
lea rdx, [rsp + 560] ; arg2: &endptr
|
||||
mov r8d, 16 ; arg3: base
|
||||
call strtoul ; EAX = byte value
|
||||
movsx r14, eax ; zero-extend byte to 64-bit (safe: 0..255)
|
||||
mov DWORD PTR [rsp + 32 + rsi*4], r14d ; pat_ints[rsi] = byte value
|
||||
inc esi
|
||||
mov r12, QWORD PTR [rsp + 560] ; r12 = endptr (now points at space/end)
|
||||
jmp @@parse_top
|
||||
|
||||
@@parse_done:
|
||||
mov DWORD PTR [rsp + 544], esi ; pat_len = esi
|
||||
|
||||
; Guard: if pat_len == 0, no scan
|
||||
test esi, esi
|
||||
jz @@not_found
|
||||
|
||||
; Outer loop: i from 0 to SizeOfImage - pat_len (inclusive)
|
||||
mov r14d, DWORD PTR [rsp + 556] ; r14d = SizeOfImage
|
||||
sub r14d, esi ; r14d = SizeOfImage - pat_len
|
||||
js @@not_found ; underflow -> image too small
|
||||
|
||||
; r12d = pat_len (repurpose r12 — pszPattern no longer needed)
|
||||
mov r12d, esi ; r12d = pat_len
|
||||
xor esi, esi ; esi = i (outer counter)
|
||||
; rbx = &pat_ints[0] = rsp + 32
|
||||
lea rbx, [rsp + 32]
|
||||
|
||||
@@outer_loop:
|
||||
cmp esi, r14d ; i > SizeOfImage - pat_len?
|
||||
jg @@not_found
|
||||
|
||||
; Inner loop: j from 0 to pat_len-1
|
||||
xor r9d, r9d ; r9d = j
|
||||
|
||||
@@inner_loop:
|
||||
cmp r9d, r12d ; j >= pat_len?
|
||||
jge @@found ; all bytes matched
|
||||
|
||||
; Load pat_ints[j] (int32: -1 or byte 0..255)
|
||||
movsx rdi, r9d
|
||||
mov eax, DWORD PTR [rbx + rdi*4] ; eax = pat_ints[j]
|
||||
cmp eax, -1
|
||||
je @@wildcard ; skip wildcard byte
|
||||
|
||||
; Compare scan byte: base[i+j] vs pat_ints[j]
|
||||
movsx rdi, esi ; rdi = i
|
||||
add rdi, r9 ; rdi = i + j
|
||||
movzx edx, BYTE PTR [r13 + rdi] ; edx = scan byte
|
||||
cmp edx, eax
|
||||
jne @@mismatch
|
||||
|
||||
@@wildcard:
|
||||
inc r9d
|
||||
jmp @@inner_loop
|
||||
|
||||
@@mismatch:
|
||||
inc esi
|
||||
jmp @@outer_loop
|
||||
|
||||
@@found:
|
||||
; Compute match address = base + i
|
||||
movsx rax, esi
|
||||
add rax, r13
|
||||
|
||||
cmp DWORD PTR [rsp + 548], 0
|
||||
je @@done
|
||||
|
||||
; address = address + offset + 4 + *(int32*)(address + offset)
|
||||
movsx rcx, DWORD PTR [rsp + 552] ; rcx = offset
|
||||
movsx rdx, DWORD PTR [rax + rcx] ; rdx = *(int32*)(address + offset)
|
||||
lea rax, [rax + rcx + 4] ; rax = address + offset + 4
|
||||
add rax, rdx ; rax += displacement
|
||||
jmp @@done
|
||||
|
||||
@@not_found:
|
||||
xor eax, eax ; return NULL
|
||||
|
||||
@@done:
|
||||
add rsp, 576
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
Utils_FindPattern ENDP
|
||||
|
||||
; Utils_sinCos(RCX=float* ScalarSin, RDX=float* ScalarCos, XMM2=float Value)
|
||||
; Computes sin and cos of Value via CRT sinf/cosf.
|
||||
; Stores results at *ScalarSin and *ScalarCos.
|
||||
; Frame: push rbp rbx rsi + sub 48
|
||||
; 3 pushes -> RSP = 0 mod 16. sub 48 (48=0) -> 0
|
||||
; Local [rsp+32]: saved Value REAL4 (XMM2 is volatile across calls)
|
||||
Utils_sinCos PROC
|
||||
push rbp
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 48
|
||||
|
||||
mov rbx, rcx ; rbx = ScalarSin ptr
|
||||
mov rsi, rdx ; rsi = ScalarCos ptr
|
||||
movss DWORD PTR [rsp + 32], xmm2 ; save Value (XMM2 volatile across calls)
|
||||
|
||||
; sin(Value)
|
||||
movss xmm0, DWORD PTR [rsp + 32]
|
||||
call sinf ; XMM0 = sin(Value)
|
||||
movss DWORD PTR [rbx], xmm0 ; *ScalarSin = sin
|
||||
|
||||
; cos(Value)
|
||||
movss xmm0, DWORD PTR [rsp + 32]
|
||||
call cosf ; XMM0 = cos(Value)
|
||||
movss DWORD PTR [rsi], xmm0 ; *ScalarCos = cos
|
||||
|
||||
add rsp, 48
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
Utils_sinCos ENDP
|
||||
|
||||
; Utils_RotToQuat(RCX=FRotator* rot, RDX=FQuat* out_quat)
|
||||
; Converts Pitch/Yaw/Roll (degrees) to quaternion X/Y/Z/W.
|
||||
; FRotator layout: Pitch[+0] Yaw[+4] Roll[+8] (all REAL4)
|
||||
; FQuat layout: X[+0] Y[+4] Z[+8] W[+12] (all REAL4)
|
||||
; Frame: push rbp rbx rsi + sub 64
|
||||
; 3 pushes (RSP=0). sub 64 (64=0) -> 0
|
||||
; Locals:
|
||||
; [rsp+32] SP [rsp+36] CP [rsp+40] SY
|
||||
; [rsp+44] CY [rsp+48] SR [rsp+52] CR
|
||||
Utils_RotToQuat PROC
|
||||
push rbp
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 64
|
||||
|
||||
mov rbx, rcx ; rbx = FRotator*
|
||||
mov rsi, rdx ; rsi = FQuat*
|
||||
|
||||
; sinCos(&SP, &CP, Pitch * DIVIDE_BY_2)
|
||||
lea rcx, [rsp + 32]
|
||||
lea rdx, [rsp + 36]
|
||||
movss xmm2, DWORD PTR [rbx]
|
||||
mulss xmm2, DWORD PTR [fDivBy2]
|
||||
call Utils_sinCos
|
||||
|
||||
; sinCos(&SY, &CY, Yaw * DIVIDE_BY_2)
|
||||
lea rcx, [rsp + 40]
|
||||
lea rdx, [rsp + 44]
|
||||
movss xmm2, DWORD PTR [rbx + 4]
|
||||
mulss xmm2, DWORD PTR [fDivBy2]
|
||||
call Utils_sinCos
|
||||
|
||||
; sinCos(&SR, &CR, Roll * DIVIDE_BY_2)
|
||||
lea rcx, [rsp + 48]
|
||||
lea rdx, [rsp + 52]
|
||||
movss xmm2, DWORD PTR [rbx + 8]
|
||||
mulss xmm2, DWORD PTR [fDivBy2]
|
||||
call Utils_sinCos
|
||||
|
||||
; Reload locals: SP=rsp+32 CP=rsp+36 SY=rsp+40 CY=rsp+44 SR=rsp+48 CR=rsp+52
|
||||
|
||||
; X = CR*SP*SY - SR*CP*CY
|
||||
movss xmm0, DWORD PTR [rsp + 52] ; CR
|
||||
mulss xmm0, DWORD PTR [rsp + 32] ; * SP
|
||||
mulss xmm0, DWORD PTR [rsp + 40] ; * SY
|
||||
movss xmm1, DWORD PTR [rsp + 48] ; SR
|
||||
mulss xmm1, DWORD PTR [rsp + 36] ; * CP
|
||||
mulss xmm1, DWORD PTR [rsp + 44] ; * CY
|
||||
subss xmm0, xmm1
|
||||
movss DWORD PTR [rsi], xmm0 ; out->X
|
||||
|
||||
; Y = -(CR*SP*CY + SR*CP*SY)
|
||||
movss xmm0, DWORD PTR [rsp + 52] ; CR
|
||||
mulss xmm0, DWORD PTR [rsp + 32] ; * SP
|
||||
mulss xmm0, DWORD PTR [rsp + 44] ; * CY
|
||||
movss xmm1, DWORD PTR [rsp + 48] ; SR
|
||||
mulss xmm1, DWORD PTR [rsp + 36] ; * CP
|
||||
mulss xmm1, DWORD PTR [rsp + 40] ; * SY
|
||||
addss xmm0, xmm1
|
||||
xorps xmm2, xmm2
|
||||
subss xmm2, xmm0 ; negate
|
||||
movss DWORD PTR [rsi + 4], xmm2 ; out->Y
|
||||
|
||||
; Z = CR*CP*SY - SR*SP*CY
|
||||
movss xmm0, DWORD PTR [rsp + 52] ; CR
|
||||
mulss xmm0, DWORD PTR [rsp + 36] ; * CP
|
||||
mulss xmm0, DWORD PTR [rsp + 40] ; * SY
|
||||
movss xmm1, DWORD PTR [rsp + 48] ; SR
|
||||
mulss xmm1, DWORD PTR [rsp + 32] ; * SP
|
||||
mulss xmm1, DWORD PTR [rsp + 44] ; * CY
|
||||
subss xmm0, xmm1
|
||||
movss DWORD PTR [rsi + 8], xmm0 ; out->Z
|
||||
|
||||
; W = CR*CP*CY + SR*SP*SY
|
||||
movss xmm0, DWORD PTR [rsp + 52] ; CR
|
||||
mulss xmm0, DWORD PTR [rsp + 36] ; * CP
|
||||
mulss xmm0, DWORD PTR [rsp + 44] ; * CY
|
||||
movss xmm1, DWORD PTR [rsp + 48] ; SR
|
||||
mulss xmm1, DWORD PTR [rsp + 32] ; * SP
|
||||
mulss xmm1, DWORD PTR [rsp + 40] ; * SY
|
||||
addss xmm0, xmm1
|
||||
movss DWORD PTR [rsi + 12], xmm0 ; out->W
|
||||
|
||||
add rsp, 64
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
Utils_RotToQuat ENDP
|
||||
|
||||
; Utils_VecToRot(RCX=FVector* vec, RDX=FRotator* out_rot)
|
||||
; FVector: X[+0] Y[+4] Z[+8]
|
||||
; FRotator: Pitch[+0] Yaw[+4] Roll[+8]
|
||||
; Yaw = atan2f(Y, X) * (180/PI)
|
||||
; Pitch = atan2f(Z, sqrtf(X*X + Y*Y)) * (180/PI)
|
||||
; Roll = 0
|
||||
; Frame: push rbp rbx rsi + sub 48 (3 pushes -> 0; sub 48 -> 0)
|
||||
Utils_VecToRot PROC
|
||||
push rbp
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 48
|
||||
|
||||
mov rbx, rcx ; rbx = FVector*
|
||||
mov rsi, rdx ; rsi = FRotator*
|
||||
|
||||
; Yaw = atan2f(Y, X) * (180/PI)
|
||||
movss xmm0, DWORD PTR [rbx + 4] ; xmm0 = Y (y argument to atan2)
|
||||
movss xmm1, DWORD PTR [rbx] ; xmm1 = X (x argument to atan2)
|
||||
call atan2f ; XMM0 = atan2(Y, X) in radians
|
||||
mulss xmm0, DWORD PTR [fRadToDeg]
|
||||
movss DWORD PTR [rsi + 4], xmm0 ; out->Yaw
|
||||
|
||||
; Pitch = atan2f(Z, sqrtf(X*X + Y*Y)) * (180/PI)
|
||||
movss xmm0, DWORD PTR [rbx] ; X
|
||||
mulss xmm0, xmm0 ; X*X
|
||||
movss xmm1, DWORD PTR [rbx + 4] ; Y
|
||||
mulss xmm1, xmm1 ; Y*Y
|
||||
addss xmm0, xmm1 ; X*X + Y*Y
|
||||
sqrtss xmm0, xmm0 ; sqrtf(X*X + Y*Y) [hardware SSE]
|
||||
movss xmm1, xmm0 ; xmm1 = sqrt (x arg)
|
||||
movss xmm0, DWORD PTR [rbx + 8] ; xmm0 = Z (y arg)
|
||||
call atan2f ; XMM0 = atan2(Z, sqrt)
|
||||
mulss xmm0, DWORD PTR [fRadToDeg]
|
||||
movss DWORD PTR [rsi], xmm0 ; out->Pitch
|
||||
|
||||
; Roll = 0.0
|
||||
xorps xmm0, xmm0
|
||||
movss DWORD PTR [rsi + 8], xmm0 ; out->Roll
|
||||
|
||||
add rsp, 48
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
Utils_VecToRot ENDP
|
||||
|
||||
; Utils_FRand() -> XMM0 (float in [0.0, 1.0))
|
||||
; Returns (float)rand() / 32767.0f
|
||||
; Frame: push rbp + sub 32 (1 push -> 0; sub 32 -> 0)
|
||||
Utils_FRand PROC
|
||||
push rbp
|
||||
sub rsp, 32
|
||||
|
||||
call rand ; EAX = random int [0, RAND_MAX]
|
||||
cvtsi2ss xmm0, eax ; convert to float
|
||||
divss xmm0, DWORD PTR [fRandMax] ; / 32767.0
|
||||
|
||||
add rsp, 32
|
||||
pop rbp
|
||||
ret
|
||||
Utils_FRand ENDP
|
||||
|
||||
; Utils_RandomIntInRange(ECX=min, EDX=max) -> EAX
|
||||
; Returns a random integer in [min, max] inclusive.
|
||||
; Uses: rand() % (max - min + 1) + min
|
||||
; Frame: push rbp rbx rsi + sub 32 (3 pushes -> 0; sub 32 -> 0)
|
||||
Utils_RandomIntInRange PROC
|
||||
push rbp
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 32
|
||||
|
||||
mov ebx, ecx ; ebx = min
|
||||
sub edx, ecx ; edx = max - min
|
||||
inc edx ; edx = range = max - min + 1
|
||||
mov esi, edx ; esi = range
|
||||
|
||||
call rand ; EAX = rand value
|
||||
|
||||
; EAX % range: use unsigned div (xdiv) since values are non-negative
|
||||
xor edx, edx
|
||||
test esi, esi
|
||||
jle @@zero_range ; guard: range <= 0 -> return min
|
||||
div esi ; EDX = EAX % range
|
||||
add edx, ebx ; result = remainder + min
|
||||
mov eax, edx
|
||||
jmp @@done
|
||||
|
||||
@@zero_range:
|
||||
mov eax, ebx ; return min
|
||||
|
||||
@@done:
|
||||
add rsp, 32
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
Utils_RandomIntInRange ENDP
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user