;; 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> = 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 '#n85'>85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205