9ccb70eeb47b98e0f61ce560adbd2739951fd22a
[openssl.git] / crypto / rc4 / asm / rc4-x86_64.pl
1 #! /usr/bin/env perl
2 # Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 #
10 # ====================================================================
11 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
12 # project. The module is, however, dual licensed under OpenSSL and
13 # CRYPTOGAMS licenses depending on where you obtain it. For further
14 # details see http://www.openssl.org/~appro/cryptogams/.
15 # ====================================================================
16 #
17 # July 2004
18 #
19 # 2.22x RC4 tune-up:-) It should be noted though that my hand [as in
20 # "hand-coded assembler"] doesn't stand for the whole improvement
21 # coefficient. It turned out that eliminating RC4_CHAR from config
22 # line results in ~40% improvement (yes, even for C implementation).
23 # Presumably it has everything to do with AMD cache architecture and
24 # RAW or whatever penalties. Once again! The module *requires* config
25 # line *without* RC4_CHAR! As for coding "secret," I bet on partial
26 # register arithmetics. For example instead of 'inc %r8; and $255,%r8'
27 # I simply 'inc %r8b'. Even though optimization manual discourages
28 # to operate on partial registers, it turned out to be the best bet.
29 # At least for AMD... How IA32E would perform remains to be seen...
30
31 # November 2004
32 #
33 # As was shown by Marc Bevand reordering of couple of load operations
34 # results in even higher performance gain of 3.3x:-) At least on
35 # Opteron... For reference, 1x in this case is RC4_CHAR C-code
36 # compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock.
37 # Latter means that if you want to *estimate* what to expect from
38 # *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz.
39
40 # November 2004
41 #
42 # Intel P4 EM64T core was found to run the AMD64 code really slow...
43 # The only way to achieve comparable performance on P4 was to keep
44 # RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to
45 # compose blended code, which would perform even within 30% marginal
46 # on either AMD and Intel platforms, I implement both cases. See
47 # rc4_skey.c for further details...
48
49 # April 2005
50 #
51 # P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing
52 # those with add/sub results in 50% performance improvement of folded
53 # loop...
54
55 # May 2005
56 #
57 # As was shown by Zou Nanhai loop unrolling can improve Intel EM64T
58 # performance by >30% [unlike P4 32-bit case that is]. But this is
59 # provided that loads are reordered even more aggressively! Both code
60 # paths, AMD64 and EM64T, reorder loads in essentially same manner
61 # as my IA-64 implementation. On Opteron this resulted in modest 5%
62 # improvement [I had to test it], while final Intel P4 performance
63 # achieves respectful 432MBps on 2.8GHz processor now. For reference.
64 # If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than
65 # RC4_INT code-path. While if executed on Opteron, it's only 25%
66 # slower than the RC4_INT one [meaning that if CPU ยต-arch detection
67 # is not implemented, then this final RC4_CHAR code-path should be
68 # preferred, as it provides better *all-round* performance].
69
70 # March 2007
71 #
72 # Intel Core2 was observed to perform poorly on both code paths:-( It
73 # apparently suffers from some kind of partial register stall, which
74 # occurs in 64-bit mode only [as virtually identical 32-bit loop was
75 # observed to outperform 64-bit one by almost 50%]. Adding two movzb to
76 # cloop1 boosts its performance by 80%! This loop appears to be optimal
77 # fit for Core2 and therefore the code was modified to skip cloop8 on
78 # this CPU.
79
80 # May 2010
81 #
82 # Intel Westmere was observed to perform suboptimally. Adding yet
83 # another movzb to cloop1 improved performance by almost 50%! Core2
84 # performance is improved too, but nominally...
85
86 # May 2011
87 #
88 # The only code path that was not modified is P4-specific one. Non-P4
89 # Intel code path optimization is heavily based on submission by Maxim
90 # Perminov, Maxim Locktyukhin and Jim Guilford of Intel. I've used
91 # some of the ideas even in attempt to optmize the original RC4_INT
92 # code path... Current performance in cycles per processed byte (less
93 # is better) and improvement coefficients relative to previous
94 # version of this module are:
95 #
96 # Opteron       5.3/+0%(*)
97 # P4            6.5
98 # Core2         6.2/+15%(**)
99 # Westmere      4.2/+60%
100 # Sandy Bridge  4.2/+120%
101 # Atom          9.3/+80%
102 # VIA Nano      6.4/+4%
103 # Ivy Bridge    4.1/+30%
104 # Bulldozer     4.5/+30%(*)
105 #
106 # (*)   But corresponding loop has less instructions, which should have
107 #       positive effect on upcoming Bulldozer, which has one less ALU.
108 #       For reference, Intel code runs at 6.8 cpb rate on Opteron.
109 # (**)  Note that Core2 result is ~15% lower than corresponding result
110 #       for 32-bit code, meaning that it's possible to improve it,
111 #       but more than likely at the cost of the others (see rc4-586.pl
112 #       to get the idea)...
113
114 $flavour = shift;
115 $output  = shift;
116 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
117
118 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
119
120 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
121 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
122 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
123 die "can't locate x86_64-xlate.pl";
124
125 open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
126 *STDOUT=*OUT;
127
128 $dat="%rdi";        # arg1
129 $len="%rsi";        # arg2
130 $inp="%rdx";        # arg3
131 $out="%rcx";        # arg4
132
133 {
134 $code=<<___;
135 .text
136 .extern OPENSSL_ia32cap_P
137
138 .globl  RC4
139 .type   RC4,\@function,4
140 .align  16
141 RC4:    or      $len,$len
142         jne     .Lentry
143         ret
144 .Lentry:
145 .cfi_startproc
146         push    %rbx
147 .cfi_push       %rbx
148         push    %r12
149 .cfi_push       %r12
150         push    %r13
151 .cfi_push       %r13
152 .Lprologue:
153         mov     $len,%r11
154         mov     $inp,%r12
155         mov     $out,%r13
156 ___
157 my $len="%r11";         # reassign input arguments
158 my $inp="%r12";
159 my $out="%r13";
160
161 my @XX=("%r10","%rsi");
162 my @TX=("%rax","%rbx");
163 my $YY="%rcx";
164 my $TY="%rdx";
165
166 $code.=<<___;
167         xor     $XX[0],$XX[0]
168         xor     $YY,$YY
169
170         lea     8($dat),$dat
171         mov     -8($dat),$XX[0]#b
172         mov     -4($dat),$YY#b
173         cmpl    \$-1,256($dat)
174         je      .LRC4_CHAR
175         mov     OPENSSL_ia32cap_P(%rip),%r8d
176         xor     $TX[1],$TX[1]
177         inc     $XX[0]#b
178         sub     $XX[0],$TX[1]
179         sub     $inp,$out
180         movl    ($dat,$XX[0],4),$TX[0]#d
181         test    \$-16,$len
182         jz      .Lloop1
183         bt      \$30,%r8d       # Intel CPU?
184         jc      .Lintel
185         and     \$7,$TX[1]
186         lea     1($XX[0]),$XX[1]
187         jz      .Loop8
188         sub     $TX[1],$len
189 .Loop8_warmup:
190         add     $TX[0]#b,$YY#b
191         movl    ($dat,$YY,4),$TY#d
192         movl    $TX[0]#d,($dat,$YY,4)
193         movl    $TY#d,($dat,$XX[0],4)
194         add     $TY#b,$TX[0]#b
195         inc     $XX[0]#b
196         movl    ($dat,$TX[0],4),$TY#d
197         movl    ($dat,$XX[0],4),$TX[0]#d
198         xorb    ($inp),$TY#b
199         movb    $TY#b,($out,$inp)
200         lea     1($inp),$inp
201         dec     $TX[1]
202         jnz     .Loop8_warmup
203
204         lea     1($XX[0]),$XX[1]
205         jmp     .Loop8
206 .align  16
207 .Loop8:
208 ___
209 for ($i=0;$i<8;$i++) {
210 $code.=<<___ if ($i==7);
211         add     \$8,$XX[1]#b
212 ___
213 $code.=<<___;
214         add     $TX[0]#b,$YY#b
215         movl    ($dat,$YY,4),$TY#d
216         movl    $TX[0]#d,($dat,$YY,4)
217         movl    `4*($i==7?-1:$i)`($dat,$XX[1],4),$TX[1]#d
218         ror     \$8,%r8                         # ror is redundant when $i=0
219         movl    $TY#d,4*$i($dat,$XX[0],4)
220         add     $TX[0]#b,$TY#b
221         movb    ($dat,$TY,4),%r8b
222 ___
223 push(@TX,shift(@TX)); #push(@XX,shift(@XX));    # "rotate" registers
224 }
225 $code.=<<___;
226         add     \$8,$XX[0]#b
227         ror     \$8,%r8
228         sub     \$8,$len
229
230         xor     ($inp),%r8
231         mov     %r8,($out,$inp)
232         lea     8($inp),$inp
233
234         test    \$-8,$len
235         jnz     .Loop8
236         cmp     \$0,$len
237         jne     .Lloop1
238         jmp     .Lexit
239
240 .align  16
241 .Lintel:
242         test    \$-32,$len
243         jz      .Lloop1
244         and     \$15,$TX[1]
245         jz      .Loop16_is_hot
246         sub     $TX[1],$len
247 .Loop16_warmup:
248         add     $TX[0]#b,$YY#b
249         movl    ($dat,$YY,4),$TY#d
250         movl    $TX[0]#d,($dat,$YY,4)
251         movl    $TY#d,($dat,$XX[0],4)
252         add     $TY#b,$TX[0]#b
253         inc     $XX[0]#b
254         movl    ($dat,$TX[0],4),$TY#d
255         movl    ($dat,$XX[0],4),$TX[0]#d
256         xorb    ($inp),$TY#b
257         movb    $TY#b,($out,$inp)
258         lea     1($inp),$inp
259         dec     $TX[1]
260         jnz     .Loop16_warmup
261
262         mov     $YY,$TX[1]
263         xor     $YY,$YY
264         mov     $TX[1]#b,$YY#b
265
266 .Loop16_is_hot:
267         lea     ($dat,$XX[0],4),$XX[1]
268 ___
269 sub RC4_loop {
270   my $i=shift;
271   my $j=$i<0?0:$i;
272   my $xmm="%xmm".($j&1);
273
274     $code.="    add     \$16,$XX[0]#b\n"                if ($i==15);
275     $code.="    movdqu  ($inp),%xmm2\n"                 if ($i==15);
276     $code.="    add     $TX[0]#b,$YY#b\n"               if ($i<=0);
277     $code.="    movl    ($dat,$YY,4),$TY#d\n";
278     $code.="    pxor    %xmm0,%xmm2\n"                  if ($i==0);
279     $code.="    psllq   \$8,%xmm1\n"                    if ($i==0);
280     $code.="    pxor    $xmm,$xmm\n"                    if ($i<=1);
281     $code.="    movl    $TX[0]#d,($dat,$YY,4)\n";
282     $code.="    add     $TY#b,$TX[0]#b\n";
283     $code.="    movl    `4*($j+1)`($XX[1]),$TX[1]#d\n"  if ($i<15);
284     $code.="    movz    $TX[0]#b,$TX[0]#d\n";
285     $code.="    movl    $TY#d,4*$j($XX[1])\n";
286     $code.="    pxor    %xmm1,%xmm2\n"                  if ($i==0);
287     $code.="    lea     ($dat,$XX[0],4),$XX[1]\n"       if ($i==15);
288     $code.="    add     $TX[1]#b,$YY#b\n"               if ($i<15);
289     $code.="    pinsrw  \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n";
290     $code.="    movdqu  %xmm2,($out,$inp)\n"            if ($i==0);
291     $code.="    lea     16($inp),$inp\n"                if ($i==0);
292     $code.="    movl    ($XX[1]),$TX[1]#d\n"            if ($i==15);
293 }
294         RC4_loop(-1);
295 $code.=<<___;
296         jmp     .Loop16_enter
297 .align  16
298 .Loop16:
299 ___
300
301 for ($i=0;$i<16;$i++) {
302     $code.=".Loop16_enter:\n"           if ($i==1);
303         RC4_loop($i);
304         push(@TX,shift(@TX));           # "rotate" registers
305 }
306 $code.=<<___;
307         mov     $YY,$TX[1]
308         xor     $YY,$YY                 # keyword to partial register
309         sub     \$16,$len
310         mov     $TX[1]#b,$YY#b
311         test    \$-16,$len
312         jnz     .Loop16
313
314         psllq   \$8,%xmm1
315         pxor    %xmm0,%xmm2
316         pxor    %xmm1,%xmm2
317         movdqu  %xmm2,($out,$inp)
318         lea     16($inp),$inp
319
320         cmp     \$0,$len
321         jne     .Lloop1
322         jmp     .Lexit
323
324 .align  16
325 .Lloop1:
326         add     $TX[0]#b,$YY#b
327         movl    ($dat,$YY,4),$TY#d
328         movl    $TX[0]#d,($dat,$YY,4)
329         movl    $TY#d,($dat,$XX[0],4)
330         add     $TY#b,$TX[0]#b
331         inc     $XX[0]#b
332         movl    ($dat,$TX[0],4),$TY#d
333         movl    ($dat,$XX[0],4),$TX[0]#d
334         xorb    ($inp),$TY#b
335         movb    $TY#b,($out,$inp)
336         lea     1($inp),$inp
337         dec     $len
338         jnz     .Lloop1
339         jmp     .Lexit
340
341 .align  16
342 .LRC4_CHAR:
343         add     \$1,$XX[0]#b
344         movzb   ($dat,$XX[0]),$TX[0]#d
345         test    \$-8,$len
346         jz      .Lcloop1
347         jmp     .Lcloop8
348 .align  16
349 .Lcloop8:
350         mov     ($inp),%r8d
351         mov     4($inp),%r9d
352 ___
353 # unroll 2x4-wise, because 64-bit rotates kill Intel P4...
354 for ($i=0;$i<4;$i++) {
355 $code.=<<___;
356         add     $TX[0]#b,$YY#b
357         lea     1($XX[0]),$XX[1]
358         movzb   ($dat,$YY),$TY#d
359         movzb   $XX[1]#b,$XX[1]#d
360         movzb   ($dat,$XX[1]),$TX[1]#d
361         movb    $TX[0]#b,($dat,$YY)
362         cmp     $XX[1],$YY
363         movb    $TY#b,($dat,$XX[0])
364         jne     .Lcmov$i                        # Intel cmov is sloooow...
365         mov     $TX[0],$TX[1]
366 .Lcmov$i:
367         add     $TX[0]#b,$TY#b
368         xor     ($dat,$TY),%r8b
369         ror     \$8,%r8d
370 ___
371 push(@TX,shift(@TX)); push(@XX,shift(@XX));     # "rotate" registers
372 }
373 for ($i=4;$i<8;$i++) {
374 $code.=<<___;
375         add     $TX[0]#b,$YY#b
376         lea     1($XX[0]),$XX[1]
377         movzb   ($dat,$YY),$TY#d
378         movzb   $XX[1]#b,$XX[1]#d
379         movzb   ($dat,$XX[1]),$TX[1]#d
380         movb    $TX[0]#b,($dat,$YY)
381         cmp     $XX[1],$YY
382         movb    $TY#b,($dat,$XX[0])
383         jne     .Lcmov$i                        # Intel cmov is sloooow...
384         mov     $TX[0],$TX[1]
385 .Lcmov$i:
386         add     $TX[0]#b,$TY#b
387         xor     ($dat,$TY),%r9b
388         ror     \$8,%r9d
389 ___
390 push(@TX,shift(@TX)); push(@XX,shift(@XX));     # "rotate" registers
391 }
392 $code.=<<___;
393         lea     -8($len),$len
394         mov     %r8d,($out)
395         lea     8($inp),$inp
396         mov     %r9d,4($out)
397         lea     8($out),$out
398
399         test    \$-8,$len
400         jnz     .Lcloop8
401         cmp     \$0,$len
402         jne     .Lcloop1
403         jmp     .Lexit
404 ___
405 $code.=<<___;
406 .align  16
407 .Lcloop1:
408         add     $TX[0]#b,$YY#b
409         movzb   $YY#b,$YY#d
410         movzb   ($dat,$YY),$TY#d
411         movb    $TX[0]#b,($dat,$YY)
412         movb    $TY#b,($dat,$XX[0])
413         add     $TX[0]#b,$TY#b
414         add     \$1,$XX[0]#b
415         movzb   $TY#b,$TY#d
416         movzb   $XX[0]#b,$XX[0]#d
417         movzb   ($dat,$TY),$TY#d
418         movzb   ($dat,$XX[0]),$TX[0]#d
419         xorb    ($inp),$TY#b
420         lea     1($inp),$inp
421         movb    $TY#b,($out)
422         lea     1($out),$out
423         sub     \$1,$len
424         jnz     .Lcloop1
425         jmp     .Lexit
426
427 .align  16
428 .Lexit:
429         sub     \$1,$XX[0]#b
430         movl    $XX[0]#d,-8($dat)
431         movl    $YY#d,-4($dat)
432
433         mov     (%rsp),%r13
434 .cfi_restore    %r13
435         mov     8(%rsp),%r12
436 .cfi_restore    %r12
437         mov     16(%rsp),%rbx
438 .cfi_restore    %rbx
439         add     \$24,%rsp
440 .cfi_adjust_cfa_offset  -24
441 .Lepilogue:
442         ret
443 .cfi_endproc
444 .size   RC4,.-RC4
445 ___
446 }
447
448 $idx="%r8";
449 $ido="%r9";
450
451 $code.=<<___;
452 .globl  RC4_set_key
453 .type   RC4_set_key,\@function,3
454 .align  16
455 RC4_set_key:
456         lea     8($dat),$dat
457         lea     ($inp,$len),$inp
458         neg     $len
459         mov     $len,%rcx
460         xor     %eax,%eax
461         xor     $ido,$ido
462         xor     %r10,%r10
463         xor     %r11,%r11
464
465         mov     OPENSSL_ia32cap_P(%rip),$idx#d
466         bt      \$20,$idx#d     # RC4_CHAR?
467         jc      .Lc1stloop
468         jmp     .Lw1stloop
469
470 .align  16
471 .Lw1stloop:
472         mov     %eax,($dat,%rax,4)
473         add     \$1,%al
474         jnc     .Lw1stloop
475
476         xor     $ido,$ido
477         xor     $idx,$idx
478 .align  16
479 .Lw2ndloop:
480         mov     ($dat,$ido,4),%r10d
481         add     ($inp,$len,1),$idx#b
482         add     %r10b,$idx#b
483         add     \$1,$len
484         mov     ($dat,$idx,4),%r11d
485         cmovz   %rcx,$len
486         mov     %r10d,($dat,$idx,4)
487         mov     %r11d,($dat,$ido,4)
488         add     \$1,$ido#b
489         jnc     .Lw2ndloop
490         jmp     .Lexit_key
491
492 .align  16
493 .Lc1stloop:
494         mov     %al,($dat,%rax)
495         add     \$1,%al
496         jnc     .Lc1stloop
497
498         xor     $ido,$ido
499         xor     $idx,$idx
500 .align  16
501 .Lc2ndloop:
502         mov     ($dat,$ido),%r10b
503         add     ($inp,$len),$idx#b
504         add     %r10b,$idx#b
505         add     \$1,$len
506         mov     ($dat,$idx),%r11b
507         jnz     .Lcnowrap
508         mov     %rcx,$len
509 .Lcnowrap:
510         mov     %r10b,($dat,$idx)
511         mov     %r11b,($dat,$ido)
512         add     \$1,$ido#b
513         jnc     .Lc2ndloop
514         movl    \$-1,256($dat)
515
516 .align  16
517 .Lexit_key:
518         xor     %eax,%eax
519         mov     %eax,-8($dat)
520         mov     %eax,-4($dat)
521         ret
522 .size   RC4_set_key,.-RC4_set_key
523
524 .globl  RC4_options
525 .type   RC4_options,\@abi-omnipotent
526 .align  16
527 RC4_options:
528         lea     .Lopts(%rip),%rax
529         mov     OPENSSL_ia32cap_P(%rip),%edx
530         bt      \$20,%edx
531         jc      .L8xchar
532         bt      \$30,%edx
533         jnc     .Ldone
534         add     \$25,%rax
535         ret
536 .L8xchar:
537         add     \$12,%rax
538 .Ldone:
539         ret
540 .align  64
541 .Lopts:
542 .asciz  "rc4(8x,int)"
543 .asciz  "rc4(8x,char)"
544 .asciz  "rc4(16x,int)"
545 .asciz  "RC4 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
546 .align  64
547 .size   RC4_options,.-RC4_options
548 ___
549
550 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
551 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
552 if ($win64) {
553 $rec="%rcx";
554 $frame="%rdx";
555 $context="%r8";
556 $disp="%r9";
557
558 $code.=<<___;
559 .extern __imp_RtlVirtualUnwind
560 .type   stream_se_handler,\@abi-omnipotent
561 .align  16
562 stream_se_handler:
563         push    %rsi
564         push    %rdi
565         push    %rbx
566         push    %rbp
567         push    %r12
568         push    %r13
569         push    %r14
570         push    %r15
571         pushfq
572         sub     \$64,%rsp
573
574         mov     120($context),%rax      # pull context->Rax
575         mov     248($context),%rbx      # pull context->Rip
576
577         lea     .Lprologue(%rip),%r10
578         cmp     %r10,%rbx               # context->Rip<prologue label
579         jb      .Lin_prologue
580
581         mov     152($context),%rax      # pull context->Rsp
582
583         lea     .Lepilogue(%rip),%r10
584         cmp     %r10,%rbx               # context->Rip>=epilogue label
585         jae     .Lin_prologue
586
587         lea     24(%rax),%rax
588
589         mov     -8(%rax),%rbx
590         mov     -16(%rax),%r12
591         mov     -24(%rax),%r13
592         mov     %rbx,144($context)      # restore context->Rbx
593         mov     %r12,216($context)      # restore context->R12
594         mov     %r13,224($context)      # restore context->R13
595
596 .Lin_prologue:
597         mov     8(%rax),%rdi
598         mov     16(%rax),%rsi
599         mov     %rax,152($context)      # restore context->Rsp
600         mov     %rsi,168($context)      # restore context->Rsi
601         mov     %rdi,176($context)      # restore context->Rdi
602
603         jmp     .Lcommon_seh_exit
604 .size   stream_se_handler,.-stream_se_handler
605
606 .type   key_se_handler,\@abi-omnipotent
607 .align  16
608 key_se_handler:
609         push    %rsi
610         push    %rdi
611         push    %rbx
612         push    %rbp
613         push    %r12
614         push    %r13
615         push    %r14
616         push    %r15
617         pushfq
618         sub     \$64,%rsp
619
620         mov     152($context),%rax      # pull context->Rsp
621         mov     8(%rax),%rdi
622         mov     16(%rax),%rsi
623         mov     %rsi,168($context)      # restore context->Rsi
624         mov     %rdi,176($context)      # restore context->Rdi
625
626 .Lcommon_seh_exit:
627
628         mov     40($disp),%rdi          # disp->ContextRecord
629         mov     $context,%rsi           # context
630         mov     \$154,%ecx              # sizeof(CONTEXT)
631         .long   0xa548f3fc              # cld; rep movsq
632
633         mov     $disp,%rsi
634         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
635         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
636         mov     0(%rsi),%r8             # arg3, disp->ControlPc
637         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
638         mov     40(%rsi),%r10           # disp->ContextRecord
639         lea     56(%rsi),%r11           # &disp->HandlerData
640         lea     24(%rsi),%r12           # &disp->EstablisherFrame
641         mov     %r10,32(%rsp)           # arg5
642         mov     %r11,40(%rsp)           # arg6
643         mov     %r12,48(%rsp)           # arg7
644         mov     %rcx,56(%rsp)           # arg8, (NULL)
645         call    *__imp_RtlVirtualUnwind(%rip)
646
647         mov     \$1,%eax                # ExceptionContinueSearch
648         add     \$64,%rsp
649         popfq
650         pop     %r15
651         pop     %r14
652         pop     %r13
653         pop     %r12
654         pop     %rbp
655         pop     %rbx
656         pop     %rdi
657         pop     %rsi
658         ret
659 .size   key_se_handler,.-key_se_handler
660
661 .section        .pdata
662 .align  4
663         .rva    .LSEH_begin_RC4
664         .rva    .LSEH_end_RC4
665         .rva    .LSEH_info_RC4
666
667         .rva    .LSEH_begin_RC4_set_key
668         .rva    .LSEH_end_RC4_set_key
669         .rva    .LSEH_info_RC4_set_key
670
671 .section        .xdata
672 .align  8
673 .LSEH_info_RC4:
674         .byte   9,0,0,0
675         .rva    stream_se_handler
676 .LSEH_info_RC4_set_key:
677         .byte   9,0,0,0
678         .rva    key_se_handler
679 ___
680 }
681
682 sub reg_part {
683 my ($reg,$conv)=@_;
684     if ($reg =~ /%r[0-9]+/)     { $reg .= $conv; }
685     elsif ($conv eq "b")        { $reg =~ s/%[er]([^x]+)x?/%$1l/;       }
686     elsif ($conv eq "w")        { $reg =~ s/%[er](.+)/%$1/;             }
687     elsif ($conv eq "d")        { $reg =~ s/%[er](.+)/%e$1/;            }
688     return $reg;
689 }
690
691 $code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
692 $code =~ s/\`([^\`]*)\`/eval $1/gem;
693
694 print $code;
695
696 close STDOUT;