#! /usr/bin/env perl # Copyright 1995-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 # The first two arguments should always be the flavour and output file path. if ($#ARGV < 1) { die "Not enough arguments provided. Two arguments are necessary: the flavour and the output file path."; } $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; push(@INC,"${dir}","${dir}../../../perlasm"); require "x86asm.pl"; $output = $ARGV[1]; open STDOUT,">$output"; &asm_init($ARGV[0]); &bn_mul_comba("bn_mul_comba8",8); &bn_mul_comba("bn_mul_comba4",4); &bn_sqr_comba("bn_sqr_comba8",8); &bn_sqr_comba("bn_sqr_comba4",4); &asm_finish(); close STDOUT or die "error closing STDOUT: $!"; sub mul_add_c { local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; # pos == -1 if eax and edx are pre-loaded, 0 to load from next # words, and 1 if load return value &comment("mul a[$ai]*b[$bi]"); # "eax" and "edx" will always be pre-loaded. # &mov("eax",&DWP($ai*4,$a,"",0)) ; # &mov("edx",&DWP($bi*4,$b,"",0)); &mul("edx"); &add($c0,"eax"); &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # laod next a &mov("eax",&wparam(0)) if $pos > 0; # load r[] ### &adc($c1,"edx"); &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0; # laod next b &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b ### &adc($c2,0); # is pos > 1, it means it is the last loop &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[]; &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a } sub sqr_add_c { local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; # pos == -1 if eax and edx are pre-loaded, 0 to load from next # words, and 1 if load return value &comment("sqr a[$ai]*a[$bi]"); # "eax" and "edx" will always be pre-loaded. # &mov("eax",&DWP($ai*4,$a,"",0)) ; # &mov("edx",&DWP($bi*4,$b,"",0)); if ($ai == $bi) { &mul("eax");} else { &mul("edx");} &add($c0,"eax"); &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a ### &adc($c1,"edx"); &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb); ### &adc($c2,0); # is pos > 1, it means it is the last loop &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b } sub sqr_add_c2 { local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; # pos == -1 if eax and edx are pre-loaded, 0 to load from next # words, and 1 if load return value &comment("sqr a[$ai]*a[$bi]"); # "eax" and "edx" will always be pre-loaded. # &mov("eax",&DWP($ai*4,$a,"",0)) ; # &mov("edx",&DWP($bi*4,$a,"",0)); if ($ai == $bi) { &mul("eax");} else { &mul("edx");} &add("eax","eax"); ### &adc("edx","edx"); ### &adc($c2,0); &add($c0,"eax"); &adc($c1,"edx"); &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b &adc($c2,0); &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb); ### } sub bn_mul_comba { local($name,$num)=@_; local($a,$b,$c0,$c1,$c2); local($i,$as,$ae,$bs,$be,$ai,$bi); local($tot,$end); &function_begin_B($name,""); $c0="ebx"; $c1="ecx"; $c2="ebp"; $a="esi"; $b="edi"; $as=0; $ae=0; $bs=0; $be=0; $tot=$num+$num-1; &push("esi"); &mov($a,&wparam(1)); &push("edi"); &mov($b,&wparam(2)); &push("ebp"); &push("ebx"); &xor($c0,$c0); &mov("eax",&DWP(0,$a,"",0)); # load the first word &xor($c1,$c1); &mov("edx",&DWP(0,$b,"",0)); # load the first second for ($i=0; $i<$tot; $i++) { $ai=$as; $bi=$bs; $end=$be+1; &comment("################## Calculate word $i"); for ($j=$bs; $j<$end; $j++) { &xor($c2,$c2) if ($j == $bs); if (($j+1) == $end) { $v=1; $v=2 if (($i+1) == $tot); } else { $v=0; } if (($j+1) != $end) { $na=($ai-1); $nb=($bi+1); } else { $na=$as+($i < ($num-1)); $nb=$bs+($i >= ($num-1)); } #printf STDERR "[$ai,$bi] -> [$na,$nb]\n"; &mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb); if ($v) { &comment("saved r[$i]"); # &mov("eax",&wparam(0)); # &mov(&DWP($i*4,"eax","",0),$c0); ($c0,$c1,$c2)=($c1,$c2,$c0); } $ai--; $bi++; } $as++ if ($i < ($num-1)); $ae++ if ($i >= ($num-1)); $bs++ if ($i >= ($num-1)); $be++ if ($i < ($num-1)); } &comment("save r[$i]"); # &mov("eax",&wparam(0)); &mov(&DWP($i*4,"eax","",0),$c0); &pop("ebx"); &pop("ebp"); &pop("edi"); &pop("esi"); &ret(); &function_end_B($name); } sub bn_sqr_comba { local($name,$num)=@_; local($r,$a,$c0,$c1,$c2)=@_; local($i,$as,$ae,$bs,$be,$ai,$bi); local($b,$tot,$end,$half); &function_begin_B($name,""); $c0="ebx"; $c1="ecx"; $c2="ebp"; $a="esi"; $r="edi"; &push("esi"); &push("edi"); &push("ebp"); &push("ebx"); &mov($r,&wparam(0)); &mov($a,&wparam(1)); &xor($c0,$c0); &xor($c1,$c1); &mov("eax",&DWP(0,$a,"",0)); # load the first word $as=0; $ae=0; $bs=0; $be=0; $tot=$num+$num-1; for ($i=0; $i<$tot; $i++) { $ai=$as; $bi=$bs; $end=$be+1; &comment("############### Calculate word $i"); for ($j=$bs; $j<$end; $j++) { &xor($c2,$c2) if ($j == $bs); if (($ai-1) < ($bi+1)) { $v=1; $v=2 if ($i+1) == $tot; } else { $v=0; } if (!$v) { $na=$ai-1; $nb=$bi+1; } else { $na=$as+($i < ($num-1)); $nb=$bs+($i >= ($num-1)); } if ($ai == $bi) { &sqr_add_c($r,$a,$ai,$bi, $c0,$c1,$c2,$v,$i,$na,$nb); } else { &sqr_add_c2($r,$a,$ai,$bi, $c0,$c1,$c2,$v,$i,$na,$nb); } if ($v) { &comment("saved r[$i]"); #&mov(&DWP($i*4,$r,"",0),$c0); ($c0,$c1,$c2)=($c1,$c2,$c0); last; } $ai--; $bi++; } $as++ if ($i < ($num-1)); $ae++ if ($i >= ($num-1)); $bs++ if ($i >= ($num-1)); $be++ if ($i < ($num-1)); } &mov(&DWP($i*4,$r,"",0),$c0); &pop("ebx"); &pop("ebp"); &pop("edi"); &pop("esi"); &ret(); &function_end_B($name); }