sha/asm/sha1-x86_64.pl: fix crash in SHAEXT code on Windows.
[openssl.git] / crypto / sha / asm / sha1-x86_64.pl
index ea288c15d5e9e4fa4b8d9dac317f1260235fefcd..97baae37cd954c7ecddb70669ce981f1a0985beb 100755 (executable)
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (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
@@ -73,6 +80,7 @@
 # Sandy Bridge 7.70            6.10/+26%       4.99/+54%
 # Ivy Bridge   6.06            4.67/+30%       4.60/+32%
 # Haswell      5.45            4.15/+31%       3.57/+53%
+# Skylake      5.18            4.06/+28%       3.54/+46%
 # Bulldozer    9.11            5.95/+53%
 # VIA Nano     9.32            7.15/+30%
 # Atom         10.3            9.17/+12%
@@ -107,7 +115,14 @@ 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) ([2-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\"";
 *STDOUT=*OUT;
 
 $ctx="%rdi";   # 1st arg
@@ -245,7 +260,8 @@ sha1_block_data_order:
        mov     OPENSSL_ia32cap_P+8(%rip),%r10d
        test    \$`1<<9`,%r8d           # check SSSE3 bit
        jz      .Lialu
-
+___
+$code.=<<___ if ($shaext);
        test    \$`1<<29`,%r10d         # check SHA bit 
        jnz     _shaext_shortcut
 ___
@@ -321,7 +337,7 @@ $code.=<<___;
        ret
 .size  sha1_block_data_order,.-sha1_block_data_order
 ___
-{{{
+if ($shaext) {{{
 ######################################################################
 # Intel SHA Extensions implementation of SHA1 update function.
 #
@@ -364,9 +380,9 @@ $code.=<<___;
 .align 16
 .Loop_shaext:
        dec             $num
-       lea             0x40($inp),%rax         # next input block
+       lea             0x40($inp),%r         # next input block
        paddd           @MSG[0],$E
-       cmovne          %rax,$inp
+       cmovne          %r8,$inp
        movdqa          $ABCD,$ABCD_SAVE        # offload $ABCD
 ___
 for($i=0;$i<20-4;$i+=2) {
@@ -1827,7 +1843,9 @@ se_handler:
 
        jmp     .Lcommon_seh_tail
 .size  se_handler,.-se_handler
+___
 
+$code.=<<___ if ($shaext);
 .type  shaext_handler,\@abi-omnipotent
 .align 16
 shaext_handler:
@@ -1860,7 +1878,9 @@ shaext_handler:
 
        jmp     .Lcommon_seh_tail
 .size  shaext_handler,.-shaext_handler
+___
 
+$code.=<<___;
 .type  ssse3_handler,\@abi-omnipotent
 .align 16
 ssse3_handler:
@@ -1956,9 +1976,13 @@ ssse3_handler:
        .rva    .LSEH_begin_sha1_block_data_order
        .rva    .LSEH_end_sha1_block_data_order
        .rva    .LSEH_info_sha1_block_data_order
+___
+$code.=<<___ if ($shaext);
        .rva    .LSEH_begin_sha1_block_data_order_shaext
        .rva    .LSEH_end_sha1_block_data_order_shaext
        .rva    .LSEH_info_sha1_block_data_order_shaext
+___
+$code.=<<___;
        .rva    .LSEH_begin_sha1_block_data_order_ssse3
        .rva    .LSEH_end_sha1_block_data_order_ssse3
        .rva    .LSEH_info_sha1_block_data_order_ssse3
@@ -1979,9 +2003,13 @@ $code.=<<___;
 .LSEH_info_sha1_block_data_order:
        .byte   9,0,0,0
        .rva    se_handler
+___
+$code.=<<___ if ($shaext);
 .LSEH_info_sha1_block_data_order_shaext:
        .byte   9,0,0,0
        .rva    shaext_handler
+___
+$code.=<<___;
 .LSEH_info_sha1_block_data_order_ssse3:
        .byte   9,0,0,0
        .rva    ssse3_handler
@@ -2022,8 +2050,12 @@ sub sha1op38 {
                "sha1msg1"  => 0xc9,
                "sha1msg2"  => 0xca     );
 
-    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-7]),\s*%xmm([0-7])/) {
+    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
       my @opcode=(0x0f,0x38);
+      my $rex=0;
+       $rex|=0x04                      if ($2>=8);
+       $rex|=0x01                      if ($1>=8);
+       unshift @opcode,0x40|$rex       if ($rex);
        push @opcode,$opcodelet{$instr};
        push @opcode,0xc0|($1&7)|(($2&7)<<3);           # ModR/M
        return ".byte\t".join(',',@opcode);