Crypto++ 8.9
Free C++ class library of cryptographic schemes
rdrand.asm
1;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2;; Copyright assigned to the Crypto++ project.
3
4;; This ASM file provides RDRAND to downlevel Microsoft tool chains.
5;; Everything "just works" under Visual Studio. Other platforms will
6;; have to run MASM/MASM-64 and then link to the object files.
7
8;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
9;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
10;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
11;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
12
13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15
16TITLE MASM_RDRAND_GenerateBlock source file
17SUBTITLE Microsoft specific ASM code to utilize RDRAND for down level Microsoft toolchains
18
19PUBLIC MASM_RDRAND_GenerateBlock
20
21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
24;; C/C++ Function prototypes (both are fastcall)
25;; X86:
26;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
27;; X64:
28;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
29
30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32
33IFDEF _M_X86 ;; Set via the command line
34
35.486
36.MODEL FLAT
37
38;; Fastcall calling conventions exports
39ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock>
40
41ENDIF
42
43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45
46IFDEF _M_X86 ;; Set via the command line
47
48.CODE
49ALIGN 8
50OPTION PROLOGUE:NONE
51OPTION EPILOGUE:NONE
52
53;; No need for Load_Arguments due to fastcall
54;; ECX (in): arg1, byte* buffer
55;; EDX (in): arg2, size_t bsize
56
57MASM_RDRAND_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
58
59 MWSIZE EQU 04h ;; machine word size
60 buffer EQU ecx
61 bsize EQU edx
62
63 ;; Top of While loop
64RDRAND_GenerateBlock_Top:
65
66 ;; Check remaining size
67 cmp bsize, 0
68 je RDRAND_GenerateBlock_Return
69
70RDRAND_Call_EAX:
71 ;; RDRAND is not available prior to VS2012. Just emit
72 ;; the byte codes using DB. This is `rdrand eax`.
73 DB 0Fh, 0C7h, 0F0h
74
75 ;; If CF=1, the number returned by RDRAND is valid.
76 ;; If CF=0, a random number was not available.
77
78 ;; Retry immediately
79 jnc RDRAND_Call_EAX
80
81RDRAND_succeeded:
82
83 cmp bsize, MWSIZE
84 jb RDRAND_Partial_Machine_Word
85
86RDRAND_Full_Machine_Word:
87
88 mov DWORD PTR [buffer], eax
89 add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
90 sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
91
92 ;; Continue
93 jmp RDRAND_GenerateBlock_Top
94
95 ;; 1,2,3 bytes remain
96RDRAND_Partial_Machine_Word:
97
98 ;; Test bit 1 to see if size is at least 2
99 test bsize, 2
100 jz RDRAND_Bit_1_Not_Set
101
102 mov WORD PTR [buffer], ax
103 shr eax, 16
104 add buffer, 2
105
106RDRAND_Bit_1_Not_Set:
107
108 ;; Test bit 0 to see if size is at least 1
109 test bsize, 1
110 jz RDRAND_Bit_0_Not_Set
111
112 mov BYTE PTR [buffer], al
113 ;; shr ax, 8
114 ;; add buffer, 1
115
116RDRAND_Bit_0_Not_Set:
117
118 ;; We've hit all the bits
119
120RDRAND_GenerateBlock_Return:
121
122 ;; Clear artifacts
123 xor eax, eax
124 ret
125
126MASM_RDRAND_GenerateBlock ENDP
127
128ENDIF ;; _M_X86
129
130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
133IFDEF _M_X64 ;; Set via the command line
134
135.CODE
136ALIGN 16
137OPTION PROLOGUE:NONE
138OPTION EPILOGUE:NONE
139
140;; No need for Load_Arguments due to fastcall
141;; RCX (in): arg1, byte* buffer
142;; RDX (in): arg2, size_t bsize
143
144MASM_RDRAND_GenerateBlock PROC FRAME ;; arg1:QWORD, arg2:QWORD
145
146 MWSIZE EQU 08h ;; machine word size
147 buffer EQU rcx
148 bsize EQU rdx
149
150.endprolog
151
152 ;; Top of While loop
153RDRAND_GenerateBlock_Top:
154
155 ;; Check remaining size
156 cmp bsize, 0
157 je RDRAND_GenerateBlock_Return
158
159RDRAND_Call_RAX:
160 ;; RDRAND is not available prior to VS2012. Just emit
161 ;; the byte codes using DB. This is `rdrand rax`.
162 DB 048h, 0Fh, 0C7h, 0F0h
163
164 ;; If CF=1, the number returned by RDRAND is valid.
165 ;; If CF=0, a random number was not available.
166
167 ;; Retry immediately
168 jnc RDRAND_Call_RAX
169
170RDRAND_succeeded:
171
172 cmp bsize, MWSIZE
173 jb RDRAND_Partial_Machine_Word
174
175RDRAND_Full_Machine_Word:
176
177 mov QWORD PTR [buffer], rax
178 add buffer, MWSIZE
179 sub bsize, MWSIZE
180
181 ;; Continue
182 jmp RDRAND_GenerateBlock_Top
183
184 ;; 1,2,3,4,5,6,7 bytes remain
185RDRAND_Partial_Machine_Word:
186
187 ;; Test bit 2 to see if size is at least 4
188 test bsize, 4
189 jz RDRAND_Bit_2_Not_Set
190
191 mov DWORD PTR [buffer], eax
192 shr rax, 32
193 add buffer, 4
194
195RDRAND_Bit_2_Not_Set:
196
197 ;; Test bit 1 to see if size is at least 2
198 test bsize, 2
199 jz RDRAND_Bit_1_Not_Set
200
201 mov WORD PTR [buffer], ax
202 shr eax, 16
203 add buffer, 2
204
205RDRAND_Bit_1_Not_Set:
206
207 ;; Test bit 0 to see if size is at least 1
208 test bsize, 1
209 jz RDRAND_Bit_0_Not_Set
210
211 mov BYTE PTR [buffer], al
212 ;; shr ax, 8
213 ;; add buffer, 1
214
215RDRAND_Bit_0_Not_Set:
216
217 ;; We've hit all the bits
218
219RDRAND_GenerateBlock_Return:
220
221 ;; Clear artifacts
222 xor rax, rax
223 ret
224
225MASM_RDRAND_GenerateBlock ENDP
226
227ENDIF ;; _M_X64
228
229;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
230;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
231
232END