Newer
Older
#!/usr/bin/env perl
#
# ====================================================================
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
# project. Rights for redistribution and usage in source and binary
# forms are granted according to the OpenSSL license.
# ====================================================================
#
# You might fail to appreciate this module performance from the first
# try. If compared to "vanilla" linux-ia32-icc target, i.e. Intel C
# without -KPIC, performance appears to be virtually identical... But
# try to configure with shared library support... Aha! Intel compiler
# "suddenly" lags behind by 30% [on P4]:-) And if compared to
# position-independent code generated by GNU C, this code performs
# more than *twice* as fast! Yes, all this buzz about PIC means that
# [unlike other implementations] this module was explicitly designed
# to be safe to use even in shared library context...
#
# Special note about instruction choice. Do you recall RC4_INT code
# performing poorly on P4? It might be the time to figure out why.
# RC4_INT code implies effective address calculations in base+offset*4
# form. Trouble is that it seems that offset scaling turned to be
# critical path... At least eliminating scaling resulted in 2.8x RC4
# performance improvement [as you might recall]. As AES code is hungry
# for scaling too, I [try to] avoid the latter by favoring off-by-2
# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF.
#
# As was shown by Dean Gaudet <dean@arctic.org>, the above note turned
# void. Performance improvement with off-by-2 shifts was observed on
# intermediate implementation, which was spilling yet another register
# to stack... Final offset*4 code below runs just a tad faster on P4,
# but exhibits up to 10% improvement on other cores.
push(@INC,"perlasm","../../perlasm");
require "x86asm.pl";
&asm_init($ARGV[0],"aes-586.pl",$ARGV[$#ARGV] eq "386");
$small_footprint=1; # $small_footprint=1 code is 4-6% slower, but
# 5 times smaller! I default to compact code.
$s0="eax";
$s1="ebx";
$s2="ecx";
$s3="edx";
sub encstep()
{ my ($i,$te,@s) = @_;
my $tmp,$out;
# lines marked with ## denote same $sN...
if ($i==3) { &mov ("edi",&DWP(12,"esp"));
&movz ($out=$s[0],&HB($s[0])); } ##
else { &mov ($out="esi",$s[0]);
&shr ($out,24); }
&mov ($out,&DWP(1024*0,$te,$out,4));
if ($i==2) { &movz ($tmp="edi",&LB($s[1])); } ##
else { $i==3?$tmp=$s[1]:&mov($tmp="edi",$s[1]);
&shr ($tmp,16);
&and ($tmp,0xFF); }
&xor ($out,&DWP(1024*1,$te,$tmp,4));
if ($i==3) { $tmp=$s[2]; &mov ($s[1],&DWP(0,"esp")); }
else { $tmp="edi"; }
&movz ($tmp,&HB($s[2]));
&xor ($out,&DWP(1024*2,$te,$tmp,4));
if ($i==3) { $tmp=$s[3]; &mov ($s[2],&DWP(4,"esp")); }
&and ($tmp,0xFF);
&xor ($out,&DWP(1024*3,$te,$tmp,4));
if ($i<2) { &mov (&DWP(4*$i,"esp"),$out); }
if ($i==3) { &mov ($s[3],"esi"); }
}
sub enclast()
{ my ($i,$te,@s)=@_;
my $tmp,$out;
if ($i==3) { &mov ("edi",&DWP(12,"esp"));
&movz ($out=$s[0],&HB($s[0])); } ##
else { &mov ($out="esi",$s[0]);
&shr ($out,24); }
&mov ($out,&DWP(0,$te,$out,4));
if ($i==2) { &movz ($tmp="edi",&LB($s[1])); } ##
else { $i==3?$tmp=$s[1]:&mov($tmp="edi",$s[1]);
&shr ($tmp,16);
&and ($tmp,0xFF); }
&mov ($tmp,&DWP(0,$te,$tmp,4));
&and ($tmp,0x00ff0000);
&xor ($out,$tmp);
if ($i==3) { $tmp=$s[2]; &mov ($s[1],&DWP(0,"esp")); }
&movz ($tmp,&HB($s[2]));
&mov ($tmp,&DWP(0,$te,$tmp,4));
&and ($tmp,0x0000ff00);
&xor ($out,$tmp);
if ($i==3) { $tmp=$s[3]; &mov ($s[2],&DWP(4,"esp")); }
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
&and ($tmp,0xFF);
&mov ($tmp,&DWP(0,$te,$tmp,4));
&and ($tmp,0x000000ff);
&xor ($out,$tmp);
if ($i<2) { &mov (&DWP(4*$i,"esp"),$out); }
if ($i==3) { &mov ($s[3],"esi"); }
}
# void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
&public_label("AES_Te");
&function_begin("AES_encrypt");
&mov ("esi",&wparam(0)); # load inp
&mov ("edi",&wparam(2)); # load key
&call (&label("pic_point")); # make it PIC!
&set_label("pic_point");
&blindpop("ebp");
&lea ("ebp",&DWP(&label("AES_Te")."-".&label("pic_point"),"ebp"));
# allocate aligned stack frame
&mov ("eax","esp");
&sub ("esp",20);
&and ("esp",-16);
&mov (&DWP(12,"esp"),"edi"); # save key
&mov (&DWP(16,"esp"),"eax"); # save %esp
&mov ($s0,&DWP(0,"esi")); # load input data
&mov ($s1,&DWP(4,"esi"));
&mov ($s2,&DWP(8,"esi"));
&mov ($s3,&DWP(12,"esi"));
#
# It's perfectly possible to implement algorithm as
# little-endian and get rid of bswaps... It would give
# less than 1% performance improvement, so I judge it
# doesn't worth the trouble...
#
&bswap ($s0);
&bswap ($s1);
&bswap ($s2);
&bswap ($s3);
&xor ($s0,&DWP(0,"edi"));
&xor ($s1,&DWP(4,"edi"));
&xor ($s2,&DWP(8,"edi"));
&xor ($s3,&DWP(12,"edi"));
&mov ("esi",&DWP(240,"edi")); # load key->rounds
if ($small_footprint) {
&lea ("esi",&DWP(-2,"esi","esi"));
&lea ("esi",&DWP(0,"edi","esi",8));
&mov (&DWP(8,"esp"),"esi"); # end of key schedule
&align (4);
&set_label("loop");
&encstep(0,"ebp",$s0,$s1,$s2,$s3);
&encstep(1,"ebp",$s1,$s2,$s3,$s0);
&encstep(2,"ebp",$s2,$s3,$s0,$s1);
&encstep(3,"ebp",$s3,$s0,$s1,$s2);
&add ("edi",16); # advance rd_key
&xor ($s0,&DWP(0,"edi"));
&xor ($s1,&DWP(4,"edi"));
&xor ($s2,&DWP(8,"edi"));
&xor ($s3,&DWP(12,"edi"));
&cmp ("edi",&DWP(8,"esp"));
&mov (&DWP(12,"esp"),"edi");
&jb (&label("loop"));
}
else {
&cmp ("esi",10);
&jle (&label("10rounds"));
&cmp ("esi",12);
&jle (&label("12rounds"));
&set_label("14rounds");
for ($i=1;$i<3;$i++) {
&encstep(0,"ebp",$s0,$s1,$s2,$s3);
&encstep(1,"ebp",$s1,$s2,$s3,$s0);
&encstep(2,"ebp",$s2,$s3,$s0,$s1);
&encstep(3,"ebp",$s3,$s0,$s1,$s2);
&xor ($s0,&DWP(16*$i+0,"edi"));
&xor ($s1,&DWP(16*$i+4,"edi"));
&xor ($s2,&DWP(16*$i+8,"edi"));
&xor ($s3,&DWP(16*$i+12,"edi"));
}
&add ("edi",32);
&mov (&DWP(12,"esp"),"edi"); # advance rd_key
&set_label("12rounds");
for ($i=1;$i<3;$i++) {
&encstep(0,"ebp",$s0,$s1,$s2,$s3);
&encstep(1,"ebp",$s1,$s2,$s3,$s0);
&encstep(2,"ebp",$s2,$s3,$s0,$s1);
&encstep(3,"ebp",$s3,$s0,$s1,$s2);
&xor ($s0,&DWP(16*$i+0,"edi"));
&xor ($s1,&DWP(16*$i+4,"edi"));
&xor ($s2,&DWP(16*$i+8,"edi"));
Loading full blame...