# Copyright (c) 2018, Amazon Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#
# Written by Nir Drucker, and Shay Gueron
# AWS Cryptographic Algorithms Group
# (ndrucker@amazon.com, gueron@amazon.com)
# based on BN_mod_inverse_odd

# 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."; }

$flavour = shift;
$output  = shift;

$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);

$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";

$avx = 2;
for (@ARGV) { $avx = 0 if (/-DMY_ASSEMBLER_IS_TOO_OLD_FOR_AVX/); }

open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;

#############################################################################
# extern int beeu_mod_inverse_vartime(BN_ULONG out[P256_LIMBS],
#                                     BN_ULONG a[P256_LIMBS],
#                                     BN_ULONG n[P256_LIMBS]);
#
# (Binary Extended Euclidean Algorithm.
#  See https://en.wikipedia.org/wiki/Binary_GCD_algorithm)
#
# Assumption 1: n is odd for the BEEU
# Assumption 2: 1 < a < n < 2^256

$out = "%rdi";
$a = "%rsi";
$n = "%rdx";

# X/Y will hold the inverse parameter
# Assumption: X,Y<2^(256)
$x0 = "%r8";
$x1 = "%r9";
$x2 = "%r10";
$x3 = "%r11";
# borrow from out (out is needed only at the end)
$x4 = "%rdi";
$y0 = "%r12";
$y1 = "%r13";
$y2 = "%r14";
$y3 = "%r15";
$y4 = "%rbp";
$shift = "%rcx";
$t0 = "%rax";
$t1 = "%rbx";
$t2 = "%rsi";
# borrow
$t3 = "%rcx";

$T0 = "%xmm0";
$T1 = "%xmm1";

# Offsets on the stack
$out_rsp = 0;
$shift_rsp = $out_rsp+0x8;
$a_rsp0 = $shift_rsp+0x8;
$a_rsp1 = $a_rsp0+0x8;
$a_rsp2 = $a_rsp1+0x8;
$a_rsp3 = $a_rsp2+0x8;
$b_rsp0 = $a_rsp3+0x8;
$b_rsp1 = $b_rsp0+0x8;
$b_rsp2 = $b_rsp1+0x8;
$b_rsp3 = $b_rsp2+0x8;

# Borrow when a_rsp/b_rsp are no longer needed.
$y_rsp0 = $a_rsp0;
$y_rsp1 = $y_rsp0+0x8;
$y_rsp2 = $y_rsp1+0x8;
$y_rsp3 = $y_rsp2+0x8;
$y_rsp4 = $y_rsp3+0x8;
$last_rsp_offset = $b_rsp3+0x8;

sub TEST_B_ZERO {
  return <<___;
    xorq $t1, $t1
    or $b_rsp0(%rsp), $t1
    or $b_rsp1(%rsp), $t1
    or $b_rsp2(%rsp), $t1
    or $b_rsp3(%rsp), $t1
    jz .Lbeeu_loop_end
___
}

$g_next_label = 0;

sub SHIFT1 {
  my ($var0, $var1, $var2, $var3, $var4) = @_;
  my $label = ".Lshift1_${g_next_label}";
  $g_next_label++;

  return <<___;
    # Ensure X is even and divide by two.
    movq \$1, $t1
    andq $var0, $t1
    jz $label
    add 0*8($n), $var0
    adc 1*8($n), $var1
    adc 2*8($n), $var2
    adc 3*8($n), $var3
    adc \$0, $var4

$label:
    shrdq \$1, $var1, $var0
    shrdq \$1, $var2, $var1
    shrdq \$1, $var3, $var2
    shrdq \$1, $var4, $var3
    shrq  \$1, $var4
___
}

sub SHIFT256 {
  my ($var) = @_;
  return <<___;
    # Copy shifted values.
    # Remember not to override t3=rcx
    movq 1*8+$var(%rsp), $t0
    movq 2*8+$var(%rsp), $t1
    movq 3*8+$var(%rsp), $t2

    shrdq %cl, $t0, 0*8+$var(%rsp)
    shrdq %cl, $t1, 1*8+$var(%rsp)
    shrdq %cl, $t2, 2*8+$var(%rsp)

    shrq  %cl, $t2
    mov $t2, 3*8+$var(%rsp)
___
}

$code.=<<___  if($avx);
.text

.type beeu_mod_inverse_vartime,\@function
.hidden beeu_mod_inverse_vartime
.globl  beeu_mod_inverse_vartime
.align 32
beeu_mod_inverse_vartime:
.cfi_startproc
    push %rbp
.cfi_push rbp
    push %r12
.cfi_push r12
    push %r13
.cfi_push r13
    push %r14
.cfi_push r14
    push %r15
.cfi_push r15
    push %rbx
.cfi_push rbx
    push %rsi
.cfi_push rsi

    sub \$$last_rsp_offset, %rsp
.cfi_adjust_cfa_offset  $last_rsp_offset
    movq $out, $out_rsp(%rsp)

    # X=1, Y=0
    movq \$1, $x0
    xorq $x1, $x1
    xorq $x2, $x2
    xorq $x3, $x3
    xorq $x4, $x4

    xorq $y0, $y0
    xorq $y1, $y1
    xorq $y2, $y2
    xorq $y3, $y3
    xorq $y4, $y4

    # Copy a/n into B/A on the stack.
    vmovdqu 0*8($a), $T0
    vmovdqu 2*8($a), $T1
    vmovdqu $T0, $b_rsp0(%rsp)
    vmovdqu $T1, $b_rsp2(%rsp)

    vmovdqu 0*8($n), $T0
    vmovdqu 2*8($n), $T1
    vmovdqu $T0, $a_rsp0(%rsp)
    vmovdqu $T1, $a_rsp2(%rsp)

.Lbeeu_loop:
    ${\TEST_B_ZERO}

    # 0 < B < |n|,
    # 0 < A <= |n|,
    # (1)      X*a  ==  B   (mod |n|),
    # (2) (-1)*Y*a  ==  A   (mod |n|)

    # Now divide B by the maximum possible power of two in the
    # integers, and divide X by the same value mod |n|. When we're
    # done, (1) still holds.
    movq \$1, $shift

    # Note that B > 0
.Lbeeu_shift_loop_XB:
    movq $shift, $t1
    andq $b_rsp0(%rsp), $t1
    jnz .Lbeeu_shift_loop_end_XB

    ${\SHIFT1($x0, $x1, $x2, $x3, $x4)}
    shl \$1, $shift

    # Test wraparound of the shift parameter. The probability to have 32 zeroes
    # in a row is small Therefore having the value below equal \$0x8000000 or
    # \$0x8000 does not affect the performance. We choose 0x8000000 because it
    # is the maximal immediate value possible.
    cmp \$0x8000000, $shift
    jne .Lbeeu_shift_loop_XB

.Lbeeu_shift_loop_end_XB:
    bsf $shift, $shift
    test $shift, $shift
    jz .Lbeeu_no_shift_XB

    ${\SHIFT256($b_rsp0)}

.Lbeeu_no_shift_XB:
    # Same for A and Y.  Afterwards, (2) still holds.
    movq \$1, $shift

    # Note that A > 0
.Lbeeu_shift_loop_YA:
    movq $shift, $t1
    andq $a_rsp0(%rsp), $t1
    jnz .Lbeeu_shift_loop_end_YA

    ${\SHIFT1($y0, $y1, $y2, $y3, $y4)}
    shl \$1, $shift

    # Test wraparound of the shift parameter. The probability to have 32 zeroes
    # in a row is small therefore having the value below equal \$0x8000000 or
    # \$0x8000 Does not affect the performance. We choose 0x8000000 because it
    # is the maximal immediate value possible.
    cmp \$0x8000000, $shift
    jne .Lbeeu_shift_loop_YA

.Lbeeu_shift_loop_end_YA:
    bsf $shift, $shift
    test $shift, $shift
    jz .Lbeeu_no_shift_YA

    ${\SHIFT256($a_rsp0)}

.Lbeeu_no_shift_YA:
    # T = B-A (A,B < 2^256)
    mov $b_rsp0(%rsp), $t0
    mov $b_rsp1(%rsp), $t1
    mov $b_rsp2(%rsp), $t2
    mov $b_rsp3(%rsp), $t3
    sub $a_rsp0(%rsp), $t0
    sbb $a_rsp1(%rsp), $t1
    sbb $a_rsp2(%rsp), $t2
    sbb $a_rsp3(%rsp), $t3  # borrow from shift
    jnc .Lbeeu_B_bigger_than_A

    # A = A - B
    mov $a_rsp0(%rsp), $t0
    mov $a_rsp1(%rsp), $t1
    mov $a_rsp2(%rsp), $t2
    mov $a_rsp3(%rsp), $t3
    sub $b_rsp0(%rsp), $t0
    sbb $b_rsp1(%rsp), $t1
    sbb $b_rsp2(%rsp), $t2
    sbb $b_rsp3(%rsp), $t3
    mov $t0, $a_rsp0(%rsp)
    mov $t1, $a_rsp1(%rsp)
    mov $t2, $a_rsp2(%rsp)
    mov $t3, $a_rsp3(%rsp)

    # Y = Y + X
    add $x0, $y0
    adc $x1, $y1
    adc $x2, $y2
    adc $x3, $y3
    adc $x4, $y4
    jmp .Lbeeu_loop

.Lbeeu_B_bigger_than_A:
    # B = T = B - A
    mov $t0, $b_rsp0(%rsp)
    mov $t1, $b_rsp1(%rsp)
    mov $t2, $b_rsp2(%rsp)
    mov $t3, $b_rsp3(%rsp)

    # X = Y + X
    add $y0, $x0
    adc $y1, $x1
    adc $y2, $x2
    adc $y3, $x3
    adc $y4, $x4

    jmp .Lbeeu_loop

.Lbeeu_loop_end:
    # The Euclid's algorithm loop ends when A == beeu(a,n);
    # Therefore (-1)*Y*a == A (mod |n|), Y>0

    # Verify that A = 1 ==> (-1)*Y*a = A = 1  (mod |n|)
    mov $a_rsp0(%rsp), $t1
    sub \$1, $t1
    or $a_rsp1(%rsp), $t1
    or $a_rsp2(%rsp), $t1
    or $a_rsp3(%rsp), $t1
    # If not, fail.
    jnz .Lbeeu_err

    # From this point on, we no longer need X
    # Therefore we use it as a temporary storage.
    # X = n
    movq 0*8($n), $x0
    movq 1*8($n), $x1
    movq 2*8($n), $x2
    movq 3*8($n), $x3
    xorq $x4, $x4

.Lbeeu_reduction_loop:
    movq $y0, $y_rsp0(%rsp)
    movq $y1, $y_rsp1(%rsp)
    movq $y2, $y_rsp2(%rsp)
    movq $y3, $y_rsp3(%rsp)
    movq $y4, $y_rsp4(%rsp)

    # If Y>n ==> Y=Y-n
    sub $x0, $y0
    sbb $x1, $y1
    sbb $x2, $y2
    sbb $x3, $y3
    sbb \$0, $y4

    # Choose old Y or new Y
    cmovc $y_rsp0(%rsp), $y0
    cmovc $y_rsp1(%rsp), $y1
    cmovc $y_rsp2(%rsp), $y2
    cmovc $y_rsp3(%rsp), $y3
    jnc .Lbeeu_reduction_loop

    # X = n - Y (n, Y < 2^256), (Cancel the (-1))
    sub $y0, $x0
    sbb $y1, $x1
    sbb $y2, $x2
    sbb $y3, $x3

.Lbeeu_save:
    # Save the inverse(<2^256) to out.
    mov $out_rsp(%rsp), $out

    movq $x0, 0*8($out)
    movq $x1, 1*8($out)
    movq $x2, 2*8($out)
    movq $x3, 3*8($out)

    # Return 1.
    movq \$1, %rax
    jmp .Lbeeu_finish

.Lbeeu_err:
    # Return 0.
    xorq %rax, %rax

.Lbeeu_finish:
    add \$$last_rsp_offset, %rsp
.cfi_adjust_cfa_offset  -$last_rsp_offset
    pop %rsi
.cfi_pop rsi
    pop %rbx
.cfi_pop rbx
    pop %r15
.cfi_pop r15
    pop %r14
.cfi_pop r14
    pop %r13
.cfi_pop r13
    pop %r12
.cfi_pop r12
    pop %rbp
.cfi_pop rbp
    ret
.cfi_endproc

.size beeu_mod_inverse_vartime, .-beeu_mod_inverse_vartime
___

print $code;
close STDOUT or die "error closing STDOUT: $!";


#!/usr/local/bin/perl

# Normal is the
# md5_block_x86(MD5_CTX *c, ULONG *X);
# version, non-normal is the
# md5_block_x86(MD5_CTX *c, ULONG *X,int blocks);

# 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." }

$normal=0;

$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
require "x86asm.pl";

$output=$ARGV[1];
open STDOUT,">$output";

&asm_init($ARGV[0]);

$A="eax";
$B="ebx";
$C="ecx";
$D="edx";
$tmp1="edi";
$tmp2="ebp";
$X="esi";

# What we need to load into $tmp for the next round
%Ltmp1=("R0",&Np($C), "R1",&Np($C), "R2",&Np($C), "R3",&Np($D));
@xo=(
 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,	# R0
 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,	# R1
 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,	# R2
 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9,	# R3
 );

&md5_block("md5_block_asm_data_order");
&asm_finish();

close STDOUT or die "error closing STDOUT: $!";

sub Np
	{
	local($p)=@_;
	local(%n)=($A,$D,$B,$A,$C,$B,$D,$C);
	return($n{$p});
	}

sub R0
	{
	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;

	&mov($tmp1,$C)  if $pos < 0;
	&mov($tmp2,&DWP($xo[$ki]*4,$K,"",0)) if $pos < 0; # very first one

	# body proper

	&comment("R0 $ki");
	&xor($tmp1,$d); # F function - part 2

	&and($tmp1,$b); # F function - part 3
	&lea($a,&DWP($t,$a,$tmp2,1));

	&xor($tmp1,$d); # F function - part 4

	&add($a,$tmp1);
	&mov($tmp1,&Np($c)) if $pos < 1;	# next tmp1 for R0
	&mov($tmp1,&Np($c)) if $pos == 1;	# next tmp1 for R1

	&rotl($a,$s);

	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);

	&add($a,$b);
	}

sub R1
	{
	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;

	&comment("R1 $ki");

	&lea($a,&DWP($t,$a,$tmp2,1));

	&xor($tmp1,$b); # G function - part 2
	&and($tmp1,$d); # G function - part 3

	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
	&xor($tmp1,$c);			# G function - part 4

	&add($a,$tmp1);
	&mov($tmp1,&Np($c)) if $pos < 1;	# G function - part 1
	&mov($tmp1,&Np($c)) if $pos == 1;	# G function - part 1

	&rotl($a,$s);

	&add($a,$b);
	}

sub R2
	{
	local($n,$pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
	# This one is different, only 3 logical operations

if (($n & 1) == 0)
	{
	&comment("R2 $ki");
	# make sure to do 'D' first, not 'B', else we clash with
	# the last add from the previous round.

	&xor($tmp1,$d); # H function - part 2

	&xor($tmp1,$b); # H function - part 3
	&lea($a,&DWP($t,$a,$tmp2,1));

	&add($a,$tmp1);

	&rotl($a,$s);

	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0));
	&mov($tmp1,&Np($c));
	}
else
	{
	&comment("R2 $ki");
	# make sure to do 'D' first, not 'B', else we clash with
	# the last add from the previous round.

	&lea($a,&DWP($t,$a,$tmp2,1));

	&add($b,$c);			# MOVED FORWARD
	&xor($tmp1,$d); # H function - part 2

	&xor($tmp1,$b); # H function - part 3
	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);

	&add($a,$tmp1);
	&mov($tmp1,&Np($c)) if $pos < 1;	# H function - part 1
	&mov($tmp1,-1) if $pos == 1;		# I function - part 1

	&rotl($a,$s);

	&add($a,$b);
	}
	}

sub R3
	{
	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;

	&comment("R3 $ki");

	# &not($tmp1)
	&xor($tmp1,$d) if $pos < 0; 	# I function - part 2

	&or($tmp1,$b);				# I function - part 3
	&lea($a,&DWP($t,$a,$tmp2,1));

	&xor($tmp1,$c); 			# I function - part 4
	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0))	if $pos != 2; # load X/k value
	&mov($tmp2,&wparam(0)) if $pos == 2;

	&add($a,$tmp1);
	&mov($tmp1,-1) if $pos < 1;	# H function - part 1
	&add($K,64) if $pos >=1 && !$normal;

	&rotl($a,$s);

	&xor($tmp1,&Np($d)) if $pos <= 0; 	# I function - part = first time
	&mov($tmp1,&DWP( 0,$tmp2,"",0)) if $pos > 0;
	&add($a,$b);
	}

sub md5_block
	{
	local($name)=@_;

	&function_begin_B($name,"",3);

	# parameter 1 is the MD5_CTX structure.
	# A	0
	# B	4
	# C	8
	# D 	12

	&push("esi");
	 &push("edi");
	&mov($tmp1,	&wparam(0)); # edi
	 &mov($X,	&wparam(1)); # esi
	&mov($C,	&wparam(2));
	 &push("ebp");
	&shl($C,	6);
	&push("ebx");
	 &add($C,	$X); # offset we end at
	&sub($C,	64);
	 &mov($A,	&DWP( 0,$tmp1,"",0));
	&push($C);	# Put on the TOS
	 &mov($B,	&DWP( 4,$tmp1,"",0));
	&mov($C,	&DWP( 8,$tmp1,"",0));
	 &mov($D,	&DWP(12,$tmp1,"",0));

	&set_label("start") unless $normal;
	&comment("");
	&comment("R0 section");

	&R0(-2,$A,$B,$C,$D,$X, 0, 7,0xd76aa478);
	&R0( 0,$D,$A,$B,$C,$X, 1,12,0xe8c7b756);
	&R0( 0,$C,$D,$A,$B,$X, 2,17,0x242070db);
	&R0( 0,$B,$C,$D,$A,$X, 3,22,0xc1bdceee);
	&R0( 0,$A,$B,$C,$D,$X, 4, 7,0xf57c0faf);
	&R0( 0,$D,$A,$B,$C,$X, 5,12,0x4787c62a);
	&R0( 0,$C,$D,$A,$B,$X, 6,17,0xa8304613);
	&R0( 0,$B,$C,$D,$A,$X, 7,22,0xfd469501);
	&R0( 0,$A,$B,$C,$D,$X, 8, 7,0x698098d8);
	&R0( 0,$D,$A,$B,$C,$X, 9,12,0x8b44f7af);
	&R0( 0,$C,$D,$A,$B,$X,10,17,0xffff5bb1);
	&R0( 0,$B,$C,$D,$A,$X,11,22,0x895cd7be);
	&R0( 0,$A,$B,$C,$D,$X,12, 7,0x6b901122);
	&R0( 0,$D,$A,$B,$C,$X,13,12,0xfd987193);
	&R0( 0,$C,$D,$A,$B,$X,14,17,0xa679438e);
	&R0( 1,$B,$C,$D,$A,$X,15,22,0x49b40821);

	&comment("");
	&comment("R1 section");
	&R1(-1,$A,$B,$C,$D,$X,16, 5,0xf61e2562);
	&R1( 0,$D,$A,$B,$C,$X,17, 9,0xc040b340);
	&R1( 0,$C,$D,$A,$B,$X,18,14,0x265e5a51);
	&R1( 0,$B,$C,$D,$A,$X,19,20,0xe9b6c7aa);
	&R1( 0,$A,$B,$C,$D,$X,20, 5,0xd62f105d);
	&R1( 0,$D,$A,$B,$C,$X,21, 9,0x02441453);
	&R1( 0,$C,$D,$A,$B,$X,22,14,0xd8a1e681);
	&R1( 0,$B,$C,$D,$A,$X,23,20,0xe7d3fbc8);
	&R1( 0,$A,$B,$C,$D,$X,24, 5,0x21e1cde6);
	&R1( 0,$D,$A,$B,$C,$X,25, 9,0xc33707d6);
	&R1( 0,$C,$D,$A,$B,$X,26,14,0xf4d50d87);
	&R1( 0,$B,$C,$D,$A,$X,27,20,0x455a14ed);
	&R1( 0,$A,$B,$C,$D,$X,28, 5,0xa9e3e905);
	&R1( 0,$D,$A,$B,$C,$X,29, 9,0xfcefa3f8);
	&R1( 0,$C,$D,$A,$B,$X,30,14,0x676f02d9);
	&R1( 1,$B,$C,$D,$A,$X,31,20,0x8d2a4c8a);

	&comment("");
	&comment("R2 section");
	&R2( 0,-1,$A,$B,$C,$D,$X,32, 4,0xfffa3942);
	&R2( 1, 0,$D,$A,$B,$C,$X,33,11,0x8771f681);
	&R2( 2, 0,$C,$D,$A,$B,$X,34,16,0x6d9d6122);
	&R2( 3, 0,$B,$C,$D,$A,$X,35,23,0xfde5380c);
	&R2( 4, 0,$A,$B,$C,$D,$X,36, 4,0xa4beea44);
	&R2( 5, 0,$D,$A,$B,$C,$X,37,11,0x4bdecfa9);
	&R2( 6, 0,$C,$D,$A,$B,$X,38,16,0xf6bb4b60);
	&R2( 7, 0,$B,$C,$D,$A,$X,39,23,0xbebfbc70);
	&R2( 8, 0,$A,$B,$C,$D,$X,40, 4,0x289b7ec6);
	&R2( 9, 0,$D,$A,$B,$C,$X,41,11,0xeaa127fa);
	&R2(10, 0,$C,$D,$A,$B,$X,42,16,0xd4ef3085);
	&R2(11, 0,$B,$C,$D,$A,$X,43,23,0x04881d05);
	&R2(12, 0,$A,$B,$C,$D,$X,44, 4,0xd9d4d039);
	&R2(13, 0,$D,$A,$B,$C,$X,45,11,0xe6db99e5);
	&R2(14, 0,$C,$D,$A,$B,$X,46,16,0x1fa27cf8);
	&R2(15, 1,$B,$C,$D,$A,$X,47,23,0xc4ac5665);

	&comment("");
	&comment("R3 section");
	&R3(-1,$A,$B,$C,$D,$X,48, 6,0xf4292244);
	&R3( 0,$D,$A,$B,$C,$X,49,10,0x432aff97);
	&R3( 0,$C,$D,$A,$B,$X,50,15,0xab9423a7);
	&R3( 0,$B,$C,$D,$A,$X,51,21,0xfc93a039);
	&R3( 0,$A,$B,$C,$D,$X,52, 6,0x655b59c3);
	&R3( 0,$D,$A,$B,$C,$X,53,10,0x8f0ccc92);
	&R3( 0,$C,$D,$A,$B,$X,54,15,0xffeff47d);
	&R3( 0,$B,$C,$D,$A,$X,55,21,0x85845dd1);
	&R3( 0,$A,$B,$C,$D,$X,56, 6,0x6fa87e4f);
	&R3( 0,$D,$A,$B,$C,$X,57,10,0xfe2ce6e0);
	&R3( 0,$C,$D,$A,$B,$X,58,15,0xa3014314);
	&R3( 0,$B,$C,$D,$A,$X,59,21,0x4e0811a1);
	&R3( 0,$A,$B,$C,$D,$X,60, 6,0xf7537e82);
	&R3( 0,$D,$A,$B,$C,$X,61,10,0xbd3af235);
	&R3( 0,$C,$D,$A,$B,$X,62,15,0x2ad7d2bb);
	&R3( 2,$B,$C,$D,$A,$X,63,21,0xeb86d391);

	# &mov($tmp2,&wparam(0));	# done in the last R3
	# &mov($tmp1,	&DWP( 0,$tmp2,"",0)); # done is the last R3

	&add($A,$tmp1);
	 &mov($tmp1,	&DWP( 4,$tmp2,"",0));

	&add($B,$tmp1);
	&mov($tmp1,	&DWP( 8,$tmp2,"",0));

	&add($C,$tmp1);
	&mov($tmp1,	&DWP(12,$tmp2,"",0));

	&add($D,$tmp1);
	&mov(&DWP( 0,$tmp2,"",0),$A);

	&mov(&DWP( 4,$tmp2,"",0),$B);
	&mov($tmp1,&swtmp(0)) unless $normal;

	&mov(&DWP( 8,$tmp2,"",0),$C);
	 &mov(&DWP(12,$tmp2,"",0),$D);

	&cmp($tmp1,$X) unless $normal;			# check count
	 &jae(&label("start")) unless $normal;

	&pop("eax"); # pop the temp variable off the stack
	 &pop("ebx");
	&pop("ebp");
	 &pop("edi");
	&pop("esi");
	 &ret();
	&function_end_B($name);
	}


#! /usr/bin/env perl
# Copyright 2021-2022 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (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

# MD5 optimized for aarch64.

use strict;

my $code;

# 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."; }

my $flavour = shift;
my $output  = shift;

$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";

open OUT,"| \"$^X\" $xlate $flavour \"$output\""
    or die "can't call $xlate: $1";
*STDOUT=*OUT;

$code .= <<EOF;

.text
.globl  md5_block_asm_data_order
.type   md5_block_asm_data_order,\@function
md5_block_asm_data_order:
        // Save all callee-saved registers
        stp     x19,x20,[sp,#-80]!
        stp     x21,x22,[sp,#16]
        stp     x23,x24,[sp,#32]
        stp     x25,x26,[sp,#48]
        stp     x27,x28,[sp,#64]

        ldp w10, w11, [x0, #0]        // Load MD5 state->A and state->B
        ldp w12, w13, [x0, #8]        // Load MD5 state->C and state->D
.align 5
md5_blocks_loop:
        eor x17, x12, x13             // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        and x16, x17, x11             // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        ldp x15, x3, [x1]             // Load 4 words of input data0 M[0]/0
        eor x14, x16, x13             // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x9, #0xa478              // Load lower half of constant 0xd76aa478
        movk x9, #0xd76a, lsl #16     // Load upper half of constant 0xd76aa478
        add w8, w10, w15              // Add dest value
        add w7, w8, w9                // Add constant 0xd76aa478
        add w6, w7, w14               // Add aux function result
        ror w6, w6, #25               // Rotate left s=7 bits
        eor x5, x11, x12              // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w4, w11, w6               // Add X parameter round 1 A=FF(A, B, C, D, 0xd76aa478, s=7, M[0])
        and x8, x5, x4                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x17, x8, x12              // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x16, #0xb756             // Load lower half of constant 0xe8c7b756
        movk x16, #0xe8c7, lsl #16    // Load upper half of constant 0xe8c7b756
        lsr x20, x15, #32             // Right shift high input value containing M[1]
        add w9, w13, w20              // Add dest value
        add w7, w9, w16               // Add constant 0xe8c7b756
        add w14, w7, w17              // Add aux function result
        ror w14, w14, #20             // Rotate left s=12 bits
        eor x6, x4, x11               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w5, w4, w14               // Add X parameter round 1 D=FF(D, A, B, C, 0xe8c7b756, s=12, M[1])
        and x8, x6, x5                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x9, x8, x11               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x16, #0x70db             // Load lower half of constant 0x242070db
        movk x16, #0x2420, lsl #16    // Load upper half of constant 0x242070db
        add w7, w12, w3               // Add dest value
        add w17, w7, w16              // Add constant 0x242070db
        add w14, w17, w9              // Add aux function result
        ror w14, w14, #15             // Rotate left s=17 bits
        eor x6, x5, x4                // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w8, w5, w14               // Add X parameter round 1 C=FF(C, D, A, B, 0x242070db, s=17, M[2])
        and x7, x6, x8                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x16, x7, x4               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x9, #0xceee              // Load lower half of constant 0xc1bdceee
        movk x9, #0xc1bd, lsl #16     // Load upper half of constant 0xc1bdceee
        lsr x21, x3, #32              // Right shift high input value containing M[3]
        add w14, w11, w21             // Add dest value
        add w6, w14, w9               // Add constant 0xc1bdceee
        add w7, w6, w16               // Add aux function result
        ror w7, w7, #10               // Rotate left s=22 bits
        eor x17, x8, x5               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w9, w8, w7                // Add X parameter round 1 B=FF(B, C, D, A, 0xc1bdceee, s=22, M[3])
        ldp x14, x7, [x1, #16]        // Load 4 words of input data0 M[4]/0w
        and x16, x17, x9              // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x16, x5               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x16, #0xfaf              // Load lower half of constant 0xf57c0faf
        movk x16, #0xf57c, lsl #16    // Load upper half of constant 0xf57c0faf
        add w17, w4, w14              // Add dest value
        add w16, w17, w16             // Add constant 0xf57c0faf
        add w4, w16, w6               // Add aux function result
        ror w4, w4, #25               // Rotate left s=7 bits
        eor x16, x9, x8               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w17, w9, w4               // Add X parameter round 1 A=FF(A, B, C, D, 0xf57c0faf, s=7, M[4])
        and x16, x16, x17             // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x16, x8               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x4, #0xc62a              // Load lower half of constant 0x4787c62a
        movk x4, #0x4787, lsl #16     // Load upper half of constant 0x4787c62a
        lsr x22, x14, #32             // Right shift high input value containing M[5]
        add w16, w5, w22              // Add dest value
        add w16, w16, w4              // Add constant 0x4787c62a
        add w5, w16, w6               // Add aux function result
        ror w5, w5, #20               // Rotate left s=12 bits
        eor x4, x17, x9               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w19, w17, w5              // Add X parameter round 1 D=FF(D, A, B, C, 0x4787c62a, s=12, M[5])
        and x6, x4, x19               // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x5, x6, x9                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x4, #0x4613              // Load lower half of constant 0xa8304613
        movk x4, #0xa830, lsl #16     // Load upper half of constant 0xa8304613
        add w6, w8, w7                // Add dest value
        add w8, w6, w4                // Add constant 0xa8304613
        add w4, w8, w5                // Add aux function result
        ror w4, w4, #15               // Rotate left s=17 bits
        eor x6, x19, x17              // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w8, w19, w4               // Add X parameter round 1 C=FF(C, D, A, B, 0xa8304613, s=17, M[6])
        and x5, x6, x8                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x4, x5, x17               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x6, #0x9501              // Load lower half of constant 0xfd469501
        movk x6, #0xfd46, lsl #16     // Load upper half of constant 0xfd469501
        lsr x23, x7, #32              // Right shift high input value containing M[7]
        add w9, w9, w23               // Add dest value
        add w5, w9, w6                // Add constant 0xfd469501
        add w9, w5, w4                // Add aux function result
        ror w9, w9, #10               // Rotate left s=22 bits
        eor x6, x8, x19               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w4, w8, w9                // Add X parameter round 1 B=FF(B, C, D, A, 0xfd469501, s=22, M[7])
        ldp x5, x16, [x1, #32]        // Load 4 words of input data0 M[8]/0
        and x9, x6, x4                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x9, x19               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x9, #0x98d8              // Load lower half of constant 0x698098d8
        movk x9, #0x6980, lsl #16     // Load upper half of constant 0x698098d8
        add w17, w17, w5              // Add dest value
        add w9, w17, w9               // Add constant 0x698098d8
        add w17, w9, w6               // Add aux function result
        ror w17, w17, #25             // Rotate left s=7 bits
        eor x9, x4, x8                // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w6, w4, w17               // Add X parameter round 1 A=FF(A, B, C, D, 0x698098d8, s=7, M[8])
        and x17, x9, x6               // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x9, x17, x8               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x17, #0xf7af             // Load lower half of constant 0x8b44f7af
        movk x17, #0x8b44, lsl #16    // Load upper half of constant 0x8b44f7af
        lsr x24, x5, #32              // Right shift high input value containing M[9]
        add w19, w19, w24             // Add dest value
        add w17, w19, w17             // Add constant 0x8b44f7af
        add w19, w17, w9              // Add aux function result
        ror w19, w19, #20             // Rotate left s=12 bits
        eor x9, x6, x4                // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w17, w6, w19              // Add X parameter round 1 D=FF(D, A, B, C, 0x8b44f7af, s=12, M[9])
        and x9, x9, x17               // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x9, x9, x4                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x11, #0x5bb1             // Load lower half of constant 0xffff5bb1
        movk x11, #0xffff, lsl #16    // Load upper half of constant 0xffff5bb1
        add w8, w8, w16               // Add dest value
        add w8, w8, w11               // Add constant 0xffff5bb1
        add w8, w8, w9                // Add aux function result
        ror w8, w8, #15               // Rotate left s=17 bits
        eor x9, x17, x6               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w8, w17, w8               // Add X parameter round 1 C=FF(C, D, A, B, 0xffff5bb1, s=17, M[10])
        and x9, x9, x8                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x9, x9, x6                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x11, #0xd7be             // Load lower half of constant 0x895cd7be
        movk x11, #0x895c, lsl #16    // Load upper half of constant 0x895cd7be
        lsr x25, x16, #32             // Right shift high input value containing M[11]
        add w4, w4, w25               // Add dest value
        add w4, w4, w11               // Add constant 0x895cd7be
        add w9, w4, w9                // Add aux function result
        ror w9, w9, #10               // Rotate left s=22 bits
        eor x4, x8, x17               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w9, w8, w9                // Add X parameter round 1 B=FF(B, C, D, A, 0x895cd7be, s=22, M[11])
        ldp x11, x12, [x1, #48]       // Load 4 words of input data0 M[12]/0
        and x4, x4, x9                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x4, x4, x17               // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x19, #0x1122             // Load lower half of constant 0x6b901122
        movk x19, #0x6b90, lsl #16    // Load upper half of constant 0x6b901122
        add w6, w6, w11               // Add dest value
        add w6, w6, w19               // Add constant 0x6b901122
        add w4, w6, w4                // Add aux function result
        ror w4, w4, #25               // Rotate left s=7 bits
        eor x6, x9, x8                // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w4, w9, w4                // Add X parameter round 1 A=FF(A, B, C, D, 0x6b901122, s=7, M[12])
        and x6, x6, x4                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x6, x8                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x19, #0x7193             // Load lower half of constant 0xfd987193
        movk x19, #0xfd98, lsl #16    // Load upper half of constant 0xfd987193
        lsr x26, x11, #32             // Right shift high input value containing M[13]
        add w17, w17, w26             // Add dest value
        add w17, w17, w19             // Add constant 0xfd987193
        add w17, w17, w6              // Add aux function result
        ror w17, w17, #20             // Rotate left s=12 bits
        eor x6, x4, x9                // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w17, w4, w17              // Add X parameter round 1 D=FF(D, A, B, C, 0xfd987193, s=12, M[13])
        and x6, x6, x17               // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x6, x9                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x13, #0x438e             // Load lower half of constant 0xa679438e
        movk x13, #0xa679, lsl #16    // Load upper half of constant 0xa679438e
        add w8, w8, w12               // Add dest value
        add w8, w8, w13               // Add constant 0xa679438e
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #15               // Rotate left s=17 bits
        eor x6, x17, x4               // Begin aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        add w8, w17, w8               // Add X parameter round 1 C=FF(C, D, A, B, 0xa679438e, s=17, M[14])
        and x6, x6, x8                // Continue aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        eor x6, x6, x4                // End aux function round 1 F(x,y,z)=(((y^z)&x)^z)
        movz x13, #0x821              // Load lower half of constant 0x49b40821
        movk x13, #0x49b4, lsl #16    // Load upper half of constant 0x49b40821
        lsr x27, x12, #32             // Right shift high input value containing M[15]
        add w9, w9, w27               // Add dest value
        add w9, w9, w13               // Add constant 0x49b40821
        add w9, w9, w6                // Add aux function result
        ror w9, w9, #10               // Rotate left s=22 bits
        bic x6, x8, x17               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w9, w8, w9                // Add X parameter round 1 B=FF(B, C, D, A, 0x49b40821, s=22, M[15])
        and x13, x9, x17              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x2562             // Load lower half of constant 0xf61e2562
        movk x13, #0xf61e, lsl #16    // Load upper half of constant 0xf61e2562
        add w4, w4, w20               // Add dest value
        add w4, w4, w13               // Add constant 0xf61e2562
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #27               // Rotate left s=5 bits
        bic x6, x9, x8                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w4, w9, w4                // Add X parameter round 2 A=GG(A, B, C, D, 0xf61e2562, s=5, M[1])
        and x13, x4, x8               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xb340             // Load lower half of constant 0xc040b340
        movk x13, #0xc040, lsl #16    // Load upper half of constant 0xc040b340
        add w17, w17, w7              // Add dest value
        add w17, w17, w13             // Add constant 0xc040b340
        add w17, w17, w6              // Add aux function result
        ror w17, w17, #23             // Rotate left s=9 bits
        bic x6, x4, x9                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w17, w4, w17              // Add X parameter round 2 D=GG(D, A, B, C, 0xc040b340, s=9, M[6])
        and x13, x17, x9              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x5a51             // Load lower half of constant 0x265e5a51
        movk x13, #0x265e, lsl #16    // Load upper half of constant 0x265e5a51
        add w8, w8, w25               // Add dest value
        add w8, w8, w13               // Add constant 0x265e5a51
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #18               // Rotate left s=14 bits
        bic x6, x17, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w8, w17, w8               // Add X parameter round 2 C=GG(C, D, A, B, 0x265e5a51, s=14, M[11])
        and x13, x8, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xc7aa             // Load lower half of constant 0xe9b6c7aa
        movk x13, #0xe9b6, lsl #16    // Load upper half of constant 0xe9b6c7aa
        add w9, w9, w15               // Add dest value
        add w9, w9, w13               // Add constant 0xe9b6c7aa
        add w9, w9, w6                // Add aux function result
        ror w9, w9, #12               // Rotate left s=20 bits
        bic x6, x8, x17               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w9, w8, w9                // Add X parameter round 2 B=GG(B, C, D, A, 0xe9b6c7aa, s=20, M[0])
        and x13, x9, x17              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x105d             // Load lower half of constant 0xd62f105d
        movk x13, #0xd62f, lsl #16    // Load upper half of constant 0xd62f105d
        add w4, w4, w22               // Add dest value
        add w4, w4, w13               // Add constant 0xd62f105d
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #27               // Rotate left s=5 bits
        bic x6, x9, x8                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w4, w9, w4                // Add X parameter round 2 A=GG(A, B, C, D, 0xd62f105d, s=5, M[5])
        and x13, x4, x8               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x1453             // Load lower half of constant 0x2441453
        movk x13, #0x244, lsl #16     // Load upper half of constant 0x2441453
        add w17, w17, w16             // Add dest value
        add w17, w17, w13             // Add constant 0x2441453
        add w17, w17, w6              // Add aux function result
        ror w17, w17, #23             // Rotate left s=9 bits
        bic x6, x4, x9                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w17, w4, w17              // Add X parameter round 2 D=GG(D, A, B, C, 0x2441453, s=9, M[10])
        and x13, x17, x9              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xe681             // Load lower half of constant 0xd8a1e681
        movk x13, #0xd8a1, lsl #16    // Load upper half of constant 0xd8a1e681
        add w8, w8, w27               // Add dest value
        add w8, w8, w13               // Add constant 0xd8a1e681
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #18               // Rotate left s=14 bits
        bic x6, x17, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w8, w17, w8               // Add X parameter round 2 C=GG(C, D, A, B, 0xd8a1e681, s=14, M[15])
        and x13, x8, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xfbc8             // Load lower half of constant 0xe7d3fbc8
        movk x13, #0xe7d3, lsl #16    // Load upper half of constant 0xe7d3fbc8
        add w9, w9, w14               // Add dest value
        add w9, w9, w13               // Add constant 0xe7d3fbc8
        add w9, w9, w6                // Add aux function result
        ror w9, w9, #12               // Rotate left s=20 bits
        bic x6, x8, x17               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w9, w8, w9                // Add X parameter round 2 B=GG(B, C, D, A, 0xe7d3fbc8, s=20, M[4])
        and x13, x9, x17              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xcde6             // Load lower half of constant 0x21e1cde6
        movk x13, #0x21e1, lsl #16    // Load upper half of constant 0x21e1cde6
        add w4, w4, w24               // Add dest value
        add w4, w4, w13               // Add constant 0x21e1cde6
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #27               // Rotate left s=5 bits
        bic x6, x9, x8                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w4, w9, w4                // Add X parameter round 2 A=GG(A, B, C, D, 0x21e1cde6, s=5, M[9])
        and x13, x4, x8               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x7d6              // Load lower half of constant 0xc33707d6
        movk x13, #0xc337, lsl #16    // Load upper half of constant 0xc33707d6
        add w17, w17, w12             // Add dest value
        add w17, w17, w13             // Add constant 0xc33707d6
        add w17, w17, w6              // Add aux function result
        ror w17, w17, #23             // Rotate left s=9 bits
        bic x6, x4, x9                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w17, w4, w17              // Add X parameter round 2 D=GG(D, A, B, C, 0xc33707d6, s=9, M[14])
        and x13, x17, x9              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xd87              // Load lower half of constant 0xf4d50d87
        movk x13, #0xf4d5, lsl #16    // Load upper half of constant 0xf4d50d87
        add w8, w8, w21               // Add dest value
        add w8, w8, w13               // Add constant 0xf4d50d87
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #18               // Rotate left s=14 bits
        bic x6, x17, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w8, w17, w8               // Add X parameter round 2 C=GG(C, D, A, B, 0xf4d50d87, s=14, M[3])
        and x13, x8, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x14ed             // Load lower half of constant 0x455a14ed
        movk x13, #0x455a, lsl #16    // Load upper half of constant 0x455a14ed
        add w9, w9, w5                // Add dest value
        add w9, w9, w13               // Add constant 0x455a14ed
        add w9, w9, w6                // Add aux function result
        ror w9, w9, #12               // Rotate left s=20 bits
        bic x6, x8, x17               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w9, w8, w9                // Add X parameter round 2 B=GG(B, C, D, A, 0x455a14ed, s=20, M[8])
        and x13, x9, x17              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xe905             // Load lower half of constant 0xa9e3e905
        movk x13, #0xa9e3, lsl #16    // Load upper half of constant 0xa9e3e905
        add w4, w4, w26               // Add dest value
        add w4, w4, w13               // Add constant 0xa9e3e905
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #27               // Rotate left s=5 bits
        bic x6, x9, x8                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w4, w9, w4                // Add X parameter round 2 A=GG(A, B, C, D, 0xa9e3e905, s=5, M[13])
        and x13, x4, x8               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0xa3f8             // Load lower half of constant 0xfcefa3f8
        movk x13, #0xfcef, lsl #16    // Load upper half of constant 0xfcefa3f8
        add w17, w17, w3              // Add dest value
        add w17, w17, w13             // Add constant 0xfcefa3f8
        add w17, w17, w6              // Add aux function result
        ror w17, w17, #23             // Rotate left s=9 bits
        bic x6, x4, x9                // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w17, w4, w17              // Add X parameter round 2 D=GG(D, A, B, C, 0xfcefa3f8, s=9, M[2])
        and x13, x17, x9              // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x2d9              // Load lower half of constant 0x676f02d9
        movk x13, #0x676f, lsl #16    // Load upper half of constant 0x676f02d9
        add w8, w8, w23               // Add dest value
        add w8, w8, w13               // Add constant 0x676f02d9
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #18               // Rotate left s=14 bits
        bic x6, x17, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        add w8, w17, w8               // Add X parameter round 2 C=GG(C, D, A, B, 0x676f02d9, s=14, M[7])
        and x13, x8, x4               // Aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        orr x6, x6, x13               // End aux function round 2 G(x,y,z)=((x&z)|(~z&y))
        movz x13, #0x4c8a             // Load lower half of constant 0x8d2a4c8a
        movk x13, #0x8d2a, lsl #16    // Load upper half of constant 0x8d2a4c8a
        add w9, w9, w11               // Add dest value
        add w9, w9, w13               // Add constant 0x8d2a4c8a
        add w9, w9, w6                // Add aux function result
        eor x6, x8, x17               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w9, w9, #12               // Rotate left s=20 bits
        movz x10, #0x3942             // Load lower half of constant 0xfffa3942
        add w9, w8, w9                // Add X parameter round 2 B=GG(B, C, D, A, 0x8d2a4c8a, s=20, M[12])
        movk x10, #0xfffa, lsl #16    // Load upper half of constant 0xfffa3942
        add w4, w4, w22               // Add dest value
        eor x6, x6, x9                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w4, w4, w10               // Add constant 0xfffa3942
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #28               // Rotate left s=4 bits
        eor x6, x9, x8                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x10, #0xf681             // Load lower half of constant 0x8771f681
        add w4, w9, w4                // Add X parameter round 3 A=HH(A, B, C, D, 0xfffa3942, s=4, M[5])
        movk x10, #0x8771, lsl #16    // Load upper half of constant 0x8771f681
        add w17, w17, w5              // Add dest value
        eor x6, x6, x4                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w17, w17, w10             // Add constant 0x8771f681
        add w17, w17, w6              // Add aux function result
        eor x6, x4, x9                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w17, w17, #21             // Rotate left s=11 bits
        movz x13, #0x6122             // Load lower half of constant 0x6d9d6122
        add w17, w4, w17              // Add X parameter round 3 D=HH(D, A, B, C, 0x8771f681, s=11, M[8])
        movk x13, #0x6d9d, lsl #16    // Load upper half of constant 0x6d9d6122
        add w8, w8, w25               // Add dest value
        eor x6, x6, x17               // End aux function round 3 H(x,y,z)=(x^y^z)
        add w8, w8, w13               // Add constant 0x6d9d6122
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #16               // Rotate left s=16 bits
        eor x6, x17, x4               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x13, #0x380c             // Load lower half of constant 0xfde5380c
        add w8, w17, w8               // Add X parameter round 3 C=HH(C, D, A, B, 0x6d9d6122, s=16, M[11])
        movk x13, #0xfde5, lsl #16    // Load upper half of constant 0xfde5380c
        add w9, w9, w12               // Add dest value
        eor x6, x6, x8                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w9, w9, w13               // Add constant 0xfde5380c
        add w9, w9, w6                // Add aux function result
        eor x6, x8, x17               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w9, w9, #9                // Rotate left s=23 bits
        movz x10, #0xea44             // Load lower half of constant 0xa4beea44
        add w9, w8, w9                // Add X parameter round 3 B=HH(B, C, D, A, 0xfde5380c, s=23, M[14])
        movk x10, #0xa4be, lsl #16    // Load upper half of constant 0xa4beea44
        add w4, w4, w20               // Add dest value
        eor x6, x6, x9                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w4, w4, w10               // Add constant 0xa4beea44
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #28               // Rotate left s=4 bits
        eor x6, x9, x8                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x10, #0xcfa9             // Load lower half of constant 0x4bdecfa9
        add w4, w9, w4                // Add X parameter round 3 A=HH(A, B, C, D, 0xa4beea44, s=4, M[1])
        movk x10, #0x4bde, lsl #16    // Load upper half of constant 0x4bdecfa9
        add w17, w17, w14             // Add dest value
        eor x6, x6, x4                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w17, w17, w10             // Add constant 0x4bdecfa9
        add w17, w17, w6              // Add aux function result
        eor x6, x4, x9                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w17, w17, #21             // Rotate left s=11 bits
        movz x13, #0x4b60             // Load lower half of constant 0xf6bb4b60
        add w17, w4, w17              // Add X parameter round 3 D=HH(D, A, B, C, 0x4bdecfa9, s=11, M[4])
        movk x13, #0xf6bb, lsl #16    // Load upper half of constant 0xf6bb4b60
        add w8, w8, w23               // Add dest value
        eor x6, x6, x17               // End aux function round 3 H(x,y,z)=(x^y^z)
        add w8, w8, w13               // Add constant 0xf6bb4b60
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #16               // Rotate left s=16 bits
        eor x6, x17, x4               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x13, #0xbc70             // Load lower half of constant 0xbebfbc70
        add w8, w17, w8               // Add X parameter round 3 C=HH(C, D, A, B, 0xf6bb4b60, s=16, M[7])
        movk x13, #0xbebf, lsl #16    // Load upper half of constant 0xbebfbc70
        add w9, w9, w16               // Add dest value
        eor x6, x6, x8                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w9, w9, w13               // Add constant 0xbebfbc70
        add w9, w9, w6                // Add aux function result
        eor x6, x8, x17               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w9, w9, #9                // Rotate left s=23 bits
        movz x10, #0x7ec6             // Load lower half of constant 0x289b7ec6
        add w9, w8, w9                // Add X parameter round 3 B=HH(B, C, D, A, 0xbebfbc70, s=23, M[10])
        movk x10, #0x289b, lsl #16    // Load upper half of constant 0x289b7ec6
        add w4, w4, w26               // Add dest value
        eor x6, x6, x9                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w4, w4, w10               // Add constant 0x289b7ec6
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #28               // Rotate left s=4 bits
        eor x6, x9, x8                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x10, #0x27fa             // Load lower half of constant 0xeaa127fa
        add w4, w9, w4                // Add X parameter round 3 A=HH(A, B, C, D, 0x289b7ec6, s=4, M[13])
        movk x10, #0xeaa1, lsl #16    // Load upper half of constant 0xeaa127fa
        add w17, w17, w15             // Add dest value
        eor x6, x6, x4                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w17, w17, w10             // Add constant 0xeaa127fa
        add w17, w17, w6              // Add aux function result
        eor x6, x4, x9                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w17, w17, #21             // Rotate left s=11 bits
        movz x13, #0x3085             // Load lower half of constant 0xd4ef3085
        add w17, w4, w17              // Add X parameter round 3 D=HH(D, A, B, C, 0xeaa127fa, s=11, M[0])
        movk x13, #0xd4ef, lsl #16    // Load upper half of constant 0xd4ef3085
        add w8, w8, w21               // Add dest value
        eor x6, x6, x17               // End aux function round 3 H(x,y,z)=(x^y^z)
        add w8, w8, w13               // Add constant 0xd4ef3085
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #16               // Rotate left s=16 bits
        eor x6, x17, x4               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x13, #0x1d05             // Load lower half of constant 0x4881d05
        add w8, w17, w8               // Add X parameter round 3 C=HH(C, D, A, B, 0xd4ef3085, s=16, M[3])
        movk x13, #0x488, lsl #16     // Load upper half of constant 0x4881d05
        add w9, w9, w7                // Add dest value
        eor x6, x6, x8                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w9, w9, w13               // Add constant 0x4881d05
        add w9, w9, w6                // Add aux function result
        eor x6, x8, x17               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w9, w9, #9                // Rotate left s=23 bits
        movz x10, #0xd039             // Load lower half of constant 0xd9d4d039
        add w9, w8, w9                // Add X parameter round 3 B=HH(B, C, D, A, 0x4881d05, s=23, M[6])
        movk x10, #0xd9d4, lsl #16    // Load upper half of constant 0xd9d4d039
        add w4, w4, w24               // Add dest value
        eor x6, x6, x9                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w4, w4, w10               // Add constant 0xd9d4d039
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #28               // Rotate left s=4 bits
        eor x6, x9, x8                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x10, #0x99e5             // Load lower half of constant 0xe6db99e5
        add w4, w9, w4                // Add X parameter round 3 A=HH(A, B, C, D, 0xd9d4d039, s=4, M[9])
        movk x10, #0xe6db, lsl #16    // Load upper half of constant 0xe6db99e5
        add w17, w17, w11             // Add dest value
        eor x6, x6, x4                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w17, w17, w10             // Add constant 0xe6db99e5
        add w17, w17, w6              // Add aux function result
        eor x6, x4, x9                // Begin aux function round 3 H(x,y,z)=(x^y^z)
        ror w17, w17, #21             // Rotate left s=11 bits
        movz x13, #0x7cf8             // Load lower half of constant 0x1fa27cf8
        add w17, w4, w17              // Add X parameter round 3 D=HH(D, A, B, C, 0xe6db99e5, s=11, M[12])
        movk x13, #0x1fa2, lsl #16    // Load upper half of constant 0x1fa27cf8
        add w8, w8, w27               // Add dest value
        eor x6, x6, x17               // End aux function round 3 H(x,y,z)=(x^y^z)
        add w8, w8, w13               // Add constant 0x1fa27cf8
        add w8, w8, w6                // Add aux function result
        ror w8, w8, #16               // Rotate left s=16 bits
        eor x6, x17, x4               // Begin aux function round 3 H(x,y,z)=(x^y^z)
        movz x13, #0x5665             // Load lower half of constant 0xc4ac5665
        add w8, w17, w8               // Add X parameter round 3 C=HH(C, D, A, B, 0x1fa27cf8, s=16, M[15])
        movk x13, #0xc4ac, lsl #16    // Load upper half of constant 0xc4ac5665
        add w9, w9, w3                // Add dest value
        eor x6, x6, x8                // End aux function round 3 H(x,y,z)=(x^y^z)
        add w9, w9, w13               // Add constant 0xc4ac5665
        add w9, w9, w6                // Add aux function result
        ror w9, w9, #9                // Rotate left s=23 bits
        movz x6, #0x2244              // Load lower half of constant 0xf4292244
        movk x6, #0xf429, lsl #16     // Load upper half of constant 0xf4292244
        add w9, w8, w9                // Add X parameter round 3 B=HH(B, C, D, A, 0xc4ac5665, s=23, M[2])
        add w4, w4, w15               // Add dest value
        orn x13, x9, x17              // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w4, w4, w6                // Add constant 0xf4292244
        eor x6, x8, x13               // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w4, w4, w6                // Add aux function result
        ror w4, w4, #26               // Rotate left s=6 bits
        movz x6, #0xff97              // Load lower half of constant 0x432aff97
        movk x6, #0x432a, lsl #16     // Load upper half of constant 0x432aff97
        add w4, w9, w4                // Add X parameter round 4 A=II(A, B, C, D, 0xf4292244, s=6, M[0])
        orn x10, x4, x8               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w17, w17, w23             // Add dest value
        eor x10, x9, x10              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w17, w17, w6              // Add constant 0x432aff97
        add w6, w17, w10              // Add aux function result
        ror w6, w6, #22               // Rotate left s=10 bits
        movz x17, #0x23a7             // Load lower half of constant 0xab9423a7
        movk x17, #0xab94, lsl #16    // Load upper half of constant 0xab9423a7
        add w6, w4, w6                // Add X parameter round 4 D=II(D, A, B, C, 0x432aff97, s=10, M[7])
        add w8, w8, w12               // Add dest value
        orn x10, x6, x9               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w8, w17               // Add constant 0xab9423a7
        eor x17, x4, x10              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w8, w17               // Add aux function result
        ror w8, w8, #17               // Rotate left s=15 bits
        movz x17, #0xa039             // Load lower half of constant 0xfc93a039
        movk x17, #0xfc93, lsl #16    // Load upper half of constant 0xfc93a039
        add w8, w6, w8                // Add X parameter round 4 C=II(C, D, A, B, 0xab9423a7, s=15, M[14])
        orn x13, x8, x4               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w9, w22               // Add dest value
        eor x13, x6, x13              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w9, w17               // Add constant 0xfc93a039
        add w17, w9, w13              // Add aux function result
        ror w17, w17, #11             // Rotate left s=21 bits
        movz x9, #0x59c3              // Load lower half of constant 0x655b59c3
        movk x9, #0x655b, lsl #16     // Load upper half of constant 0x655b59c3
        add w17, w8, w17              // Add X parameter round 4 B=II(B, C, D, A, 0xfc93a039, s=21, M[5])
        add w4, w4, w11               // Add dest value
        orn x13, x17, x6              // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w4, w9                // Add constant 0x655b59c3
        eor x4, x8, x13               // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w9, w4                // Add aux function result
        ror w9, w9, #26               // Rotate left s=6 bits
        movz x4, #0xcc92              // Load lower half of constant 0x8f0ccc92
        movk x4, #0x8f0c, lsl #16     // Load upper half of constant 0x8f0ccc92
        add w9, w17, w9               // Add X parameter round 4 A=II(A, B, C, D, 0x655b59c3, s=6, M[12])
        orn x10, x9, x8               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w6, w6, w21               // Add dest value
        eor x10, x17, x10             // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w4, w6, w4                // Add constant 0x8f0ccc92
        add w6, w4, w10               // Add aux function result
        ror w6, w6, #22               // Rotate left s=10 bits
        movz x4, #0xf47d              // Load lower half of constant 0xffeff47d
        movk x4, #0xffef, lsl #16     // Load upper half of constant 0xffeff47d
        add w6, w9, w6                // Add X parameter round 4 D=II(D, A, B, C, 0x8f0ccc92, s=10, M[3])
        add w8, w8, w16               // Add dest value
        orn x10, x6, x17              // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w8, w4                // Add constant 0xffeff47d
        eor x4, x9, x10               // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w8, w4                // Add aux function result
        ror w8, w8, #17               // Rotate left s=15 bits
        movz x4, #0x5dd1              // Load lower half of constant 0x85845dd1
        movk x4, #0x8584, lsl #16     // Load upper half of constant 0x85845dd1
        add w8, w6, w8                // Add X parameter round 4 C=II(C, D, A, B, 0xffeff47d, s=15, M[10])
        orn x10, x8, x9               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w17, w20             // Add dest value
        eor x17, x6, x10              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w15, w4              // Add constant 0x85845dd1
        add w4, w15, w17              // Add aux function result
        ror w4, w4, #11               // Rotate left s=21 bits
        movz x15, #0x7e4f             // Load lower half of constant 0x6fa87e4f
        movk x15, #0x6fa8, lsl #16    // Load upper half of constant 0x6fa87e4f
        add w17, w8, w4               // Add X parameter round 4 B=II(B, C, D, A, 0x85845dd1, s=21, M[1])
        add w4, w9, w5                // Add dest value
        orn x9, x17, x6               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w4, w15              // Add constant 0x6fa87e4f
        eor x4, x8, x9                // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w15, w4               // Add aux function result
        ror w9, w9, #26               // Rotate left s=6 bits
        movz x15, #0xe6e0             // Load lower half of constant 0xfe2ce6e0
        movk x15, #0xfe2c, lsl #16    // Load upper half of constant 0xfe2ce6e0
        add w4, w17, w9               // Add X parameter round 4 A=II(A, B, C, D, 0x6fa87e4f, s=6, M[8])
        orn x9, x4, x8                // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w6, w6, w27               // Add dest value
        eor x9, x17, x9               // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w6, w15              // Add constant 0xfe2ce6e0
        add w6, w15, w9               // Add aux function result
        ror w6, w6, #22               // Rotate left s=10 bits
        movz x9, #0x4314              // Load lower half of constant 0xa3014314
        movk x9, #0xa301, lsl #16     // Load upper half of constant 0xa3014314
        add w15, w4, w6               // Add X parameter round 4 D=II(D, A, B, C, 0xfe2ce6e0, s=10, M[15])
        add w6, w8, w7                // Add dest value
        orn x7, x15, x17              // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w6, w9                // Add constant 0xa3014314
        eor x9, x4, x7                // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w6, w8, w9                // Add aux function result
        ror w6, w6, #17               // Rotate left s=15 bits
        movz x7, #0x11a1              // Load lower half of constant 0x4e0811a1
        movk x7, #0x4e08, lsl #16     // Load upper half of constant 0x4e0811a1
        add w8, w15, w6               // Add X parameter round 4 C=II(C, D, A, B, 0xa3014314, s=15, M[6])
        orn x9, x8, x4                // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w6, w17, w26              // Add dest value
        eor x17, x15, x9              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w9, w6, w7                // Add constant 0x4e0811a1
        add w7, w9, w17               // Add aux function result
        ror w7, w7, #11               // Rotate left s=21 bits
        movz x6, #0x7e82              // Load lower half of constant 0xf7537e82
        movk x6, #0xf753, lsl #16     // Load upper half of constant 0xf7537e82
        add w9, w8, w7                // Add X parameter round 4 B=II(B, C, D, A, 0x4e0811a1, s=21, M[13])
        add w17, w4, w14              // Add dest value
        orn x7, x9, x15               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w14, w17, w6              // Add constant 0xf7537e82
        eor x4, x8, x7                // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w17, w14, w4              // Add aux function result
        ror w17, w17, #26             // Rotate left s=6 bits
        movz x6, #0xf235              // Load lower half of constant 0xbd3af235
        movk x6, #0xbd3a, lsl #16     // Load upper half of constant 0xbd3af235
        add w7, w9, w17               // Add X parameter round 4 A=II(A, B, C, D, 0xf7537e82, s=6, M[4])
        orn x14, x7, x8               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w4, w15, w25              // Add dest value
        eor x17, x9, x14              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w4, w6               // Add constant 0xbd3af235
        add w16, w15, w17             // Add aux function result
        ror w16, w16, #22             // Rotate left s=10 bits
        movz x14, #0xd2bb             // Load lower half of constant 0x2ad7d2bb
        movk x14, #0x2ad7, lsl #16    // Load upper half of constant 0x2ad7d2bb
        add w4, w7, w16               // Add X parameter round 4 D=II(D, A, B, C, 0xbd3af235, s=10, M[11])
        add w6, w8, w3                // Add dest value
        orn x15, x4, x9               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w17, w6, w14              // Add constant 0x2ad7d2bb
        eor x16, x7, x15              // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w8, w17, w16              // Add aux function result
        ror w8, w8, #17               // Rotate left s=15 bits
        movz x3, #0xd391              // Load lower half of constant 0xeb86d391
        movk x3, #0xeb86, lsl #16     // Load upper half of constant 0xeb86d391
        add w14, w4, w8               // Add X parameter round 4 C=II(C, D, A, B, 0x2ad7d2bb, s=15, M[2])
        orn x6, x14, x7               // Begin aux function round 4 I(x,y,z)=((~z|x)^y)
        add w15, w9, w24              // Add dest value
        eor x17, x4, x6               // End aux function round 4 I(x,y,z)=((~z|x)^y)
        add w16, w15, w3              // Add constant 0xeb86d391
        add w8, w16, w17              // Add aux function result
        ror w8, w8, #11               // Rotate left s=21 bits
        ldp w6, w15, [x0]             // Reload MD5 state->A and state->B
        ldp w5, w9, [x0, #8]          // Reload MD5 state->C and state->D
        add w3, w14, w8               // Add X parameter round 4 B=II(B, C, D, A, 0xeb86d391, s=21, M[9])
        add w13, w4, w9               // Add result of MD5 rounds to state->D
        add w12, w14, w5              // Add result of MD5 rounds to state->C
        add w10, w7, w6               // Add result of MD5 rounds to state->A
        add w11, w3, w15              // Add result of MD5 rounds to state->B
        stp w12, w13, [x0, #8]        // Store MD5 states C,D
        stp w10, w11, [x0]            // Store MD5 states A,B
        add x1, x1, #64               // Increment data pointer
        subs w2, w2, #1               // Decrement block counter
        b.ne md5_blocks_loop

        ldp     x21,x22,[sp,#16]
        ldp     x23,x24,[sp,#32]
        ldp     x25,x26,[sp,#48]
        ldp     x27,x28,[sp,#64]
        ldp     x19,x20,[sp],#80
        ret

EOF

# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
#		CONTEXT *context,DISPATCHER_CONTEXT *disp)

print $code;

close STDOUT or die "error closing STDOUT: $!";


#!/usr/bin/perl -w
#
# MD5 optimized for AMD64.
#
# Author: Marc Bevand <bevand_m (at) epita.fr>
# Licence: I hereby disclaim the copyright on this code and place it
# in the public domain.
#

use strict;

my $code;

# round1_step() does:
#   dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s)
#   %r10d = X[k_next]
#   %r11d = z' (copy of z for the next step)
# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC)
sub round1_step
{
    my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
    $code .= " mov	0*4(%rsi),	%r10d		/* (NEXT STEP) X[0] */\n" if ($pos == -1);
    $code .= " mov	%edx,		%r11d		/* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
    $code .= <<EOF;
	xor	$y,		%r11d		/* y ^ ... */
	lea	$T_i($dst,%r10d),$dst		/* Const + dst + ... */
	and	$x,		%r11d		/* x & ... */
	xor	$z,		%r11d		/* z ^ ... */
	mov	$k_next*4(%rsi),%r10d		/* (NEXT STEP) X[$k_next] */
	add	%r11d,		$dst		/* dst += ... */
	rol	\$$s,		$dst		/* dst <<< s */
	mov	$y,		%r11d		/* (NEXT STEP) z' = $y */
	add	$x,		$dst		/* dst += x */
EOF
}

# round2_step() does:
#   dst = x + ((dst + G(x,y,z) + X[k] + T_i) <<< s)
#   %r10d = X[k_next]
#   %r11d = z' (copy of z for the next step)
#   %r12d = z' (copy of z for the next step)
# Each round2_step() takes about 5.4 clocks (11 instructions, 2.0 IPC)
sub round2_step
{
    my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
    $code .= " mov	1*4(%rsi),	%r10d		/* (NEXT STEP) X[1] */\n" if ($pos == -1);
    $code .= " mov	%edx,		%r11d		/* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
    $code .= " mov	%edx,		%r12d		/* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
    $code .= <<EOF;
	not	%r11d				/* not z */
	lea	$T_i($dst,%r10d),$dst		/* Const + dst + ... */
	and	$x,		%r12d		/* x & z */
	and	$y,		%r11d		/* y & (not z) */
	mov	$k_next*4(%rsi),%r10d		/* (NEXT STEP) X[$k_next] */
	or	%r11d,		%r12d		/* (y & (not z)) | (x & z) */
	mov	$y,		%r11d		/* (NEXT STEP) z' = $y */
	add	%r12d,		$dst		/* dst += ... */
	mov	$y,		%r12d		/* (NEXT STEP) z' = $y */
	rol	\$$s,		$dst		/* dst <<< s */
	add	$x,		$dst		/* dst += x */
EOF
}

# round3_step() does:
#   dst = x + ((dst + H(x,y,z) + X[k] + T_i) <<< s)
#   %r10d = X[k_next]
#   %r11d = y' (copy of y for the next step)
# Each round3_step() takes about 4.2 clocks (8 instructions, 1.9 IPC)
sub round3_step
{
    my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
    $code .= " mov	5*4(%rsi),	%r10d		/* (NEXT STEP) X[5] */\n" if ($pos == -1);
    $code .= " mov	%ecx,		%r11d		/* (NEXT STEP) y' = %ecx */\n" if ($pos == -1);
    $code .= <<EOF;
	lea	$T_i($dst,%r10d),$dst		/* Const + dst + ... */
	mov	$k_next*4(%rsi),%r10d		/* (NEXT STEP) X[$k_next] */
	xor	$z,		%r11d		/* z ^ ... */
	xor	$x,		%r11d		/* x ^ ... */
	add	%r11d,		$dst		/* dst += ... */
	rol	\$$s,		$dst		/* dst <<< s */
	mov	$x,		%r11d		/* (NEXT STEP) y' = $x */
	add	$x,		$dst		/* dst += x */
EOF
}

# round4_step() does:
#   dst = x + ((dst + I(x,y,z) + X[k] + T_i) <<< s)
#   %r10d = X[k_next]
#   %r11d = not z' (copy of not z for the next step)
# Each round4_step() takes about 5.2 clocks (9 instructions, 1.7 IPC)
sub round4_step
{
    my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
    $code .= " mov	0*4(%rsi),	%r10d		/* (NEXT STEP) X[0] */\n" if ($pos == -1);
    $code .= " mov	\$0xffffffff,	%r11d\n" if ($pos == -1);
    $code .= " xor	%edx,		%r11d		/* (NEXT STEP) not z' = not %edx*/\n"
    if ($pos == -1);
    $code .= <<EOF;
	lea	$T_i($dst,%r10d),$dst		/* Const + dst + ... */
	or	$x,		%r11d		/* x | ... */
	xor	$y,		%r11d		/* y ^ ... */
	add	%r11d,		$dst		/* dst += ... */
	mov	$k_next*4(%rsi),%r10d		/* (NEXT STEP) X[$k_next] */
	mov	\$0xffffffff,	%r11d
	rol	\$$s,		$dst		/* dst <<< s */
	xor	$y,		%r11d		/* (NEXT STEP) not z' = not $y */
	add	$x,		$dst		/* dst += x */
EOF
}

no warnings qw(uninitialized);

# 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."; }

my $flavour = shift;
my $output  = shift;

my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);

$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
( $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 OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;

$code .= <<EOF;
.text
.align 16

.globl md5_block_asm_data_order
.type md5_block_asm_data_order,\@function,3
md5_block_asm_data_order:
.cfi_startproc
	push	%rbp
.cfi_push	rbp
	push	%rbx
.cfi_push	rbx
	push	%r12
.cfi_push	r12
	push	%r14
.cfi_push	r14
	push	%r15
.cfi_push	r15
.Lprologue:

	# rdi = arg #1 (ctx, MD5_CTX pointer)
	# rsi = arg #2 (ptr, data pointer)
	# rdx = arg #3 (nbr, number of 16-word blocks to process)
	mov	%rdi,		%rbp	# rbp = ctx
	shl	\$6,		%rdx	# rdx = nbr in bytes
	lea	(%rsi,%rdx),	%rdi	# rdi = end
	mov	0*4(%rbp),	%eax	# eax = ctx->A
	mov	1*4(%rbp),	%ebx	# ebx = ctx->B
	mov	2*4(%rbp),	%ecx	# ecx = ctx->C
	mov	3*4(%rbp),	%edx	# edx = ctx->D
	# end is 'rdi'
	# ptr is 'rsi'
	# A is 'eax'
	# B is 'ebx'
	# C is 'ecx'
	# D is 'edx'

	cmp	%rdi,		%rsi		# cmp end with ptr
	je	.Lend				# jmp if ptr == end

	# BEGIN of loop over 16-word blocks
.Lloop:	# save old values of A, B, C, D
	mov	%eax,		%r8d
	mov	%ebx,		%r9d
	mov	%ecx,		%r14d
	mov	%edx,		%r15d
EOF
round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7');
round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12');
round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17');
round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22');
round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7');
round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12');
round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17');
round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22');
round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7');
round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12');
round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17');
round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22');
round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7');
round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12');
round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17');
round1_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x49b40821','22');

round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5');
round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9');
round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14');
round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20');
round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5');
round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9');
round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14');
round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20');
round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5');
round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9');
round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14');
round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20');
round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5');
round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9');
round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14');
round2_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x8d2a4c8a','20');

round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4');
round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11');
round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16');
round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23');
round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4');
round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11');
round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16');
round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23');
round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4');
round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11');
round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16');
round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23');
round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4');
round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11');
round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16');
round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23');

round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6');
round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10');
round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15');
round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21');
round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6');
round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10');
round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15');
round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21');
round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6');
round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10');
round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15');
round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21');
round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6');
round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10');
round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15');
round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21');
$code .= <<EOF;
	# add old values of A, B, C, D
	add	%r8d,	%eax
	add	%r9d,	%ebx
	add	%r14d,	%ecx
	add	%r15d,	%edx

	# loop control
	add	\$64,		%rsi		# ptr += 64
	cmp	%rdi,		%rsi		# cmp end with ptr
	jb	.Lloop				# jmp if ptr < end
	# END of loop over 16-word blocks

.Lend:
	mov	%eax,		0*4(%rbp)	# ctx->A = A
	mov	%ebx,		1*4(%rbp)	# ctx->B = B
	mov	%ecx,		2*4(%rbp)	# ctx->C = C
	mov	%edx,		3*4(%rbp)	# ctx->D = D

	mov	(%rsp),%r15
.cfi_restore r15
	mov	8(%rsp),%r14
.cfi_restore r14
	mov	16(%rsp),%r12
.cfi_restore r12
	mov	24(%rsp),%rbx
.cfi_restore rbx
	mov	32(%rsp),%rbp
.cfi_restore rbp
	add	\$40,%rsp
.cfi_adjust_cfa_offset	-40
.Lepilogue:
	ret
.cfi_endproc
.size md5_block_asm_data_order,.-md5_block_asm_data_order
EOF

# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
if ($win64) {
my $rec="%rcx";
my $frame="%rdx";
my $context="%r8";
my $disp="%r9";

$code.=<<___;
.extern	__imp_RtlVirtualUnwind
.type	se_handler,\@abi-omnipotent
.align	16
se_handler:
	push	%rsi
	push	%rdi
	push	%rbx
	push	%rbp
	push	%r12
	push	%r13
	push	%r14
	push	%r15
	pushfq
	sub	\$64,%rsp

	mov	120($context),%rax	# pull context->Rax
	mov	248($context),%rbx	# pull context->Rip

	lea	.Lprologue(%rip),%r10
	cmp	%r10,%rbx		# context->Rip<.Lprologue
	jb	.Lin_prologue

	mov	152($context),%rax	# pull context->Rsp

	lea	.Lepilogue(%rip),%r10
	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
	jae	.Lin_prologue

	lea	40(%rax),%rax

	mov	-8(%rax),%rbp
	mov	-16(%rax),%rbx
	mov	-24(%rax),%r12
	mov	-32(%rax),%r14
	mov	-40(%rax),%r15
	mov	%rbx,144($context)	# restore context->Rbx
	mov	%rbp,160($context)	# restore context->Rbp
	mov	%r12,216($context)	# restore context->R12
	mov	%r14,232($context)	# restore context->R14
	mov	%r15,240($context)	# restore context->R15

.Lin_prologue:
	mov	8(%rax),%rdi
	mov	16(%rax),%rsi
	mov	%rax,152($context)	# restore context->Rsp
	mov	%rsi,168($context)	# restore context->Rsi
	mov	%rdi,176($context)	# restore context->Rdi

	mov	40($disp),%rdi		# disp->ContextRecord
	mov	$context,%rsi		# context
	mov	\$154,%ecx		# sizeof(CONTEXT)
	.long	0xa548f3fc		# cld; rep movsq

	mov	$disp,%rsi
	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
	mov	0(%rsi),%r8		# arg3, disp->ControlPc
	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
	mov	40(%rsi),%r10		# disp->ContextRecord
	lea	56(%rsi),%r11		# &disp->HandlerData
	lea	24(%rsi),%r12		# &disp->EstablisherFrame
	mov	%r10,32(%rsp)		# arg5
	mov	%r11,40(%rsp)		# arg6
	mov	%r12,48(%rsp)		# arg7
	mov	%rcx,56(%rsp)		# arg8, (NULL)
	call	*__imp_RtlVirtualUnwind(%rip)

	mov	\$1,%eax		# ExceptionContinueSearch
	add	\$64,%rsp
	popfq
	pop	%r15
	pop	%r14
	pop	%r13
	pop	%r12
	pop	%rbp
	pop	%rbx
	pop	%rdi
	pop	%rsi
	ret
.size	se_handler,.-se_handler

.section	.pdata
.align	4
	.rva	.LSEH_begin_md5_block_asm_data_order
	.rva	.LSEH_end_md5_block_asm_data_order
	.rva	.LSEH_info_md5_block_asm_data_order

.section	.xdata
.align	8
.LSEH_info_md5_block_asm_data_order:
	.byte	9,0,0,0
	.rva	se_handler
___
}

print $code;

close STDOUT or die "error closing STDOUT: $!";