Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

596 lines
11 KiB

  1. ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
  2. ;; Copyright assigned to the Crypto++ project.
  3. ;; This ASM file provides RDRAND and RDSEED to downlevel Unix and Linux tool chains.
  4. ;; Additionally, the inline assembly code produced by GCC and Clang is not that
  5. ;; impressive. However, using this code requires NASM and an edit to the GNUmakefile.
  6. ;; nasm -f elf32 rdrand.S -DX86 -g -o rdrand-x86.o
  7. ;; nasm -f elfx32 rdrand.S -DX32 -g -o rdrand-x32.o
  8. ;; nasm -f elf64 rdrand.S -DX64 -g -o rdrand-x64.o
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  11. ;; Naming convention used in rdrand.{h|cpp|asm|S}
  12. ;; MSC = Microsoft Compiler (and compatibles)
  13. ;; GCC = GNU Compiler (and compatibles)
  14. ;; ALL = MSC and GCC (and compatibles)
  15. ;; RRA = RDRAND, Assembly
  16. ;; RSA = RDSEED, Assembly
  17. ;; RRI = RDRAND, Intrinsic
  18. ;; RSA = RDSEED, Intrinsic
  19. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  20. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21. ;; C/C++ Function prototypes
  22. ;; X86, X32 and X64:
  23. ;; extern "C" int NASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
  24. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  25. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  26. ;; Return values
  27. %define RDRAND_SUCCESS 1
  28. %define RDRAND_FAILURE 0
  29. %define RDSEED_SUCCESS 1
  30. %define RDSEED_FAILURE 0
  31. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  32. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  33. %ifdef X86 or X32 ;; Set via the command line
  34. ;; Arg1, byte* buffer
  35. ;; Arg2, size_t bsize
  36. ;; Arg3, unsigned int safety
  37. ;; EAX (out): success (1), failure (0)
  38. global NASM_RRA_GenerateBlock
  39. section .text
  40. %ifdef X86
  41. align 8
  42. cpu 486
  43. %else
  44. align 16
  45. %endif
  46. NASM_RRA_GenerateBlock:
  47. %ifdef X86
  48. %define arg1 [ebp+04h]
  49. %define arg2 [ebp+08h]
  50. %define arg3 [ebp+0ch]
  51. %define MWSIZE 04h ;; machine word size
  52. %else
  53. %define MWSIZE 08h ;; machine word size
  54. %endif
  55. %define buffer edi
  56. %define bsize esi
  57. %define safety edx
  58. %ifdef X86
  59. .Load_Arguments:
  60. mov buffer, arg1
  61. mov bsize, arg2
  62. mov safety, arg3
  63. %endif
  64. .Validate_Pointer:
  65. cmp buffer, 0
  66. je .GenerateBlock_PreRet
  67. ;; Top of While loop
  68. .GenerateBlock_Top:
  69. ;; Check remaining size
  70. cmp bsize, 0
  71. je .GenerateBlock_Success
  72. %ifdef X86
  73. .Call_RDRAND_EAX:
  74. %else
  75. .Call_RDRAND_RAX:
  76. DB 48h ;; X32 can use the full register, issue the REX.w prefix
  77. %endif
  78. ;; RDRAND is not available prior to VS2012. Just emit
  79. ;; the byte codes using DB. This is `rdrand eax`.
  80. DB 0Fh, 07h, F0h
  81. ;; If CF=1, the number returned by RDRAND is valid.
  82. ;; If CF=0, a random number was not available.
  83. jc .RDRAND_succeeded
  84. .RDRAND_failed:
  85. ;; Exit if we've reached the limit
  86. cmp safety, 0
  87. je .GenerateBlock_Failure
  88. dec safety
  89. jmp .GenerateBlock_Top
  90. .RDRAND_succeeded:
  91. cmp bsize, MWSIZE
  92. jb .Partial_Machine_Word
  93. .Full_Machine_Word:
  94. %ifdef X32
  95. mov [buffer+4], eax ;; We can only move 4 at a time
  96. DB 048h ;; Combined, these result in
  97. shr eax, 32 ;; `shr rax, 32`
  98. %endif
  99. mov [buffer], eax
  100. add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
  101. sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
  102. ;; Continue
  103. jmp .GenerateBlock_Top
  104. ;; 1,2,3 bytes remain for X86
  105. ;; 1,2,3,4,5,6,7 remain for X32
  106. .Partial_Machine_Word:
  107. %ifdef X32
  108. ;; Test bit 2 to see if size is at least 4
  109. test bsize, 4
  110. jz .Bit_2_Not_Set
  111. mov [buffer], eax
  112. add buffer, 4
  113. DB 048h ;; Combined, these result in
  114. shr eax, 32 ;; `shr rax, 32`
  115. .Bit_2_Not_Set:
  116. %endif
  117. ;; Test bit 1 to see if size is at least 2
  118. test bsize, 2
  119. jz .Bit_1_Not_Set
  120. mov [buffer], ax
  121. shr eax, 16
  122. add buffer, 2
  123. .Bit_1_Not_Set:
  124. ;; Test bit 0 to see if size is at least 1
  125. test bsize, 1
  126. jz .GenerateBlock_Success
  127. mov [buffer], al
  128. .Bit_0_Not_Set:
  129. ;; We've hit all the bits
  130. jmp .GenerateBlock_Success
  131. .GenerateBlock_PreRet:
  132. ;; Test for success (was the request completely fulfilled?)
  133. cmp bsize, 0
  134. je .GenerateBlock_Success
  135. .GenerateBlock_Failure:
  136. xor eax, eax
  137. mov al, RDRAND_FAILURE
  138. ret
  139. .GenerateBlock_Success:
  140. xor eax, eax
  141. mov al, RDRAND_SUCCESS
  142. ret
  143. %endif ;; X86 and X32
  144. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  145. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  146. %ifdef X64 ;; Set via the command line
  147. global NASM_RRA_GenerateBlock
  148. section .text
  149. align 16
  150. ;; Arg1, byte* buffer
  151. ;; Arg2, size_t bsize
  152. ;; Arg3, unsigned int safety
  153. ;; RAX (out): success (1), failure (0)
  154. NASM_RRA_GenerateBlock:
  155. %define MWSIZE 08h ;; machine word size
  156. %define buffer rdi
  157. %define bsize rsi
  158. %define safety edx
  159. ;; No need for Load_Arguments due to fastcall
  160. .Validate_Pointer:
  161. ;; Validate pointer
  162. cmp buffer, 0
  163. je .GenerateBlock_PreRet
  164. ;; Top of While loop
  165. .GenerateBlock_Top:
  166. ;; Check remaining size
  167. cmp bsize, 0
  168. je .GenerateBlock_Success
  169. .Call_RDRAND_RAX:
  170. ;; RDRAND is not available prior to VS2012. Just emit
  171. ;; the byte codes using DB. This is `rdrand rax`.
  172. DB 048h, 0Fh, 0C7h, 0F0h
  173. ;; If CF=1, the number returned by RDRAND is valid.
  174. ;; If CF=0, a random number was not available.
  175. jc .RDRAND_succeeded
  176. .RDRAND_failed:
  177. ;; Exit if we've reached the limit
  178. cmp safety, 0h
  179. je .GenerateBlock_Failure
  180. dec safety
  181. jmp .GenerateBlock_Top
  182. .RDRAND_succeeded:
  183. cmp bsize, MWSIZE
  184. jb .Partial_Machine_Word
  185. .Full_Machine_Word:
  186. mov [buffer], rax
  187. add buffer, MWSIZE
  188. sub bsize, MWSIZE
  189. ;; Continue
  190. jmp .GenerateBlock_Top
  191. ;; 1,2,3,4,5,6,7 bytes remain
  192. .Partial_Machine_Word:
  193. ;; Test bit 2 to see if size is at least 4
  194. test bsize, 4
  195. jz .Bit_2_Not_Set
  196. mov [buffer], eax
  197. shr rax, 32
  198. add buffer, 4
  199. .Bit_2_Not_Set:
  200. ;; Test bit 1 to see if size is at least 2
  201. test bsize, 2
  202. jz .Bit_1_Not_Set
  203. mov [buffer], ax
  204. shr eax, 16
  205. add buffer, 2
  206. .Bit_1_Not_Set:
  207. ;; Test bit 0 to see if size is at least 1
  208. test bsize, 1
  209. jz .GenerateBlock_Success
  210. mov [buffer], al
  211. .Bit_0_Not_Set:
  212. ;; We've hit all the bits
  213. jmp .GenerateBlock_Success
  214. .GenerateBlock_PreRet:
  215. ;; Test for success (was the request completely fulfilled?)
  216. cmp bsize, 0
  217. je .GenerateBlock_Success
  218. .GenerateBlock_Failure:
  219. xor rax, rax
  220. mov al, RDRAND_FAILURE
  221. ret
  222. .GenerateBlock_Success:
  223. xor rax, rax
  224. mov al, RDRAND_SUCCESS
  225. ret
  226. %endif ;; X64
  227. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  229. %ifdef X86 or X32 ;; Set via the command line
  230. ;; Arg1, byte* buffer
  231. ;; Arg2, size_t bsize
  232. ;; Arg3, unsigned int safety
  233. ;; EAX (out): success (1), failure (0)
  234. global NASM_RSA_GenerateBlock
  235. section .text
  236. align 8
  237. %ifdef X86
  238. align 8
  239. cpu 486
  240. %else
  241. align 16
  242. %endif
  243. NASM_RSA_GenerateBlock:
  244. %ifdef X86
  245. %define arg1 [ebp+04h]
  246. %define arg2 [ebp+08h]
  247. %define arg3 [ebp+0ch]
  248. %define MWSIZE 04h ;; machine word size
  249. %else
  250. %define MWSIZE 08h ;; machine word size
  251. %endif
  252. %define buffer edi
  253. %define bsize esi
  254. %define safety edx
  255. %ifdef X86
  256. .Load_Arguments:
  257. mov buffer, arg1
  258. mov bsize, arg2
  259. mov safety, arg3
  260. %endif
  261. .Validate_Pointer:
  262. cmp buffer, 0
  263. je .GenerateBlock_PreRet
  264. ;; Top of While loop
  265. .GenerateBlock_Top:
  266. ;; Check remaining size
  267. cmp bsize, 0
  268. je .GenerateBlock_Success
  269. %ifdef X86
  270. .Call_RDSEED_EAX:
  271. %else
  272. .Call_RDSEED_RAX:
  273. DB 48h ;; X32 can use the full register, issue the REX.w prefix
  274. %endif
  275. ;; RDSEED is not available prior to VS2012. Just emit
  276. ;; the byte codes using DB. This is `rdseed eax`.
  277. DB 0Fh, 0C7h, 0F8h
  278. ;; If CF=1, the number returned by RDSEED is valid.
  279. ;; If CF=0, a random number was not available.
  280. jc .RDSEED_succeeded
  281. .RDSEED_failed:
  282. ;; Exit if we've reached the limit
  283. cmp safety, 0
  284. je .GenerateBlock_Failure
  285. dec safety
  286. jmp .GenerateBlock_Top
  287. .RDSEED_succeeded:
  288. cmp bsize, MWSIZE
  289. jb .Partial_Machine_Word
  290. .Full_Machine_Word:
  291. mov [buffer], eax
  292. add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
  293. sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
  294. ;; Continue
  295. jmp .GenerateBlock_Top
  296. ;; 1,2,3 bytes remain for X86
  297. ;; 1,2,3,4,5,6,7 remain for X32
  298. .Partial_Machine_Word:
  299. %ifdef X32
  300. ;; Test bit 2 to see if size is at least 4
  301. test bsize, 4
  302. jz .Bit_2_Not_Set
  303. mov [buffer], eax
  304. add buffer, 4
  305. DB 048h ;; Combined, these result in
  306. shr eax, 32 ;; `shr rax, 32`
  307. .Bit_2_Not_Set:
  308. %endif
  309. ;; Test bit 1 to see if size is at least 2
  310. test bsize, 2
  311. jz .Bit_1_Not_Set
  312. mov [buffer], ax
  313. shr eax, 16
  314. add buffer, 2
  315. .Bit_1_Not_Set:
  316. ;; Test bit 0 to see if size is at least 1
  317. test bsize, 1
  318. jz .GenerateBlock_Success
  319. mov [buffer], al
  320. .Bit_0_Not_Set:
  321. ;; We've hit all the bits
  322. jmp .GenerateBlock_Success
  323. .GenerateBlock_PreRet:
  324. ;; Test for success (was the request completely fulfilled?)
  325. cmp bsize, 0
  326. je .GenerateBlock_Success
  327. .GenerateBlock_Failure:
  328. xor eax, eax
  329. mov al, RDSEED_FAILURE
  330. ret
  331. .GenerateBlock_Success:
  332. xor eax, eax
  333. mov al, RDSEED_SUCCESS
  334. ret
  335. %endif ;; X86 and X32
  336. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  337. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  338. %ifdef X64 ;; Set via the command line
  339. global NASM_RSA_GenerateBlock
  340. section .text
  341. align 16
  342. ;; Arg1, byte* buffer
  343. ;; Arg2, size_t bsize
  344. ;; Arg3, unsigned int safety
  345. ;; RAX (out): success (1), failure (0)
  346. NASM_RSA_GenerateBlock:
  347. %define MWSIZE 08h ;; machine word size
  348. %define buffer rdi
  349. %define bsize rsi
  350. %define safety edx
  351. ;; No need for Load_Arguments due to fastcall
  352. .Validate_Pointer:
  353. ;; Validate pointer
  354. cmp buffer, 0
  355. je .GenerateBlock_PreRet
  356. ;; Top of While loop
  357. .GenerateBlock_Top:
  358. ;; Check remaining size
  359. cmp bsize, 0
  360. je .GenerateBlock_Success
  361. .Call_RDSEED_RAX:
  362. ;; RDSEED is not available prior to VS2012. Just emit
  363. ;; the byte codes using DB. This is `rdseed rax`.
  364. DB 048h, 0Fh, 0C7h, 0F8h
  365. ;; If CF=1, the number returned by RDSEED is valid.
  366. ;; If CF=0, a random number was not available.
  367. jc .RDSEED_succeeded
  368. .RDSEED_failed:
  369. ;; Exit if we've reached the limit
  370. cmp safety, 0
  371. je .GenerateBlock_Failure
  372. dec safety
  373. jmp .GenerateBlock_Top
  374. .RDSEED_succeeded:
  375. cmp bsize, MWSIZE
  376. jb .Partial_Machine_Word
  377. .Full_Machine_Word:
  378. mov [buffer], rax
  379. add buffer, MWSIZE
  380. sub bsize, MWSIZE
  381. ;; Continue
  382. jmp .GenerateBlock_Top
  383. ;; 1,2,3,4,5,6,7 bytes remain
  384. .Partial_Machine_Word:
  385. ;; Test bit 2 to see if size is at least 4
  386. test bsize, 4
  387. jz .Bit_2_Not_Set
  388. mov [buffer], eax
  389. shr rax, 32
  390. add buffer, 4
  391. .Bit_2_Not_Set:
  392. ;; Test bit 1 to see if size is at least 2
  393. test bsize, 2
  394. jz .Bit_1_Not_Set
  395. mov [buffer], ax
  396. shr eax, 16
  397. add buffer, 2
  398. .Bit_1_Not_Set:
  399. ;; Test bit 0 to see if size is at least 1
  400. test bsize, 1
  401. jz .GenerateBlock_Success
  402. mov [buffer], al
  403. .Bit_0_Not_Set:
  404. ;; We've hit all the bits
  405. jmp .GenerateBlock_Success
  406. .GenerateBlock_PreRet:
  407. ;; Test for success (was the request completely fulfilled?)
  408. cmp bsize, 0
  409. je .GenerateBlock_Success
  410. .GenerateBlock_Failure:
  411. xor rax, rax
  412. mov al, RDSEED_FAILURE
  413. ret
  414. .GenerateBlock_Success:
  415. xor rax, rax
  416. mov al, RDSEED_SUCCESS
  417. ret
  418. %endif ;; _M_X64
  419. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  420. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;