x86_64 assembly pack: make Windows build more robust.
[openssl.git] / crypto / rc4 / asm / rc4-md5-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9
10 # June 2011
11 #
12 # This is RC4+MD5 "stitch" implementation. The idea, as spelled in
13 # http://download.intel.com/design/intarch/papers/323686.pdf, is that
14 # since both algorithms exhibit instruction-level parallelism, ILP,
15 # below theoretical maximum, interleaving them would allow to utilize
16 # processor resources better and achieve better performance. RC4
17 # instruction sequence is virtually identical to rc4-x86_64.pl, which
18 # is heavily based on submission by Maxim Perminov, Maxim Locktyukhin
19 # and Jim Guilford of Intel. MD5 is fresh implementation aiming to
20 # minimize register usage, which was used as "main thread" with RC4
21 # weaved into it, one RC4 round per one MD5 round. In addition to the
22 # stiched subroutine the script can generate standalone replacement
23 # md5_block_asm_data_order and RC4. Below are performance numbers in
24 # cycles per processed byte, less is better, for these the standalone
25 # subroutines, sum of them, and stitched one:
26 #
27 #               RC4     MD5     RC4+MD5 stitch  gain
28 # Opteron       6.5(*)  5.4     11.9    7.0     +70%(*)
29 # Core2         6.5     5.8     12.3    7.7     +60%
30 # Westmere      4.3     5.2     9.5     7.0     +36%
31 # Sandy Bridge  4.2     5.5     9.7     6.8     +43%
32 # Atom          9.3     6.5     15.8    11.1    +42%
33 # VIA Nano      6.3     5.4     11.7    8.6     +37%
34 # Ivy Bridge    4.1     5.2     9.3     6.0     +54%
35 # Bulldozer     4.5     5.4     9.9     7.7     +29%
36 #
37 # (*)   rc4-x86_64.pl delivers 5.3 on Opteron, so real improvement
38 #       is +53%...
39
40 my ($rc4,$md5)=(1,1);   # what to generate?
41 my $D="#" if (!$md5);   # if set to "#", MD5 is stitched into RC4(),
42                         # but its result is discarded. Idea here is
43                         # to be able to use 'openssl speed rc4' for
44                         # benchmarking the stitched subroutine... 
45
46 my $flavour = shift;
47 my $output  = shift;
48 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
49
50 my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
51
52 $0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
53 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
54 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
55 die "can't locate x86_64-xlate.pl";
56
57 open OUT,"| \"$^X\" $xlate $flavour $output";
58 *STDOUT=*OUT;
59
60 my ($dat,$in0,$out,$ctx,$inp,$len, $func,$nargs);
61
62 if ($rc4 && !$md5) {
63   ($dat,$len,$in0,$out) = ("%rdi","%rsi","%rdx","%rcx");
64   $func="RC4";                          $nargs=4;
65 } elsif ($md5 && !$rc4) {
66   ($ctx,$inp,$len) = ("%rdi","%rsi","%rdx");
67   $func="md5_block_asm_data_order";     $nargs=3;
68 } else {
69   ($dat,$in0,$out,$ctx,$inp,$len) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
70   $func="rc4_md5_enc";                  $nargs=6;
71   # void rc4_md5_enc(
72   #             RC4_KEY *key,           #
73   #             const void *in0,        # RC4 input
74   #             void *out,              # RC4 output
75   #             MD5_CTX *ctx,           #
76   #             const void *inp,        # MD5 input
77   #             size_t len);            # number of 64-byte blocks
78 }
79
80 my @K=( 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
81         0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
82         0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
83         0x6b901122,0xfd987193,0xa679438e,0x49b40821,
84
85         0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,
86         0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
87         0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,
88         0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
89
90         0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,
91         0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
92         0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
93         0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
94
95         0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,
96         0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
97         0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
98         0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391     );
99
100 my @V=("%r8d","%r9d","%r10d","%r11d");  # MD5 registers
101 my $tmp="%r12d";
102
103 my @XX=("%rbp","%rsi");                 # RC4 registers
104 my @TX=("%rax","%rbx");
105 my $YY="%rcx";
106 my $TY="%rdx";
107
108 my $MOD=32;                             # 16, 32 or 64
109
110 $code.=<<___;
111 .text
112 .align 16
113
114 .globl  $func
115 .type   $func,\@function,$nargs
116 $func:
117         cmp     \$0,$len
118         je      .Labort
119         push    %rbx
120         push    %rbp
121         push    %r12
122         push    %r13
123         push    %r14
124         push    %r15
125         sub     \$40,%rsp
126 .Lbody:
127 ___
128 if ($rc4) {
129 $code.=<<___;
130 $D#md5# mov     $ctx,%r11               # reassign arguments
131         mov     $len,%r12
132         mov     $in0,%r13
133         mov     $out,%r14
134 $D#md5# mov     $inp,%r15
135 ___
136     $ctx="%r11" if ($md5);              # reassign arguments
137     $len="%r12";
138     $in0="%r13";
139     $out="%r14";
140     $inp="%r15" if ($md5);
141     $inp=$in0   if (!$md5);
142 $code.=<<___;
143         xor     $XX[0],$XX[0]
144         xor     $YY,$YY
145
146         lea     8($dat),$dat
147         mov     -8($dat),$XX[0]#b
148         mov     -4($dat),$YY#b
149
150         inc     $XX[0]#b
151         sub     $in0,$out
152         movl    ($dat,$XX[0],4),$TX[0]#d
153 ___
154 $code.=<<___ if (!$md5);
155         xor     $TX[1],$TX[1]
156         test    \$-128,$len
157         jz      .Loop1
158         sub     $XX[0],$TX[1]
159         and     \$`$MOD-1`,$TX[1]
160         jz      .Loop${MOD}_is_hot
161         sub     $TX[1],$len
162 .Loop${MOD}_warmup:
163         add     $TX[0]#b,$YY#b
164         movl    ($dat,$YY,4),$TY#d
165         movl    $TX[0]#d,($dat,$YY,4)
166         movl    $TY#d,($dat,$XX[0],4)
167         add     $TY#b,$TX[0]#b
168         inc     $XX[0]#b
169         movl    ($dat,$TX[0],4),$TY#d
170         movl    ($dat,$XX[0],4),$TX[0]#d
171         xorb    ($in0),$TY#b
172         movb    $TY#b,($out,$in0)
173         lea     1($in0),$in0
174         dec     $TX[1]
175         jnz     .Loop${MOD}_warmup
176
177         mov     $YY,$TX[1]
178         xor     $YY,$YY
179         mov     $TX[1]#b,$YY#b
180
181 .Loop${MOD}_is_hot:
182         mov     $len,32(%rsp)           # save original $len
183         shr     \$6,$len                # number of 64-byte blocks
184 ___
185   if ($D && !$md5) {                    # stitch in dummy MD5
186     $md5=1;
187     $ctx="%r11";
188     $inp="%r15";
189     $code.=<<___;
190         mov     %rsp,$ctx
191         mov     $in0,$inp
192 ___
193   }
194 }
195 $code.=<<___;
196 #rc4#   add     $TX[0]#b,$YY#b
197 #rc4#   lea     ($dat,$XX[0],4),$XX[1]
198         shl     \$6,$len
199         add     $inp,$len               # pointer to the end of input
200         mov     $len,16(%rsp)
201
202 #md5#   mov     $ctx,24(%rsp)           # save pointer to MD5_CTX
203 #md5#   mov     0*4($ctx),$V[0]         # load current hash value from MD5_CTX
204 #md5#   mov     1*4($ctx),$V[1]
205 #md5#   mov     2*4($ctx),$V[2]
206 #md5#   mov     3*4($ctx),$V[3]
207         jmp     .Loop
208
209 .align  16
210 .Loop:
211 #md5#   mov     $V[0],0*4(%rsp)         # put aside current hash value
212 #md5#   mov     $V[1],1*4(%rsp)
213 #md5#   mov     $V[2],2*4(%rsp)
214 #md5#   mov     $V[3],$tmp              # forward reference
215 #md5#   mov     $V[3],3*4(%rsp)
216 ___
217
218 sub R0 {
219   my ($i,$a,$b,$c,$d)=@_;
220   my @rot0=(7,12,17,22);
221   my $j=$i%16;
222   my $k=$i%$MOD;
223   my $xmm="%xmm".($j&1);
224     $code.="    movdqu  ($in0),%xmm2\n"         if ($rc4 && $j==15);
225     $code.="    add     \$$MOD,$XX[0]#b\n"      if ($rc4 && $j==15 && $k==$MOD-1);
226     $code.="    pxor    $xmm,$xmm\n"            if ($rc4 && $j<=1);
227     $code.=<<___;
228 #rc4#   movl    ($dat,$YY,4),$TY#d
229 #md5#   xor     $c,$tmp
230 #rc4#   movl    $TX[0]#d,($dat,$YY,4)
231 #md5#   and     $b,$tmp
232 #md5#   add     4*`$j`($inp),$a
233 #rc4#   add     $TY#b,$TX[0]#b
234 #rc4#   movl    `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
235 #md5#   add     \$$K[$i],$a
236 #md5#   xor     $d,$tmp
237 #rc4#   movz    $TX[0]#b,$TX[0]#d
238 #rc4#   movl    $TY#d,4*$k($XX[1])
239 #md5#   add     $tmp,$a
240 #rc4#   add     $TX[1]#b,$YY#b
241 #md5#   rol     \$$rot0[$j%4],$a
242 #md5#   mov     `$j==15?"$b":"$c"`,$tmp         # forward reference
243 #rc4#   pinsrw  \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
244 #md5#   add     $b,$a
245 ___
246     $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
247         mov     $YY,$XX[1]
248         xor     $YY,$YY                         # keyword to partial register
249         mov     $XX[1]#b,$YY#b
250         lea     ($dat,$XX[0],4),$XX[1]
251 ___
252     $code.=<<___ if ($rc4 && $j==15);
253         psllq   \$8,%xmm1
254         pxor    %xmm0,%xmm2
255         pxor    %xmm1,%xmm2
256 ___
257 }
258 sub R1 {
259   my ($i,$a,$b,$c,$d)=@_;
260   my @rot1=(5,9,14,20);
261   my $j=$i%16;
262   my $k=$i%$MOD;
263   my $xmm="%xmm".($j&1);
264     $code.="    movdqu  16($in0),%xmm3\n"       if ($rc4 && $j==15);
265     $code.="    add     \$$MOD,$XX[0]#b\n"      if ($rc4 && $j==15 && $k==$MOD-1);
266     $code.="    pxor    $xmm,$xmm\n"            if ($rc4 && $j<=1);
267     $code.=<<___;
268 #rc4#   movl    ($dat,$YY,4),$TY#d
269 #md5#   xor     $b,$tmp
270 #rc4#   movl    $TX[0]#d,($dat,$YY,4)
271 #md5#   and     $d,$tmp
272 #md5#   add     4*`((1+5*$j)%16)`($inp),$a
273 #rc4#   add     $TY#b,$TX[0]#b
274 #rc4#   movl    `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
275 #md5#   add     \$$K[$i],$a
276 #md5#   xor     $c,$tmp
277 #rc4#   movz    $TX[0]#b,$TX[0]#d
278 #rc4#   movl    $TY#d,4*$k($XX[1])
279 #md5#   add     $tmp,$a
280 #rc4#   add     $TX[1]#b,$YY#b
281 #md5#   rol     \$$rot1[$j%4],$a
282 #md5#   mov     `$j==15?"$c":"$b"`,$tmp         # forward reference
283 #rc4#   pinsrw  \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
284 #md5#   add     $b,$a
285 ___
286     $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
287         mov     $YY,$XX[1]
288         xor     $YY,$YY                         # keyword to partial register
289         mov     $XX[1]#b,$YY#b
290         lea     ($dat,$XX[0],4),$XX[1]
291 ___
292     $code.=<<___ if ($rc4 && $j==15);
293         psllq   \$8,%xmm1
294         pxor    %xmm0,%xmm3
295         pxor    %xmm1,%xmm3
296 ___
297 }
298 sub R2 {
299   my ($i,$a,$b,$c,$d)=@_;
300   my @rot2=(4,11,16,23);
301   my $j=$i%16;
302   my $k=$i%$MOD;
303   my $xmm="%xmm".($j&1);
304     $code.="    movdqu  32($in0),%xmm4\n"       if ($rc4 && $j==15);
305     $code.="    add     \$$MOD,$XX[0]#b\n"      if ($rc4 && $j==15 && $k==$MOD-1);
306     $code.="    pxor    $xmm,$xmm\n"            if ($rc4 && $j<=1);
307     $code.=<<___;
308 #rc4#   movl    ($dat,$YY,4),$TY#d
309 #md5#   xor     $c,$tmp
310 #rc4#   movl    $TX[0]#d,($dat,$YY,4)
311 #md5#   xor     $b,$tmp
312 #md5#   add     4*`((5+3*$j)%16)`($inp),$a
313 #rc4#   add     $TY#b,$TX[0]#b
314 #rc4#   movl    `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
315 #md5#   add     \$$K[$i],$a
316 #rc4#   movz    $TX[0]#b,$TX[0]#d
317 #md5#   add     $tmp,$a
318 #rc4#   movl    $TY#d,4*$k($XX[1])
319 #rc4#   add     $TX[1]#b,$YY#b
320 #md5#   rol     \$$rot2[$j%4],$a
321 #md5#   mov     `$j==15?"\\\$-1":"$c"`,$tmp     # forward reference
322 #rc4#   pinsrw  \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
323 #md5#   add     $b,$a
324 ___
325     $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
326         mov     $YY,$XX[1]
327         xor     $YY,$YY                         # keyword to partial register
328         mov     $XX[1]#b,$YY#b
329         lea     ($dat,$XX[0],4),$XX[1]
330 ___
331     $code.=<<___ if ($rc4 && $j==15);
332         psllq   \$8,%xmm1
333         pxor    %xmm0,%xmm4
334         pxor    %xmm1,%xmm4
335 ___
336 }
337 sub R3 {
338   my ($i,$a,$b,$c,$d)=@_;
339   my @rot3=(6,10,15,21);
340   my $j=$i%16;
341   my $k=$i%$MOD;
342   my $xmm="%xmm".($j&1);
343     $code.="    movdqu  48($in0),%xmm5\n"       if ($rc4 && $j==15);
344     $code.="    add     \$$MOD,$XX[0]#b\n"      if ($rc4 && $j==15 && $k==$MOD-1);
345     $code.="    pxor    $xmm,$xmm\n"            if ($rc4 && $j<=1);
346     $code.=<<___;
347 #rc4#   movl    ($dat,$YY,4),$TY#d
348 #md5#   xor     $d,$tmp
349 #rc4#   movl    $TX[0]#d,($dat,$YY,4)
350 #md5#   or      $b,$tmp
351 #md5#   add     4*`((7*$j)%16)`($inp),$a
352 #rc4#   add     $TY#b,$TX[0]#b
353 #rc4#   movl    `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
354 #md5#   add     \$$K[$i],$a
355 #rc4#   movz    $TX[0]#b,$TX[0]#d
356 #md5#   xor     $c,$tmp
357 #rc4#   movl    $TY#d,4*$k($XX[1])
358 #md5#   add     $tmp,$a
359 #rc4#   add     $TX[1]#b,$YY#b
360 #md5#   rol     \$$rot3[$j%4],$a
361 #md5#   mov     \$-1,$tmp                       # forward reference
362 #rc4#   pinsrw  \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
363 #md5#   add     $b,$a
364 ___
365     $code.=<<___ if ($rc4 && $j==15);
366         mov     $XX[0],$XX[1]
367         xor     $XX[0],$XX[0]                   # keyword to partial register
368         mov     $XX[1]#b,$XX[0]#b
369         mov     $YY,$XX[1]
370         xor     $YY,$YY                         # keyword to partial register
371         mov     $XX[1]#b,$YY#b
372         lea     ($dat,$XX[0],4),$XX[1]
373         psllq   \$8,%xmm1
374         pxor    %xmm0,%xmm5
375         pxor    %xmm1,%xmm5
376 ___
377 }
378
379 my $i=0;
380 for(;$i<16;$i++) { R0($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
381 for(;$i<32;$i++) { R1($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
382 for(;$i<48;$i++) { R2($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
383 for(;$i<64;$i++) { R3($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
384
385 $code.=<<___;
386 #md5#   add     0*4(%rsp),$V[0]         # accumulate hash value
387 #md5#   add     1*4(%rsp),$V[1]
388 #md5#   add     2*4(%rsp),$V[2]
389 #md5#   add     3*4(%rsp),$V[3]
390
391 #rc4#   movdqu  %xmm2,($out,$in0)       # write RC4 output
392 #rc4#   movdqu  %xmm3,16($out,$in0)
393 #rc4#   movdqu  %xmm4,32($out,$in0)
394 #rc4#   movdqu  %xmm5,48($out,$in0)
395 #md5#   lea     64($inp),$inp
396 #rc4#   lea     64($in0),$in0
397         cmp     16(%rsp),$inp           # are we done?
398         jb      .Loop
399
400 #md5#   mov     24(%rsp),$len           # restore pointer to MD5_CTX
401 #rc4#   sub     $TX[0]#b,$YY#b          # correct $YY
402 #md5#   mov     $V[0],0*4($len)         # write MD5_CTX
403 #md5#   mov     $V[1],1*4($len)
404 #md5#   mov     $V[2],2*4($len)
405 #md5#   mov     $V[3],3*4($len)
406 ___
407 $code.=<<___ if ($rc4 && (!$md5 || $D));
408         mov     32(%rsp),$len           # restore original $len
409         and     \$63,$len               # remaining bytes
410         jnz     .Loop1
411         jmp     .Ldone
412         
413 .align  16
414 .Loop1:
415         add     $TX[0]#b,$YY#b
416         movl    ($dat,$YY,4),$TY#d
417         movl    $TX[0]#d,($dat,$YY,4)
418         movl    $TY#d,($dat,$XX[0],4)
419         add     $TY#b,$TX[0]#b
420         inc     $XX[0]#b
421         movl    ($dat,$TX[0],4),$TY#d
422         movl    ($dat,$XX[0],4),$TX[0]#d
423         xorb    ($in0),$TY#b
424         movb    $TY#b,($out,$in0)
425         lea     1($in0),$in0
426         dec     $len
427         jnz     .Loop1
428
429 .Ldone:
430 ___
431 $code.=<<___;
432 #rc4#   sub     \$1,$XX[0]#b
433 #rc4#   movl    $XX[0]#d,-8($dat)
434 #rc4#   movl    $YY#d,-4($dat)
435
436         mov     40(%rsp),%r15
437         mov     48(%rsp),%r14
438         mov     56(%rsp),%r13
439         mov     64(%rsp),%r12
440         mov     72(%rsp),%rbp
441         mov     80(%rsp),%rbx
442         lea     88(%rsp),%rsp
443 .Lepilogue:
444 .Labort:
445         ret
446 .size $func,.-$func
447 ___
448
449 if ($rc4 && $D) {       # sole purpose of this section is to provide
450                         # option to use the generated module as drop-in
451                         # replacement for rc4-x86_64.pl for debugging
452                         # and testing purposes...
453 my ($idx,$ido)=("%r8","%r9");
454 my ($dat,$len,$inp)=("%rdi","%rsi","%rdx");
455
456 $code.=<<___;
457 .globl  RC4_set_key
458 .type   RC4_set_key,\@function,3
459 .align  16
460 RC4_set_key:
461         lea     8($dat),$dat
462         lea     ($inp,$len),$inp
463         neg     $len
464         mov     $len,%rcx
465         xor     %eax,%eax
466         xor     $ido,$ido
467         xor     %r10,%r10
468         xor     %r11,%r11
469         jmp     .Lw1stloop
470
471 .align  16
472 .Lw1stloop:
473         mov     %eax,($dat,%rax,4)
474         add     \$1,%al
475         jnc     .Lw1stloop
476
477         xor     $ido,$ido
478         xor     $idx,$idx
479 .align  16
480 .Lw2ndloop:
481         mov     ($dat,$ido,4),%r10d
482         add     ($inp,$len,1),$idx#b
483         add     %r10b,$idx#b
484         add     \$1,$len
485         mov     ($dat,$idx,4),%r11d
486         cmovz   %rcx,$len
487         mov     %r10d,($dat,$idx,4)
488         mov     %r11d,($dat,$ido,4)
489         add     \$1,$ido#b
490         jnc     .Lw2ndloop
491
492         xor     %eax,%eax
493         mov     %eax,-8($dat)
494         mov     %eax,-4($dat)
495         ret
496 .size   RC4_set_key,.-RC4_set_key
497
498 .globl  RC4_options
499 .type   RC4_options,\@abi-omnipotent
500 .align  16
501 RC4_options:
502         lea     .Lopts(%rip),%rax
503         ret
504 .align  64
505 .Lopts:
506 .asciz  "rc4(64x,int)"
507 .align  64
508 .size   RC4_options,.-RC4_options
509 ___
510 }
511 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
512 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
513 if ($win64) {
514 my $rec="%rcx";
515 my $frame="%rdx";
516 my $context="%r8";
517 my $disp="%r9";
518
519 $code.=<<___;
520 .extern __imp_RtlVirtualUnwind
521 .type   se_handler,\@abi-omnipotent
522 .align  16
523 se_handler:
524         push    %rsi
525         push    %rdi
526         push    %rbx
527         push    %rbp
528         push    %r12
529         push    %r13
530         push    %r14
531         push    %r15
532         pushfq
533         sub     \$64,%rsp
534
535         mov     120($context),%rax      # pull context->Rax
536         mov     248($context),%rbx      # pull context->Rip
537
538         lea     .Lbody(%rip),%r10
539         cmp     %r10,%rbx               # context->Rip<.Lbody
540         jb      .Lin_prologue
541
542         mov     152($context),%rax      # pull context->Rsp
543
544         lea     .Lepilogue(%rip),%r10
545         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
546         jae     .Lin_prologue
547
548         mov     40(%rax),%r15
549         mov     48(%rax),%r14
550         mov     56(%rax),%r13
551         mov     64(%rax),%r12
552         mov     72(%rax),%rbp
553         mov     80(%rax),%rbx
554         lea     88(%rax),%rax
555
556         mov     %rbx,144($context)      # restore context->Rbx
557         mov     %rbp,160($context)      # restore context->Rbp
558         mov     %r12,216($context)      # restore context->R12
559         mov     %r13,224($context)      # restore context->R12
560         mov     %r14,232($context)      # restore context->R14
561         mov     %r15,240($context)      # restore context->R15
562
563 .Lin_prologue:
564         mov     8(%rax),%rdi
565         mov     16(%rax),%rsi
566         mov     %rax,152($context)      # restore context->Rsp
567         mov     %rsi,168($context)      # restore context->Rsi
568         mov     %rdi,176($context)      # restore context->Rdi
569
570         mov     40($disp),%rdi          # disp->ContextRecord
571         mov     $context,%rsi           # context
572         mov     \$154,%ecx              # sizeof(CONTEXT)
573         .long   0xa548f3fc              # cld; rep movsq
574
575         mov     $disp,%rsi
576         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
577         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
578         mov     0(%rsi),%r8             # arg3, disp->ControlPc
579         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
580         mov     40(%rsi),%r10           # disp->ContextRecord
581         lea     56(%rsi),%r11           # &disp->HandlerData
582         lea     24(%rsi),%r12           # &disp->EstablisherFrame
583         mov     %r10,32(%rsp)           # arg5
584         mov     %r11,40(%rsp)           # arg6
585         mov     %r12,48(%rsp)           # arg7
586         mov     %rcx,56(%rsp)           # arg8, (NULL)
587         call    *__imp_RtlVirtualUnwind(%rip)
588
589         mov     \$1,%eax                # ExceptionContinueSearch
590         add     \$64,%rsp
591         popfq
592         pop     %r15
593         pop     %r14
594         pop     %r13
595         pop     %r12
596         pop     %rbp
597         pop     %rbx
598         pop     %rdi
599         pop     %rsi
600         ret
601 .size   se_handler,.-se_handler
602
603 .section        .pdata
604 .align  4
605         .rva    .LSEH_begin_$func
606         .rva    .LSEH_end_$func
607         .rva    .LSEH_info_$func
608
609 .section        .xdata
610 .align  8
611 .LSEH_info_$func:
612         .byte   9,0,0,0
613         .rva    se_handler
614 ___
615 }
616
617 sub reg_part {
618 my ($reg,$conv)=@_;
619     if ($reg =~ /%r[0-9]+/)     { $reg .= $conv; }
620     elsif ($conv eq "b")        { $reg =~ s/%[er]([^x]+)x?/%$1l/;       }
621     elsif ($conv eq "w")        { $reg =~ s/%[er](.+)/%$1/;             }
622     elsif ($conv eq "d")        { $reg =~ s/%[er](.+)/%e$1/;            }
623     return $reg;
624 }
625
626 $code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
627 $code =~ s/\`([^\`]*)\`/eval $1/gem;
628 $code =~ s/pinsrw\s+\$0,/movd   /gm;
629
630 $code =~ s/#md5#//gm    if ($md5);
631 $code =~ s/#rc4#//gm    if ($rc4);
632
633 print $code;
634
635 close STDOUT;