xref: /openssl/crypto/aes/asm/vpaes-x86_64.pl (revision 7ed6de99)
1#! /usr/bin/env perl
2# Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9
10######################################################################
11## Constant-time SSSE3 AES core implementation.
12## version 0.1
13##
14## By Mike Hamburg (Stanford University), 2009
15## Public domain.
16##
17## For details see http://shiftleft.org/papers/vector_aes/ and
18## http://crypto.stanford.edu/vpaes/.
19
20######################################################################
21# September 2011.
22#
23# Interface to OpenSSL as "almost" drop-in replacement for
24# aes-x86_64.pl. "Almost" refers to the fact that AES_cbc_encrypt
25# doesn't handle partial vectors (doesn't have to if called from
26# EVP only). "Drop-in" implies that this module doesn't share key
27# schedule structure with the original nor does it make assumption
28# about its alignment...
29#
30# Performance summary. aes-x86_64.pl column lists large-block CBC
31# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
32# byte processed with 128-bit key, and vpaes-x86_64.pl column -
33# [also large-block CBC] encrypt/decrypt.
34#
35#		aes-x86_64.pl		vpaes-x86_64.pl
36#
37# Core 2(**)	29.6/41.1/14.3		21.9/25.2(***)
38# Nehalem	29.6/40.3/14.6		10.0/11.8
39# Atom		57.3/74.2/32.1		60.9/77.2(***)
40# Silvermont	52.7/64.0/19.5		48.8/60.8(***)
41# Goldmont	38.9/49.0/17.8		10.6/12.6
42#
43# (*)	"Hyper-threading" in the context refers rather to cache shared
44#	among multiple cores, than to specifically Intel HTT. As vast
45#	majority of contemporary cores share cache, slower code path
46#	is common place. In other words "with-hyper-threading-off"
47#	results are presented mostly for reference purposes.
48#
49# (**)	"Core 2" refers to initial 65nm design, a.k.a. Conroe.
50#
51# (***)	Less impressive improvement on Core 2 and Atom is due to slow
52#	pshufb,	yet it's respectable +36%/62% improvement on Core 2
53#	(as implied, over "hyper-threading-safe" code path).
54#
55#						<appro@openssl.org>
56
57# $output is the last argument if it looks like a file (it has an extension)
58# $flavour is the first argument if it doesn't look like a file
59$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
60$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
61
62$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
63
64$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
65( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
66( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
67die "can't locate x86_64-xlate.pl";
68
69open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""
70    or die "can't call $xlate: $!";
71*STDOUT=*OUT;
72
73$PREFIX="vpaes";
74
75$code.=<<___;
76.text
77
78##
79##  _aes_encrypt_core
80##
81##  AES-encrypt %xmm0.
82##
83##  Inputs:
84##     %xmm0 = input
85##     %xmm9-%xmm15 as in _vpaes_preheat
86##    (%rdx) = scheduled keys
87##
88##  Output in %xmm0
89##  Clobbers  %xmm1-%xmm5, %r9, %r10, %r11, %rax
90##  Preserves %xmm6 - %xmm8 so you get some local vectors
91##
92##
93.type	_vpaes_encrypt_core,\@abi-omnipotent
94.align 16
95_vpaes_encrypt_core:
96.cfi_startproc
97	mov	%rdx,	%r9
98	mov	\$16,	%r11
99	mov	240(%rdx),%eax
100	movdqa	%xmm9,	%xmm1
101	movdqa	.Lk_ipt(%rip), %xmm2	# iptlo
102	pandn	%xmm0,	%xmm1
103	movdqu	(%r9),	%xmm5		# round0 key
104	psrld	\$4,	%xmm1
105	pand	%xmm9,	%xmm0
106	pshufb	%xmm0,	%xmm2
107	movdqa	.Lk_ipt+16(%rip), %xmm0	# ipthi
108	pshufb	%xmm1,	%xmm0
109	pxor	%xmm5,	%xmm2
110	add	\$16,	%r9
111	pxor	%xmm2,	%xmm0
112	lea	.Lk_mc_backward(%rip),%r10
113	jmp	.Lenc_entry
114
115.align 16
116.Lenc_loop:
117	# middle of middle round
118	movdqa  %xmm13,	%xmm4	# 4 : sb1u
119	movdqa  %xmm12,	%xmm0	# 0 : sb1t
120	pshufb  %xmm2,	%xmm4	# 4 = sb1u
121	pshufb  %xmm3,	%xmm0	# 0 = sb1t
122	pxor	%xmm5,	%xmm4	# 4 = sb1u + k
123	movdqa  %xmm15,	%xmm5	# 4 : sb2u
124	pxor	%xmm4,	%xmm0	# 0 = A
125	movdqa	-0x40(%r11,%r10), %xmm1		# .Lk_mc_forward[]
126	pshufb	%xmm2,	%xmm5	# 4 = sb2u
127	movdqa	(%r11,%r10), %xmm4		# .Lk_mc_backward[]
128	movdqa	%xmm14, %xmm2	# 2 : sb2t
129	pshufb	%xmm3,  %xmm2	# 2 = sb2t
130	movdqa	%xmm0,  %xmm3	# 3 = A
131	pxor	%xmm5,	%xmm2	# 2 = 2A
132	pshufb  %xmm1,  %xmm0	# 0 = B
133	add	\$16,	%r9	# next key
134	pxor	%xmm2,  %xmm0	# 0 = 2A+B
135	pshufb	%xmm4,	%xmm3	# 3 = D
136	add	\$16,	%r11	# next mc
137	pxor	%xmm0,	%xmm3	# 3 = 2A+B+D
138	pshufb  %xmm1,	%xmm0	# 0 = 2B+C
139	and	\$0x30,	%r11	# ... mod 4
140	sub	\$1,%rax	# nr--
141	pxor	%xmm3,	%xmm0	# 0 = 2A+3B+C+D
142
143.Lenc_entry:
144	# top of round
145	movdqa  %xmm9, 	%xmm1	# 1 : i
146	movdqa	%xmm11, %xmm5	# 2 : a/k
147	pandn	%xmm0, 	%xmm1	# 1 = i<<4
148	psrld	\$4,   	%xmm1   # 1 = i
149	pand	%xmm9, 	%xmm0   # 0 = k
150	pshufb  %xmm0,  %xmm5	# 2 = a/k
151	movdqa	%xmm10,	%xmm3  	# 3 : 1/i
152	pxor	%xmm1,	%xmm0	# 0 = j
153	pshufb  %xmm1, 	%xmm3  	# 3 = 1/i
154	movdqa	%xmm10,	%xmm4  	# 4 : 1/j
155	pxor	%xmm5, 	%xmm3  	# 3 = iak = 1/i + a/k
156	pshufb	%xmm0, 	%xmm4  	# 4 = 1/j
157	movdqa	%xmm10,	%xmm2  	# 2 : 1/iak
158	pxor	%xmm5, 	%xmm4  	# 4 = jak = 1/j + a/k
159	pshufb  %xmm3,	%xmm2  	# 2 = 1/iak
160	movdqa	%xmm10, %xmm3   # 3 : 1/jak
161	pxor	%xmm0, 	%xmm2  	# 2 = io
162	pshufb  %xmm4,  %xmm3   # 3 = 1/jak
163	movdqu	(%r9),	%xmm5
164	pxor	%xmm1,  %xmm3   # 3 = jo
165	jnz	.Lenc_loop
166
167	# middle of last round
168	movdqa	-0x60(%r10), %xmm4	# 3 : sbou	.Lk_sbo
169	movdqa	-0x50(%r10), %xmm0	# 0 : sbot	.Lk_sbo+16
170	pshufb  %xmm2,  %xmm4	# 4 = sbou
171	pxor	%xmm5,  %xmm4	# 4 = sb1u + k
172	pshufb  %xmm3,	%xmm0	# 0 = sb1t
173	movdqa	0x40(%r11,%r10), %xmm1		# .Lk_sr[]
174	pxor	%xmm4,	%xmm0	# 0 = A
175	pshufb	%xmm1,	%xmm0
176	ret
177.cfi_endproc
178.size	_vpaes_encrypt_core,.-_vpaes_encrypt_core
179
180##
181##  Decryption core
182##
183##  Same API as encryption core.
184##
185.type	_vpaes_decrypt_core,\@abi-omnipotent
186.align	16
187_vpaes_decrypt_core:
188.cfi_startproc
189	mov	%rdx,	%r9		# load key
190	mov	240(%rdx),%eax
191	movdqa	%xmm9,	%xmm1
192	movdqa	.Lk_dipt(%rip), %xmm2	# iptlo
193	pandn	%xmm0,	%xmm1
194	mov	%rax,	%r11
195	psrld	\$4,	%xmm1
196	movdqu	(%r9),	%xmm5		# round0 key
197	shl	\$4,	%r11
198	pand	%xmm9,	%xmm0
199	pshufb	%xmm0,	%xmm2
200	movdqa	.Lk_dipt+16(%rip), %xmm0 # ipthi
201	xor	\$0x30,	%r11
202	lea	.Lk_dsbd(%rip),%r10
203	pshufb	%xmm1,	%xmm0
204	and	\$0x30,	%r11
205	pxor	%xmm5,	%xmm2
206	movdqa	.Lk_mc_forward+48(%rip), %xmm5
207	pxor	%xmm2,	%xmm0
208	add	\$16,	%r9
209	add	%r10,	%r11
210	jmp	.Ldec_entry
211
212.align 16
213.Ldec_loop:
214##
215##  Inverse mix columns
216##
217	movdqa  -0x20(%r10),%xmm4	# 4 : sb9u
218	movdqa  -0x10(%r10),%xmm1	# 0 : sb9t
219	pshufb	%xmm2,	%xmm4		# 4 = sb9u
220	pshufb	%xmm3,	%xmm1		# 0 = sb9t
221	pxor	%xmm4,	%xmm0
222	movdqa  0x00(%r10),%xmm4	# 4 : sbdu
223	pxor	%xmm1,	%xmm0		# 0 = ch
224	movdqa  0x10(%r10),%xmm1	# 0 : sbdt
225
226	pshufb	%xmm2,	%xmm4		# 4 = sbdu
227	pshufb	%xmm5,	%xmm0		# MC ch
228	pshufb	%xmm3,	%xmm1		# 0 = sbdt
229	pxor	%xmm4,	%xmm0		# 4 = ch
230	movdqa  0x20(%r10),%xmm4	# 4 : sbbu
231	pxor	%xmm1,	%xmm0		# 0 = ch
232	movdqa  0x30(%r10),%xmm1	# 0 : sbbt
233
234	pshufb	%xmm2,	%xmm4		# 4 = sbbu
235	pshufb	%xmm5,	%xmm0		# MC ch
236	pshufb	%xmm3,	%xmm1		# 0 = sbbt
237	pxor	%xmm4,	%xmm0		# 4 = ch
238	movdqa  0x40(%r10),%xmm4	# 4 : sbeu
239	pxor	%xmm1,	%xmm0		# 0 = ch
240	movdqa  0x50(%r10),%xmm1	# 0 : sbet
241
242	pshufb	%xmm2,	%xmm4		# 4 = sbeu
243	pshufb	%xmm5,	%xmm0		# MC ch
244	pshufb	%xmm3,	%xmm1		# 0 = sbet
245	pxor	%xmm4,	%xmm0		# 4 = ch
246	add	\$16, %r9		# next round key
247	palignr	\$12,	%xmm5,	%xmm5
248	pxor	%xmm1,	%xmm0		# 0 = ch
249	sub	\$1,%rax		# nr--
250
251.Ldec_entry:
252	# top of round
253	movdqa  %xmm9, 	%xmm1	# 1 : i
254	pandn	%xmm0, 	%xmm1	# 1 = i<<4
255	movdqa	%xmm11, %xmm2	# 2 : a/k
256	psrld	\$4,    %xmm1	# 1 = i
257	pand	%xmm9, 	%xmm0	# 0 = k
258	pshufb  %xmm0,  %xmm2	# 2 = a/k
259	movdqa	%xmm10,	%xmm3	# 3 : 1/i
260	pxor	%xmm1,	%xmm0	# 0 = j
261	pshufb  %xmm1, 	%xmm3	# 3 = 1/i
262	movdqa	%xmm10,	%xmm4	# 4 : 1/j
263	pxor	%xmm2, 	%xmm3	# 3 = iak = 1/i + a/k
264	pshufb	%xmm0, 	%xmm4	# 4 = 1/j
265	pxor	%xmm2, 	%xmm4	# 4 = jak = 1/j + a/k
266	movdqa	%xmm10,	%xmm2	# 2 : 1/iak
267	pshufb  %xmm3,	%xmm2	# 2 = 1/iak
268	movdqa	%xmm10, %xmm3	# 3 : 1/jak
269	pxor	%xmm0, 	%xmm2	# 2 = io
270	pshufb  %xmm4,  %xmm3	# 3 = 1/jak
271	movdqu	(%r9),	%xmm0
272	pxor	%xmm1,  %xmm3	# 3 = jo
273	jnz	.Ldec_loop
274
275	# middle of last round
276	movdqa	0x60(%r10), %xmm4	# 3 : sbou
277	pshufb  %xmm2,  %xmm4	# 4 = sbou
278	pxor	%xmm0,  %xmm4	# 4 = sb1u + k
279	movdqa	0x70(%r10), %xmm0	# 0 : sbot
280	movdqa	-0x160(%r11), %xmm2	# .Lk_sr-.Lk_dsbd=-0x160
281	pshufb  %xmm3,	%xmm0	# 0 = sb1t
282	pxor	%xmm4,	%xmm0	# 0 = A
283	pshufb	%xmm2,	%xmm0
284	ret
285.cfi_endproc
286.size	_vpaes_decrypt_core,.-_vpaes_decrypt_core
287
288########################################################
289##                                                    ##
290##                  AES key schedule                  ##
291##                                                    ##
292########################################################
293.type	_vpaes_schedule_core,\@abi-omnipotent
294.align	16
295_vpaes_schedule_core:
296.cfi_startproc
297	# rdi = key
298	# rsi = size in bits
299	# rdx = buffer
300	# rcx = direction.  0=encrypt, 1=decrypt
301
302	call	_vpaes_preheat		# load the tables
303	movdqa	.Lk_rcon(%rip), %xmm8	# load rcon
304	movdqu	(%rdi),	%xmm0		# load key (unaligned)
305
306	# input transform
307	movdqa	%xmm0,	%xmm3
308	lea	.Lk_ipt(%rip), %r11
309	call	_vpaes_schedule_transform
310	movdqa	%xmm0,	%xmm7
311
312	lea	.Lk_sr(%rip),%r10
313	test	%rcx,	%rcx
314	jnz	.Lschedule_am_decrypting
315
316	# encrypting, output zeroth round key after transform
317	movdqu	%xmm0,	(%rdx)
318	jmp	.Lschedule_go
319
320.Lschedule_am_decrypting:
321	# decrypting, output zeroth round key after shiftrows
322	movdqa	(%r8,%r10),%xmm1
323	pshufb  %xmm1,	%xmm3
324	movdqu	%xmm3,	(%rdx)
325	xor	\$0x30, %r8
326
327.Lschedule_go:
328	cmp	\$192,	%esi
329	ja	.Lschedule_256
330	je	.Lschedule_192
331	# 128: fall though
332
333##
334##  .schedule_128
335##
336##  128-bit specific part of key schedule.
337##
338##  This schedule is really simple, because all its parts
339##  are accomplished by the subroutines.
340##
341.Lschedule_128:
342	mov	\$10, %esi
343
344.Loop_schedule_128:
345	call 	_vpaes_schedule_round
346	dec	%rsi
347	jz 	.Lschedule_mangle_last
348	call	_vpaes_schedule_mangle	# write output
349	jmp 	.Loop_schedule_128
350
351##
352##  .aes_schedule_192
353##
354##  192-bit specific part of key schedule.
355##
356##  The main body of this schedule is the same as the 128-bit
357##  schedule, but with more smearing.  The long, high side is
358##  stored in %xmm7 as before, and the short, low side is in
359##  the high bits of %xmm6.
360##
361##  This schedule is somewhat nastier, however, because each
362##  round produces 192 bits of key material, or 1.5 round keys.
363##  Therefore, on each cycle we do 2 rounds and produce 3 round
364##  keys.
365##
366.align	16
367.Lschedule_192:
368	movdqu	8(%rdi),%xmm0		# load key part 2 (very unaligned)
369	call	_vpaes_schedule_transform	# input transform
370	movdqa	%xmm0,	%xmm6		# save short part
371	pxor	%xmm4,	%xmm4		# clear 4
372	movhlps	%xmm4,	%xmm6		# clobber low side with zeros
373	mov	\$4,	%esi
374
375.Loop_schedule_192:
376	call	_vpaes_schedule_round
377	palignr	\$8,%xmm6,%xmm0
378	call	_vpaes_schedule_mangle	# save key n
379	call	_vpaes_schedule_192_smear
380	call	_vpaes_schedule_mangle	# save key n+1
381	call	_vpaes_schedule_round
382	dec	%rsi
383	jz 	.Lschedule_mangle_last
384	call	_vpaes_schedule_mangle	# save key n+2
385	call	_vpaes_schedule_192_smear
386	jmp	.Loop_schedule_192
387
388##
389##  .aes_schedule_256
390##
391##  256-bit specific part of key schedule.
392##
393##  The structure here is very similar to the 128-bit
394##  schedule, but with an additional "low side" in
395##  %xmm6.  The low side's rounds are the same as the
396##  high side's, except no rcon and no rotation.
397##
398.align	16
399.Lschedule_256:
400	movdqu	16(%rdi),%xmm0		# load key part 2 (unaligned)
401	call	_vpaes_schedule_transform	# input transform
402	mov	\$7, %esi
403
404.Loop_schedule_256:
405	call	_vpaes_schedule_mangle	# output low result
406	movdqa	%xmm0,	%xmm6		# save cur_lo in xmm6
407
408	# high round
409	call	_vpaes_schedule_round
410	dec	%rsi
411	jz 	.Lschedule_mangle_last
412	call	_vpaes_schedule_mangle
413
414	# low round. swap xmm7 and xmm6
415	pshufd	\$0xFF,	%xmm0,	%xmm0
416	movdqa	%xmm7,	%xmm5
417	movdqa	%xmm6,	%xmm7
418	call	_vpaes_schedule_low_round
419	movdqa	%xmm5,	%xmm7
420
421	jmp	.Loop_schedule_256
422
423
424##
425##  .aes_schedule_mangle_last
426##
427##  Mangler for last round of key schedule
428##  Mangles %xmm0
429##    when encrypting, outputs out(%xmm0) ^ 63
430##    when decrypting, outputs unskew(%xmm0)
431##
432##  Always called right before return... jumps to cleanup and exits
433##
434.align	16
435.Lschedule_mangle_last:
436	# schedule last round key from xmm0
437	lea	.Lk_deskew(%rip),%r11	# prepare to deskew
438	test	%rcx, 	%rcx
439	jnz	.Lschedule_mangle_last_dec
440
441	# encrypting
442	movdqa	(%r8,%r10),%xmm1
443	pshufb	%xmm1,	%xmm0		# output permute
444	lea	.Lk_opt(%rip),	%r11	# prepare to output transform
445	add	\$32,	%rdx
446
447.Lschedule_mangle_last_dec:
448	add	\$-16,	%rdx
449	pxor	.Lk_s63(%rip),	%xmm0
450	call	_vpaes_schedule_transform # output transform
451	movdqu	%xmm0,	(%rdx)		# save last key
452
453	# cleanup
454	pxor	%xmm0,  %xmm0
455	pxor	%xmm1,  %xmm1
456	pxor	%xmm2,  %xmm2
457	pxor	%xmm3,  %xmm3
458	pxor	%xmm4,  %xmm4
459	pxor	%xmm5,  %xmm5
460	pxor	%xmm6,  %xmm6
461	pxor	%xmm7,  %xmm7
462	ret
463.cfi_endproc
464.size	_vpaes_schedule_core,.-_vpaes_schedule_core
465
466##
467##  .aes_schedule_192_smear
468##
469##  Smear the short, low side in the 192-bit key schedule.
470##
471##  Inputs:
472##    %xmm7: high side, b  a  x  y
473##    %xmm6:  low side, d  c  0  0
474##    %xmm13: 0
475##
476##  Outputs:
477##    %xmm6: b+c+d  b+c  0  0
478##    %xmm0: b+c+d  b+c  b  a
479##
480.type	_vpaes_schedule_192_smear,\@abi-omnipotent
481.align	16
482_vpaes_schedule_192_smear:
483.cfi_startproc
484	pshufd	\$0x80,	%xmm6,	%xmm1	# d c 0 0 -> c 0 0 0
485	pshufd	\$0xFE,	%xmm7,	%xmm0	# b a _ _ -> b b b a
486	pxor	%xmm1,	%xmm6		# -> c+d c 0 0
487	pxor	%xmm1,	%xmm1
488	pxor	%xmm0,	%xmm6		# -> b+c+d b+c b a
489	movdqa	%xmm6,	%xmm0
490	movhlps	%xmm1,	%xmm6		# clobber low side with zeros
491	ret
492.cfi_endproc
493.size	_vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
494
495##
496##  .aes_schedule_round
497##
498##  Runs one main round of the key schedule on %xmm0, %xmm7
499##
500##  Specifically, runs subbytes on the high dword of %xmm0
501##  then rotates it by one byte and xors into the low dword of
502##  %xmm7.
503##
504##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
505##  next rcon.
506##
507##  Smears the dwords of %xmm7 by xoring the low into the
508##  second low, result into third, result into highest.
509##
510##  Returns results in %xmm7 = %xmm0.
511##  Clobbers %xmm1-%xmm4, %r11.
512##
513.type	_vpaes_schedule_round,\@abi-omnipotent
514.align	16
515_vpaes_schedule_round:
516.cfi_startproc
517	# extract rcon from xmm8
518	pxor	%xmm1,	%xmm1
519	palignr	\$15,	%xmm8,	%xmm1
520	palignr	\$15,	%xmm8,	%xmm8
521	pxor	%xmm1,	%xmm7
522
523	# rotate
524	pshufd	\$0xFF,	%xmm0,	%xmm0
525	palignr	\$1,	%xmm0,	%xmm0
526
527	# fall through...
528
529	# low round: same as high round, but no rotation and no rcon.
530_vpaes_schedule_low_round:
531	# smear xmm7
532	movdqa	%xmm7,	%xmm1
533	pslldq	\$4,	%xmm7
534	pxor	%xmm1,	%xmm7
535	movdqa	%xmm7,	%xmm1
536	pslldq	\$8,	%xmm7
537	pxor	%xmm1,	%xmm7
538	pxor	.Lk_s63(%rip), %xmm7
539
540	# subbytes
541	movdqa  %xmm9, 	%xmm1
542	pandn	%xmm0, 	%xmm1
543	psrld	\$4,    %xmm1		# 1 = i
544	pand	%xmm9, 	%xmm0		# 0 = k
545	movdqa	%xmm11, %xmm2		# 2 : a/k
546	pshufb  %xmm0,  %xmm2		# 2 = a/k
547	pxor	%xmm1,	%xmm0		# 0 = j
548	movdqa	%xmm10,	%xmm3		# 3 : 1/i
549	pshufb  %xmm1, 	%xmm3		# 3 = 1/i
550	pxor	%xmm2, 	%xmm3		# 3 = iak = 1/i + a/k
551	movdqa	%xmm10,	%xmm4		# 4 : 1/j
552	pshufb	%xmm0, 	%xmm4		# 4 = 1/j
553	pxor	%xmm2, 	%xmm4		# 4 = jak = 1/j + a/k
554	movdqa	%xmm10,	%xmm2		# 2 : 1/iak
555	pshufb  %xmm3,	%xmm2		# 2 = 1/iak
556	pxor	%xmm0, 	%xmm2		# 2 = io
557	movdqa	%xmm10, %xmm3		# 3 : 1/jak
558	pshufb  %xmm4,  %xmm3		# 3 = 1/jak
559	pxor	%xmm1,  %xmm3		# 3 = jo
560	movdqa	%xmm13, %xmm4		# 4 : sbou
561	pshufb  %xmm2,  %xmm4		# 4 = sbou
562	movdqa	%xmm12, %xmm0		# 0 : sbot
563	pshufb  %xmm3,	%xmm0		# 0 = sb1t
564	pxor	%xmm4, 	%xmm0		# 0 = sbox output
565
566	# add in smeared stuff
567	pxor	%xmm7,	%xmm0
568	movdqa	%xmm0,	%xmm7
569	ret
570.cfi_endproc
571.size	_vpaes_schedule_round,.-_vpaes_schedule_round
572
573##
574##  .aes_schedule_transform
575##
576##  Linear-transform %xmm0 according to tables at (%r11)
577##
578##  Requires that %xmm9 = 0x0F0F... as in preheat
579##  Output in %xmm0
580##  Clobbers %xmm1, %xmm2
581##
582.type	_vpaes_schedule_transform,\@abi-omnipotent
583.align	16
584_vpaes_schedule_transform:
585.cfi_startproc
586	movdqa	%xmm9,	%xmm1
587	pandn	%xmm0,	%xmm1
588	psrld	\$4,	%xmm1
589	pand	%xmm9,	%xmm0
590	movdqa	(%r11), %xmm2 	# lo
591	pshufb	%xmm0,	%xmm2
592	movdqa	16(%r11), %xmm0 # hi
593	pshufb	%xmm1,	%xmm0
594	pxor	%xmm2,	%xmm0
595	ret
596.cfi_endproc
597.size	_vpaes_schedule_transform,.-_vpaes_schedule_transform
598
599##
600##  .aes_schedule_mangle
601##
602##  Mangle xmm0 from (basis-transformed) standard version
603##  to our version.
604##
605##  On encrypt,
606##    xor with 0x63
607##    multiply by circulant 0,1,1,1
608##    apply shiftrows transform
609##
610##  On decrypt,
611##    xor with 0x63
612##    multiply by "inverse mixcolumns" circulant E,B,D,9
613##    deskew
614##    apply shiftrows transform
615##
616##
617##  Writes out to (%rdx), and increments or decrements it
618##  Keeps track of round number mod 4 in %r8
619##  Preserves xmm0
620##  Clobbers xmm1-xmm5
621##
622.type	_vpaes_schedule_mangle,\@abi-omnipotent
623.align	16
624_vpaes_schedule_mangle:
625.cfi_startproc
626	movdqa	%xmm0,	%xmm4	# save xmm0 for later
627	movdqa	.Lk_mc_forward(%rip),%xmm5
628	test	%rcx, 	%rcx
629	jnz	.Lschedule_mangle_dec
630
631	# encrypting
632	add	\$16,	%rdx
633	pxor	.Lk_s63(%rip),%xmm4
634	pshufb	%xmm5,	%xmm4
635	movdqa	%xmm4,	%xmm3
636	pshufb	%xmm5,	%xmm4
637	pxor	%xmm4,	%xmm3
638	pshufb	%xmm5,	%xmm4
639	pxor	%xmm4,	%xmm3
640
641	jmp	.Lschedule_mangle_both
642.align	16
643.Lschedule_mangle_dec:
644	# inverse mix columns
645	lea	.Lk_dksd(%rip),%r11
646	movdqa	%xmm9,	%xmm1
647	pandn	%xmm4,	%xmm1
648	psrld	\$4,	%xmm1	# 1 = hi
649	pand	%xmm9,	%xmm4	# 4 = lo
650
651	movdqa	0x00(%r11), %xmm2
652	pshufb	%xmm4,	%xmm2
653	movdqa	0x10(%r11), %xmm3
654	pshufb	%xmm1,	%xmm3
655	pxor	%xmm2,	%xmm3
656	pshufb	%xmm5,	%xmm3
657
658	movdqa	0x20(%r11), %xmm2
659	pshufb	%xmm4,	%xmm2
660	pxor	%xmm3,	%xmm2
661	movdqa	0x30(%r11), %xmm3
662	pshufb	%xmm1,	%xmm3
663	pxor	%xmm2,	%xmm3
664	pshufb	%xmm5,	%xmm3
665
666	movdqa	0x40(%r11), %xmm2
667	pshufb	%xmm4,	%xmm2
668	pxor	%xmm3,	%xmm2
669	movdqa	0x50(%r11), %xmm3
670	pshufb	%xmm1,	%xmm3
671	pxor	%xmm2,	%xmm3
672	pshufb	%xmm5,	%xmm3
673
674	movdqa	0x60(%r11), %xmm2
675	pshufb	%xmm4,	%xmm2
676	pxor	%xmm3,	%xmm2
677	movdqa	0x70(%r11), %xmm3
678	pshufb	%xmm1,	%xmm3
679	pxor	%xmm2,	%xmm3
680
681	add	\$-16,	%rdx
682
683.Lschedule_mangle_both:
684	movdqa	(%r8,%r10),%xmm1
685	pshufb	%xmm1,%xmm3
686	add	\$-16,	%r8
687	and	\$0x30,	%r8
688	movdqu	%xmm3,	(%rdx)
689	ret
690.cfi_endproc
691.size	_vpaes_schedule_mangle,.-_vpaes_schedule_mangle
692
693#
694# Interface to OpenSSL
695#
696.globl	${PREFIX}_set_encrypt_key
697.type	${PREFIX}_set_encrypt_key,\@function,3
698.align	16
699${PREFIX}_set_encrypt_key:
700.cfi_startproc
701	endbranch
702___
703$code.=<<___ if ($win64);
704	lea	-0xb8(%rsp),%rsp
705	movaps	%xmm6,0x10(%rsp)
706	movaps	%xmm7,0x20(%rsp)
707	movaps	%xmm8,0x30(%rsp)
708	movaps	%xmm9,0x40(%rsp)
709	movaps	%xmm10,0x50(%rsp)
710	movaps	%xmm11,0x60(%rsp)
711	movaps	%xmm12,0x70(%rsp)
712	movaps	%xmm13,0x80(%rsp)
713	movaps	%xmm14,0x90(%rsp)
714	movaps	%xmm15,0xa0(%rsp)
715.Lenc_key_body:
716___
717$code.=<<___;
718	mov	%esi,%eax
719	shr	\$5,%eax
720	add	\$5,%eax
721	mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
722
723	mov	\$0,%ecx
724	mov	\$0x30,%r8d
725	call	_vpaes_schedule_core
726___
727$code.=<<___ if ($win64);
728	movaps	0x10(%rsp),%xmm6
729	movaps	0x20(%rsp),%xmm7
730	movaps	0x30(%rsp),%xmm8
731	movaps	0x40(%rsp),%xmm9
732	movaps	0x50(%rsp),%xmm10
733	movaps	0x60(%rsp),%xmm11
734	movaps	0x70(%rsp),%xmm12
735	movaps	0x80(%rsp),%xmm13
736	movaps	0x90(%rsp),%xmm14
737	movaps	0xa0(%rsp),%xmm15
738	lea	0xb8(%rsp),%rsp
739.Lenc_key_epilogue:
740___
741$code.=<<___;
742	xor	%eax,%eax
743	ret
744.cfi_endproc
745.size	${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
746
747.globl	${PREFIX}_set_decrypt_key
748.type	${PREFIX}_set_decrypt_key,\@function,3
749.align	16
750${PREFIX}_set_decrypt_key:
751.cfi_startproc
752	endbranch
753___
754$code.=<<___ if ($win64);
755	lea	-0xb8(%rsp),%rsp
756	movaps	%xmm6,0x10(%rsp)
757	movaps	%xmm7,0x20(%rsp)
758	movaps	%xmm8,0x30(%rsp)
759	movaps	%xmm9,0x40(%rsp)
760	movaps	%xmm10,0x50(%rsp)
761	movaps	%xmm11,0x60(%rsp)
762	movaps	%xmm12,0x70(%rsp)
763	movaps	%xmm13,0x80(%rsp)
764	movaps	%xmm14,0x90(%rsp)
765	movaps	%xmm15,0xa0(%rsp)
766.Ldec_key_body:
767___
768$code.=<<___;
769	mov	%esi,%eax
770	shr	\$5,%eax
771	add	\$5,%eax
772	mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
773	shl	\$4,%eax
774	lea	16(%rdx,%rax),%rdx
775
776	mov	\$1,%ecx
777	mov	%esi,%r8d
778	shr	\$1,%r8d
779	and	\$32,%r8d
780	xor	\$32,%r8d	# nbits==192?0:32
781	call	_vpaes_schedule_core
782___
783$code.=<<___ if ($win64);
784	movaps	0x10(%rsp),%xmm6
785	movaps	0x20(%rsp),%xmm7
786	movaps	0x30(%rsp),%xmm8
787	movaps	0x40(%rsp),%xmm9
788	movaps	0x50(%rsp),%xmm10
789	movaps	0x60(%rsp),%xmm11
790	movaps	0x70(%rsp),%xmm12
791	movaps	0x80(%rsp),%xmm13
792	movaps	0x90(%rsp),%xmm14
793	movaps	0xa0(%rsp),%xmm15
794	lea	0xb8(%rsp),%rsp
795.Ldec_key_epilogue:
796___
797$code.=<<___;
798	xor	%eax,%eax
799	ret
800.cfi_endproc
801.size	${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
802
803.globl	${PREFIX}_encrypt
804.type	${PREFIX}_encrypt,\@function,3
805.align	16
806${PREFIX}_encrypt:
807.cfi_startproc
808	endbranch
809___
810$code.=<<___ if ($win64);
811	lea	-0xb8(%rsp),%rsp
812	movaps	%xmm6,0x10(%rsp)
813	movaps	%xmm7,0x20(%rsp)
814	movaps	%xmm8,0x30(%rsp)
815	movaps	%xmm9,0x40(%rsp)
816	movaps	%xmm10,0x50(%rsp)
817	movaps	%xmm11,0x60(%rsp)
818	movaps	%xmm12,0x70(%rsp)
819	movaps	%xmm13,0x80(%rsp)
820	movaps	%xmm14,0x90(%rsp)
821	movaps	%xmm15,0xa0(%rsp)
822.Lenc_body:
823___
824$code.=<<___;
825	movdqu	(%rdi),%xmm0
826	call	_vpaes_preheat
827	call	_vpaes_encrypt_core
828	movdqu	%xmm0,(%rsi)
829___
830$code.=<<___ if ($win64);
831	movaps	0x10(%rsp),%xmm6
832	movaps	0x20(%rsp),%xmm7
833	movaps	0x30(%rsp),%xmm8
834	movaps	0x40(%rsp),%xmm9
835	movaps	0x50(%rsp),%xmm10
836	movaps	0x60(%rsp),%xmm11
837	movaps	0x70(%rsp),%xmm12
838	movaps	0x80(%rsp),%xmm13
839	movaps	0x90(%rsp),%xmm14
840	movaps	0xa0(%rsp),%xmm15
841	lea	0xb8(%rsp),%rsp
842.Lenc_epilogue:
843___
844$code.=<<___;
845	ret
846.cfi_endproc
847.size	${PREFIX}_encrypt,.-${PREFIX}_encrypt
848
849.globl	${PREFIX}_decrypt
850.type	${PREFIX}_decrypt,\@function,3
851.align	16
852${PREFIX}_decrypt:
853.cfi_startproc
854	endbranch
855___
856$code.=<<___ if ($win64);
857	lea	-0xb8(%rsp),%rsp
858	movaps	%xmm6,0x10(%rsp)
859	movaps	%xmm7,0x20(%rsp)
860	movaps	%xmm8,0x30(%rsp)
861	movaps	%xmm9,0x40(%rsp)
862	movaps	%xmm10,0x50(%rsp)
863	movaps	%xmm11,0x60(%rsp)
864	movaps	%xmm12,0x70(%rsp)
865	movaps	%xmm13,0x80(%rsp)
866	movaps	%xmm14,0x90(%rsp)
867	movaps	%xmm15,0xa0(%rsp)
868.Ldec_body:
869___
870$code.=<<___;
871	movdqu	(%rdi),%xmm0
872	call	_vpaes_preheat
873	call	_vpaes_decrypt_core
874	movdqu	%xmm0,(%rsi)
875___
876$code.=<<___ if ($win64);
877	movaps	0x10(%rsp),%xmm6
878	movaps	0x20(%rsp),%xmm7
879	movaps	0x30(%rsp),%xmm8
880	movaps	0x40(%rsp),%xmm9
881	movaps	0x50(%rsp),%xmm10
882	movaps	0x60(%rsp),%xmm11
883	movaps	0x70(%rsp),%xmm12
884	movaps	0x80(%rsp),%xmm13
885	movaps	0x90(%rsp),%xmm14
886	movaps	0xa0(%rsp),%xmm15
887	lea	0xb8(%rsp),%rsp
888.Ldec_epilogue:
889___
890$code.=<<___;
891	ret
892.cfi_endproc
893.size	${PREFIX}_decrypt,.-${PREFIX}_decrypt
894___
895{
896my ($inp,$out,$len,$key,$ivp,$enc)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
897# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
898#                       size_t length, const AES_KEY *key,
899#                       unsigned char *ivp,const int enc);
900$code.=<<___;
901.globl	${PREFIX}_cbc_encrypt
902.type	${PREFIX}_cbc_encrypt,\@function,6
903.align	16
904${PREFIX}_cbc_encrypt:
905.cfi_startproc
906	endbranch
907	xchg	$key,$len
908___
909($len,$key)=($key,$len);
910$code.=<<___;
911	sub	\$16,$len
912	jc	.Lcbc_abort
913___
914$code.=<<___ if ($win64);
915	lea	-0xb8(%rsp),%rsp
916	movaps	%xmm6,0x10(%rsp)
917	movaps	%xmm7,0x20(%rsp)
918	movaps	%xmm8,0x30(%rsp)
919	movaps	%xmm9,0x40(%rsp)
920	movaps	%xmm10,0x50(%rsp)
921	movaps	%xmm11,0x60(%rsp)
922	movaps	%xmm12,0x70(%rsp)
923	movaps	%xmm13,0x80(%rsp)
924	movaps	%xmm14,0x90(%rsp)
925	movaps	%xmm15,0xa0(%rsp)
926.Lcbc_body:
927___
928$code.=<<___;
929	movdqu	($ivp),%xmm6		# load IV
930	sub	$inp,$out
931	call	_vpaes_preheat
932	cmp	\$0,${enc}d
933	je	.Lcbc_dec_loop
934	jmp	.Lcbc_enc_loop
935.align	16
936.Lcbc_enc_loop:
937	movdqu	($inp),%xmm0
938	pxor	%xmm6,%xmm0
939	call	_vpaes_encrypt_core
940	movdqa	%xmm0,%xmm6
941	movdqu	%xmm0,($out,$inp)
942	lea	16($inp),$inp
943	sub	\$16,$len
944	jnc	.Lcbc_enc_loop
945	jmp	.Lcbc_done
946.align	16
947.Lcbc_dec_loop:
948	movdqu	($inp),%xmm0
949	movdqa	%xmm0,%xmm7
950	call	_vpaes_decrypt_core
951	pxor	%xmm6,%xmm0
952	movdqa	%xmm7,%xmm6
953	movdqu	%xmm0,($out,$inp)
954	lea	16($inp),$inp
955	sub	\$16,$len
956	jnc	.Lcbc_dec_loop
957.Lcbc_done:
958	movdqu	%xmm6,($ivp)		# save IV
959___
960$code.=<<___ if ($win64);
961	movaps	0x10(%rsp),%xmm6
962	movaps	0x20(%rsp),%xmm7
963	movaps	0x30(%rsp),%xmm8
964	movaps	0x40(%rsp),%xmm9
965	movaps	0x50(%rsp),%xmm10
966	movaps	0x60(%rsp),%xmm11
967	movaps	0x70(%rsp),%xmm12
968	movaps	0x80(%rsp),%xmm13
969	movaps	0x90(%rsp),%xmm14
970	movaps	0xa0(%rsp),%xmm15
971	lea	0xb8(%rsp),%rsp
972.Lcbc_epilogue:
973___
974$code.=<<___;
975.Lcbc_abort:
976	ret
977.cfi_endproc
978.size	${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
979___
980}
981$code.=<<___;
982##
983##  _aes_preheat
984##
985##  Fills register %r10 -> .aes_consts (so you can -fPIC)
986##  and %xmm9-%xmm15 as specified below.
987##
988.type	_vpaes_preheat,\@abi-omnipotent
989.align	16
990_vpaes_preheat:
991.cfi_startproc
992	lea	.Lk_s0F(%rip), %r10
993	movdqa	-0x20(%r10), %xmm10	# .Lk_inv
994	movdqa	-0x10(%r10), %xmm11	# .Lk_inv+16
995	movdqa	0x00(%r10), %xmm9	# .Lk_s0F
996	movdqa	0x30(%r10), %xmm13	# .Lk_sb1
997	movdqa	0x40(%r10), %xmm12	# .Lk_sb1+16
998	movdqa	0x50(%r10), %xmm15	# .Lk_sb2
999	movdqa	0x60(%r10), %xmm14	# .Lk_sb2+16
1000	ret
1001.cfi_endproc
1002.size	_vpaes_preheat,.-_vpaes_preheat
1003########################################################
1004##                                                    ##
1005##                     Constants                      ##
1006##                                                    ##
1007########################################################
1008.type	_vpaes_consts,\@object
1009.section .rodata align=64
1010.align	64
1011_vpaes_consts:
1012.Lk_inv:	# inv, inva
1013	.quad	0x0E05060F0D080180, 0x040703090A0B0C02
1014	.quad	0x01040A060F0B0780, 0x030D0E0C02050809
1015
1016.Lk_s0F:	# s0F
1017	.quad	0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F
1018
1019.Lk_ipt:	# input transform (lo, hi)
1020	.quad	0xC2B2E8985A2A7000, 0xCABAE09052227808
1021	.quad	0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81
1022
1023.Lk_sb1:	# sb1u, sb1t
1024	.quad	0xB19BE18FCB503E00, 0xA5DF7A6E142AF544
1025	.quad	0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF
1026.Lk_sb2:	# sb2u, sb2t
1027	.quad	0xE27A93C60B712400, 0x5EB7E955BC982FCD
1028	.quad	0x69EB88400AE12900, 0xC2A163C8AB82234A
1029.Lk_sbo:	# sbou, sbot
1030	.quad	0xD0D26D176FBDC700, 0x15AABF7AC502A878
1031	.quad	0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA
1032
1033.Lk_mc_forward:	# mc_forward
1034	.quad	0x0407060500030201, 0x0C0F0E0D080B0A09
1035	.quad	0x080B0A0904070605, 0x000302010C0F0E0D
1036	.quad	0x0C0F0E0D080B0A09, 0x0407060500030201
1037	.quad	0x000302010C0F0E0D, 0x080B0A0904070605
1038
1039.Lk_mc_backward:# mc_backward
1040	.quad	0x0605040702010003, 0x0E0D0C0F0A09080B
1041	.quad	0x020100030E0D0C0F, 0x0A09080B06050407
1042	.quad	0x0E0D0C0F0A09080B, 0x0605040702010003
1043	.quad	0x0A09080B06050407, 0x020100030E0D0C0F
1044
1045.Lk_sr:		# sr
1046	.quad	0x0706050403020100, 0x0F0E0D0C0B0A0908
1047	.quad	0x030E09040F0A0500, 0x0B06010C07020D08
1048	.quad	0x0F060D040B020900, 0x070E050C030A0108
1049	.quad	0x0B0E0104070A0D00, 0x0306090C0F020508
1050
1051.Lk_rcon:	# rcon
1052	.quad	0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81
1053
1054.Lk_s63:	# s63: all equal to 0x63 transformed
1055	.quad	0x5B5B5B5B5B5B5B5B, 0x5B5B5B5B5B5B5B5B
1056
1057.Lk_opt:	# output transform
1058	.quad	0xFF9F4929D6B66000, 0xF7974121DEBE6808
1059	.quad	0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0
1060
1061.Lk_deskew:	# deskew tables: inverts the sbox's "skew"
1062	.quad	0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A
1063	.quad	0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77
1064
1065##
1066##  Decryption stuff
1067##  Key schedule constants
1068##
1069.Lk_dksd:	# decryption key schedule: invskew x*D
1070	.quad	0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9
1071	.quad	0x41C277F4B5368300, 0x5FDC69EAAB289D1E
1072.Lk_dksb:	# decryption key schedule: invskew x*B
1073	.quad	0x9A4FCA1F8550D500, 0x03D653861CC94C99
1074	.quad	0x115BEDA7B6FC4A00, 0xD993256F7E3482C8
1075.Lk_dkse:	# decryption key schedule: invskew x*E + 0x63
1076	.quad	0xD5031CCA1FC9D600, 0x53859A4C994F5086
1077	.quad	0xA23196054FDC7BE8, 0xCD5EF96A20B31487
1078.Lk_dks9:	# decryption key schedule: invskew x*9
1079	.quad	0xB6116FC87ED9A700, 0x4AED933482255BFC
1080	.quad	0x4576516227143300, 0x8BB89FACE9DAFDCE
1081
1082##
1083##  Decryption stuff
1084##  Round function constants
1085##
1086.Lk_dipt:	# decryption input transform
1087	.quad	0x0F505B040B545F00, 0x154A411E114E451A
1088	.quad	0x86E383E660056500, 0x12771772F491F194
1089
1090.Lk_dsb9:	# decryption sbox output *9*u, *9*t
1091	.quad	0x851C03539A86D600, 0xCAD51F504F994CC9
1092	.quad	0xC03B1789ECD74900, 0x725E2C9EB2FBA565
1093.Lk_dsbd:	# decryption sbox output *D*u, *D*t
1094	.quad	0x7D57CCDFE6B1A200, 0xF56E9B13882A4439
1095	.quad	0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3
1096.Lk_dsbb:	# decryption sbox output *B*u, *B*t
1097	.quad	0xD022649296B44200, 0x602646F6B0F2D404
1098	.quad	0xC19498A6CD596700, 0xF3FF0C3E3255AA6B
1099.Lk_dsbe:	# decryption sbox output *E*u, *E*t
1100	.quad	0x46F2929626D4D000, 0x2242600464B4F6B0
1101	.quad	0x0C55A6CDFFAAC100, 0x9467F36B98593E32
1102.Lk_dsbo:	# decryption sbox final output
1103	.quad	0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
1104	.quad	0x12D7560F93441D00, 0xCA4B8159D8C58E9C
1105.align	64
1106.size	_vpaes_consts,.-_vpaes_consts
1107.asciz	"Vector Permutation AES for x86_64/SSSE3, Mike Hamburg (Stanford University)"
1108___
1109
1110if ($win64) {
1111# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1112#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
1113$rec="%rcx";
1114$frame="%rdx";
1115$context="%r8";
1116$disp="%r9";
1117
1118$code.=<<___;
1119.extern	__imp_RtlVirtualUnwind
1120.type	se_handler,\@abi-omnipotent
1121.align	16
1122se_handler:
1123	push	%rsi
1124	push	%rdi
1125	push	%rbx
1126	push	%rbp
1127	push	%r12
1128	push	%r13
1129	push	%r14
1130	push	%r15
1131	pushfq
1132	sub	\$64,%rsp
1133
1134	mov	120($context),%rax	# pull context->Rax
1135	mov	248($context),%rbx	# pull context->Rip
1136
1137	mov	8($disp),%rsi		# disp->ImageBase
1138	mov	56($disp),%r11		# disp->HandlerData
1139
1140	mov	0(%r11),%r10d		# HandlerData[0]
1141	lea	(%rsi,%r10),%r10	# prologue label
1142	cmp	%r10,%rbx		# context->Rip<prologue label
1143	jb	.Lin_prologue
1144
1145	mov	152($context),%rax	# pull context->Rsp
1146
1147	mov	4(%r11),%r10d		# HandlerData[1]
1148	lea	(%rsi,%r10),%r10	# epilogue label
1149	cmp	%r10,%rbx		# context->Rip>=epilogue label
1150	jae	.Lin_prologue
1151
1152	lea	16(%rax),%rsi		# %xmm save area
1153	lea	512($context),%rdi	# &context.Xmm6
1154	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
1155	.long	0xa548f3fc		# cld; rep movsq
1156	lea	0xb8(%rax),%rax		# adjust stack pointer
1157
1158.Lin_prologue:
1159	mov	8(%rax),%rdi
1160	mov	16(%rax),%rsi
1161	mov	%rax,152($context)	# restore context->Rsp
1162	mov	%rsi,168($context)	# restore context->Rsi
1163	mov	%rdi,176($context)	# restore context->Rdi
1164
1165	mov	40($disp),%rdi		# disp->ContextRecord
1166	mov	$context,%rsi		# context
1167	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
1168	.long	0xa548f3fc		# cld; rep movsq
1169
1170	mov	$disp,%rsi
1171	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
1172	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
1173	mov	0(%rsi),%r8		# arg3, disp->ControlPc
1174	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
1175	mov	40(%rsi),%r10		# disp->ContextRecord
1176	lea	56(%rsi),%r11		# &disp->HandlerData
1177	lea	24(%rsi),%r12		# &disp->EstablisherFrame
1178	mov	%r10,32(%rsp)		# arg5
1179	mov	%r11,40(%rsp)		# arg6
1180	mov	%r12,48(%rsp)		# arg7
1181	mov	%rcx,56(%rsp)		# arg8, (NULL)
1182	call	*__imp_RtlVirtualUnwind(%rip)
1183
1184	mov	\$1,%eax		# ExceptionContinueSearch
1185	add	\$64,%rsp
1186	popfq
1187	pop	%r15
1188	pop	%r14
1189	pop	%r13
1190	pop	%r12
1191	pop	%rbp
1192	pop	%rbx
1193	pop	%rdi
1194	pop	%rsi
1195	ret
1196.size	se_handler,.-se_handler
1197
1198.section	.pdata
1199.align	4
1200	.rva	.LSEH_begin_${PREFIX}_set_encrypt_key
1201	.rva	.LSEH_end_${PREFIX}_set_encrypt_key
1202	.rva	.LSEH_info_${PREFIX}_set_encrypt_key
1203
1204	.rva	.LSEH_begin_${PREFIX}_set_decrypt_key
1205	.rva	.LSEH_end_${PREFIX}_set_decrypt_key
1206	.rva	.LSEH_info_${PREFIX}_set_decrypt_key
1207
1208	.rva	.LSEH_begin_${PREFIX}_encrypt
1209	.rva	.LSEH_end_${PREFIX}_encrypt
1210	.rva	.LSEH_info_${PREFIX}_encrypt
1211
1212	.rva	.LSEH_begin_${PREFIX}_decrypt
1213	.rva	.LSEH_end_${PREFIX}_decrypt
1214	.rva	.LSEH_info_${PREFIX}_decrypt
1215
1216	.rva	.LSEH_begin_${PREFIX}_cbc_encrypt
1217	.rva	.LSEH_end_${PREFIX}_cbc_encrypt
1218	.rva	.LSEH_info_${PREFIX}_cbc_encrypt
1219
1220.section	.xdata
1221.align	8
1222.LSEH_info_${PREFIX}_set_encrypt_key:
1223	.byte	9,0,0,0
1224	.rva	se_handler
1225	.rva	.Lenc_key_body,.Lenc_key_epilogue	# HandlerData[]
1226.LSEH_info_${PREFIX}_set_decrypt_key:
1227	.byte	9,0,0,0
1228	.rva	se_handler
1229	.rva	.Ldec_key_body,.Ldec_key_epilogue	# HandlerData[]
1230.LSEH_info_${PREFIX}_encrypt:
1231	.byte	9,0,0,0
1232	.rva	se_handler
1233	.rva	.Lenc_body,.Lenc_epilogue		# HandlerData[]
1234.LSEH_info_${PREFIX}_decrypt:
1235	.byte	9,0,0,0
1236	.rva	se_handler
1237	.rva	.Ldec_body,.Ldec_epilogue		# HandlerData[]
1238.LSEH_info_${PREFIX}_cbc_encrypt:
1239	.byte	9,0,0,0
1240	.rva	se_handler
1241	.rva	.Lcbc_body,.Lcbc_epilogue		# HandlerData[]
1242___
1243}
1244
1245$code =~ s/\`([^\`]*)\`/eval($1)/gem;
1246
1247print $code;
1248
1249close STDOUT or die "error closing STDOUT: $!";
1250