Add some missing cfi frame info in aesni-sha and sha-x86_64.pl
[openssl.git] / crypto / sha / asm / sha512-x86_64.pl
index 8f4e6516260b22ecad3b01d8693b212c05ba52c0..e7140defb6c6ae981c6152db91227b98f4b8c246 100755 (executable)
@@ -1,9 +1,16 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
 #
 # ====================================================================
 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
 # project. Rights for redistribution and usage in source and binary
-# forms are granted according to the OpenSSL license.
+# forms are granted according to the License.
 # ====================================================================
 #
 # sha256/512_block procedure for x86_64.
@@ -34,7 +41,7 @@
 # level parallelism, on a given CPU implementation in this case.
 #
 # Special note on Intel EM64T. While Opteron CPU exhibits perfect
-# perfromance ratio of 1.5 between 64- and 32-bit flavors [see above],
+# performance ratio of 1.5 between 64- and 32-bit flavors [see above],
 # [currently available] EM64T CPUs apparently are far from it. On the
 # contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
 # sha256_block:-( This is presumably because 64-bit shifts/rotates
@@ -44,7 +51,7 @@
 #
 # Optimization including one of Pavel Semjanov's ideas, alternative
 # Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and
-# unfortunately -10% SHA512 on P4 [which nobody should care about
+# unfortunately -2% SHA512 on P4 [which nobody should care about
 # that much].
 #
 # June 2012.
 # significant 128-bit halves and data from second to most significant.
 # The data is then processed with same SIMD instruction sequence as
 # for AVX, but with %ymm as operands. Side effect is increased stack
-# frame, 448 additional bytes in SHA256 and 1152 in SHA512.
+# frame, 448 additional bytes in SHA256 and 1152 in SHA512, and 1.2KB
+# code size increase.
+#
+# March 2014.
+#
+# Add support for Intel SHA Extensions.
 
 ######################################################################
 # Current performance in cycles per processed byte (less is better):
 #
 #              SHA256  SSSE3       AVX/XOP(*)      SHA512  AVX/XOP(*)
 #
-# AMD K8       15.1    -           -               9.70    -
-# P4           17.5    -           -               33.4    -
-# Core 2       15.5    13.8(+12%)  -               10.3    -
-# Westmere     15.1    12.7(+19%)  -               9.72    -
+# AMD K8       14.9    -           -               9.57    -
+# P4           17.3    -           -               30.8    -
+# Core 2       15.6    13.8(+13%)  -               9.97    -
+# Westmere     14.8    12.3(+19%)  -               9.58    -
 # Sandy Bridge 17.4    14.2(+23%)  11.6(+50%(**))  11.2    8.10(+38%(**))
 # Ivy Bridge   12.6    10.5(+20%)  10.3(+22%)      8.17    7.22(+13%)
-# Bulldozer    21.5    13.7(+57%)  13.7(+57%(***)) 13.5    8.58(+57%)
+# Haswell      12.2    9.28(+31%)  7.80(+56%)      7.66    5.40(+42%)
+# Skylake      11.4    9.03(+26%)  7.70(+48%)      7.25    5.20(+40%)
+# Bulldozer    21.1    13.6(+54%)  13.6(+54%(***)) 13.5    8.58(+57%)
+# Ryzen                11.0    9.02(+22%)  2.05(+440%)     7.05    5.67(+20%)
 # VIA Nano     23.0    16.5(+39%)  -               14.7    -
-# Atom         23.0    18.7(+23%)  -               14.7    -
+# Atom         23.0    18.9(+22%)  -               14.7    -
+# Silvermont   27.4    20.6(+33%)  -               17.5    -
+# Knights L    27.4    21.0(+30%)  19.6(+40%)      17.5    12.8(+37%)
+# Goldmont     18.9    14.3(+32%)  4.16(+350%)     12.0    -
 #
-# (*)  whichever best applicable;
+# (*)  whichever best applicable, including SHAEXT;
 # (**) switch from ror to shrd stands for fair share of improvement;
 # (***)        execution time is fully determined by remaining integer-only
 #      part, body_00_15; reducing the amount of SIMD instructions
 #      below certain limit makes no difference/sense; to conserve
 #      space SHA256 XOP code path is therefore omitted;
 
-$flavour = shift;
-$output  = shift;
-if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+# $output is the last argument if it looks like a file (it has an extension)
+# $flavour is the first argument if it doesn't look like a file
+$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
+$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
 
 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
 
@@ -117,7 +136,15 @@ if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
        $avx = ($1>=10) + ($1>=11);
 }
 
-open OUT,"| \"$^X\" $xlate $flavour $output";
+if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
+       $avx = ($2>=3.0) + ($2>3.0);
+}
+
+$shaext=1;     ### set to zero if compiling for 1.0.1
+$avx=1         if (!$shaext && $avx);
+
+open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""
+    or die "can't call $xlate: $!";
 *STDOUT=*OUT;
 
 if ($output =~ /512/) {
@@ -153,7 +180,7 @@ $Tbl="%rbp";
 $_ctx="16*$SZ+0*8(%rsp)";
 $_inp="16*$SZ+1*8(%rsp)";
 $_end="16*$SZ+2*8(%rsp)";
-$_rsp="16*$SZ+3*8(%rsp)";
+$_rsp="`16*$SZ+3*8`(%rsp)";
 $framesz="16*$SZ+4*8";
 
 
@@ -166,8 +193,8 @@ $code.=<<___;
        ror     \$`$Sigma1[2]-$Sigma1[1]`,$a0
        mov     $f,$a2
 
-       ror     \$`$Sigma0[2]-$Sigma0[1]`,$a1
        xor     $e,$a0
+       ror     \$`$Sigma0[2]-$Sigma0[1]`,$a1
        xor     $g,$a2                  # f^g
 
        mov     $T1,`$SZ*($i&0xf)`(%rsp)
@@ -186,25 +213,22 @@ $code.=<<___;
        add     ($Tbl),$T1              # T1+=K[round]
        xor     $a,$a1
 
-       ror     \$$Sigma1[0],$a0        # Sigma1(e)
        xor     $b,$a2                  # a^b, b^c in next round
+       ror     \$$Sigma1[0],$a0        # Sigma1(e)
        mov     $b,$h
 
-       ror     \$$Sigma0[0],$a1        # Sigma0(a)
        and     $a2,$a3
+       ror     \$$Sigma0[0],$a1        # Sigma0(a)
        add     $a0,$T1                 # T1+=Sigma1(e)
 
        xor     $a3,$h                  # h=Maj(a,b,c)=Ch(a^b,c,b)
        add     $T1,$d                  # d+=T1
        add     $T1,$h                  # h+=T1
-___
-$code.=<<___ if ($i>=15);
-       mov     `$SZ*(($i+2)&0xf)`(%rsp),$a0
-___
-$code.=<<___;
+
        lea     $STRIDE($Tbl),$Tbl      # round++
+___
+$code.=<<___ if ($i<15);
        add     $a1,$h                  # h+=Sigma0(a)
-
 ___
        ($a2,$a3) = ($a3,$a2);
 }
@@ -213,28 +237,29 @@ sub ROUND_16_XX()
 { my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
 
 $code.=<<___;
-       #mov    `$SZ*(($i+1)&0xf)`(%rsp),$a0
-       mov     `$SZ*(($i+14)&0xf)`(%rsp),$a1
+       mov     `$SZ*(($i+1)&0xf)`(%rsp),$a0
+       mov     `$SZ*(($i+14)&0xf)`(%rsp),$a2
 
        mov     $a0,$T1
        ror     \$`$sigma0[1]-$sigma0[0]`,$a0
-       mov     $a1,$a2
-       ror     \$`$sigma1[1]-$sigma1[0]`,$a1
+       add     $a1,$a                  # modulo-scheduled h+=Sigma0(a)
+       mov     $a2,$a1
+       ror     \$`$sigma1[1]-$sigma1[0]`,$a2
 
        xor     $T1,$a0
        shr     \$$sigma0[2],$T1
        ror     \$$sigma0[0],$a0
-       xor     $a2,$a1
-       shr     \$$sigma1[2],$a2
+       xor     $a1,$a2
+       shr     \$$sigma1[2],$a1
 
+       ror     \$$sigma1[0],$a2
        xor     $a0,$T1                 # sigma0(X[(i+1)&0xf])
-       ror     \$$sigma1[0],$a1
+       xor     $a1,$a2                 # sigma1(X[(i+14)&0xf])
        add     `$SZ*(($i+9)&0xf)`(%rsp),$T1
-       xor     $a2,$a1                 # sigma1(X[(i+14)&0xf])
 
        add     `$SZ*($i&0xf)`(%rsp),$T1
        mov     $e,$a0
-       add     $a1,$T1
+       add     $a2,$T1
        mov     $a,$a1
 ___
        &ROUND_00_15(@_);
@@ -248,6 +273,7 @@ $code=<<___;
 .type  $func,\@function,3
 .align 16
 $func:
+.cfi_startproc
 ___
 $code.=<<___ if ($SZ==4 || $avx);
        lea     OPENSSL_ia32cap_P(%rip),%r11
@@ -255,6 +281,10 @@ $code.=<<___ if ($SZ==4 || $avx);
        mov     4(%r11),%r10d
        mov     8(%r11),%r11d
 ___
+$code.=<<___ if ($SZ==4 && $shaext);
+       test    \$`1<<29`,%r11d         # check for SHA
+       jnz     _shaext_shortcut
+___
 $code.=<<___ if ($avx && $SZ==8);
        test    \$`1<<11`,%r10d         # check for XOP
        jnz     .Lxop_shortcut
@@ -276,13 +306,20 @@ $code.=<<___ if ($SZ==4);
        jnz     .Lssse3_shortcut
 ___
 $code.=<<___;
+       mov     %rsp,%rax               # copy %rsp
+.cfi_def_cfa_register  %rax
        push    %rbx
+.cfi_push      %rbx
        push    %rbp
+.cfi_push      %rbp
        push    %r12
+.cfi_push      %r12
        push    %r13
+.cfi_push      %r13
        push    %r14
+.cfi_push      %r14
        push    %r15
-       mov     %rsp,%r11               # copy %rsp
+.cfi_push      %r15
        shl     \$4,%rdx                # num*16
        sub     \$$framesz,%rsp
        lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
@@ -290,7 +327,8 @@ $code.=<<___;
        mov     $ctx,$_ctx              # save ctx, 1st arg
        mov     $inp,$_inp              # save inp, 2nd arh
        mov     %rdx,$_end              # save end pointer, "3rd" arg
-       mov     %r11,$_rsp              # save copy of %rsp
+       mov     %rax,$_rsp              # save copy of %rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 .Lprologue:
 
        mov     $SZ*0($ctx),$A
@@ -332,6 +370,7 @@ $code.=<<___;
        jnz     .Lrounds_16_xx
 
        mov     $_ctx,$ctx
+       add     $a1,$A                  # modulo-scheduled h+=Sigma0(a)
        lea     16*$SZ($inp),$inp
 
        add     $SZ*0($ctx),$A
@@ -356,15 +395,24 @@ $code.=<<___;
        jb      .Lloop
 
        mov     $_rsp,%rsi
-       mov     (%rsi),%r15
-       mov     8(%rsi),%r14
-       mov     16(%rsi),%r13
-       mov     24(%rsi),%r12
-       mov     32(%rsi),%rbp
-       mov     40(%rsi),%rbx
-       lea     48(%rsi),%rsp
+.cfi_def_cfa   %rsi,8
+       mov     -48(%rsi),%r15
+.cfi_restore   %r15
+       mov     -40(%rsi),%r14
+.cfi_restore   %r14
+       mov     -32(%rsi),%r13
+.cfi_restore   %r13
+       mov     -24(%rsi),%r12
+.cfi_restore   %r12
+       mov     -16(%rsi),%rbp
+.cfi_restore   %rbp
+       mov     -8(%rsi),%rbx
+.cfi_restore   %rbx
+       lea     (%rsi),%rsp
+.cfi_def_cfa_register  %rsp
 .Lepilogue:
        ret
+.cfi_endproc
 .size  $func,.-$func
 ___
 
@@ -509,6 +557,168 @@ ___
 ######################################################################
 # SIMD code paths
 #
+if ($SZ==4 && $shaext) {{{
+######################################################################
+# Intel SHA Extensions implementation of SHA256 update function.
+#
+my ($ctx,$inp,$num,$Tbl)=("%rdi","%rsi","%rdx","%rcx");
+
+my ($Wi,$ABEF,$CDGH,$TMP,$BSWAP,$ABEF_SAVE,$CDGH_SAVE)=map("%xmm$_",(0..2,7..10));
+my @MSG=map("%xmm$_",(3..6));
+
+$code.=<<___;
+.type  sha256_block_data_order_shaext,\@function,3
+.align 64
+sha256_block_data_order_shaext:
+_shaext_shortcut:
+.cfi_startproc
+___
+$code.=<<___ if ($win64);
+       lea     `-8-5*16`(%rsp),%rsp
+       movaps  %xmm6,-8-5*16(%rax)
+       movaps  %xmm7,-8-4*16(%rax)
+       movaps  %xmm8,-8-3*16(%rax)
+       movaps  %xmm9,-8-2*16(%rax)
+       movaps  %xmm10,-8-1*16(%rax)
+.Lprologue_shaext:
+___
+$code.=<<___;
+       lea             K256+0x80(%rip),$Tbl
+       movdqu          ($ctx),$ABEF            # DCBA
+       movdqu          16($ctx),$CDGH          # HGFE
+       movdqa          0x200-0x80($Tbl),$TMP   # byte swap mask
+
+       pshufd          \$0x1b,$ABEF,$Wi        # ABCD
+       pshufd          \$0xb1,$ABEF,$ABEF      # CDAB
+       pshufd          \$0x1b,$CDGH,$CDGH      # EFGH
+       movdqa          $TMP,$BSWAP             # offload
+       palignr         \$8,$CDGH,$ABEF         # ABEF
+       punpcklqdq      $Wi,$CDGH               # CDGH
+       jmp             .Loop_shaext
+
+.align 16
+.Loop_shaext:
+       movdqu          ($inp),@MSG[0]
+       movdqu          0x10($inp),@MSG[1]
+       movdqu          0x20($inp),@MSG[2]
+       pshufb          $TMP,@MSG[0]
+       movdqu          0x30($inp),@MSG[3]
+
+       movdqa          0*32-0x80($Tbl),$Wi
+       paddd           @MSG[0],$Wi
+       pshufb          $TMP,@MSG[1]
+       movdqa          $CDGH,$CDGH_SAVE        # offload
+       sha256rnds2     $ABEF,$CDGH             # 0-3
+       pshufd          \$0x0e,$Wi,$Wi
+       nop
+       movdqa          $ABEF,$ABEF_SAVE        # offload
+       sha256rnds2     $CDGH,$ABEF
+
+       movdqa          1*32-0x80($Tbl),$Wi
+       paddd           @MSG[1],$Wi
+       pshufb          $TMP,@MSG[2]
+       sha256rnds2     $ABEF,$CDGH             # 4-7
+       pshufd          \$0x0e,$Wi,$Wi
+       lea             0x40($inp),$inp
+       sha256msg1      @MSG[1],@MSG[0]
+       sha256rnds2     $CDGH,$ABEF
+
+       movdqa          2*32-0x80($Tbl),$Wi
+       paddd           @MSG[2],$Wi
+       pshufb          $TMP,@MSG[3]
+       sha256rnds2     $ABEF,$CDGH             # 8-11
+       pshufd          \$0x0e,$Wi,$Wi
+       movdqa          @MSG[3],$TMP
+       palignr         \$4,@MSG[2],$TMP
+       nop
+       paddd           $TMP,@MSG[0]
+       sha256msg1      @MSG[2],@MSG[1]
+       sha256rnds2     $CDGH,$ABEF
+
+       movdqa          3*32-0x80($Tbl),$Wi
+       paddd           @MSG[3],$Wi
+       sha256msg2      @MSG[3],@MSG[0]
+       sha256rnds2     $ABEF,$CDGH             # 12-15
+       pshufd          \$0x0e,$Wi,$Wi
+       movdqa          @MSG[0],$TMP
+       palignr         \$4,@MSG[3],$TMP
+       nop
+       paddd           $TMP,@MSG[1]
+       sha256msg1      @MSG[3],@MSG[2]
+       sha256rnds2     $CDGH,$ABEF
+___
+for($i=4;$i<16-3;$i++) {
+$code.=<<___;
+       movdqa          $i*32-0x80($Tbl),$Wi
+       paddd           @MSG[0],$Wi
+       sha256msg2      @MSG[0],@MSG[1]
+       sha256rnds2     $ABEF,$CDGH             # 16-19...
+       pshufd          \$0x0e,$Wi,$Wi
+       movdqa          @MSG[1],$TMP
+       palignr         \$4,@MSG[0],$TMP
+       nop
+       paddd           $TMP,@MSG[2]
+       sha256msg1      @MSG[0],@MSG[3]
+       sha256rnds2     $CDGH,$ABEF
+___
+       push(@MSG,shift(@MSG));
+}
+$code.=<<___;
+       movdqa          13*32-0x80($Tbl),$Wi
+       paddd           @MSG[0],$Wi
+       sha256msg2      @MSG[0],@MSG[1]
+       sha256rnds2     $ABEF,$CDGH             # 52-55
+       pshufd          \$0x0e,$Wi,$Wi
+       movdqa          @MSG[1],$TMP
+       palignr         \$4,@MSG[0],$TMP
+       sha256rnds2     $CDGH,$ABEF
+       paddd           $TMP,@MSG[2]
+
+       movdqa          14*32-0x80($Tbl),$Wi
+       paddd           @MSG[1],$Wi
+       sha256rnds2     $ABEF,$CDGH             # 56-59
+       pshufd          \$0x0e,$Wi,$Wi
+       sha256msg2      @MSG[1],@MSG[2]
+       movdqa          $BSWAP,$TMP
+       sha256rnds2     $CDGH,$ABEF
+
+       movdqa          15*32-0x80($Tbl),$Wi
+       paddd           @MSG[2],$Wi
+       nop
+       sha256rnds2     $ABEF,$CDGH             # 60-63
+       pshufd          \$0x0e,$Wi,$Wi
+       dec             $num
+       nop
+       sha256rnds2     $CDGH,$ABEF
+
+       paddd           $CDGH_SAVE,$CDGH
+       paddd           $ABEF_SAVE,$ABEF
+       jnz             .Loop_shaext
+
+       pshufd          \$0xb1,$CDGH,$CDGH      # DCHG
+       pshufd          \$0x1b,$ABEF,$TMP       # FEBA
+       pshufd          \$0xb1,$ABEF,$ABEF      # BAFE
+       punpckhqdq      $CDGH,$ABEF             # DCBA
+       palignr         \$8,$TMP,$CDGH          # HGFE
+
+       movdqu  $ABEF,($ctx)
+       movdqu  $CDGH,16($ctx)
+___
+$code.=<<___ if ($win64);
+       movaps  -8-5*16(%rax),%xmm6
+       movaps  -8-4*16(%rax),%xmm7
+       movaps  -8-3*16(%rax),%xmm8
+       movaps  -8-2*16(%rax),%xmm9
+       movaps  -8-1*16(%rax),%xmm10
+       mov     %rax,%rsp
+.Lepilogue_shaext:
+___
+$code.=<<___;
+       ret
+.cfi_endproc
+.size  sha256_block_data_order_shaext,.-sha256_block_data_order_shaext
+___
+}}}
 {{{
 
 my $a4=$T1;
@@ -529,8 +739,8 @@ sub body_00_15 () {
        '&mov   ($a,$a1)',
        '&mov   ($a4,$f)',
 
-       '&xor   ($a0,$e)',
        '&ror   ($a1,$Sigma0[2]-$Sigma0[1])',
+       '&xor   ($a0,$e)',
        '&xor   ($a4,$g)',                      # f^g
 
        '&ror   ($a0,$Sigma1[1]-$Sigma1[0])',
@@ -541,20 +751,20 @@ sub body_00_15 () {
        '&add   ($h,$SZ*($i&15)."(%rsp)")',     # h+=X[i]+K[i]
        '&mov   ($a2,$a)',
 
-       '&ror   ($a1,$Sigma0[1]-$Sigma0[0])',
        '&xor   ($a4,$g)',                      # Ch(e,f,g)=((f^g)&e)^g
+       '&ror   ($a1,$Sigma0[1]-$Sigma0[0])',
        '&xor   ($a2,$b)',                      # a^b, b^c in next round
 
-       '&ror   ($a0,$Sigma1[0])',              # Sigma1(e)
        '&add   ($h,$a4)',                      # h+=Ch(e,f,g)
+       '&ror   ($a0,$Sigma1[0])',              # Sigma1(e)
        '&and   ($a3,$a2)',                     # (b^c)&(a^b)
 
        '&xor   ($a1,$a)',
        '&add   ($h,$a0)',                      # h+=Sigma1(e)
        '&xor   ($a3,$b)',                      # Maj(a,b,c)=Ch(a^b,c,b)
 
-       '&add   ($d,$h)',                       # d+=h
        '&ror   ($a1,$Sigma0[0])',              # Sigma0(a)
+       '&add   ($d,$h)',                       # d+=h
        '&add   ($h,$a3)',                      # h+=Maj(a,b,c)
 
        '&mov   ($a0,$d)',
@@ -574,14 +784,22 @@ $code.=<<___;
 .type  ${func}_ssse3,\@function,3
 .align 64
 ${func}_ssse3:
+.cfi_startproc
 .Lssse3_shortcut:
+       mov     %rsp,%rax               # copy %rsp
+.cfi_def_cfa_register  %rax
        push    %rbx
+.cfi_push      %rbx
        push    %rbp
+.cfi_push      %rbp
        push    %r12
+.cfi_push      %r12
        push    %r13
+.cfi_push      %r13
        push    %r14
+.cfi_push      %r14
        push    %r15
-       mov     %rsp,%r11               # copy %rsp
+.cfi_push      %r15
        shl     \$4,%rdx                # num*16
        sub     \$`$framesz+$win64*16*4`,%rsp
        lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
@@ -589,7 +807,8 @@ ${func}_ssse3:
        mov     $ctx,$_ctx              # save ctx, 1st arg
        mov     $inp,$_inp              # save inp, 2nd arh
        mov     %rdx,$_end              # save end pointer, "3rd" arg
-       mov     %r11,$_rsp              # save copy of %rsp
+       mov     %rax,$_rsp              # save copy of %rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 ___
 $code.=<<___ if ($win64);
        movaps  %xmm6,16*$SZ+32(%rsp)
@@ -620,13 +839,13 @@ $code.=<<___;
        movdqu  0x00($inp),@X[0]
        movdqu  0x10($inp),@X[1]
        movdqu  0x20($inp),@X[2]
-       movdqu  0x30($inp),@X[3]
        pshufb  $t3,@X[0]
+       movdqu  0x30($inp),@X[3]
        lea     $TABLE(%rip),$Tbl
        pshufb  $t3,@X[1]
        movdqa  0x00($Tbl),$t0
-       pshufb  $t3,@X[2]
        movdqa  0x20($Tbl),$t1
+       pshufb  $t3,@X[2]
        paddd   @X[0],$t0
        movdqa  0x40($Tbl),$t2
        pshufb  $t3,@X[3]
@@ -646,7 +865,7 @@ $code.=<<___;
 
 .align 16
 .Lssse3_00_47:
-       sub     \$-16*2*$SZ,$Tbl        # size optimization
+       sub     \$`-16*2*$SZ`,$Tbl      # size optimization
 ___
 sub Xupdate_256_SSSE3 () {
        (
@@ -702,145 +921,147 @@ my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
            eval(shift(@insns));
            eval(shift(@insns));
        }
-    } else {                   # squeeze extra 3% on Westmere and Atom
+    } else {                   # squeeze extra 4% on Westmere and 19% on Atom
          eval(shift(@insns));  #@
-         eval(shift(@insns));
        &movdqa         ($t0,@X[1]);
          eval(shift(@insns));
+         eval(shift(@insns));
        &movdqa         ($t3,@X[3]);
+         eval(shift(@insns));  #@
+         eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));  #@
          eval(shift(@insns));
        &palignr        ($t0,@X[0],$SZ);        # X[1..4]
-         eval(shift(@insns));  #@
          eval(shift(@insns));
-        &palignr       ($t3,@X[2],$SZ);        # X[9..12]
          eval(shift(@insns));
+        &palignr       ($t3,@X[2],$SZ);        # X[9..12]
          eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));  #@
-         eval(shift(@insns));
        &movdqa         ($t1,$t0);
          eval(shift(@insns));
+         eval(shift(@insns));
        &movdqa         ($t2,$t0);
          eval(shift(@insns));  #@
          eval(shift(@insns));
-         eval(shift(@insns));
        &psrld          ($t0,$sigma0[2]);
          eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));
         &paddd         (@X[0],$t3);            # X[0..3] += X[9..12]
-         eval(shift(@insns));
          eval(shift(@insns));  #@
          eval(shift(@insns));
        &psrld          ($t2,$sigma0[0]);
          eval(shift(@insns));
          eval(shift(@insns));
-         eval(shift(@insns));  #@
-         eval(shift(@insns));
         &pshufd        ($t3,@X[3],0b11111010); # X[4..15]
          eval(shift(@insns));
+         eval(shift(@insns));  #@
        &pslld          ($t1,8*$SZ-$sigma0[1]);
          eval(shift(@insns));
+         eval(shift(@insns));
        &pxor           ($t0,$t2);
          eval(shift(@insns));  #@
          eval(shift(@insns));
-       &psrld          ($t2,$sigma0[1]-$sigma0[0]);
+         eval(shift(@insns));
          eval(shift(@insns));  #@
+       &psrld          ($t2,$sigma0[1]-$sigma0[0]);
          eval(shift(@insns));
        &pxor           ($t0,$t1);
          eval(shift(@insns));
          eval(shift(@insns));
        &pslld          ($t1,$sigma0[1]-$sigma0[0]);
          eval(shift(@insns));
+         eval(shift(@insns));
        &pxor           ($t0,$t2);
          eval(shift(@insns));
          eval(shift(@insns));  #@
-         eval(shift(@insns));
         &movdqa        ($t2,$t3);
          eval(shift(@insns));
-         eval(shift(@insns));  #@
          eval(shift(@insns));
        &pxor           ($t0,$t1);              # sigma0(X[1..4])
+         eval(shift(@insns));  #@
          eval(shift(@insns));
          eval(shift(@insns));
         &psrld         ($t3,$sigma1[2]);
          eval(shift(@insns));
          eval(shift(@insns));
        &paddd          (@X[0],$t0);            # X[0..3] += sigma0(X[1..4])
-         eval(shift(@insns));
          eval(shift(@insns));  #@
          eval(shift(@insns));
-         eval(shift(@insns));
         &psrlq         ($t2,$sigma1[0]);
          eval(shift(@insns));
-         eval(shift(@insns));  #@
          eval(shift(@insns));
          eval(shift(@insns));
         &pxor          ($t3,$t2);
+         eval(shift(@insns));  #@
+         eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));  #@
         &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
          eval(shift(@insns));
-         eval(shift(@insns));  #@
          eval(shift(@insns));
         &pxor          ($t3,$t2);
-         eval(shift(@insns));
+         eval(shift(@insns));  #@
          eval(shift(@insns));
          eval(shift(@insns));
         #&pshufb       ($t3,$t4);              # sigma1(X[14..15])
         &pshufd        ($t3,$t3,0b10000000);
          eval(shift(@insns));
-         eval(shift(@insns));  #@
+         eval(shift(@insns));
          eval(shift(@insns));
         &psrldq        ($t3,8);
          eval(shift(@insns));
          eval(shift(@insns));  #@
+         eval(shift(@insns));
+         eval(shift(@insns));
+         eval(shift(@insns));  #@
        &paddd          (@X[0],$t3);            # X[0..1] += sigma1(X[14..15])
          eval(shift(@insns));
-        &pshufd        ($t3,@X[0],0b01010000); # X[16..17]
          eval(shift(@insns));
          eval(shift(@insns));
+        &pshufd        ($t3,@X[0],0b01010000); # X[16..17]
          eval(shift(@insns));
+         eval(shift(@insns));  #@
          eval(shift(@insns));
         &movdqa        ($t2,$t3);
          eval(shift(@insns));
-         eval(shift(@insns));  #@
          eval(shift(@insns));
         &psrld         ($t3,$sigma1[2]);
          eval(shift(@insns));
-        &psrlq         ($t2,$sigma1[0]);
-         eval(shift(@insns));
          eval(shift(@insns));  #@
+        &psrlq         ($t2,$sigma1[0]);
          eval(shift(@insns));
          eval(shift(@insns));
         &pxor          ($t3,$t2);
+         eval(shift(@insns));  #@
+         eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));  #@
          eval(shift(@insns));
         &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
-         eval(shift(@insns));  #@
          eval(shift(@insns));
          eval(shift(@insns));
          eval(shift(@insns));
         &pxor          ($t3,$t2);
          eval(shift(@insns));
          eval(shift(@insns));
-       &movdqa         ($t2,16*2*$j."($Tbl)");
          eval(shift(@insns));  #@
-         eval(shift(@insns));
         #&pshufb       ($t3,$t5);
         &pshufd        ($t3,$t3,0b00001000);
          eval(shift(@insns));
+         eval(shift(@insns));
+       &movdqa         ($t2,16*2*$j."($Tbl)");
          eval(shift(@insns));  #@
          eval(shift(@insns));
         &pslldq        ($t3,8);
          eval(shift(@insns));
          eval(shift(@insns));
-       &paddd          (@X[0],$t3);            # X[2..3] += sigma1(X[16..17])
          eval(shift(@insns));
+       &paddd          (@X[0],$t3);            # X[2..3] += sigma1(X[16..17])
+         eval(shift(@insns));  #@
          eval(shift(@insns));
          eval(shift(@insns));
     }
@@ -886,6 +1107,7 @@ $code.=<<___;
        jb      .Lloop_ssse3
 
        mov     $_rsp,%rsi
+.cfi_def_cfa   %rsi,8
 ___
 $code.=<<___ if ($win64);
        movaps  16*$SZ+32(%rsp),%xmm6
@@ -894,15 +1116,23 @@ $code.=<<___ if ($win64);
        movaps  16*$SZ+80(%rsp),%xmm9
 ___
 $code.=<<___;
-       mov     (%rsi),%r15
-       mov     8(%rsi),%r14
-       mov     16(%rsi),%r13
-       mov     24(%rsi),%r12
-       mov     32(%rsi),%rbp
-       mov     40(%rsi),%rbx
-       lea     48(%rsi),%rsp
+       mov     -48(%rsi),%r15
+.cfi_restore   %r15
+       mov     -40(%rsi),%r14
+.cfi_restore   %r14
+       mov     -32(%rsi),%r13
+.cfi_restore   %r13
+       mov     -24(%rsi),%r12
+.cfi_restore   %r12
+       mov     -16(%rsi),%rbp
+.cfi_restore   %rbp
+       mov     -8(%rsi),%rbx
+.cfi_restore   %rbx
+       lea     (%rsi),%rsp
+.cfi_def_cfa_register  %rsp
 .Lepilogue_ssse3:
        ret
+.cfi_endproc
 .size  ${func}_ssse3,.-${func}_ssse3
 ___
 }
@@ -916,14 +1146,22 @@ $code.=<<___;
 .type  ${func}_xop,\@function,3
 .align 64
 ${func}_xop:
+.cfi_startproc
 .Lxop_shortcut:
+       mov     %rsp,%rax               # copy %rsp
+.cfi_def_cfa_register  %rax
        push    %rbx
+.cfi_push      %rbx
        push    %rbp
+.cfi_push      %rbp
        push    %r12
+.cfi_push      %r12
        push    %r13
+.cfi_push      %r13
        push    %r14
+.cfi_push      %r14
        push    %r15
-       mov     %rsp,%r11               # copy %rsp
+.cfi_push      %r15
        shl     \$4,%rdx                # num*16
        sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
        lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
@@ -931,7 +1169,8 @@ ${func}_xop:
        mov     $ctx,$_ctx              # save ctx, 1st arg
        mov     $inp,$_inp              # save inp, 2nd arh
        mov     %rdx,$_end              # save end pointer, "3rd" arg
-       mov     %r11,$_rsp              # save copy of %rsp
+       mov     %rax,$_rsp              # save copy of %rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 ___
 $code.=<<___ if ($win64);
        movaps  %xmm6,16*$SZ+32(%rsp)
@@ -946,7 +1185,7 @@ ___
 $code.=<<___;
 .Lprologue_xop:
 
-       vzeroall
+       vzeroupper
        mov     $SZ*0($ctx),$A
        mov     $SZ*1($ctx),$B
        mov     $SZ*2($ctx),$C
@@ -990,7 +1229,7 @@ $code.=<<___;
 
 .align 16
 .Lxop_00_47:
-       sub     \$-16*2*$SZ,$Tbl        # size optimization
+       sub     \$`-16*2*$SZ`,$Tbl      # size optimization
 ___
 sub XOP_256_00_47 () {
 my $j = shift;
@@ -1152,7 +1391,7 @@ $code.=<<___;
 
 .align 16
 .Lxop_00_47:
-       add     \$16*2*$SZ,$Tbl
+       add     \$`16*2*$SZ`,$Tbl
 ___
 sub XOP_512_00_47 () {
 my $j = shift;
@@ -1258,7 +1497,8 @@ $code.=<<___;
        jb      .Lloop_xop
 
        mov     $_rsp,%rsi
-       vzeroall
+.cfi_def_cfa   %rsi,8
+       vzeroupper
 ___
 $code.=<<___ if ($win64);
        movaps  16*$SZ+32(%rsp),%xmm6
@@ -1271,15 +1511,23 @@ $code.=<<___ if ($win64 && $SZ>4);
        movaps  16*$SZ+112(%rsp),%xmm11
 ___
 $code.=<<___;
-       mov     (%rsi),%r15
-       mov     8(%rsi),%r14
-       mov     16(%rsi),%r13
-       mov     24(%rsi),%r12
-       mov     32(%rsi),%rbp
-       mov     40(%rsi),%rbx
-       lea     48(%rsi),%rsp
+       mov     -48(%rsi),%r15
+.cfi_restore   %r15
+       mov     -40(%rsi),%r14
+.cfi_restore   %r14
+       mov     -32(%rsi),%r13
+.cfi_restore   %r13
+       mov     -24(%rsi),%r12
+.cfi_restore   %r12
+       mov     -16(%rsi),%rbp
+.cfi_restore   %rbp
+       mov     -8(%rsi),%rbx
+.cfi_restore   %rbx
+       lea     (%rsi),%rsp
+.cfi_def_cfa_register  %rsp
 .Lepilogue_xop:
        ret
+.cfi_endproc
 .size  ${func}_xop,.-${func}_xop
 ___
 }
@@ -1292,14 +1540,22 @@ $code.=<<___;
 .type  ${func}_avx,\@function,3
 .align 64
 ${func}_avx:
+.cfi_startproc
 .Lavx_shortcut:
+       mov     %rsp,%rax               # copy %rsp
+.cfi_def_cfa_register  %rax
        push    %rbx
+.cfi_push      %rbx
        push    %rbp
+.cfi_push      %rbp
        push    %r12
+.cfi_push      %r12
        push    %r13
+.cfi_push      %r13
        push    %r14
+.cfi_push      %r14
        push    %r15
-       mov     %rsp,%r11               # copy %rsp
+.cfi_push      %r15
        shl     \$4,%rdx                # num*16
        sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
        lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
@@ -1307,7 +1563,8 @@ ${func}_avx:
        mov     $ctx,$_ctx              # save ctx, 1st arg
        mov     $inp,$_inp              # save inp, 2nd arh
        mov     %rdx,$_end              # save end pointer, "3rd" arg
-       mov     %r11,$_rsp              # save copy of %rsp
+       mov     %rax,$_rsp              # save copy of %rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 ___
 $code.=<<___ if ($win64);
        movaps  %xmm6,16*$SZ+32(%rsp)
@@ -1322,7 +1579,7 @@ ___
 $code.=<<___;
 .Lprologue_avx:
 
-       vzeroall
+       vzeroupper
        mov     $SZ*0($ctx),$A
        mov     $SZ*1($ctx),$B
        mov     $SZ*2($ctx),$C
@@ -1368,7 +1625,7 @@ $code.=<<___;
 
 .align 16
 .Lavx_00_47:
-       sub     \$-16*2*$SZ,$Tbl        # size optimization
+       sub     \$`-16*2*$SZ`,$Tbl      # size optimization
 ___
 sub Xupdate_256_AVX () {
        (
@@ -1482,7 +1739,7 @@ $code.=<<___;
 
 .align 16
 .Lavx_00_47:
-       add     \$16*2*$SZ,$Tbl
+       add     \$`16*2*$SZ`,$Tbl
 ___
 sub Xupdate_512_AVX () {
        (
@@ -1566,7 +1823,8 @@ $code.=<<___;
        jb      .Lloop_avx
 
        mov     $_rsp,%rsi
-       vzeroall
+.cfi_def_cfa   %rsi,8
+       vzeroupper
 ___
 $code.=<<___ if ($win64);
        movaps  16*$SZ+32(%rsp),%xmm6
@@ -1579,15 +1837,23 @@ $code.=<<___ if ($win64 && $SZ>4);
        movaps  16*$SZ+112(%rsp),%xmm11
 ___
 $code.=<<___;
-       mov     (%rsi),%r15
-       mov     8(%rsi),%r14
-       mov     16(%rsi),%r13
-       mov     24(%rsi),%r12
-       mov     32(%rsi),%rbp
-       mov     40(%rsi),%rbx
-       lea     48(%rsi),%rsp
+       mov     -48(%rsi),%r15
+.cfi_restore   %r15
+       mov     -40(%rsi),%r14
+.cfi_restore   %r14
+       mov     -32(%rsi),%r13
+.cfi_restore   %r13
+       mov     -24(%rsi),%r12
+.cfi_restore   %r12
+       mov     -16(%rsi),%rbp
+.cfi_restore   %rbp
+       mov     -8(%rsi),%rbx
+.cfi_restore   %rbx
+       lea     (%rsi),%rsp
+.cfi_def_cfa_register  %rsp
 .Lepilogue_avx:
        ret
+.cfi_endproc
 .size  ${func}_avx,.-${func}_avx
 ___
 
@@ -1595,7 +1861,7 @@ if ($avx>1) {{
 ######################################################################
 # AVX2+BMI code path
 #
-my $a5=$SZ==4?"%esi":"%rsi";   # zap $inp 
+my $a5=$SZ==4?"%esi":"%rsi";   # zap $inp
 my $PUSH8=8*2*$SZ;
 use integer;
 
@@ -1643,14 +1909,22 @@ $code.=<<___;
 .type  ${func}_avx2,\@function,3
 .align 64
 ${func}_avx2:
+.cfi_startproc
 .Lavx2_shortcut:
+       mov     %rsp,%rax               # copy %rsp
+.cfi_def_cfa_register  %rax
        push    %rbx
+.cfi_push      %rbx
        push    %rbp
+.cfi_push      %rbp
        push    %r12
+.cfi_push      %r12
        push    %r13
+.cfi_push      %r13
        push    %r14
+.cfi_push      %r14
        push    %r15
-       mov     %rsp,%r11               # copy %rsp
+.cfi_push      %r15
        sub     \$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp
        shl     \$4,%rdx                # num*16
        and     \$-256*$SZ,%rsp         # align stack frame
@@ -1659,7 +1933,8 @@ ${func}_avx2:
        mov     $ctx,$_ctx              # save ctx, 1st arg
        mov     $inp,$_inp              # save inp, 2nd arh
        mov     %rdx,$_end              # save end pointer, "3rd" arg
-       mov     %r11,$_rsp              # save copy of %rsp
+       mov     %rax,$_rsp              # save copy of %rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 ___
 $code.=<<___ if ($win64);
        movaps  %xmm6,16*$SZ+32(%rsp)
@@ -1674,7 +1949,7 @@ ___
 $code.=<<___;
 .Lprologue_avx2:
 
-       vzeroall
+       vzeroupper
        sub     \$-16*$SZ,$inp          # inp++, size optimization
        mov     $SZ*0($ctx),$A
        mov     $inp,%r12               # borrow $T1
@@ -1721,7 +1996,23 @@ $code.=<<___;
        vmovdqa $t0,0x00(%rsp)
        xor     $a1,$a1
        vmovdqa $t1,0x20(%rsp)
+___
+$code.=<<___ if (!$win64);
+# temporarily use %rdi as frame pointer
+       mov     $_rsp,%rdi
+.cfi_def_cfa   %rdi,8
+___
+$code.=<<___;
        lea     -$PUSH8(%rsp),%rsp
+___
+$code.=<<___ if (!$win64);
+# the frame info is at $_rsp, but the stack is moving...
+# so a second frame pointer is saved at -8(%rsp)
+# that is in the red zone
+       mov     %rdi,-8(%rsp)
+.cfi_cfa_expression    %rsp-8,deref,+8
+___
+$code.=<<___;
        mov     $B,$a3
        vmovdqa $t2,0x00(%rsp)
        xor     $C,$a3                  # magic
@@ -1741,7 +2032,18 @@ my @X = @_;
 my @insns = (&$body,&$body,&$body,&$body);     # 96 instructions
 my $base = "+2*$PUSH8(%rsp)";
 
-       &lea    ("%rsp","-$PUSH8(%rsp)")        if (($j%2)==0);
+       if (($j%2)==0) {
+       &lea    ("%rsp","-$PUSH8(%rsp)");
+$code.=<<___ if (!$win64);
+.cfi_cfa_expression    %rsp+`$PUSH8-8`,deref,+8
+# copy secondary frame pointer to new location again at -8(%rsp)
+       pushq   $PUSH8-8(%rsp)
+.cfi_cfa_expression    %rsp,deref,+8
+       lea     8(%rsp),%rsp
+.cfi_cfa_expression    %rsp-8,deref,+8
+___
+       }
+
        foreach (Xupdate_256_AVX()) {           # 29 instructions
            eval;
            eval(shift(@insns));
@@ -1812,7 +2114,23 @@ $code.=<<___;
        vmovdqa $t2,0x40(%rsp)
        vpaddq  0x40($Tbl),@X[6],$t2
        vmovdqa $t3,0x60(%rsp)
+___
+$code.=<<___ if (!$win64);
+# temporarily use %rdi as frame pointer
+       mov     $_rsp,%rdi
+.cfi_def_cfa   %rdi,8
+___
+$code.=<<___;
        lea     -$PUSH8(%rsp),%rsp
+___
+$code.=<<___ if (!$win64);
+# the frame info is at $_rsp, but the stack is moving...
+# so a second frame pointer is saved at -8(%rsp)
+# that is in the red zone
+       mov     %rdi,-8(%rsp)
+.cfi_cfa_expression    %rsp-8,deref,+8
+___
+$code.=<<___;
        vpaddq  0x60($Tbl),@X[7],$t3
        vmovdqa $t0,0x00(%rsp)
        xor     $a1,$a1
@@ -1836,7 +2154,18 @@ my @X = @_;
 my @insns = (&$body,&$body);                   # 48 instructions
 my $base = "+2*$PUSH8(%rsp)";
 
-       &lea    ("%rsp","-$PUSH8(%rsp)")        if (($j%4)==0);
+       if (($j%4)==0) {
+       &lea    ("%rsp","-$PUSH8(%rsp)");
+$code.=<<___ if (!$win64);
+.cfi_cfa_expression    %rsp+`$PUSH8-8`,deref,+8
+# copy secondary frame pointer to new location again at -8(%rsp)
+       pushq   $PUSH8-8(%rsp)
+.cfi_cfa_expression    %rsp,deref,+8
+       lea     8(%rsp),%rsp
+.cfi_cfa_expression    %rsp-8,deref,+8
+___
+       }
+
        foreach (Xupdate_512_AVX()) {           # 23 instructions
            eval;
            if ($_ !~ /\;$/) {
@@ -1911,6 +2240,8 @@ $code.=<<___;
        add     $a1,$A
        #mov    `2*$SZ*$rounds+8`(%rsp),$inp    # $_inp
        lea     `2*$SZ*($rounds-8)`(%rsp),%rsp
+# restore frame pointer to original location at $_rsp
+.cfi_cfa_expression    $_rsp,deref,+8
 
        add     $SZ*0($ctx),$A
        add     $SZ*1($ctx),$B
@@ -1936,32 +2267,43 @@ $code.=<<___;
 
        jbe     .Loop_avx2
        lea     (%rsp),$Tbl
+# temporarily use $Tbl as index to $_rsp
+# this avoids the need to save a secondary frame pointer at -8(%rsp)
+.cfi_cfa_expression    $Tbl+`16*$SZ+3*8`,deref,+8
 
 .Ldone_avx2:
-       lea     ($Tbl),%rsp
-       mov     $_rsp,%rsi
-       vzeroall
+       mov     `16*$SZ+3*8`($Tbl),%rsi
+.cfi_def_cfa   %rsi,8
+       vzeroupper
 ___
 $code.=<<___ if ($win64);
-       movaps  16*$SZ+32(%rsp),%xmm6
-       movaps  16*$SZ+48(%rsp),%xmm7
-       movaps  16*$SZ+64(%rsp),%xmm8
-       movaps  16*$SZ+80(%rsp),%xmm9
+       movaps  16*$SZ+32($Tbl),%xmm6
+       movaps  16*$SZ+48($Tbl),%xmm7
+       movaps  16*$SZ+64($Tbl),%xmm8
+       movaps  16*$SZ+80($Tbl),%xmm9
 ___
 $code.=<<___ if ($win64 && $SZ>4);
-       movaps  16*$SZ+96(%rsp),%xmm10
-       movaps  16*$SZ+112(%rsp),%xmm11
+       movaps  16*$SZ+96($Tbl),%xmm10
+       movaps  16*$SZ+112($Tbl),%xmm11
 ___
 $code.=<<___;
-       mov     (%rsi),%r15
-       mov     8(%rsi),%r14
-       mov     16(%rsi),%r13
-       mov     24(%rsi),%r12
-       mov     32(%rsi),%rbp
-       mov     40(%rsi),%rbx
-       lea     48(%rsi),%rsp
+       mov     -48(%rsi),%r15
+.cfi_restore   %r15
+       mov     -40(%rsi),%r14
+.cfi_restore   %r14
+       mov     -32(%rsi),%r13
+.cfi_restore   %r13
+       mov     -24(%rsi),%r12
+.cfi_restore   %r12
+       mov     -16(%rsi),%rbp
+.cfi_restore   %rbp
+       mov     -8(%rsi),%rbx
+.cfi_restore   %rbx
+       lea     (%rsi),%rsp
+.cfi_def_cfa_register  %rsp
 .Lepilogue_avx2:
        ret
+.cfi_endproc
 .size  ${func}_avx2,.-${func}_avx2
 ___
 }}
@@ -2021,7 +2363,6 @@ ___
 $code.=<<___;
        mov     %rax,%rsi               # put aside Rsp
        mov     16*$SZ+3*8(%rax),%rax   # pull $_rsp
-       lea     48(%rax),%rax
 
        mov     -8(%rax),%rbx
        mov     -16(%rax),%rbp
@@ -2084,13 +2425,55 @@ $code.=<<___;
        pop     %rsi
        ret
 .size  se_handler,.-se_handler
+___
+
+$code.=<<___ if ($SZ==4 && $shaext);
+.type  shaext_handler,\@abi-omnipotent
+.align 16
+shaext_handler:
+       push    %rsi
+       push    %rdi
+       push    %rbx
+       push    %rbp
+       push    %r12
+       push    %r13
+       push    %r14
+       push    %r15
+       pushfq
+       sub     \$64,%rsp
+
+       mov     120($context),%rax      # pull context->Rax
+       mov     248($context),%rbx      # pull context->Rip
+
+       lea     .Lprologue_shaext(%rip),%r10
+       cmp     %r10,%rbx               # context->Rip<.Lprologue
+       jb      .Lin_prologue
+
+       lea     .Lepilogue_shaext(%rip),%r10
+       cmp     %r10,%rbx               # context->Rip>=.Lepilogue
+       jae     .Lin_prologue
+
+       lea     -8-5*16(%rax),%rsi
+       lea     512($context),%rdi      # &context.Xmm6
+       mov     \$10,%ecx
+       .long   0xa548f3fc              # cld; rep movsq
+
+       jmp     .Lin_prologue
+.size  shaext_handler,.-shaext_handler
+___
 
+$code.=<<___;
 .section       .pdata
 .align 4
        .rva    .LSEH_begin_$func
        .rva    .LSEH_end_$func
        .rva    .LSEH_info_$func
 ___
+$code.=<<___ if ($SZ==4 && $shaext);
+       .rva    .LSEH_begin_${func}_shaext
+       .rva    .LSEH_end_${func}_shaext
+       .rva    .LSEH_info_${func}_shaext
+___
 $code.=<<___ if ($SZ==4);
        .rva    .LSEH_begin_${func}_ssse3
        .rva    .LSEH_end_${func}_ssse3
@@ -2119,6 +2502,11 @@ $code.=<<___;
        .rva    se_handler
        .rva    .Lprologue,.Lepilogue                   # HandlerData[]
 ___
+$code.=<<___ if ($SZ==4 && $shaext);
+.LSEH_info_${func}_shaext:
+       .byte   9,0,0,0
+       .rva    shaext_handler
+___
 $code.=<<___ if ($SZ==4);
 .LSEH_info_${func}_ssse3:
        .byte   9,0,0,0
@@ -2145,6 +2533,28 @@ $code.=<<___ if ($avx>1);
 ___
 }
 
-$code =~ s/\`([^\`]*)\`/eval $1/gem;
-print $code;
+sub sha256op38 {
+    my $instr = shift;
+    my %opcodelet = (
+               "sha256rnds2" => 0xcb,
+               "sha256msg1"  => 0xcc,
+               "sha256msg2"  => 0xcd   );
+
+    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-7]),\s*%xmm([0-7])/) {
+      my @opcode=(0x0f,0x38);
+       push @opcode,$opcodelet{$instr};
+       push @opcode,0xc0|($1&7)|(($2&7)<<3);           # ModR/M
+       return ".byte\t".join(',',@opcode);
+    } else {
+       return $instr."\t".@_[0];
+    }
+}
+
+foreach (split("\n",$code)) {
+       s/\`([^\`]*)\`/eval $1/geo;
+
+       s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/geo;
+
+       print $_,"\n";
+}
 close STDOUT;