1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
#!/usr/bin/env perl
#
# ====================================================================
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
# project. The module is, however, dual licensed under OpenSSL and
# CRYPTOGAMS licenses depending on where you obtain it. For further
# details see http://www.openssl.org/~appro/cryptogams/.
# ====================================================================
#
# sha1_block procedure for x86_64.
#
# It was brought to my attention that on EM64T compiler-generated code
# was far behind 32-bit assembler implementation. This is unlike on
# Opteron where compiler-generated code was only 15% behind 32-bit
# assembler, which originally made it hard to motivate the effort.
# There was suggestion to mechanically translate 32-bit code, but I
# dismissed it, reasoning that x86_64 offers enough register bank
# capacity to fully utilize SHA-1 parallelism. Therefore this fresh
# implementation:-) However! While 64-bit code does performs better
# on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
# x86_64 does offer larger *addressable* bank, but out-of-order core
# reaches for even more registers through dynamic aliasing, and EM64T
# core must have managed to run-time optimize even 32-bit code just as
# good as 64-bit one. Performance improvement is summarized in the
# following table:
#
# gcc 3.4 32-bit asm cycles/byte
# Opteron +45% +20% 6.8
# Xeon P4 +65% +0% 9.9
# Core2 +60% +10% 7.0
$output=shift;
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open STDOUT,"| $^X $xlate $output";
$ctx="%rdi"; # 1st arg
$inp="%rsi"; # 2nd arg
$num="%rdx"; # 3rd arg
# reassign arguments in order to produce more compact code
$ctx="%r8";
$inp="%r9";
$num="%r10";
$xi="%eax";
$t0="%ebx";
$t1="%ecx";
$A="%edx";
$B="%esi";
$C="%edi";
$D="%ebp";
$E="%r11d";
$T="%r12d";
@V=($A,$B,$C,$D,$E,$T);
sub PROLOGUE {
my $func=shift;
$code.=<<___;
.globl $func
.type $func,\@function,3
.align 16
$func:
push %rbx
push %rbp
push %r12
mov %rsp,%rax
mov %rdi,$ctx # reassigned argument
sub \$`8+16*4`,%rsp
mov %rsi,$inp # reassigned argument
and \$-64,%rsp
mov %rdx,$num # reassigned argument
mov %rax,`16*4`(%rsp)
mov 0($ctx),$A
mov 4($ctx),$B
mov 8($ctx),$C
mov 12($ctx),$D
mov 16($ctx),$E
___
}
sub EPILOGUE {
my $func=shift;
$code.=<<___;
mov `16*4`(%rsp),%rsp
pop %r12
pop %rbp
pop %rbx
ret
.size $func,.-$func
___
}
sub BODY_00_19 {
my ($i,$a,$b,$c,$d,$e,$f,$host)=@_;
my $j=$i+1;
$code.=<<___ if ($i==0);
mov `4*$i`($inp),$xi
`"bswap $xi" if(!defined($host))`
mov $xi,`4*$i`(%rsp)
___
$code.=<<___ if ($i<15);
lea 0x5a827999($xi,$e),$f
mov $c,$t0
mov `4*$j`($inp),$xi
mov $a,$e
xor $d,$t0
`"bswap $xi" if(!defined($host))`
rol \$5,$e
and $b,$t0
mov $xi,`4*$j`(%rsp)
add $e,$f
xor $d,$t0
rol \$30,$b
add $t0,$f
___
$code.=<<___ if ($i>=15);
lea 0x5a827999($xi,$e),$f
mov `4*($j%16)`(%rsp),$xi
mov $c,$t0
mov $a,$e
xor `4*(($j+2)%16)`(%rsp),$xi
xor $d,$t0
rol \$5,$e
xor `4*(($j+8)%16)`(%rsp),$xi
and $b,$t0
add $e,$f
xor `4*(($j+13)%16)`(%rsp),$xi
xor $d,$t0
rol \$30,$b
add $t0,$f
rol \$1,$xi
mov $xi,`4*($j%16)`(%rsp)
___
}
sub BODY_20_39 {
my ($i,$a,$b,$c,$d,$e,$f)=@_;
my $j=$i+1;
my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
$code.=<<___ if ($i<79);
lea $K($xi,$e),$f
mov `4*($j%16)`(%rsp),$xi
mov $c,$t0
mov $a,$e
xor `4*(($j+2)%16)`(%rsp),$xi
xor $b,$t0
rol \$5,$e
xor `4*(($j+8)%16)`(%rsp),$xi
xor $d,$t0
add $e,$f
xor `4*(($j+13)%16)`(%rsp),$xi
rol \$30,$b
add $t0,$f
rol \$1,$xi
___
$code.=<<___ if ($i<76);
mov $xi,`4*($j%16)`(%rsp)
___
$code.=<<___ if ($i==79);
lea $K($xi,$e),$f
mov $c,$t0
mov $a,$e
xor $b,$t0
rol \$5,$e
xor $d,$t0
add $e,$f
rol \$30,$b
add $t0,$f
___
}
sub BODY_40_59 {
my ($i,$a,$b,$c,$d,$e,$f)=@_;
my $j=$i+1;
$code.=<<___;
lea 0x8f1bbcdc($xi,$e),$f
mov `4*($j%16)`(%rsp),$xi
mov $b,$t0
mov $b,$t1
xor `4*(($j+2)%16)`(%rsp),$xi
mov $a,$e
and $c,$t0
xor `4*(($j+8)%16)`(%rsp),$xi
or $c,$t1
rol \$5,$e
xor `4*(($j+13)%16)`(%rsp),$xi
and $d,$t1
add $e,$f
rol \$1,$xi
or $t1,$t0
rol \$30,$b
mov $xi,`4*($j%16)`(%rsp)
add $t0,$f
___
}
$code=".text\n";
&PROLOGUE("sha1_block_data_order");
$code.=".align 4\n.Lloop:\n";
for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
$code.=<<___;
add 0($ctx),$E
add 4($ctx),$T
add 8($ctx),$A
add 12($ctx),$B
add 16($ctx),$C
mov $E,0($ctx)
mov $T,4($ctx)
mov $A,8($ctx)
mov $B,12($ctx)
mov $C,16($ctx)
xchg $E,$A # mov $E,$A
xchg $T,$B # mov $T,$B
xchg $E,$C # mov $A,$C
xchg $T,$D # mov $B,$D
# mov $C,$E
lea `16*4`($inp),$inp
sub \$1,$num
jnz .Lloop
___
&EPILOGUE("sha1_block_data_order");
$code.=<<___;
.asciz "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
___
####################################################################
$code =~ s/\`([^\`]*)\`/eval $1/gem;
print $code;
close STDOUT;
|