1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-11 11:08:02 -06:00

Windows: use separate assembly files for RDRAND and RDSEED in order to fix a mysterious crash when MASM_RDSEED_GenerateBlock is called after MASM_RDRAND_GenerateBlock.

This commit is contained in:
Mounir IDRASSI
2019-10-30 00:15:28 +01:00
parent 3b5d4771a0
commit 7a35ecb154
6 changed files with 291 additions and 228 deletions

View File

@@ -397,6 +397,21 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)" <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command> </Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)" <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="rdseed_ml.asm">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo %(Filename)%(Extension) &amp; ml64.exe /nologo /D_M_X64 /W3 /Cx /Zi /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo %(Filename)%(Extension) &amp; ml64.exe /nologo /D_M_X64 /W3 /Cx /Zi /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
</Command> </Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>

View File

@@ -217,5 +217,8 @@
<CustomBuild Include="rdrand_ml.asm"> <CustomBuild Include="rdrand_ml.asm">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="rdseed_ml.asm">
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -60,4 +60,8 @@ TC_ASM_ERR_LOG = ..\Driver\build_errors_asm.log
"$(OBJ_PATH)\$(O)\rdrand_ml.obj": rdrand_ml.asm "$(OBJ_PATH)\$(O)\rdrand_ml.obj": rdrand_ml.asm
$(VC_MLEXE) $(VC_MLFLAGS) /Fo "$@" /c rdrand_ml.asm 2>$(TC_ASM_ERR_LOG) $(VC_MLEXE) $(VC_MLFLAGS) /Fo "$@" /c rdrand_ml.asm 2>$(TC_ASM_ERR_LOG)
"$(OBJ_PATH)\$(O)\rdseed_ml.obj": rdseed_ml.asm
$(VC_MLEXE) $(VC_MLFLAGS) /Fo "$@" /c rdseed_ml.asm 2>$(TC_ASM_ERR_LOG)

View File

@@ -25,6 +25,7 @@ SOURCES = \
gost89_$(TC_ARCH).asm \ gost89_$(TC_ARCH).asm \
Aes_hw_cpu.asm \ Aes_hw_cpu.asm \
rdrand_ml.asm \ rdrand_ml.asm \
rdseed_ml.asm \
Aeskey.c \ Aeskey.c \
Aestab.c \ Aestab.c \
chacha-xmm.c \ chacha-xmm.c \

View File

@@ -1,9 +1,9 @@
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
;; Copyright assigned to the Crypto++ project. ;; Copyright assigned to the Crypto++ project.
;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains. ;; This ASM file provides RDRAND to downlevel Microsoft tool chains.
;; Everything "just works" under Visual Studio. Other platforms will have to ;; Everything "just works" under Visual Studio. Other platforms will
;; run MASM/MASM-64 and then link to the object files. ;; have to run MASM/MASM-64 and then link to the object files.
;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh ;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi ;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
@@ -13,11 +13,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TITLE MASM_RDRAND_GenerateBlock and MASM_RDSEED_GenerateBlock TITLE MASM_RDRAND_GenerateBlock source file
SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains SUBTITLE Microsoft specific ASM code to utilize RDRAND for down level Microsoft toolchains
PUBLIC MASM_RDRAND_GenerateBlock PUBLIC MASM_RDRAND_GenerateBlock
PUBLIC MASM_RDSEED_GenerateBlock
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -38,7 +37,6 @@ IFDEF _M_X86 ;; Set via the command line
;; Fastcall calling conventions exports ;; Fastcall calling conventions exports
ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock> ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock>
ALIAS <@MASM_RDSEED_GenerateBlock@8> = <MASM_RDSEED_GenerateBlock>
ENDIF ENDIF
@@ -63,13 +61,13 @@ MASM_RDRAND_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
bsize EQU edx bsize EQU edx
;; Top of While loop ;; Top of While loop
GenerateBlock_Top: RDRAND_GenerateBlock_Top:
;; Check remaining size ;; Check remaining size
cmp bsize, 0 cmp bsize, 0
je GenerateBlock_Return je RDRAND_GenerateBlock_Return
Call_RDRAND_EAX: RDRAND_Call_EAX:
;; RDRAND is not available prior to VS2012. Just emit ;; RDRAND is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdrand eax`. ;; the byte codes using DB. This is `rdrand eax`.
DB 0Fh, 0C7h, 0F0h DB 0Fh, 0C7h, 0F0h
@@ -78,46 +76,48 @@ Call_RDRAND_EAX:
;; If CF=0, a random number was not available. ;; If CF=0, a random number was not available.
;; Retry immediately ;; Retry immediately
jnc Call_RDRAND_EAX jnc RDRAND_Call_EAX
RDRAND_succeeded: RDRAND_succeeded:
cmp bsize, MWSIZE cmp bsize, MWSIZE
jb Partial_Machine_Word jb RDRAND_Partial_Machine_Word
Full_Machine_Word: RDRAND_Full_Machine_Word:
mov DWORD PTR [buffer], eax mov DWORD PTR [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
;; Continue ;; Continue
jmp GenerateBlock_Top jmp RDRAND_GenerateBlock_Top
;; 1,2,3 bytes remain ;; 1,2,3 bytes remain
Partial_Machine_Word: RDRAND_Partial_Machine_Word:
;; Test bit 1 to see if size is at least 2 ;; Test bit 1 to see if size is at least 2
test bsize, 2 test bsize, 2
jz Bit_1_Not_Set jz RDRAND_Bit_1_Not_Set
mov WORD PTR [buffer], ax mov WORD PTR [buffer], ax
shr eax, 16 shr eax, 16
add buffer, 2 add buffer, 2
Bit_1_Not_Set: RDRAND_Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1 ;; Test bit 0 to see if size is at least 1
test bsize, 1 test bsize, 1
jz Bit_0_Not_Set jz RDRAND_Bit_0_Not_Set
mov BYTE PTR [buffer], al mov BYTE PTR [buffer], al
;; shr ax, 8
;; add buffer, 1
Bit_0_Not_Set: RDRAND_Bit_0_Not_Set:
;; We've hit all the bits ;; We've hit all the bits
GenerateBlock_Return: RDRAND_GenerateBlock_Return:
;; Clear artifacts ;; Clear artifacts
xor eax, eax xor eax, eax
@@ -127,9 +127,6 @@ MASM_RDRAND_GenerateBlock ENDP
ENDIF ;; _M_X86 ENDIF ;; _M_X86
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -151,13 +148,13 @@ MASM_RDRAND_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
bsize EQU rdx bsize EQU rdx
;; Top of While loop ;; Top of While loop
GenerateBlock_Top: RDRAND_GenerateBlock_Top:
;; Check remaining size ;; Check remaining size
cmp bsize, 0 cmp bsize, 0
je GenerateBlock_Return je RDRAND_GenerateBlock_Return
Call_RDRAND_RAX: RDRAND_Call_RAX:
;; RDRAND is not available prior to VS2012. Just emit ;; RDRAND is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdrand rax`. ;; the byte codes using DB. This is `rdrand rax`.
DB 048h, 0Fh, 0C7h, 0F0h DB 048h, 0Fh, 0C7h, 0F0h
@@ -166,254 +163,67 @@ Call_RDRAND_RAX:
;; If CF=0, a random number was not available. ;; If CF=0, a random number was not available.
;; Retry immediately ;; Retry immediately
jnc Call_RDRAND_RAX jnc RDRAND_Call_RAX
RDRAND_succeeded: RDRAND_succeeded:
cmp bsize, MWSIZE cmp bsize, MWSIZE
jb Partial_Machine_Word jb RDRAND_Partial_Machine_Word
Full_Machine_Word: RDRAND_Full_Machine_Word:
mov QWORD PTR [buffer], rax mov QWORD PTR [buffer], rax
add buffer, MWSIZE add buffer, MWSIZE
sub bsize, MWSIZE sub bsize, MWSIZE
;; Continue ;; Continue
jmp GenerateBlock_Top jmp RDRAND_GenerateBlock_Top
;; 1,2,3,4,5,6,7 bytes remain ;; 1,2,3,4,5,6,7 bytes remain
Partial_Machine_Word: RDRAND_Partial_Machine_Word:
;; Test bit 2 to see if size is at least 4 ;; Test bit 2 to see if size is at least 4
test bsize, 4 test bsize, 4
jz Bit_2_Not_Set jz RDRAND_Bit_2_Not_Set
mov DWORD PTR [buffer], eax mov DWORD PTR [buffer], eax
shr rax, 32 shr rax, 32
add buffer, 4 add buffer, 4
Bit_2_Not_Set: RDRAND_Bit_2_Not_Set:
;; Test bit 1 to see if size is at least 2 ;; Test bit 1 to see if size is at least 2
test bsize, 2 test bsize, 2
jz Bit_1_Not_Set jz RDRAND_Bit_1_Not_Set
mov WORD PTR [buffer], ax mov WORD PTR [buffer], ax
shr eax, 16 shr eax, 16
add buffer, 2 add buffer, 2
Bit_1_Not_Set: RDRAND_Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1 ;; Test bit 0 to see if size is at least 1
test bsize, 1 test bsize, 1
jz Bit_0_Not_Set jz RDRAND_Bit_0_Not_Set
mov BYTE PTR [buffer], al mov BYTE PTR [buffer], al
;; shr ax, 8
;; add buffer, 1
Bit_0_Not_Set: RDRAND_Bit_0_Not_Set:
;; We've hit all the bits ;; We've hit all the bits
GenerateBlock_Return: RDRAND_GenerateBlock_Return:
;; Clear artifacts
xor rax, rax
ret
MASM_RDRAND_GenerateBlock ENDP
ENDIF ;; _M_X64
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFDEF _M_X86 ;; Set via the command line
.CODE
ALIGN 8
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
;; No need for Load_Arguments due to fastcall
;; ECX (in): arg1, byte* buffer
;; EDX (in): arg2, size_t bsize
MASM_RDSEED_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
MWSIZE EQU 04h ;; machine word size
buffer EQU ecx
bsize EQU edx
;; Top of While loop
GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je GenerateBlock_Return
Call_RDSEED_EAX:
;; RDSEED is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdseed eax`.
DB 0Fh, 0C7h, 0F8h
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
;; Retry immediately
jnc Call_RDSEED_EAX
RDSEED_succeeded:
cmp bsize, MWSIZE
jb Partial_Machine_Word
Full_Machine_Word:
mov DWORD PTR [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
;; Continue
jmp GenerateBlock_Top
;; 1,2,3 bytes remain
Partial_Machine_Word:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz Bit_1_Not_Set
mov WORD PTR [buffer], ax
shr eax, 16
add buffer, 2
Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz Bit_0_Not_Set
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits
GenerateBlock_Return:
;; Clear artifacts
xor eax, eax
ret
MASM_RDSEED_GenerateBlock ENDP
ENDIF ;; _M_X86
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFDEF _M_X64 ;; Set via the command line
.CODE
ALIGN 16
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
;; No need for Load_Arguments due to fastcall
;; RCX (in): arg1, byte* buffer
;; RDX (in): arg2, size_t bsize
MASM_RDSEED_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
MWSIZE EQU 08h ;; machine word size
buffer EQU rcx
bsize EQU rdx
;; Top of While loop
GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je GenerateBlock_Return
Call_RDSEED_RAX:
;; RDSEED is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdseed rax`.
DB 048h, 0Fh, 0C7h, 0F8h
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
;; Retry immediately
jnc Call_RDSEED_RAX
RDSEED_succeeded:
cmp bsize, MWSIZE
jb Partial_Machine_Word
Full_Machine_Word:
mov QWORD PTR [buffer], rax
add buffer, MWSIZE
sub bsize, MWSIZE
;; Continue
jmp GenerateBlock_Top
;; 1,2,3,4,5,6,7 bytes remain
Partial_Machine_Word:
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz Bit_2_Not_Set
mov DWORD PTR [buffer], eax
shr rax, 32
add buffer, 4
Bit_2_Not_Set:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz Bit_1_Not_Set
mov WORD PTR [buffer], ax
shr eax, 16
add buffer, 2
Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz Bit_0_Not_Set
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits
GenerateBlock_Return:
;; Clear artifacts ;; Clear artifacts
xor rax, rax xor rax, rax
ret ret
MASM_RDSEED_GenerateBlock ENDP MASM_RDRAND_GenerateBlock ENDP
ENDIF ;; _M_X64 ENDIF ;; _M_X64
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

230
src/Crypto/rdseed_ml.asm Normal file
View File

@@ -0,0 +1,230 @@
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
;; Copyright assigned to the Crypto++ project.
;; This ASM file provides RDSEED to downlevel Microsoft tool chains.
;; Everything "just works" under Visual Studio. Other platforms will
;; have to run MASM/MASM-64 and then link to the object files.
;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TITLE MASM_RDSEED_GenerateBlock source file
SUBTITLE Microsoft specific ASM code to utilize RDSEED for down level Microsoft toolchains
PUBLIC MASM_RDSEED_GenerateBlock
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; C/C++ Function prototypes (both are fastcall)
;; X86:
;; extern "C" void __fastcall MASM_RDSEED_GenerateBlock(byte* ptr, size_t size);
;; X64:
;; extern "C" void __fastcall MASM_RDSEED_GenerateBlock(byte* ptr, size_t size);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFDEF _M_X86 ;; Set via the command line
.486
.MODEL FLAT
;; Fastcall calling conventions exports
ALIAS <@MASM_RDSEED_GenerateBlock@8> = <MASM_RDSEED_GenerateBlock>
ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFDEF _M_X86 ;; Set via the command line
.CODE
ALIGN 8
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
;; No need for Load_Arguments due to fastcall
;; ECX (in): arg1, byte* buffer
;; EDX (in): arg2, size_t bsize
MASM_RDSEED_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
MWSIZE EQU 04h ;; machine word size
buffer EQU ecx
bsize EQU edx
;; Top of While loop
RDSEED_GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je RDSEED_GenerateBlock_Return
RDSEED_Call_EAX:
;; RDSEED is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdseed eax`.
DB 0Fh, 0C7h, 0F8h
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
;; Retry immediately
jnc RDSEED_Call_EAX
RDSEED_succeeded:
cmp bsize, MWSIZE
jb RDSEED_Partial_Machine_Word
RDSEED_Full_Machine_Word:
mov DWORD PTR [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
;; Continue
jmp RDSEED_GenerateBlock_Top
;; 1,2,3 bytes remain
RDSEED_Partial_Machine_Word:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz RDSEED_Bit_1_Not_Set
mov WORD PTR [buffer], ax
shr eax, 16
add buffer, 2
RDSEED_Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz RDSEED_Bit_0_Not_Set
mov BYTE PTR [buffer], al
;; shr ax, 8
;; add buffer, 1
RDSEED_Bit_0_Not_Set:
;; We've hit all the bits
RDSEED_GenerateBlock_Return:
;; Clear artifacts
xor eax, eax
ret
MASM_RDSEED_GenerateBlock ENDP
ENDIF ;; _M_X86
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFDEF _M_X64 ;; Set via the command line
.CODE
ALIGN 16
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
;; No need for Load_Arguments due to fastcall
;; RCX (in): arg1, byte* buffer
;; RDX (in): arg2, size_t bsize
MASM_RDSEED_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
MWSIZE EQU 08h ;; machine word size
buffer EQU rcx
bsize EQU rdx
;; Top of While loop
RDSEED_GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je RDSEED_GenerateBlock_Return
RDSEED_Call_RAX:
;; RDSEED is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdseed rax`.
DB 048h, 0Fh, 0C7h, 0F8h
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
;; Retry immediately
jnc RDSEED_Call_RAX
RDSEED_succeeded:
cmp bsize, MWSIZE
jb RDSEED_Partial_Machine_Word
RDSEED_Full_Machine_Word:
mov QWORD PTR [buffer], rax
add buffer, MWSIZE
sub bsize, MWSIZE
;; Continue
jmp RDSEED_GenerateBlock_Top
;; 1,2,3,4,5,6,7 bytes remain
RDSEED_Partial_Machine_Word:
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz RDSEED_Bit_2_Not_Set
mov DWORD PTR [buffer], eax
shr rax, 32
add buffer, 4
RDSEED_Bit_2_Not_Set:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz RDSEED_Bit_1_Not_Set
mov WORD PTR [buffer], ax
shr eax, 16
add buffer, 2
RDSEED_Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz RDSEED_Bit_0_Not_Set
mov BYTE PTR [buffer], al
;; shr ax, 8
;; add buffer, 1
RDSEED_Bit_0_Not_Set:
;; We've hit all the bits
RDSEED_GenerateBlock_Return:
;; Clear artifacts
xor rax, rax
ret
MASM_RDSEED_GenerateBlock ENDP
ENDIF ;; _M_X64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
END