|  | // Copyright 2013 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  | // | 
|  | // ARM version of md5block.go | 
|  |  | 
|  | #include "textflag.h" | 
|  |  | 
|  | // Register definitions | 
|  | #define Rtable	R0	// Pointer to MD5 constants table | 
|  | #define Rdata	R1	// Pointer to data to hash | 
|  | #define Ra	R2	// MD5 accumulator | 
|  | #define Rb	R3	// MD5 accumulator | 
|  | #define Rc	R4	// MD5 accumulator | 
|  | #define Rd	R5	// MD5 accumulator | 
|  | #define Rc0	R6	// MD5 constant | 
|  | #define Rc1	R7	// MD5 constant | 
|  | #define Rc2	R8	// MD5 constant | 
|  | // r9, r10 are forbidden | 
|  | // r11 is OK provided you check the assembler that no synthetic instructions use it | 
|  | #define Rc3	R11	// MD5 constant | 
|  | #define Rt0	R12	// temporary | 
|  | #define Rt1	R14	// temporary | 
|  |  | 
|  | // func block(dig *digest, p []byte) | 
|  | // 0(FP) is *digest | 
|  | // 4(FP) is p.array (struct Slice) | 
|  | // 8(FP) is p.len | 
|  | //12(FP) is p.cap | 
|  | // | 
|  | // Stack frame | 
|  | #define p_end	end-4(SP)	// pointer to the end of data | 
|  | #define p_data	data-8(SP)	// current data pointer | 
|  | #define buf	buffer-(8+4*16)(SP)	//16 words temporary buffer | 
|  | // 3 words at 4..12(R13) for called routine parameters | 
|  |  | 
|  | TEXT	·block(SB), NOSPLIT, $84-16 | 
|  | MOVW	p+4(FP), Rdata	// pointer to the data | 
|  | MOVW	p_len+8(FP), Rt0	// number of bytes | 
|  | ADD	Rdata, Rt0 | 
|  | MOVW	Rt0, p_end	// pointer to end of data | 
|  |  | 
|  | loop: | 
|  | MOVW	Rdata, p_data	// Save Rdata | 
|  | AND.S	$3, Rdata, Rt0	// TST $3, Rdata not working see issue 5921 | 
|  | BEQ	aligned			// aligned detected - skip copy | 
|  |  | 
|  | // Copy the unaligned source data into the aligned temporary buffer | 
|  | // memmove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers | 
|  | MOVW	$buf, Rtable	// to | 
|  | MOVW	$64, Rc0		// n | 
|  | MOVM.IB	[Rtable,Rdata,Rc0], (R13) | 
|  | BL	runtime·memmove(SB) | 
|  |  | 
|  | // Point to the local aligned copy of the data | 
|  | MOVW	$buf, Rdata | 
|  |  | 
|  | aligned: | 
|  | // Point to the table of constants | 
|  | // A PC relative add would be cheaper than this | 
|  | MOVW	$·table(SB), Rtable | 
|  |  | 
|  | // Load up initial MD5 accumulator | 
|  | MOVW	dig+0(FP), Rc0 | 
|  | MOVM.IA (Rc0), [Ra,Rb,Rc,Rd] | 
|  |  | 
|  | // a += (((c^d)&b)^d) + X[index] + const | 
|  | // a = a<<shift | a>>(32-shift) + b | 
|  | #define ROUND1(Ra, Rb, Rc, Rd, index, shift, Rconst) \ | 
|  | EOR	Rc, Rd, Rt0		; \ | 
|  | AND	Rb, Rt0			; \ | 
|  | EOR	Rd, Rt0			; \ | 
|  | MOVW	(index<<2)(Rdata), Rt1	; \ | 
|  | ADD	Rt1, Rt0			; \ | 
|  | ADD	Rconst, Rt0			; \ | 
|  | ADD	Rt0, Ra			; \ | 
|  | ADD	Ra@>(32-shift), Rb, Ra	; | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND1(Ra, Rb, Rc, Rd,  0,	7, Rc0) | 
|  | ROUND1(Rd, Ra, Rb, Rc,  1, 12, Rc1) | 
|  | ROUND1(Rc, Rd, Ra, Rb,  2, 17, Rc2) | 
|  | ROUND1(Rb, Rc, Rd, Ra,  3, 22, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND1(Ra, Rb, Rc, Rd,  4,	7, Rc0) | 
|  | ROUND1(Rd, Ra, Rb, Rc,  5, 12, Rc1) | 
|  | ROUND1(Rc, Rd, Ra, Rb,  6, 17, Rc2) | 
|  | ROUND1(Rb, Rc, Rd, Ra,  7, 22, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND1(Ra, Rb, Rc, Rd,  8,	7, Rc0) | 
|  | ROUND1(Rd, Ra, Rb, Rc,  9, 12, Rc1) | 
|  | ROUND1(Rc, Rd, Ra, Rb, 10, 17, Rc2) | 
|  | ROUND1(Rb, Rc, Rd, Ra, 11, 22, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND1(Ra, Rb, Rc, Rd, 12,	7, Rc0) | 
|  | ROUND1(Rd, Ra, Rb, Rc, 13, 12, Rc1) | 
|  | ROUND1(Rc, Rd, Ra, Rb, 14, 17, Rc2) | 
|  | ROUND1(Rb, Rc, Rd, Ra, 15, 22, Rc3) | 
|  |  | 
|  | // a += (((b^c)&d)^c) + X[index] + const | 
|  | // a = a<<shift | a>>(32-shift) + b | 
|  | #define ROUND2(Ra, Rb, Rc, Rd, index, shift, Rconst) \ | 
|  | EOR	Rb, Rc, Rt0		; \ | 
|  | AND	Rd, Rt0			; \ | 
|  | EOR	Rc, Rt0			; \ | 
|  | MOVW	(index<<2)(Rdata), Rt1	; \ | 
|  | ADD	Rt1, Rt0			; \ | 
|  | ADD	Rconst, Rt0			; \ | 
|  | ADD	Rt0, Ra			; \ | 
|  | ADD	Ra@>(32-shift), Rb, Ra	; | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND2(Ra, Rb, Rc, Rd,  1,	5, Rc0) | 
|  | ROUND2(Rd, Ra, Rb, Rc,  6,	9, Rc1) | 
|  | ROUND2(Rc, Rd, Ra, Rb, 11, 14, Rc2) | 
|  | ROUND2(Rb, Rc, Rd, Ra,  0, 20, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND2(Ra, Rb, Rc, Rd,  5,	5, Rc0) | 
|  | ROUND2(Rd, Ra, Rb, Rc, 10,	9, Rc1) | 
|  | ROUND2(Rc, Rd, Ra, Rb, 15, 14, Rc2) | 
|  | ROUND2(Rb, Rc, Rd, Ra,  4, 20, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND2(Ra, Rb, Rc, Rd,  9,	5, Rc0) | 
|  | ROUND2(Rd, Ra, Rb, Rc, 14,	9, Rc1) | 
|  | ROUND2(Rc, Rd, Ra, Rb,  3, 14, Rc2) | 
|  | ROUND2(Rb, Rc, Rd, Ra,  8, 20, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND2(Ra, Rb, Rc, Rd, 13,	5, Rc0) | 
|  | ROUND2(Rd, Ra, Rb, Rc,  2,	9, Rc1) | 
|  | ROUND2(Rc, Rd, Ra, Rb,  7, 14, Rc2) | 
|  | ROUND2(Rb, Rc, Rd, Ra, 12, 20, Rc3) | 
|  |  | 
|  | // a += (b^c^d) + X[index] + const | 
|  | // a = a<<shift | a>>(32-shift) + b | 
|  | #define ROUND3(Ra, Rb, Rc, Rd, index, shift, Rconst) \ | 
|  | EOR	Rb, Rc, Rt0		; \ | 
|  | EOR	Rd, Rt0			; \ | 
|  | MOVW	(index<<2)(Rdata), Rt1	; \ | 
|  | ADD	Rt1, Rt0			; \ | 
|  | ADD	Rconst, Rt0			; \ | 
|  | ADD	Rt0, Ra			; \ | 
|  | ADD	Ra@>(32-shift), Rb, Ra	; | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND3(Ra, Rb, Rc, Rd,  5,	4, Rc0) | 
|  | ROUND3(Rd, Ra, Rb, Rc,  8, 11, Rc1) | 
|  | ROUND3(Rc, Rd, Ra, Rb, 11, 16, Rc2) | 
|  | ROUND3(Rb, Rc, Rd, Ra, 14, 23, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND3(Ra, Rb, Rc, Rd,  1,	4, Rc0) | 
|  | ROUND3(Rd, Ra, Rb, Rc,  4, 11, Rc1) | 
|  | ROUND3(Rc, Rd, Ra, Rb,  7, 16, Rc2) | 
|  | ROUND3(Rb, Rc, Rd, Ra, 10, 23, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND3(Ra, Rb, Rc, Rd, 13,	4, Rc0) | 
|  | ROUND3(Rd, Ra, Rb, Rc,  0, 11, Rc1) | 
|  | ROUND3(Rc, Rd, Ra, Rb,  3, 16, Rc2) | 
|  | ROUND3(Rb, Rc, Rd, Ra,  6, 23, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND3(Ra, Rb, Rc, Rd,  9,	4, Rc0) | 
|  | ROUND3(Rd, Ra, Rb, Rc, 12, 11, Rc1) | 
|  | ROUND3(Rc, Rd, Ra, Rb, 15, 16, Rc2) | 
|  | ROUND3(Rb, Rc, Rd, Ra,  2, 23, Rc3) | 
|  |  | 
|  | // a += (c^(b|^d)) + X[index] + const | 
|  | // a = a<<shift | a>>(32-shift) + b | 
|  | #define ROUND4(Ra, Rb, Rc, Rd, index, shift, Rconst) \ | 
|  | MVN	Rd, Rt0			; \ | 
|  | ORR	Rb, Rt0			; \ | 
|  | EOR	Rc, Rt0			; \ | 
|  | MOVW	(index<<2)(Rdata), Rt1	; \ | 
|  | ADD	Rt1, Rt0			; \ | 
|  | ADD	Rconst, Rt0			; \ | 
|  | ADD	Rt0, Ra			; \ | 
|  | ADD	Ra@>(32-shift), Rb, Ra	; | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND4(Ra, Rb, Rc, Rd,  0,	6, Rc0) | 
|  | ROUND4(Rd, Ra, Rb, Rc,  7, 10, Rc1) | 
|  | ROUND4(Rc, Rd, Ra, Rb, 14, 15, Rc2) | 
|  | ROUND4(Rb, Rc, Rd, Ra,  5, 21, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND4(Ra, Rb, Rc, Rd, 12,	6, Rc0) | 
|  | ROUND4(Rd, Ra, Rb, Rc,  3, 10, Rc1) | 
|  | ROUND4(Rc, Rd, Ra, Rb, 10, 15, Rc2) | 
|  | ROUND4(Rb, Rc, Rd, Ra,  1, 21, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND4(Ra, Rb, Rc, Rd,  8,	6, Rc0) | 
|  | ROUND4(Rd, Ra, Rb, Rc, 15, 10, Rc1) | 
|  | ROUND4(Rc, Rd, Ra, Rb,  6, 15, Rc2) | 
|  | ROUND4(Rb, Rc, Rd, Ra, 13, 21, Rc3) | 
|  |  | 
|  | MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] | 
|  | ROUND4(Ra, Rb, Rc, Rd,  4,	6, Rc0) | 
|  | ROUND4(Rd, Ra, Rb, Rc, 11, 10, Rc1) | 
|  | ROUND4(Rc, Rd, Ra, Rb,  2, 15, Rc2) | 
|  | ROUND4(Rb, Rc, Rd, Ra,  9, 21, Rc3) | 
|  |  | 
|  | MOVW	dig+0(FP), Rt0 | 
|  | MOVM.IA (Rt0), [Rc0,Rc1,Rc2,Rc3] | 
|  |  | 
|  | ADD	Rc0, Ra | 
|  | ADD	Rc1, Rb | 
|  | ADD	Rc2, Rc | 
|  | ADD	Rc3, Rd | 
|  |  | 
|  | MOVM.IA [Ra,Rb,Rc,Rd], (Rt0) | 
|  |  | 
|  | MOVW	p_data, Rdata | 
|  | MOVW	p_end, Rt0 | 
|  | ADD	$64, Rdata | 
|  | CMP	Rt0, Rdata | 
|  | BLO	loop | 
|  |  | 
|  | RET | 
|  |  | 
|  | // MD5 constants table | 
|  |  | 
|  | // Round 1 | 
|  | DATA	·table+0x00(SB)/4, $0xd76aa478 | 
|  | DATA	·table+0x04(SB)/4, $0xe8c7b756 | 
|  | DATA	·table+0x08(SB)/4, $0x242070db | 
|  | DATA	·table+0x0c(SB)/4, $0xc1bdceee | 
|  | DATA	·table+0x10(SB)/4, $0xf57c0faf | 
|  | DATA	·table+0x14(SB)/4, $0x4787c62a | 
|  | DATA	·table+0x18(SB)/4, $0xa8304613 | 
|  | DATA	·table+0x1c(SB)/4, $0xfd469501 | 
|  | DATA	·table+0x20(SB)/4, $0x698098d8 | 
|  | DATA	·table+0x24(SB)/4, $0x8b44f7af | 
|  | DATA	·table+0x28(SB)/4, $0xffff5bb1 | 
|  | DATA	·table+0x2c(SB)/4, $0x895cd7be | 
|  | DATA	·table+0x30(SB)/4, $0x6b901122 | 
|  | DATA	·table+0x34(SB)/4, $0xfd987193 | 
|  | DATA	·table+0x38(SB)/4, $0xa679438e | 
|  | DATA	·table+0x3c(SB)/4, $0x49b40821 | 
|  | // Round 2 | 
|  | DATA	·table+0x40(SB)/4, $0xf61e2562 | 
|  | DATA	·table+0x44(SB)/4, $0xc040b340 | 
|  | DATA	·table+0x48(SB)/4, $0x265e5a51 | 
|  | DATA	·table+0x4c(SB)/4, $0xe9b6c7aa | 
|  | DATA	·table+0x50(SB)/4, $0xd62f105d | 
|  | DATA	·table+0x54(SB)/4, $0x02441453 | 
|  | DATA	·table+0x58(SB)/4, $0xd8a1e681 | 
|  | DATA	·table+0x5c(SB)/4, $0xe7d3fbc8 | 
|  | DATA	·table+0x60(SB)/4, $0x21e1cde6 | 
|  | DATA	·table+0x64(SB)/4, $0xc33707d6 | 
|  | DATA	·table+0x68(SB)/4, $0xf4d50d87 | 
|  | DATA	·table+0x6c(SB)/4, $0x455a14ed | 
|  | DATA	·table+0x70(SB)/4, $0xa9e3e905 | 
|  | DATA	·table+0x74(SB)/4, $0xfcefa3f8 | 
|  | DATA	·table+0x78(SB)/4, $0x676f02d9 | 
|  | DATA	·table+0x7c(SB)/4, $0x8d2a4c8a | 
|  | // Round 3 | 
|  | DATA	·table+0x80(SB)/4, $0xfffa3942 | 
|  | DATA	·table+0x84(SB)/4, $0x8771f681 | 
|  | DATA	·table+0x88(SB)/4, $0x6d9d6122 | 
|  | DATA	·table+0x8c(SB)/4, $0xfde5380c | 
|  | DATA	·table+0x90(SB)/4, $0xa4beea44 | 
|  | DATA	·table+0x94(SB)/4, $0x4bdecfa9 | 
|  | DATA	·table+0x98(SB)/4, $0xf6bb4b60 | 
|  | DATA	·table+0x9c(SB)/4, $0xbebfbc70 | 
|  | DATA	·table+0xa0(SB)/4, $0x289b7ec6 | 
|  | DATA	·table+0xa4(SB)/4, $0xeaa127fa | 
|  | DATA	·table+0xa8(SB)/4, $0xd4ef3085 | 
|  | DATA	·table+0xac(SB)/4, $0x04881d05 | 
|  | DATA	·table+0xb0(SB)/4, $0xd9d4d039 | 
|  | DATA	·table+0xb4(SB)/4, $0xe6db99e5 | 
|  | DATA	·table+0xb8(SB)/4, $0x1fa27cf8 | 
|  | DATA	·table+0xbc(SB)/4, $0xc4ac5665 | 
|  | // Round 4 | 
|  | DATA	·table+0xc0(SB)/4, $0xf4292244 | 
|  | DATA	·table+0xc4(SB)/4, $0x432aff97 | 
|  | DATA	·table+0xc8(SB)/4, $0xab9423a7 | 
|  | DATA	·table+0xcc(SB)/4, $0xfc93a039 | 
|  | DATA	·table+0xd0(SB)/4, $0x655b59c3 | 
|  | DATA	·table+0xd4(SB)/4, $0x8f0ccc92 | 
|  | DATA	·table+0xd8(SB)/4, $0xffeff47d | 
|  | DATA	·table+0xdc(SB)/4, $0x85845dd1 | 
|  | DATA	·table+0xe0(SB)/4, $0x6fa87e4f | 
|  | DATA	·table+0xe4(SB)/4, $0xfe2ce6e0 | 
|  | DATA	·table+0xe8(SB)/4, $0xa3014314 | 
|  | DATA	·table+0xec(SB)/4, $0x4e0811a1 | 
|  | DATA	·table+0xf0(SB)/4, $0xf7537e82 | 
|  | DATA	·table+0xf4(SB)/4, $0xbd3af235 | 
|  | DATA	·table+0xf8(SB)/4, $0x2ad7d2bb | 
|  | DATA	·table+0xfc(SB)/4, $0xeb86d391 | 
|  | // Global definition | 
|  | GLOBL	·table(SB),8,$256 |