Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / crypto / bn / asm / x86_64-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9
10 # October 2005.
11 #
12 # Montgomery multiplication routine for x86_64. While it gives modest
13 # 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more
14 # than twice, >2x, as fast. Most common rsa1024 sign is improved by
15 # respectful 50%. It remains to be seen if loop unrolling and
16 # dedicated squaring routine can provide further improvement...
17
18 # July 2011.
19 #
20 # Add dedicated squaring procedure. Performance improvement varies
21 # from platform to platform, but in average it's ~5%/15%/25%/33%
22 # for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
23
24 # August 2011.
25 #
26 # Unroll and modulo-schedule inner loops in such manner that they
27 # are "fallen through" for input lengths of 8, which is critical for
28 # 1024-bit RSA *sign*. Average performance improvement in comparison
29 # to *initial* version of this module from 2005 is ~0%/30%/40%/45%
30 # for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
31
32 # June 2013.
33 #
34 # Optimize reduction in squaring procedure and improve 1024+-bit RSA
35 # sign performance by 10-16% on Intel Sandy Bridge and later
36 # (virtually same on non-Intel processors).
37
38 # August 2013.
39 #
40 # Add MULX/ADOX/ADCX code path.
41
42 $flavour = shift;
43 $output  = shift;
44 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
45
46 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
47
48 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
49 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
50 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
51 die "can't locate x86_64-xlate.pl";
52
53 open OUT,"| \"$^X\" $xlate $flavour $output";
54 *STDOUT=*OUT;
55
56 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
57                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
58         $addx = ($1>=2.23);
59 }
60
61 if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
62             `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
63         $addx = ($1>=2.10);
64 }
65
66 if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
67             `ml64 2>&1` =~ /Version ([0-9]+)\./) {
68         $addx = ($1>=12);
69 }
70
71 # int bn_mul_mont(
72 $rp="%rdi";     # BN_ULONG *rp,
73 $ap="%rsi";     # const BN_ULONG *ap,
74 $bp="%rdx";     # const BN_ULONG *bp,
75 $np="%rcx";     # const BN_ULONG *np,
76 $n0="%r8";      # const BN_ULONG *n0,
77 $num="%r9";     # int num);
78 $lo0="%r10";
79 $hi0="%r11";
80 $hi1="%r13";
81 $i="%r14";
82 $j="%r15";
83 $m0="%rbx";
84 $m1="%rbp";
85
86 $code=<<___;
87 .text
88
89 .extern OPENSSL_ia32cap_P
90
91 .globl  bn_mul_mont
92 .type   bn_mul_mont,\@function,6
93 .align  16
94 bn_mul_mont:
95         test    \$3,${num}d
96         jnz     .Lmul_enter
97         cmp     \$8,${num}d
98         jb      .Lmul_enter
99 ___
100 $code.=<<___ if ($addx);
101         mov     OPENSSL_ia32cap_P+8(%rip),%r11d
102 ___
103 $code.=<<___;
104         cmp     $ap,$bp
105         jne     .Lmul4x_enter
106         test    \$7,${num}d
107         jz      .Lsqr8x_enter
108         jmp     .Lmul4x_enter
109
110 .align  16
111 .Lmul_enter:
112         push    %rbx
113         push    %rbp
114         push    %r12
115         push    %r13
116         push    %r14
117         push    %r15
118
119         mov     ${num}d,${num}d
120         lea     2($num),%r10
121         mov     %rsp,%r11
122         neg     %r10
123         lea     (%rsp,%r10,8),%rsp      # tp=alloca(8*(num+2))
124         and     \$-1024,%rsp            # minimize TLB usage
125
126         mov     %r11,8(%rsp,$num,8)     # tp[num+1]=%rsp
127 .Lmul_body:
128         mov     $bp,%r12                # reassign $bp
129 ___
130                 $bp="%r12";
131 $code.=<<___;
132         mov     ($n0),$n0               # pull n0[0] value
133         mov     ($bp),$m0               # m0=bp[0]
134         mov     ($ap),%rax
135
136         xor     $i,$i                   # i=0
137         xor     $j,$j                   # j=0
138
139         mov     $n0,$m1
140         mulq    $m0                     # ap[0]*bp[0]
141         mov     %rax,$lo0
142         mov     ($np),%rax
143
144         imulq   $lo0,$m1                # "tp[0]"*n0
145         mov     %rdx,$hi0
146
147         mulq    $m1                     # np[0]*m1
148         add     %rax,$lo0               # discarded
149         mov     8($ap),%rax
150         adc     \$0,%rdx
151         mov     %rdx,$hi1
152
153         lea     1($j),$j                # j++
154         jmp     .L1st_enter
155
156 .align  16
157 .L1st:
158         add     %rax,$hi1
159         mov     ($ap,$j,8),%rax
160         adc     \$0,%rdx
161         add     $hi0,$hi1               # np[j]*m1+ap[j]*bp[0]
162         mov     $lo0,$hi0
163         adc     \$0,%rdx
164         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
165         mov     %rdx,$hi1
166
167 .L1st_enter:
168         mulq    $m0                     # ap[j]*bp[0]
169         add     %rax,$hi0
170         mov     ($np,$j,8),%rax
171         adc     \$0,%rdx
172         lea     1($j),$j                # j++
173         mov     %rdx,$lo0
174
175         mulq    $m1                     # np[j]*m1
176         cmp     $num,$j
177         jne     .L1st
178
179         add     %rax,$hi1
180         mov     ($ap),%rax              # ap[0]
181         adc     \$0,%rdx
182         add     $hi0,$hi1               # np[j]*m1+ap[j]*bp[0]
183         adc     \$0,%rdx
184         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
185         mov     %rdx,$hi1
186         mov     $lo0,$hi0
187
188         xor     %rdx,%rdx
189         add     $hi0,$hi1
190         adc     \$0,%rdx
191         mov     $hi1,-8(%rsp,$num,8)
192         mov     %rdx,(%rsp,$num,8)      # store upmost overflow bit
193
194         lea     1($i),$i                # i++
195         jmp     .Louter
196 .align  16
197 .Louter:
198         mov     ($bp,$i,8),$m0          # m0=bp[i]
199         xor     $j,$j                   # j=0
200         mov     $n0,$m1
201         mov     (%rsp),$lo0
202         mulq    $m0                     # ap[0]*bp[i]
203         add     %rax,$lo0               # ap[0]*bp[i]+tp[0]
204         mov     ($np),%rax
205         adc     \$0,%rdx
206
207         imulq   $lo0,$m1                # tp[0]*n0
208         mov     %rdx,$hi0
209
210         mulq    $m1                     # np[0]*m1
211         add     %rax,$lo0               # discarded
212         mov     8($ap),%rax
213         adc     \$0,%rdx
214         mov     8(%rsp),$lo0            # tp[1]
215         mov     %rdx,$hi1
216
217         lea     1($j),$j                # j++
218         jmp     .Linner_enter
219
220 .align  16
221 .Linner:
222         add     %rax,$hi1
223         mov     ($ap,$j,8),%rax
224         adc     \$0,%rdx
225         add     $lo0,$hi1               # np[j]*m1+ap[j]*bp[i]+tp[j]
226         mov     (%rsp,$j,8),$lo0
227         adc     \$0,%rdx
228         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
229         mov     %rdx,$hi1
230
231 .Linner_enter:
232         mulq    $m0                     # ap[j]*bp[i]
233         add     %rax,$hi0
234         mov     ($np,$j,8),%rax
235         adc     \$0,%rdx
236         add     $hi0,$lo0               # ap[j]*bp[i]+tp[j]
237         mov     %rdx,$hi0
238         adc     \$0,$hi0
239         lea     1($j),$j                # j++
240
241         mulq    $m1                     # np[j]*m1
242         cmp     $num,$j
243         jne     .Linner
244
245         add     %rax,$hi1
246         mov     ($ap),%rax              # ap[0]
247         adc     \$0,%rdx
248         add     $lo0,$hi1               # np[j]*m1+ap[j]*bp[i]+tp[j]
249         mov     (%rsp,$j,8),$lo0
250         adc     \$0,%rdx
251         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
252         mov     %rdx,$hi1
253
254         xor     %rdx,%rdx
255         add     $hi0,$hi1
256         adc     \$0,%rdx
257         add     $lo0,$hi1               # pull upmost overflow bit
258         adc     \$0,%rdx
259         mov     $hi1,-8(%rsp,$num,8)
260         mov     %rdx,(%rsp,$num,8)      # store upmost overflow bit
261
262         lea     1($i),$i                # i++
263         cmp     $num,$i
264         jb      .Louter
265
266         xor     $i,$i                   # i=0 and clear CF!
267         mov     (%rsp),%rax             # tp[0]
268         lea     (%rsp),$ap              # borrow ap for tp
269         mov     $num,$j                 # j=num
270         jmp     .Lsub
271 .align  16
272 .Lsub:  sbb     ($np,$i,8),%rax
273         mov     %rax,($rp,$i,8)         # rp[i]=tp[i]-np[i]
274         mov     8($ap,$i,8),%rax        # tp[i+1]
275         lea     1($i),$i                # i++
276         dec     $j                      # doesn't affect CF!
277         jnz     .Lsub
278
279         sbb     \$0,%rax                # handle upmost overflow bit
280         xor     $i,$i
281         mov     $num,$j                 # j=num
282 .align  16
283 .Lcopy:                                 # copy or in-place refresh
284         mov     (%rsp,$i,8),$ap
285         mov     ($rp,$i,8),$np
286         xor     $np,$ap                 # conditional select:
287         and     %rax,$ap                # ((ap ^ np) & %rax) ^ np
288         xor     $np,$ap                 # ap = borrow?tp:rp
289         mov     $i,(%rsp,$i,8)          # zap temporary vector
290         mov     $ap,($rp,$i,8)          # rp[i]=tp[i]
291         lea     1($i),$i
292         sub     \$1,$j
293         jnz     .Lcopy
294
295         mov     8(%rsp,$num,8),%rsi     # restore %rsp
296         mov     \$1,%rax
297         mov     (%rsi),%r15
298         mov     8(%rsi),%r14
299         mov     16(%rsi),%r13
300         mov     24(%rsi),%r12
301         mov     32(%rsi),%rbp
302         mov     40(%rsi),%rbx
303         lea     48(%rsi),%rsp
304 .Lmul_epilogue:
305         ret
306 .size   bn_mul_mont,.-bn_mul_mont
307 ___
308 {{{
309 my @A=("%r10","%r11");
310 my @N=("%r13","%rdi");
311 $code.=<<___;
312 .type   bn_mul4x_mont,\@function,6
313 .align  16
314 bn_mul4x_mont:
315 .Lmul4x_enter:
316 ___
317 $code.=<<___ if ($addx);
318         and     \$0x80100,%r11d
319         cmp     \$0x80100,%r11d
320         je      .Lmulx4x_enter
321 ___
322 $code.=<<___;
323         push    %rbx
324         push    %rbp
325         push    %r12
326         push    %r13
327         push    %r14
328         push    %r15
329
330         mov     ${num}d,${num}d
331         lea     4($num),%r10
332         mov     %rsp,%r11
333         neg     %r10
334         lea     (%rsp,%r10,8),%rsp      # tp=alloca(8*(num+4))
335         and     \$-1024,%rsp            # minimize TLB usage
336
337         mov     %r11,8(%rsp,$num,8)     # tp[num+1]=%rsp
338 .Lmul4x_body:
339         mov     $rp,16(%rsp,$num,8)     # tp[num+2]=$rp
340         mov     %rdx,%r12               # reassign $bp
341 ___
342                 $bp="%r12";
343 $code.=<<___;
344         mov     ($n0),$n0               # pull n0[0] value
345         mov     ($bp),$m0               # m0=bp[0]
346         mov     ($ap),%rax
347
348         xor     $i,$i                   # i=0
349         xor     $j,$j                   # j=0
350
351         mov     $n0,$m1
352         mulq    $m0                     # ap[0]*bp[0]
353         mov     %rax,$A[0]
354         mov     ($np),%rax
355
356         imulq   $A[0],$m1               # "tp[0]"*n0
357         mov     %rdx,$A[1]
358
359         mulq    $m1                     # np[0]*m1
360         add     %rax,$A[0]              # discarded
361         mov     8($ap),%rax
362         adc     \$0,%rdx
363         mov     %rdx,$N[1]
364
365         mulq    $m0
366         add     %rax,$A[1]
367         mov     8($np),%rax
368         adc     \$0,%rdx
369         mov     %rdx,$A[0]
370
371         mulq    $m1
372         add     %rax,$N[1]
373         mov     16($ap),%rax
374         adc     \$0,%rdx
375         add     $A[1],$N[1]
376         lea     4($j),$j                # j++
377         adc     \$0,%rdx
378         mov     $N[1],(%rsp)
379         mov     %rdx,$N[0]
380         jmp     .L1st4x
381 .align  16
382 .L1st4x:
383         mulq    $m0                     # ap[j]*bp[0]
384         add     %rax,$A[0]
385         mov     -16($np,$j,8),%rax
386         adc     \$0,%rdx
387         mov     %rdx,$A[1]
388
389         mulq    $m1                     # np[j]*m1
390         add     %rax,$N[0]
391         mov     -8($ap,$j,8),%rax
392         adc     \$0,%rdx
393         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
394         adc     \$0,%rdx
395         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
396         mov     %rdx,$N[1]
397
398         mulq    $m0                     # ap[j]*bp[0]
399         add     %rax,$A[1]
400         mov     -8($np,$j,8),%rax
401         adc     \$0,%rdx
402         mov     %rdx,$A[0]
403
404         mulq    $m1                     # np[j]*m1
405         add     %rax,$N[1]
406         mov     ($ap,$j,8),%rax
407         adc     \$0,%rdx
408         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
409         adc     \$0,%rdx
410         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
411         mov     %rdx,$N[0]
412
413         mulq    $m0                     # ap[j]*bp[0]
414         add     %rax,$A[0]
415         mov     ($np,$j,8),%rax
416         adc     \$0,%rdx
417         mov     %rdx,$A[1]
418
419         mulq    $m1                     # np[j]*m1
420         add     %rax,$N[0]
421         mov     8($ap,$j,8),%rax
422         adc     \$0,%rdx
423         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
424         adc     \$0,%rdx
425         mov     $N[0],-8(%rsp,$j,8)     # tp[j-1]
426         mov     %rdx,$N[1]
427
428         mulq    $m0                     # ap[j]*bp[0]
429         add     %rax,$A[1]
430         mov     8($np,$j,8),%rax
431         adc     \$0,%rdx
432         lea     4($j),$j                # j++
433         mov     %rdx,$A[0]
434
435         mulq    $m1                     # np[j]*m1
436         add     %rax,$N[1]
437         mov     -16($ap,$j,8),%rax
438         adc     \$0,%rdx
439         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
440         adc     \$0,%rdx
441         mov     $N[1],-32(%rsp,$j,8)    # tp[j-1]
442         mov     %rdx,$N[0]
443         cmp     $num,$j
444         jb      .L1st4x
445
446         mulq    $m0                     # ap[j]*bp[0]
447         add     %rax,$A[0]
448         mov     -16($np,$j,8),%rax
449         adc     \$0,%rdx
450         mov     %rdx,$A[1]
451
452         mulq    $m1                     # np[j]*m1
453         add     %rax,$N[0]
454         mov     -8($ap,$j,8),%rax
455         adc     \$0,%rdx
456         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
457         adc     \$0,%rdx
458         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
459         mov     %rdx,$N[1]
460
461         mulq    $m0                     # ap[j]*bp[0]
462         add     %rax,$A[1]
463         mov     -8($np,$j,8),%rax
464         adc     \$0,%rdx
465         mov     %rdx,$A[0]
466
467         mulq    $m1                     # np[j]*m1
468         add     %rax,$N[1]
469         mov     ($ap),%rax              # ap[0]
470         adc     \$0,%rdx
471         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
472         adc     \$0,%rdx
473         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
474         mov     %rdx,$N[0]
475
476         xor     $N[1],$N[1]
477         add     $A[0],$N[0]
478         adc     \$0,$N[1]
479         mov     $N[0],-8(%rsp,$j,8)
480         mov     $N[1],(%rsp,$j,8)       # store upmost overflow bit
481
482         lea     1($i),$i                # i++
483 .align  4
484 .Louter4x:
485         mov     ($bp,$i,8),$m0          # m0=bp[i]
486         xor     $j,$j                   # j=0
487         mov     (%rsp),$A[0]
488         mov     $n0,$m1
489         mulq    $m0                     # ap[0]*bp[i]
490         add     %rax,$A[0]              # ap[0]*bp[i]+tp[0]
491         mov     ($np),%rax
492         adc     \$0,%rdx
493
494         imulq   $A[0],$m1               # tp[0]*n0
495         mov     %rdx,$A[1]
496
497         mulq    $m1                     # np[0]*m1
498         add     %rax,$A[0]              # "$N[0]", discarded
499         mov     8($ap),%rax
500         adc     \$0,%rdx
501         mov     %rdx,$N[1]
502
503         mulq    $m0                     # ap[j]*bp[i]
504         add     %rax,$A[1]
505         mov     8($np),%rax
506         adc     \$0,%rdx
507         add     8(%rsp),$A[1]           # +tp[1]
508         adc     \$0,%rdx
509         mov     %rdx,$A[0]
510
511         mulq    $m1                     # np[j]*m1
512         add     %rax,$N[1]
513         mov     16($ap),%rax
514         adc     \$0,%rdx
515         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[i]+tp[j]
516         lea     4($j),$j                # j+=2
517         adc     \$0,%rdx
518         mov     $N[1],(%rsp)            # tp[j-1]
519         mov     %rdx,$N[0]
520         jmp     .Linner4x
521 .align  16
522 .Linner4x:
523         mulq    $m0                     # ap[j]*bp[i]
524         add     %rax,$A[0]
525         mov     -16($np,$j,8),%rax
526         adc     \$0,%rdx
527         add     -16(%rsp,$j,8),$A[0]    # ap[j]*bp[i]+tp[j]
528         adc     \$0,%rdx
529         mov     %rdx,$A[1]
530
531         mulq    $m1                     # np[j]*m1
532         add     %rax,$N[0]
533         mov     -8($ap,$j,8),%rax
534         adc     \$0,%rdx
535         add     $A[0],$N[0]
536         adc     \$0,%rdx
537         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
538         mov     %rdx,$N[1]
539
540         mulq    $m0                     # ap[j]*bp[i]
541         add     %rax,$A[1]
542         mov     -8($np,$j,8),%rax
543         adc     \$0,%rdx
544         add     -8(%rsp,$j,8),$A[1]
545         adc     \$0,%rdx
546         mov     %rdx,$A[0]
547
548         mulq    $m1                     # np[j]*m1
549         add     %rax,$N[1]
550         mov     ($ap,$j,8),%rax
551         adc     \$0,%rdx
552         add     $A[1],$N[1]
553         adc     \$0,%rdx
554         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
555         mov     %rdx,$N[0]
556
557         mulq    $m0                     # ap[j]*bp[i]
558         add     %rax,$A[0]
559         mov     ($np,$j,8),%rax
560         adc     \$0,%rdx
561         add     (%rsp,$j,8),$A[0]       # ap[j]*bp[i]+tp[j]
562         adc     \$0,%rdx
563         mov     %rdx,$A[1]
564
565         mulq    $m1                     # np[j]*m1
566         add     %rax,$N[0]
567         mov     8($ap,$j,8),%rax
568         adc     \$0,%rdx
569         add     $A[0],$N[0]
570         adc     \$0,%rdx
571         mov     $N[0],-8(%rsp,$j,8)     # tp[j-1]
572         mov     %rdx,$N[1]
573
574         mulq    $m0                     # ap[j]*bp[i]
575         add     %rax,$A[1]
576         mov     8($np,$j,8),%rax
577         adc     \$0,%rdx
578         add     8(%rsp,$j,8),$A[1]
579         adc     \$0,%rdx
580         lea     4($j),$j                # j++
581         mov     %rdx,$A[0]
582
583         mulq    $m1                     # np[j]*m1
584         add     %rax,$N[1]
585         mov     -16($ap,$j,8),%rax
586         adc     \$0,%rdx
587         add     $A[1],$N[1]
588         adc     \$0,%rdx
589         mov     $N[1],-32(%rsp,$j,8)    # tp[j-1]
590         mov     %rdx,$N[0]
591         cmp     $num,$j
592         jb      .Linner4x
593
594         mulq    $m0                     # ap[j]*bp[i]
595         add     %rax,$A[0]
596         mov     -16($np,$j,8),%rax
597         adc     \$0,%rdx
598         add     -16(%rsp,$j,8),$A[0]    # ap[j]*bp[i]+tp[j]
599         adc     \$0,%rdx
600         mov     %rdx,$A[1]
601
602         mulq    $m1                     # np[j]*m1
603         add     %rax,$N[0]
604         mov     -8($ap,$j,8),%rax
605         adc     \$0,%rdx
606         add     $A[0],$N[0]
607         adc     \$0,%rdx
608         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
609         mov     %rdx,$N[1]
610
611         mulq    $m0                     # ap[j]*bp[i]
612         add     %rax,$A[1]
613         mov     -8($np,$j,8),%rax
614         adc     \$0,%rdx
615         add     -8(%rsp,$j,8),$A[1]
616         adc     \$0,%rdx
617         lea     1($i),$i                # i++
618         mov     %rdx,$A[0]
619
620         mulq    $m1                     # np[j]*m1
621         add     %rax,$N[1]
622         mov     ($ap),%rax              # ap[0]
623         adc     \$0,%rdx
624         add     $A[1],$N[1]
625         adc     \$0,%rdx
626         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
627         mov     %rdx,$N[0]
628
629         xor     $N[1],$N[1]
630         add     $A[0],$N[0]
631         adc     \$0,$N[1]
632         add     (%rsp,$num,8),$N[0]     # pull upmost overflow bit
633         adc     \$0,$N[1]
634         mov     $N[0],-8(%rsp,$j,8)
635         mov     $N[1],(%rsp,$j,8)       # store upmost overflow bit
636
637         cmp     $num,$i
638         jb      .Louter4x
639 ___
640 {
641 my @ri=("%rax","%rdx",$m0,$m1);
642 $code.=<<___;
643         mov     16(%rsp,$num,8),$rp     # restore $rp
644         mov     0(%rsp),@ri[0]          # tp[0]
645         mov     8(%rsp),@ri[1]          # tp[1]
646         shr     \$2,$num                # num/=4
647         lea     (%rsp),$ap              # borrow ap for tp
648         xor     $i,$i                   # i=0 and clear CF!
649
650         sub     0($np),@ri[0]
651         mov     16($ap),@ri[2]          # tp[2]
652         mov     24($ap),@ri[3]          # tp[3]
653         sbb     8($np),@ri[1]
654         lea     -1($num),$j             # j=num/4-1
655         jmp     .Lsub4x
656 .align  16
657 .Lsub4x:
658         mov     @ri[0],0($rp,$i,8)      # rp[i]=tp[i]-np[i]
659         mov     @ri[1],8($rp,$i,8)      # rp[i]=tp[i]-np[i]
660         sbb     16($np,$i,8),@ri[2]
661         mov     32($ap,$i,8),@ri[0]     # tp[i+1]
662         mov     40($ap,$i,8),@ri[1]
663         sbb     24($np,$i,8),@ri[3]
664         mov     @ri[2],16($rp,$i,8)     # rp[i]=tp[i]-np[i]
665         mov     @ri[3],24($rp,$i,8)     # rp[i]=tp[i]-np[i]
666         sbb     32($np,$i,8),@ri[0]
667         mov     48($ap,$i,8),@ri[2]
668         mov     56($ap,$i,8),@ri[3]
669         sbb     40($np,$i,8),@ri[1]
670         lea     4($i),$i                # i++
671         dec     $j                      # doesnn't affect CF!
672         jnz     .Lsub4x
673
674         mov     @ri[0],0($rp,$i,8)      # rp[i]=tp[i]-np[i]
675         mov     32($ap,$i,8),@ri[0]     # load overflow bit
676         sbb     16($np,$i,8),@ri[2]
677         mov     @ri[1],8($rp,$i,8)      # rp[i]=tp[i]-np[i]
678         sbb     24($np,$i,8),@ri[3]
679         mov     @ri[2],16($rp,$i,8)     # rp[i]=tp[i]-np[i]
680
681         sbb     \$0,@ri[0]              # handle upmost overflow bit
682         mov     @ri[0],%xmm0
683         punpcklqdq %xmm0,%xmm0          # extend mask to 128 bits
684         mov     @ri[3],24($rp,$i,8)     # rp[i]=tp[i]-np[i]
685         xor     $i,$i                   # i=0
686
687         mov     $num,$j
688         pxor    %xmm5,%xmm5
689         jmp     .Lcopy4x
690 .align  16
691 .Lcopy4x:                               # copy or in-place refresh
692         movdqu  (%rsp,$i),%xmm2
693         movdqu  16(%rsp,$i),%xmm4
694         movdqu  ($rp,$i),%xmm1
695         movdqu  16($rp,$i),%xmm3
696         pxor    %xmm1,%xmm2             # conditional select
697         pxor    %xmm3,%xmm4
698         pand    %xmm0,%xmm2
699         pand    %xmm0,%xmm4
700         pxor    %xmm1,%xmm2
701         pxor    %xmm3,%xmm4
702         movdqu  %xmm2,($rp,$i)
703         movdqu  %xmm4,16($rp,$i)
704         movdqa  %xmm5,(%rsp,$i)         # zap temporary vectors
705         movdqa  %xmm5,16(%rsp,$i)
706
707         lea     32($i),$i
708         dec     $j
709         jnz     .Lcopy4x
710
711         shl     \$2,$num
712 ___
713 }
714 $code.=<<___;
715         mov     8(%rsp,$num,8),%rsi     # restore %rsp
716         mov     \$1,%rax
717         mov     (%rsi),%r15
718         mov     8(%rsi),%r14
719         mov     16(%rsi),%r13
720         mov     24(%rsi),%r12
721         mov     32(%rsi),%rbp
722         mov     40(%rsi),%rbx
723         lea     48(%rsi),%rsp
724 .Lmul4x_epilogue:
725         ret
726 .size   bn_mul4x_mont,.-bn_mul4x_mont
727 ___
728 }}}
729 \f{{{
730 ######################################################################
731 # void bn_sqr8x_mont(
732 my $rptr="%rdi";        # const BN_ULONG *rptr,
733 my $aptr="%rsi";        # const BN_ULONG *aptr,
734 my $bptr="%rdx";        # not used
735 my $nptr="%rcx";        # const BN_ULONG *nptr,
736 my $n0  ="%r8";         # const BN_ULONG *n0);
737 my $num ="%r9";         # int num, has to be divisible by 8
738
739 my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
740 my @A0=("%r10","%r11");
741 my @A1=("%r12","%r13");
742 my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
743
744 $code.=<<___    if ($addx);
745 .extern bn_sqrx8x_internal              # see x86_64-mont5 module
746 ___
747 $code.=<<___;
748 .extern bn_sqr8x_internal               # see x86_64-mont5 module
749
750 .type   bn_sqr8x_mont,\@function,6
751 .align  32
752 bn_sqr8x_mont:
753 .Lsqr8x_enter:
754         mov     %rsp,%rax
755         push    %rbx
756         push    %rbp
757         push    %r12
758         push    %r13
759         push    %r14
760         push    %r15
761
762         mov     ${num}d,%r10d
763         shl     \$3,${num}d             # convert $num to bytes
764         shl     \$3+2,%r10              # 4*$num
765         neg     $num
766
767         ##############################################################
768         # ensure that stack frame doesn't alias with $aptr modulo
769         # 4096. this is done to allow memory disambiguation logic
770         # do its job.
771         #
772         lea     -64(%rsp,$num,4),%r11
773         mov     ($n0),$n0               # *n0
774         sub     $aptr,%r11
775         and     \$4095,%r11
776         cmp     %r11,%r10
777         jb      .Lsqr8x_sp_alt
778         sub     %r11,%rsp               # align with $aptr
779         lea     -64(%rsp,$num,4),%rsp   # alloca(frame+4*$num)
780         jmp     .Lsqr8x_sp_done
781
782 .align  32
783 .Lsqr8x_sp_alt:
784         lea     4096-64(,$num,4),%r10   # 4096-frame-4*$num
785         lea     -64(%rsp,$num,4),%rsp   # alloca(frame+4*$num)
786         sub     %r10,%r11
787         mov     \$0,%r10
788         cmovc   %r10,%r11
789         sub     %r11,%rsp
790 .Lsqr8x_sp_done:
791         and     \$-64,%rsp
792         mov     $num,%r10       
793         neg     $num
794
795         lea     64(%rsp,$num,2),%r11    # copy of modulus
796         mov     $n0,  32(%rsp)
797         mov     %rax, 40(%rsp)          # save original %rsp
798 .Lsqr8x_body:
799
800         mov     $num,$i
801         movq    %r11, %xmm2             # save pointer to modulus copy
802         shr     \$3+2,$i
803         mov     OPENSSL_ia32cap_P+8(%rip),%eax
804         jmp     .Lsqr8x_copy_n
805
806 .align  32
807 .Lsqr8x_copy_n:
808         movq    8*0($nptr),%xmm0
809         movq    8*1($nptr),%xmm1
810         movq    8*2($nptr),%xmm3
811         movq    8*3($nptr),%xmm4
812         lea     8*4($nptr),$nptr
813         movdqa  %xmm0,16*0(%r11)
814         movdqa  %xmm1,16*1(%r11)
815         movdqa  %xmm3,16*2(%r11)
816         movdqa  %xmm4,16*3(%r11)
817         lea     16*4(%r11),%r11
818         dec     $i
819         jnz     .Lsqr8x_copy_n
820
821         pxor    %xmm0,%xmm0
822         movq    $rptr,%xmm1             # save $rptr
823         movq    %r10, %xmm3             # -$num
824 ___
825 $code.=<<___ if ($addx);
826         and     \$0x80100,%eax
827         cmp     \$0x80100,%eax
828         jne     .Lsqr8x_nox
829
830         call    bn_sqrx8x_internal      # see x86_64-mont5 module
831
832         pxor    %xmm0,%xmm0
833         lea     48(%rsp),%rax
834         lea     64(%rsp,$num,2),%rdx
835         shr     \$3+2,$num
836         mov     40(%rsp),%rsi           # restore %rsp
837         jmp     .Lsqr8x_zero
838
839 .align  32
840 .Lsqr8x_nox:
841 ___
842 $code.=<<___;
843         call    bn_sqr8x_internal       # see x86_64-mont5 module
844
845         pxor    %xmm0,%xmm0
846         lea     48(%rsp),%rax
847         lea     64(%rsp,$num,2),%rdx
848         shr     \$3+2,$num
849         mov     40(%rsp),%rsi           # restore %rsp
850         jmp     .Lsqr8x_zero
851
852 .align  32
853 .Lsqr8x_zero:
854         movdqa  %xmm0,16*0(%rax)        # wipe t
855         movdqa  %xmm0,16*1(%rax)
856         movdqa  %xmm0,16*2(%rax)
857         movdqa  %xmm0,16*3(%rax)
858         lea     16*4(%rax),%rax
859         movdqa  %xmm0,16*0(%rdx)        # wipe n
860         movdqa  %xmm0,16*1(%rdx)
861         movdqa  %xmm0,16*2(%rdx)
862         movdqa  %xmm0,16*3(%rdx)
863         lea     16*4(%rdx),%rdx
864         dec     $num
865         jnz     .Lsqr8x_zero
866
867         mov     \$1,%rax
868         mov     -48(%rsi),%r15
869         mov     -40(%rsi),%r14
870         mov     -32(%rsi),%r13
871         mov     -24(%rsi),%r12
872         mov     -16(%rsi),%rbp
873         mov     -8(%rsi),%rbx
874         lea     (%rsi),%rsp
875 .Lsqr8x_epilogue:
876         ret
877 .size   bn_sqr8x_mont,.-bn_sqr8x_mont
878 ___
879 }}}
880 \f
881 if ($addx) {{{
882 my $bp="%rdx";  # original value
883
884 $code.=<<___;
885 .type   bn_mulx4x_mont,\@function,6
886 .align  32
887 bn_mulx4x_mont:
888 .Lmulx4x_enter:
889         mov     %rsp,%rax
890         push    %rbx
891         push    %rbp
892         push    %r12
893         push    %r13
894         push    %r14
895         push    %r15
896
897         shl     \$3,${num}d             # convert $num to bytes
898         .byte   0x67
899         xor     %r10,%r10
900         sub     $num,%r10               # -$num
901         mov     ($n0),$n0               # *n0
902         lea     -72(%rsp,%r10),%rsp     # alloca(frame+$num+8)
903         lea     ($bp,$num),%r10
904         and     \$-128,%rsp
905         ##############################################################
906         # Stack layout
907         # +0    num
908         # +8    off-loaded &b[i]
909         # +16   end of b[num]
910         # +24   saved n0
911         # +32   saved rp
912         # +40   saved %rsp
913         # +48   inner counter
914         # +56
915         # +64   tmp[num+1]
916         #
917         mov     $num,0(%rsp)            # save $num
918         shr     \$5,$num
919         mov     %r10,16(%rsp)           # end of b[num]
920         sub     \$1,$num
921         mov     $n0, 24(%rsp)           # save *n0
922         mov     $rp, 32(%rsp)           # save $rp
923         mov     %rax,40(%rsp)           # save original %rsp
924         mov     $num,48(%rsp)           # inner counter
925         jmp     .Lmulx4x_body
926
927 .align  32
928 .Lmulx4x_body:
929 ___
930 my ($aptr, $bptr, $nptr, $tptr, $mi,  $bi,  $zero, $num)=
931    ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
932 my $rptr=$bptr;
933 $code.=<<___;
934         lea     8($bp),$bptr
935         mov     ($bp),%rdx              # b[0], $bp==%rdx actually
936         lea     64+32(%rsp),$tptr
937         mov     %rdx,$bi
938
939         mulx    0*8($aptr),$mi,%rax     # a[0]*b[0]
940         mulx    1*8($aptr),%r11,%r14    # a[1]*b[0]
941         add     %rax,%r11
942         mov     $bptr,8(%rsp)           # off-load &b[i]
943         mulx    2*8($aptr),%r12,%r13    # ...
944         adc     %r14,%r12
945         adc     \$0,%r13
946
947         mov     $mi,$bptr               # borrow $bptr
948         imulq   24(%rsp),$mi            # "t[0]"*n0
949         xor     $zero,$zero             # cf=0, of=0
950
951         mulx    3*8($aptr),%rax,%r14
952          mov    $mi,%rdx
953         lea     4*8($aptr),$aptr
954         adcx    %rax,%r13
955         adcx    $zero,%r14              # cf=0
956
957         mulx    0*8($nptr),%rax,%r10
958         adcx    %rax,$bptr              # discarded
959         adox    %r11,%r10
960         mulx    1*8($nptr),%rax,%r11
961         adcx    %rax,%r10
962         adox    %r12,%r11
963         .byte   0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00    # mulx  2*8($nptr),%rax,%r12
964         mov     48(%rsp),$bptr          # counter value
965         mov     %r10,-4*8($tptr)
966         adcx    %rax,%r11
967         adox    %r13,%r12
968         mulx    3*8($nptr),%rax,%r15
969          mov    $bi,%rdx
970         mov     %r11,-3*8($tptr)
971         adcx    %rax,%r12
972         adox    $zero,%r15              # of=0
973         lea     4*8($nptr),$nptr
974         mov     %r12,-2*8($tptr)
975
976         jmp     .Lmulx4x_1st
977
978 .align  32
979 .Lmulx4x_1st:
980         adcx    $zero,%r15              # cf=0, modulo-scheduled
981         mulx    0*8($aptr),%r10,%rax    # a[4]*b[0]
982         adcx    %r14,%r10
983         mulx    1*8($aptr),%r11,%r14    # a[5]*b[0]
984         adcx    %rax,%r11
985         mulx    2*8($aptr),%r12,%rax    # ...
986         adcx    %r14,%r12
987         mulx    3*8($aptr),%r13,%r14
988          .byte  0x67,0x67
989          mov    $mi,%rdx
990         adcx    %rax,%r13
991         adcx    $zero,%r14              # cf=0
992         lea     4*8($aptr),$aptr
993         lea     4*8($tptr),$tptr
994
995         adox    %r15,%r10
996         mulx    0*8($nptr),%rax,%r15
997         adcx    %rax,%r10
998         adox    %r15,%r11
999         mulx    1*8($nptr),%rax,%r15
1000         adcx    %rax,%r11
1001         adox    %r15,%r12
1002         mulx    2*8($nptr),%rax,%r15
1003         mov     %r10,-5*8($tptr)
1004         adcx    %rax,%r12
1005         mov     %r11,-4*8($tptr)
1006         adox    %r15,%r13
1007         mulx    3*8($nptr),%rax,%r15
1008          mov    $bi,%rdx
1009         mov     %r12,-3*8($tptr)
1010         adcx    %rax,%r13
1011         adox    $zero,%r15
1012         lea     4*8($nptr),$nptr
1013         mov     %r13,-2*8($tptr)
1014
1015         dec     $bptr                   # of=0, pass cf
1016         jnz     .Lmulx4x_1st
1017
1018         mov     0(%rsp),$num            # load num
1019         mov     8(%rsp),$bptr           # re-load &b[i]
1020         adc     $zero,%r15              # modulo-scheduled
1021         add     %r15,%r14
1022         sbb     %r15,%r15               # top-most carry
1023         mov     %r14,-1*8($tptr)
1024         jmp     .Lmulx4x_outer
1025
1026 .align  32
1027 .Lmulx4x_outer:
1028         mov     ($bptr),%rdx            # b[i]
1029         lea     8($bptr),$bptr          # b++
1030         sub     $num,$aptr              # rewind $aptr
1031         mov     %r15,($tptr)            # save top-most carry
1032         lea     64+4*8(%rsp),$tptr
1033         sub     $num,$nptr              # rewind $nptr
1034
1035         mulx    0*8($aptr),$mi,%r11     # a[0]*b[i]
1036         xor     %ebp,%ebp               # xor   $zero,$zero     # cf=0, of=0
1037         mov     %rdx,$bi
1038         mulx    1*8($aptr),%r14,%r12    # a[1]*b[i]
1039         adox    -4*8($tptr),$mi
1040         adcx    %r14,%r11
1041         mulx    2*8($aptr),%r15,%r13    # ...
1042         adox    -3*8($tptr),%r11
1043         adcx    %r15,%r12
1044         adox    $zero,%r12
1045         adcx    $zero,%r13
1046
1047         mov     $bptr,8(%rsp)           # off-load &b[i]
1048         .byte   0x67
1049         mov     $mi,%r15
1050         imulq   24(%rsp),$mi            # "t[0]"*n0
1051         xor     %ebp,%ebp               # xor   $zero,$zero     # cf=0, of=0
1052
1053         mulx    3*8($aptr),%rax,%r14
1054          mov    $mi,%rdx
1055         adox    -2*8($tptr),%r12
1056         adcx    %rax,%r13
1057         adox    -1*8($tptr),%r13
1058         adcx    $zero,%r14
1059         lea     4*8($aptr),$aptr
1060         adox    $zero,%r14
1061
1062         mulx    0*8($nptr),%rax,%r10
1063         adcx    %rax,%r15               # discarded
1064         adox    %r11,%r10
1065         mulx    1*8($nptr),%rax,%r11
1066         adcx    %rax,%r10
1067         adox    %r12,%r11
1068         mulx    2*8($nptr),%rax,%r12
1069         mov     %r10,-4*8($tptr)
1070         adcx    %rax,%r11
1071         adox    %r13,%r12
1072         mulx    3*8($nptr),%rax,%r15
1073          mov    $bi,%rdx
1074         mov     %r11,-3*8($tptr)
1075         lea     4*8($nptr),$nptr
1076         adcx    %rax,%r12
1077         adox    $zero,%r15              # of=0
1078         mov     48(%rsp),$bptr          # counter value
1079         mov     %r12,-2*8($tptr)
1080
1081         jmp     .Lmulx4x_inner
1082
1083 .align  32
1084 .Lmulx4x_inner:
1085         mulx    0*8($aptr),%r10,%rax    # a[4]*b[i]
1086         adcx    $zero,%r15              # cf=0, modulo-scheduled
1087         adox    %r14,%r10
1088         mulx    1*8($aptr),%r11,%r14    # a[5]*b[i]
1089         adcx    0*8($tptr),%r10
1090         adox    %rax,%r11
1091         mulx    2*8($aptr),%r12,%rax    # ...
1092         adcx    1*8($tptr),%r11
1093         adox    %r14,%r12
1094         mulx    3*8($aptr),%r13,%r14
1095          mov    $mi,%rdx
1096         adcx    2*8($tptr),%r12
1097         adox    %rax,%r13
1098         adcx    3*8($tptr),%r13
1099         adox    $zero,%r14              # of=0
1100         lea     4*8($aptr),$aptr
1101         lea     4*8($tptr),$tptr
1102         adcx    $zero,%r14              # cf=0
1103
1104         adox    %r15,%r10
1105         mulx    0*8($nptr),%rax,%r15
1106         adcx    %rax,%r10
1107         adox    %r15,%r11
1108         mulx    1*8($nptr),%rax,%r15
1109         adcx    %rax,%r11
1110         adox    %r15,%r12
1111         mulx    2*8($nptr),%rax,%r15
1112         mov     %r10,-5*8($tptr)
1113         adcx    %rax,%r12
1114         adox    %r15,%r13
1115         mulx    3*8($nptr),%rax,%r15
1116          mov    $bi,%rdx
1117         mov     %r11,-4*8($tptr)
1118         mov     %r12,-3*8($tptr)
1119         adcx    %rax,%r13
1120         adox    $zero,%r15
1121         lea     4*8($nptr),$nptr
1122         mov     %r13,-2*8($tptr)
1123
1124         dec     $bptr                   # of=0, pass cf
1125         jnz     .Lmulx4x_inner
1126
1127         mov     0(%rsp),$num            # load num
1128         mov     8(%rsp),$bptr           # re-load &b[i]
1129         adc     $zero,%r15              # modulo-scheduled
1130         sub     0*8($tptr),$zero        # pull top-most carry
1131         adc     %r15,%r14
1132         mov     -8($nptr),$mi
1133         sbb     %r15,%r15               # top-most carry
1134         mov     %r14,-1*8($tptr)
1135
1136         cmp     16(%rsp),$bptr
1137         jne     .Lmulx4x_outer
1138
1139         sub     %r14,$mi                # compare top-most words
1140         sbb     $mi,$mi
1141         or      $mi,%r15
1142
1143         neg     $num
1144         xor     %rdx,%rdx
1145         mov     32(%rsp),$rptr          # restore rp
1146         lea     64(%rsp),$tptr
1147
1148         pxor    %xmm0,%xmm0
1149         mov     0*8($nptr,$num),%r8
1150         mov     1*8($nptr,$num),%r9
1151         neg     %r8
1152         jmp     .Lmulx4x_sub_entry
1153
1154 .align  32
1155 .Lmulx4x_sub:
1156         mov     0*8($nptr,$num),%r8
1157         mov     1*8($nptr,$num),%r9
1158         not     %r8
1159 .Lmulx4x_sub_entry:
1160         mov     2*8($nptr,$num),%r10
1161         not     %r9
1162         and     %r15,%r8
1163         mov     3*8($nptr,$num),%r11
1164         not     %r10
1165         and     %r15,%r9
1166         not     %r11
1167         and     %r15,%r10
1168         and     %r15,%r11
1169
1170         neg     %rdx                    # mov %rdx,%cf
1171         adc     0*8($tptr),%r8
1172         adc     1*8($tptr),%r9
1173         movdqa  %xmm0,($tptr)
1174         adc     2*8($tptr),%r10
1175         adc     3*8($tptr),%r11
1176         movdqa  %xmm0,16($tptr)
1177         lea     4*8($tptr),$tptr
1178         sbb     %rdx,%rdx               # mov %cf,%rdx
1179
1180         mov     %r8,0*8($rptr)
1181         mov     %r9,1*8($rptr)
1182         mov     %r10,2*8($rptr)
1183         mov     %r11,3*8($rptr)
1184         lea     4*8($rptr),$rptr
1185
1186         add     \$32,$num
1187         jnz     .Lmulx4x_sub
1188
1189         mov     40(%rsp),%rsi           # restore %rsp
1190         mov     \$1,%rax
1191         mov     -48(%rsi),%r15
1192         mov     -40(%rsi),%r14
1193         mov     -32(%rsi),%r13
1194         mov     -24(%rsi),%r12
1195         mov     -16(%rsi),%rbp
1196         mov     -8(%rsi),%rbx
1197         lea     (%rsi),%rsp
1198 .Lmulx4x_epilogue:
1199         ret
1200 .size   bn_mulx4x_mont,.-bn_mulx4x_mont
1201 ___
1202 }}}
1203 $code.=<<___;
1204 .asciz  "Montgomery Multiplication for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1205 .align  16
1206 ___
1207
1208 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1209 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1210 if ($win64) {
1211 $rec="%rcx";
1212 $frame="%rdx";
1213 $context="%r8";
1214 $disp="%r9";
1215
1216 $code.=<<___;
1217 .extern __imp_RtlVirtualUnwind
1218 .type   mul_handler,\@abi-omnipotent
1219 .align  16
1220 mul_handler:
1221         push    %rsi
1222         push    %rdi
1223         push    %rbx
1224         push    %rbp
1225         push    %r12
1226         push    %r13
1227         push    %r14
1228         push    %r15
1229         pushfq
1230         sub     \$64,%rsp
1231
1232         mov     120($context),%rax      # pull context->Rax
1233         mov     248($context),%rbx      # pull context->Rip
1234
1235         mov     8($disp),%rsi           # disp->ImageBase
1236         mov     56($disp),%r11          # disp->HandlerData
1237
1238         mov     0(%r11),%r10d           # HandlerData[0]
1239         lea     (%rsi,%r10),%r10        # end of prologue label
1240         cmp     %r10,%rbx               # context->Rip<end of prologue label
1241         jb      .Lcommon_seh_tail
1242
1243         mov     152($context),%rax      # pull context->Rsp
1244
1245         mov     4(%r11),%r10d           # HandlerData[1]
1246         lea     (%rsi,%r10),%r10        # epilogue label
1247         cmp     %r10,%rbx               # context->Rip>=epilogue label
1248         jae     .Lcommon_seh_tail
1249
1250         mov     192($context),%r10      # pull $num
1251         mov     8(%rax,%r10,8),%rax     # pull saved stack pointer
1252         lea     48(%rax),%rax
1253
1254         mov     -8(%rax),%rbx
1255         mov     -16(%rax),%rbp
1256         mov     -24(%rax),%r12
1257         mov     -32(%rax),%r13
1258         mov     -40(%rax),%r14
1259         mov     -48(%rax),%r15
1260         mov     %rbx,144($context)      # restore context->Rbx
1261         mov     %rbp,160($context)      # restore context->Rbp
1262         mov     %r12,216($context)      # restore context->R12
1263         mov     %r13,224($context)      # restore context->R13
1264         mov     %r14,232($context)      # restore context->R14
1265         mov     %r15,240($context)      # restore context->R15
1266
1267         jmp     .Lcommon_seh_tail
1268 .size   mul_handler,.-mul_handler
1269
1270 .type   sqr_handler,\@abi-omnipotent
1271 .align  16
1272 sqr_handler:
1273         push    %rsi
1274         push    %rdi
1275         push    %rbx
1276         push    %rbp
1277         push    %r12
1278         push    %r13
1279         push    %r14
1280         push    %r15
1281         pushfq
1282         sub     \$64,%rsp
1283
1284         mov     120($context),%rax      # pull context->Rax
1285         mov     248($context),%rbx      # pull context->Rip
1286
1287         mov     8($disp),%rsi           # disp->ImageBase
1288         mov     56($disp),%r11          # disp->HandlerData
1289
1290         mov     0(%r11),%r10d           # HandlerData[0]
1291         lea     (%rsi,%r10),%r10        # end of prologue label
1292         cmp     %r10,%rbx               # context->Rip<.Lsqr_body
1293         jb      .Lcommon_seh_tail
1294
1295         mov     152($context),%rax      # pull context->Rsp
1296
1297         mov     4(%r11),%r10d           # HandlerData[1]
1298         lea     (%rsi,%r10),%r10        # epilogue label
1299         cmp     %r10,%rbx               # context->Rip>=.Lsqr_epilogue
1300         jae     .Lcommon_seh_tail
1301
1302         mov     40(%rax),%rax           # pull saved stack pointer
1303
1304         mov     -8(%rax),%rbx
1305         mov     -16(%rax),%rbp
1306         mov     -24(%rax),%r12
1307         mov     -32(%rax),%r13
1308         mov     -40(%rax),%r14
1309         mov     -48(%rax),%r15
1310         mov     %rbx,144($context)      # restore context->Rbx
1311         mov     %rbp,160($context)      # restore context->Rbp
1312         mov     %r12,216($context)      # restore context->R12
1313         mov     %r13,224($context)      # restore context->R13
1314         mov     %r14,232($context)      # restore context->R14
1315         mov     %r15,240($context)      # restore context->R15
1316
1317 .Lcommon_seh_tail:
1318         mov     8(%rax),%rdi
1319         mov     16(%rax),%rsi
1320         mov     %rax,152($context)      # restore context->Rsp
1321         mov     %rsi,168($context)      # restore context->Rsi
1322         mov     %rdi,176($context)      # restore context->Rdi
1323
1324         mov     40($disp),%rdi          # disp->ContextRecord
1325         mov     $context,%rsi           # context
1326         mov     \$154,%ecx              # sizeof(CONTEXT)
1327         .long   0xa548f3fc              # cld; rep movsq
1328
1329         mov     $disp,%rsi
1330         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1331         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1332         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1333         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1334         mov     40(%rsi),%r10           # disp->ContextRecord
1335         lea     56(%rsi),%r11           # &disp->HandlerData
1336         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1337         mov     %r10,32(%rsp)           # arg5
1338         mov     %r11,40(%rsp)           # arg6
1339         mov     %r12,48(%rsp)           # arg7
1340         mov     %rcx,56(%rsp)           # arg8, (NULL)
1341         call    *__imp_RtlVirtualUnwind(%rip)
1342
1343         mov     \$1,%eax                # ExceptionContinueSearch
1344         add     \$64,%rsp
1345         popfq
1346         pop     %r15
1347         pop     %r14
1348         pop     %r13
1349         pop     %r12
1350         pop     %rbp
1351         pop     %rbx
1352         pop     %rdi
1353         pop     %rsi
1354         ret
1355 .size   sqr_handler,.-sqr_handler
1356
1357 .section        .pdata
1358 .align  4
1359         .rva    .LSEH_begin_bn_mul_mont
1360         .rva    .LSEH_end_bn_mul_mont
1361         .rva    .LSEH_info_bn_mul_mont
1362
1363         .rva    .LSEH_begin_bn_mul4x_mont
1364         .rva    .LSEH_end_bn_mul4x_mont
1365         .rva    .LSEH_info_bn_mul4x_mont
1366
1367         .rva    .LSEH_begin_bn_sqr8x_mont
1368         .rva    .LSEH_end_bn_sqr8x_mont
1369         .rva    .LSEH_info_bn_sqr8x_mont
1370 ___
1371 $code.=<<___ if ($addx);
1372         .rva    .LSEH_begin_bn_mulx4x_mont
1373         .rva    .LSEH_end_bn_mulx4x_mont
1374         .rva    .LSEH_info_bn_mulx4x_mont
1375 ___
1376 $code.=<<___;
1377 .section        .xdata
1378 .align  8
1379 .LSEH_info_bn_mul_mont:
1380         .byte   9,0,0,0
1381         .rva    mul_handler
1382         .rva    .Lmul_body,.Lmul_epilogue       # HandlerData[]
1383 .LSEH_info_bn_mul4x_mont:
1384         .byte   9,0,0,0
1385         .rva    mul_handler
1386         .rva    .Lmul4x_body,.Lmul4x_epilogue   # HandlerData[]
1387 .LSEH_info_bn_sqr8x_mont:
1388         .byte   9,0,0,0
1389         .rva    sqr_handler
1390         .rva    .Lsqr8x_body,.Lsqr8x_epilogue   # HandlerData[]
1391 ___
1392 $code.=<<___ if ($addx);
1393 .LSEH_info_bn_mulx4x_mont:
1394         .byte   9,0,0,0
1395         .rva    sqr_handler
1396         .rva    .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
1397 ___
1398 }
1399
1400 print $code;
1401 close STDOUT;