ext-cryptopp/rdrand.S

447 lines
9.8 KiB
ArmAsm
Raw Normal View History

2015-11-23 00:17:15 +00:00
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
;; Copyright assigned to the Crypto++ project.
;; This ASM file provides RDRAND and RDSEED to downlevel Unix and Linux tool chains.
;; Additionally, the inline assembly code produced by GCC and Clang is not that
;; impressive. However, using this code requires NASM and an edit to the GNUmakefile.
;; nasm -f elf32 rdrand.S -DX86 -g -o rdrand-x86.o
;; nasm -f elfx32 rdrand.S -DX32 -g -o rdrand-x32.o
;; nasm -f elf64 rdrand.S -DX64 -g -o rdrand-x64.o
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; C/C++ Function prototypes
;; X86, X32 and X64:
;; extern "C" void NASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
;; extern "C" void NASM_RDSEED_GenerateBlock(byte* ptr, size_t size);
2015-11-23 00:17:15 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X86 or X32 ;; Set via the command line
;; Arg1, byte* buffer
;; Arg2, size_t bsize
global NASM_RDRAND_GenerateBlock
section .text
2015-11-23 00:17:15 +00:00
%ifdef X86
align 8
cpu 486
2015-11-23 00:17:15 +00:00
%else
align 16
2015-11-23 00:17:15 +00:00
%endif
NASM_RDRAND_GenerateBlock:
2015-11-23 00:17:15 +00:00
%ifdef X86
%define arg1 [ebp+04h]
%define arg2 [ebp+08h]
%define MWSIZE 04h ;; machine word size
%else
%define MWSIZE 08h ;; machine word size
%endif
%define buffer edi
%define bsize esi
2015-11-23 00:17:15 +00:00
%ifdef X86
.Load_Arguments:
mov buffer, arg1
mov bsize, arg2
2015-11-23 00:17:15 +00:00
%endif
;; Top of While loop
2015-11-23 00:17:15 +00:00
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Return
2015-11-23 00:17:15 +00:00
.Call_RDRAND:
2015-11-23 00:17:15 +00:00
%ifdef X86
.Call_RDRAND_EAX:
%else
.Call_RDRAND_RAX:
DB 48h ;; X32 can use the full register, issue the REX.w prefix
2015-11-23 00:17:15 +00:00
%endif
;; RDRAND is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdrand eax`.
DB 0Fh, 07h, 0F0h
2015-11-23 00:17:15 +00:00
;; If CF=1, the number returned by RDRAND is valid.
;; If CF=0, a random number was not available.
jnc .Call_RDRAND
2015-11-23 00:17:15 +00:00
.RDRAND_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Full_Machine_Word:
%ifdef X32
mov [buffer+4], eax ;; We can only move 4 at a time
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
2015-11-23 00:17:15 +00:00
%endif
mov [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
2016-06-22 01:22:50 +00:00
;; Continue
jmp .GenerateBlock_Top
2015-11-23 00:17:15 +00:00
;; 1,2,3 bytes remain for X86
;; 1,2,3,4,5,6,7 remain for X32
2015-11-23 00:17:15 +00:00
.Partial_Machine_Word:
%ifdef X32
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], eax
add buffer, 4
2015-11-23 00:17:15 +00:00
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
2015-11-23 00:17:15 +00:00
.Bit_2_Not_Set:
%endif
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], ax
shr eax, 16
add buffer, 2
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Bit_1_Not_Set:
2016-06-22 01:22:50 +00:00
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz .Bit_0_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], al
2015-11-23 00:17:15 +00:00
.Bit_0_Not_Set:
;; We've hit all the bits
2016-06-22 01:22:50 +00:00
.GenerateBlock_Return:
2015-11-23 00:17:15 +00:00
xor eax, eax
ret
2015-11-23 00:17:15 +00:00
%endif ;; X86 and X32
2015-11-23 00:17:15 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X64 ;; Set via the command line
2015-11-23 00:17:15 +00:00
global NASM_RDRAND_GenerateBlock
section .text
align 16
2015-11-23 00:17:15 +00:00
;; Arg1, byte* buffer
;; Arg2, size_t bsize
NASM_RDRAND_GenerateBlock:
2015-11-23 00:17:15 +00:00
%define MWSIZE 08h ;; machine word size
%define buffer rdi
%define bsize rsi
;; No need for Load_Arguments due to fastcall
2015-11-23 00:17:15 +00:00
;; Top of While loop
2015-11-23 00:17:15 +00:00
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Return
2015-11-23 00:17:15 +00:00
.Call_RDRAND_RAX:
;; RDRAND is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdrand rax`.
DB 048h, 0Fh, 0C7h, 0F0h
2015-11-23 00:17:15 +00:00
;; If CF=1, the number returned by RDRAND is valid.
;; If CF=0, a random number was not available.
jnc .Call_RDRAND_RAX
2015-11-23 00:17:15 +00:00
.RDRAND_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Full_Machine_Word:
mov [buffer], rax
add buffer, MWSIZE
sub bsize, MWSIZE
2015-11-23 00:17:15 +00:00
;; Continue
jmp .GenerateBlock_Top
2015-11-23 00:17:15 +00:00
;; 1,2,3,4,5,6,7 bytes remain
2015-11-23 00:17:15 +00:00
.Partial_Machine_Word:
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], eax
shr rax, 32
add buffer, 4
2015-11-23 00:17:15 +00:00
.Bit_2_Not_Set:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], ax
shr eax, 16
add buffer, 2
2015-11-23 00:17:15 +00:00
.Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz .Bit_0_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], al
2015-11-23 00:17:15 +00:00
.Bit_0_Not_Set:
;; We've hit all the bits
2016-06-22 01:22:50 +00:00
.GenerateBlock_Return:
2015-11-23 00:17:15 +00:00
xor rax, rax
ret
2015-11-23 00:17:15 +00:00
%endif ;; X64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X86 or X32 ;; Set via the command line
;; Arg1, byte* buffer
;; Arg2, size_t bsize
global NASM_RDSEED_GenerateBlock
section .text
align 8
2015-11-23 00:17:15 +00:00
%ifdef X86
align 8
cpu 486
2015-11-23 00:17:15 +00:00
%else
align 16
2015-11-23 00:17:15 +00:00
%endif
NASM_RDSEED_GenerateBlock:
2015-11-23 00:17:15 +00:00
%ifdef X86
%define arg1 [ebp+04h]
%define arg2 [ebp+08h]
%define MWSIZE 04h ;; machine word size
%else
%define MWSIZE 08h ;; machine word size
%endif
%define buffer edi
%define bsize esi
2015-11-23 00:17:15 +00:00
%ifdef X86
.Load_Arguments:
mov buffer, arg1
mov bsize, arg2
2015-11-23 00:17:15 +00:00
%endif
;; Top of While loop
2015-11-23 00:17:15 +00:00
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Return
2015-11-23 00:17:15 +00:00
.Call_RDSEED:
2015-11-23 00:17:15 +00:00
%ifdef X86
.Call_RDSEED_EAX:
%else
.Call_RDSEED_RAX:
DB 48h ;; X32 can use the full register, issue the REX.w prefix
2015-11-23 00:17:15 +00:00
%endif
;; RDSEED is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdseed eax`.
DB 0Fh, 0C7h, 0F8h
2016-06-22 01:22:50 +00:00
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
jnc .Call_RDSEED
2015-11-23 00:17:15 +00:00
.RDSEED_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Full_Machine_Word:
mov [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
2016-06-22 01:22:50 +00:00
;; Continue
jmp .GenerateBlock_Top
2015-11-23 00:17:15 +00:00
;; 1,2,3 bytes remain for X86
;; 1,2,3,4,5,6,7 remain for X32
2015-11-23 00:17:15 +00:00
.Partial_Machine_Word:
%ifdef X32
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], eax
add buffer, 4
2015-11-23 00:17:15 +00:00
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
2015-11-23 00:17:15 +00:00
.Bit_2_Not_Set:
%endif
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], ax
shr eax, 16
add buffer, 2
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Bit_1_Not_Set:
2016-06-22 01:22:50 +00:00
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz .Bit_0_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], al
2015-11-23 00:17:15 +00:00
.Bit_0_Not_Set:
;; We've hit all the bits
2015-11-23 00:17:15 +00:00
.GenerateBlock_Return:
2016-06-22 01:22:50 +00:00
xor eax, eax
ret
2015-11-23 00:17:15 +00:00
%endif ;; X86 and X32
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X64 ;; Set via the command line
2015-11-23 00:17:15 +00:00
global NASM_RDSEED_GenerateBlock
section .text
align 16
2015-11-23 00:17:15 +00:00
;; Arg1, byte* buffer
;; Arg2, size_t bsize
NASM_RDSEED_GenerateBlock:
2015-11-23 00:17:15 +00:00
%define MWSIZE 08h ;; machine word size
%define buffer rdi
%define bsize rsi
;; No need for Load_Arguments due to fastcall
2015-11-23 00:17:15 +00:00
;; Top of While loop
2015-11-23 00:17:15 +00:00
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Return
2015-11-23 00:17:15 +00:00
.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
2015-11-23 00:17:15 +00:00
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
jnc .Call_RDSEED_RAX
2015-11-23 00:17:15 +00:00
.RDSEED_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
2016-06-22 01:22:50 +00:00
2015-11-23 00:17:15 +00:00
.Full_Machine_Word:
mov [buffer], rax
add buffer, MWSIZE
sub bsize, MWSIZE
2015-11-23 00:17:15 +00:00
;; Continue
jmp .GenerateBlock_Top
2015-11-23 00:17:15 +00:00
;; 1,2,3,4,5,6,7 bytes remain
2015-11-23 00:17:15 +00:00
.Partial_Machine_Word:
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], eax
shr rax, 32
add buffer, 4
2015-11-23 00:17:15 +00:00
.Bit_2_Not_Set:
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], ax
shr eax, 16
add buffer, 2
2015-11-23 00:17:15 +00:00
.Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
jz .Bit_0_Not_Set
2015-11-23 00:17:15 +00:00
mov [buffer], al
2015-11-23 00:17:15 +00:00
.Bit_0_Not_Set:
;; We've hit all the bits
2016-06-22 01:22:50 +00:00
.GenerateBlock_Return:
2015-11-23 00:17:15 +00:00
xor rax, rax
ret
2016-06-22 01:22:50 +00:00
%endif ;; _M_X64
2015-11-23 00:17:15 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;