summaryrefslogtreecommitdiff
path: root/lib/libcrypto/perlasm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libcrypto/perlasm')
-rw-r--r--lib/libcrypto/perlasm/LICENSE127
-rw-r--r--lib/libcrypto/perlasm/alpha.pl434
-rw-r--r--lib/libcrypto/perlasm/cbc.pl342
-rw-r--r--lib/libcrypto/perlasm/readme124
-rw-r--r--lib/libcrypto/perlasm/version5
-rw-r--r--lib/libcrypto/perlasm/x86asm.pl118
-rw-r--r--lib/libcrypto/perlasm/x86ms.pl365
-rw-r--r--lib/libcrypto/perlasm/x86nasm.pl366
-rw-r--r--lib/libcrypto/perlasm/x86unix.pl472
9 files changed, 2353 insertions, 0 deletions
diff --git a/lib/libcrypto/perlasm/LICENSE b/lib/libcrypto/perlasm/LICENSE
new file mode 100644
index 000000000..3fd259ac3
--- /dev/null
+++ b/lib/libcrypto/perlasm/LICENSE
@@ -0,0 +1,127 @@
+
+ LICENSE ISSUES
+ ==============
+
+ The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
+ the OpenSSL License and the original SSLeay license apply to the toolkit.
+ See below for the actual license texts. Actually both licenses are BSD-style
+ Open Source licenses. In case of any license issues related to OpenSSL
+ please contact openssl-core@openssl.org.
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
diff --git a/lib/libcrypto/perlasm/alpha.pl b/lib/libcrypto/perlasm/alpha.pl
new file mode 100644
index 000000000..fe69ca5a3
--- /dev/null
+++ b/lib/libcrypto/perlasm/alpha.pl
@@ -0,0 +1,434 @@
+#!/usr/bin/perl
+
+package alpha;
+use Carp qw(croak cluck);
+
+$label="100";
+
+$n_debug=0;
+$smear_regs=1;
+$reg_alloc=1;
+
+$align="3";
+$com_start="#";
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+# General registers
+
+%regs=( 'r0', '$0',
+ 'r1', '$1',
+ 'r2', '$2',
+ 'r3', '$3',
+ 'r4', '$4',
+ 'r5', '$5',
+ 'r6', '$6',
+ 'r7', '$7',
+ 'r8', '$8',
+ 'r9', '$22',
+ 'r10', '$23',
+ 'r11', '$24',
+ 'r12', '$25',
+ 'r13', '$27',
+ 'r14', '$28',
+ 'r15', '$21', # argc == 5
+ 'r16', '$20', # argc == 4
+ 'r17', '$19', # argc == 3
+ 'r18', '$18', # argc == 2
+ 'r19', '$17', # argc == 1
+ 'r20', '$16', # argc == 0
+ 'r21', '$9', # save 0
+ 'r22', '$10', # save 1
+ 'r23', '$11', # save 2
+ 'r24', '$12', # save 3
+ 'r25', '$13', # save 4
+ 'r26', '$14', # save 5
+
+ 'a0', '$16',
+ 'a1', '$17',
+ 'a2', '$18',
+ 'a3', '$19',
+ 'a4', '$20',
+ 'a5', '$21',
+
+ 's0', '$9',
+ 's1', '$10',
+ 's2', '$11',
+ 's3', '$12',
+ 's4', '$13',
+ 's5', '$14',
+ 'zero', '$31',
+ 'sp', '$30',
+ );
+
+$main'reg_s0="r21";
+$main'reg_s1="r22";
+$main'reg_s2="r23";
+$main'reg_s3="r24";
+$main'reg_s4="r25";
+$main'reg_s5="r26";
+
+@reg=( '$0', '$1' ,'$2' ,'$3' ,'$4' ,'$5' ,'$6' ,'$7' ,'$8',
+ '$22','$23','$24','$25','$20','$21','$27','$28');
+
+
+sub main'sub { &out3("subq",@_); }
+sub main'add { &out3("addq",@_); }
+sub main'mov { &out3("bis",$_[0],$_[0],$_[1]); }
+sub main'or { &out3("bis",@_); }
+sub main'bis { &out3("bis",@_); }
+sub main'br { &out1("br",@_); }
+sub main'ld { &out2("ldq",@_); }
+sub main'st { &out2("stq",@_); }
+sub main'cmpult { &out3("cmpult",@_); }
+sub main'cmplt { &out3("cmplt",@_); }
+sub main'bgt { &out2("bgt",@_); }
+sub main'ble { &out2("ble",@_); }
+sub main'blt { &out2("blt",@_); }
+sub main'mul { &out3("mulq",@_); }
+sub main'muh { &out3("umulh",@_); }
+
+$main'QWS=8;
+
+sub main'asm_add
+ {
+ push(@out,@_);
+ }
+
+sub main'asm_finish
+ {
+ &main'file_end();
+ print &main'asm_get_output();
+ }
+
+sub main'asm_init
+ {
+ ($type,$fn)=@_;
+ $filename=$fn;
+
+ &main'asm_init_output();
+ &main'comment("Don't even think of reading this code");
+ &main'comment("It was automatically generated by $filename");
+ &main'comment("Which is a perl program used to generate the alpha assember.");
+ &main'comment("eric <eay\@cryptsoft.com>");
+ &main'comment("");
+
+ $filename =~ s/\.pl$//;
+ &main'file($filename);
+ }
+
+sub conv
+ {
+ local($r)=@_;
+ local($v);
+
+ return($regs{$r}) if defined($regs{$r});
+ return($r);
+ }
+
+sub main'QWPw
+ {
+ local($off,$reg)=@_;
+
+ return(&main'QWP($off*8,$reg));
+ }
+
+sub main'QWP
+ {
+ local($off,$reg)=@_;
+
+ $ret="$off(".&conv($reg).")";
+ return($ret);
+ }
+
+sub out3
+ {
+ local($name,$p1,$p2,$p3)=@_;
+
+ $p1=&conv($p1);
+ $p2=&conv($p2);
+ $p3=&conv($p3);
+ push(@out,"\t$name\t");
+ $l=length($p1)+1;
+ push(@out,$p1.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ $l=length($p2)+1;
+ push(@out,$p2.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ push(@out,&conv($p3)."\n");
+ }
+
+sub out2
+ {
+ local($name,$p1,$p2,$p3)=@_;
+
+ $p1=&conv($p1);
+ $p2=&conv($p2);
+ push(@out,"\t$name\t");
+ $l=length($p1)+1;
+ push(@out,$p1.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ push(@out,&conv($p2)."\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+
+ $p1=&conv($p1);
+ push(@out,"\t$name\t".$p1."\n");
+ }
+
+sub out0
+ {
+ push(@out,"\t$_[0]\n");
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ # DEC Alpha assember
+ # Generated from perl scripts contains in SSLeay
+ .file 1 "$file.s"
+ .set noat
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func)=@_;
+
+print STDERR "$func\n";
+ local($tmp)=<<"EOF";
+ .text
+ .align $align
+ .globl $func
+ .ent $func
+${func}:
+${func}..ng:
+ .frame \$30,0,\$26,0
+ .prologue 0
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ ret \$31,(\$26),1
+ .end $func
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ ret \$31,(\$26),1
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ push(@out,"\t.end $func\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ if ($num < 6)
+ {
+ $num=20-$num;
+ return("r$num");
+ }
+ else
+ { return(&main'QWP($stack+$num*8,"sp")); }
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*8;
+ &main'sub("sp",$num*8,"sp");
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*8;
+ &main'add("sp",$num*8,"sp");
+ }
+
+sub main'swtmp
+ {
+ return(&main'QWP(($_[0])*8,"sp"));
+ }
+
+# Should use swtmp, which is above sp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'QWP(-($num+1)*4,"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=$label;
+ $label++;
+ }
+ return('$'.$label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=$label;
+ $label++;
+ }
+# push(@out,".align $align\n") if ($_[1] != 0);
+ push(@out,'$'."$label{$_[0]}:\n");
+ }
+
+sub main'file_end
+ {
+ }
+
+sub main'data_word
+ {
+ push(@out,"\t.long $_[0]\n");
+ }
+
+@pool_free=();
+@pool_taken=();
+$curr_num=0;
+$max=0;
+
+sub main'init_pool
+ {
+ local($args)=@_;
+ local($i);
+
+ @pool_free=();
+ for ($i=(14+(6-$args)); $i >= 0; $i--)
+ {
+ push(@pool_free,"r$i");
+ }
+ print STDERR "START :register pool:@pool_free\n";
+ $curr_num=$max=0;
+ }
+
+sub main'fin_pool
+ {
+ printf STDERR "END %2d:register pool:@pool_free\n",$max;
+ }
+
+sub main'GR
+ {
+ local($r)=@_;
+ local($i,@n,$_);
+
+ foreach (@pool_free)
+ {
+ if ($r ne $_)
+ { push(@n,$_); }
+ else
+ {
+ $curr_num++;
+ $max=$curr_num if ($curr_num > $max);
+ }
+ }
+ @pool_free=@n;
+print STDERR "GR:@pool_free\n" if $reg_alloc;
+ return(@_);
+ }
+
+sub main'NR
+ {
+ local($num)=@_;
+ local(@ret);
+
+ $num=1 if $num == 0;
+ ($#pool_free >= ($num-1)) || croak "out of registers: want $num, have @pool_free";
+ while ($num > 0)
+ {
+ push(@ret,pop @pool_free);
+ $curr_num++;
+ $max=$curr_num if ($curr_num > $max);
+ $num--
+ }
+ print STDERR "nr @ret\n" if $n_debug;
+print STDERR "NR:@pool_free\n" if $reg_alloc;
+ return(@ret);
+
+ }
+
+sub main'FR
+ {
+ local(@r)=@_;
+ local(@a,$v,$w);
+
+ print STDERR "fr @r\n" if $n_debug;
+# cluck "fr @r";
+ for $w (@pool_free)
+ {
+ foreach $v (@r)
+ {
+ croak "double register free of $v (@pool_free)" if $w eq $v;
+ }
+ }
+ foreach $v (@r)
+ {
+ croak "bad argument to FR" if ($v !~ /^r\d+$/);
+ if ($smear_regs)
+ { unshift(@pool_free,$v); }
+ else { push(@pool_free,$v); }
+ $curr_num--;
+ }
+print STDERR "FR:@pool_free\n" if $reg_alloc;
+ }
+1;
diff --git a/lib/libcrypto/perlasm/cbc.pl b/lib/libcrypto/perlasm/cbc.pl
new file mode 100644
index 000000000..278930579
--- /dev/null
+++ b/lib/libcrypto/perlasm/cbc.pl
@@ -0,0 +1,342 @@
+#!/usr/bin/perl
+
+# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+# des_cblock (*input);
+# des_cblock (*output);
+# long length;
+# des_key_schedule schedule;
+# des_cblock (*ivec);
+# int enc;
+#
+# calls
+# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+#
+
+#&cbc("des_ncbc_encrypt","des_encrypt",0);
+#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
+# 1,4,5,3,5,-1);
+#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
+# 0,4,5,3,5,-1);
+#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
+# 0,6,7,3,4,5);
+#
+# When doing a cipher that needs bigendian order,
+# for encrypt, the iv is kept in bigendian form,
+# while for decrypt, it is kept in little endian.
+sub cbc
+ {
+ local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
+ # name is the function name
+ # enc_func and dec_func and the functions to call for encrypt/decrypt
+ # swap is true if byte order needs to be reversed
+ # iv_off is parameter number for the iv
+ # enc_off is parameter number for the encrypt/decrypt flag
+ # p1,p2,p3 are the offsets for parameters to be passed to the
+ # underlying calls.
+
+ &function_begin_B($name,"");
+ &comment("");
+
+ $in="esi";
+ $out="edi";
+ $count="ebp";
+
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ $data_off=4;
+ $data_off+=4 if ($p1 > 0);
+ $data_off+=4 if ($p2 > 0);
+ $data_off+=4 if ($p3 > 0);
+
+ &mov($count, &wparam(2)); # length
+
+ &comment("getting iv ptr from parameter $iv_off");
+ &mov("ebx", &wparam($iv_off)); # Get iv ptr
+
+ &mov($in, &DWP(0,"ebx","",0));# iv[0]
+ &mov($out, &DWP(4,"ebx","",0));# iv[1]
+
+ &push($out);
+ &push($in);
+ &push($out); # used in decrypt for iv[1]
+ &push($in); # used in decrypt for iv[0]
+
+ &mov("ebx", "esp"); # This is the address of tin[2]
+
+ &mov($in, &wparam(0)); # in
+ &mov($out, &wparam(1)); # out
+
+ # We have loaded them all, how lets push things
+ &comment("getting encrypt flag from parameter $enc_off");
+ &mov("ecx", &wparam($enc_off)); # Get enc flag
+ if ($p3 > 0)
+ {
+ &comment("get and push parameter $p3");
+ if ($enc_off != $p3)
+ { &mov("eax", &wparam($p3)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p2 > 0)
+ {
+ &comment("get and push parameter $p2");
+ if ($enc_off != $p2)
+ { &mov("eax", &wparam($p2)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p1 > 0)
+ {
+ &comment("get and push parameter $p1");
+ if ($enc_off != $p1)
+ { &mov("eax", &wparam($p1)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ &push("ebx"); # push data/iv
+
+ &cmp("ecx",0);
+ &jz(&label("decrypt"));
+
+ &and($count,0xfffffff8);
+ &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0]
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1]
+
+ &jz(&label("encrypt_finish"));
+
+ #############################################################
+
+ &set_label("encrypt_loop");
+ # encrypt start
+ # "eax" and "ebx" hold iv (or the last cipher text)
+
+ &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ # eax and ebx are the next iv.
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("encrypt_loop"));
+
+###################################################################3
+ &set_label("encrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+ &xor("ecx","ecx");
+ &xor("edx","edx");
+ &mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
+ &jmp_ptr($count);
+
+&set_label("ej7");
+ &xor("edx", "edx") if $ppro; # ppro friendly
+ &movb(&HB("edx"), &BP(6,$in,"",0));
+ &shl("edx",8);
+&set_label("ej6");
+ &movb(&HB("edx"), &BP(5,$in,"",0));
+&set_label("ej5");
+ &movb(&LB("edx"), &BP(4,$in,"",0));
+&set_label("ej4");
+ &mov("ecx", &DWP(0,$in,"",0));
+ &jmp(&label("ejend"));
+&set_label("ej3");
+ &movb(&HB("ecx"), &BP(2,$in,"",0));
+ &xor("ecx", "ecx") if $ppro; # ppro friendly
+ &shl("ecx",8);
+&set_label("ej2");
+ &movb(&HB("ecx"), &BP(1,$in,"",0));
+&set_label("ej1");
+ &movb(&LB("ecx"), &BP(0,$in,"",0));
+&set_label("ejend");
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ &jmp(&label("finish"));
+
+ #############################################################
+ #############################################################
+ &set_label("decrypt",1);
+ # decrypt start
+ &and($count,0xfffffff8);
+ # The next 2 instructions are only for if the jz is taken
+ &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+ &jz(&label("decrypt_finish"));
+
+ &set_label("decrypt_loop");
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+ &mov(&DWP(0,$out,"",0),"ecx");
+ &mov(&DWP(4,$out,"",0),"edx");
+
+ &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv
+ &mov(&DWP($data_off+12,"esp","",0), "ebx"); #
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("decrypt_loop"));
+############################ ENDIT #######################3
+ &set_label("decrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ # this is for when we exit
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+&set_label("dj7");
+ &rotr("edx", 16);
+ &movb(&BP(6,$out,"",0), &LB("edx"));
+ &shr("edx",16);
+&set_label("dj6");
+ &movb(&BP(5,$out,"",0), &HB("edx"));
+&set_label("dj5");
+ &movb(&BP(4,$out,"",0), &LB("edx"));
+&set_label("dj4");
+ &mov(&DWP(0,$out,"",0), "ecx");
+ &jmp(&label("djend"));
+&set_label("dj3");
+ &rotr("ecx", 16);
+ &movb(&BP(2,$out,"",0), &LB("ecx"));
+ &shl("ecx",16);
+&set_label("dj2");
+ &movb(&BP(1,$in,"",0), &HB("ecx"));
+&set_label("dj1");
+ &movb(&BP(0,$in,"",0), &LB("ecx"));
+&set_label("djend");
+
+ # final iv is still in eax:ebx
+ &jmp(&label("finish"));
+
+
+############################ FINISH #######################3
+ &set_label("finish",1);
+ &mov("ecx", &wparam($iv_off)); # Get iv ptr
+
+ #################################################
+ $total=16+4;
+ $total+=4 if ($p1 > 0);
+ $total+=4 if ($p2 > 0);
+ $total+=4 if ($p3 > 0);
+ &add("esp",$total);
+
+ &mov(&DWP(0,"ecx","",0), "eax"); # save iv
+ &mov(&DWP(4,"ecx","",0), "ebx"); # save iv
+
+ &function_end_A($name);
+
+ &set_label("cbc_enc_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("ej1"));
+ &data_word(&label("ej2"));
+ &data_word(&label("ej3"));
+ &data_word(&label("ej4"));
+ &data_word(&label("ej5"));
+ &data_word(&label("ej6"));
+ &data_word(&label("ej7"));
+ &set_label("cbc_dec_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("dj1"));
+ &data_word(&label("dj2"));
+ &data_word(&label("dj3"));
+ &data_word(&label("dj4"));
+ &data_word(&label("dj5"));
+ &data_word(&label("dj6"));
+ &data_word(&label("dj7"));
+
+ &function_end_B($name);
+
+ }
+
+1;
diff --git a/lib/libcrypto/perlasm/readme b/lib/libcrypto/perlasm/readme
new file mode 100644
index 000000000..f02bbee75
--- /dev/null
+++ b/lib/libcrypto/perlasm/readme
@@ -0,0 +1,124 @@
+The perl scripts in this directory are my 'hack' to generate
+multiple different assembler formats via the one origional script.
+
+The way to use this library is to start with adding the path to this directory
+and then include it.
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+
+The first thing we do is setup the file and type of assember
+
+&asm_init($ARGV[0],$0);
+
+The first argument is the 'type'. Currently
+'cpp', 'sol', 'a.out', 'elf' or 'win32'.
+Argument 2 is the file name.
+
+The reciprocal function is
+&asm_finish() which should be called at the end.
+
+There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
+and x86unix.pl which is the unix (gas) version.
+
+Functions of interest are:
+&external_label("des_SPtrans"); declare and external variable
+&LB(reg); Low byte for a register
+&HB(reg); High byte for a register
+&BP(off,base,index,scale) Byte pointer addressing
+&DWP(off,base,index,scale) Word pointer addressing
+&stack_push(num) Basically a 'sub esp, num*4' with extra
+&stack_pop(num) inverse of stack_push
+&function_begin(name,extra) Start a function with pushing of
+ edi, esi, ebx and ebp. extra is extra win32
+ external info that may be required.
+&function_begin_B(name,extra) Same as norma function_begin but no pushing.
+&function_end(name) Call at end of function.
+&function_end_A(name) Standard pop and ret, for use inside functions
+&function_end_B(name) Call at end but with poping or 'ret'.
+&swtmp(num) Address on stack temp word.
+&wparam(num) Parameter number num, that was push
+ in C convention. This all works over pushes
+ and pops.
+&comment("hello there") Put in a comment.
+&label("loop") Refer to a label, normally a jmp target.
+&set_label("loop") Set a label at this point.
+&data_word(word) Put in a word of data.
+
+So how does this all hold together? Given
+
+int calc(int len, int *data)
+ {
+ int i,j=0;
+
+ for (i=0; i<len; i++)
+ {
+ j+=other(data[i]);
+ }
+ }
+
+So a very simple version of this function could be coded as
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+
+ &asm_init($ARGV[0],"cacl.pl");
+
+ &external_label("other");
+
+ $tmp1= "eax";
+ $j= "edi";
+ $data= "esi";
+ $i= "ebp";
+
+ &comment("a simple function");
+ &function_begin("calc");
+ &mov( $data, &wparam(1)); # data
+ &xor( $j, $j);
+ &xor( $i, $i);
+
+ &set_label("loop");
+ &cmp( $i, &wparam(0));
+ &jge( &label("end"));
+
+ &mov( $tmp1, &DWP(0,$data,$i,4));
+ &push( $tmp1);
+ &call( "other");
+ &add( $j, "eax");
+ &pop( $tmp1);
+ &inc( $i);
+ &jmp( &label("loop"));
+
+ &set_label("end");
+ &mov( "eax", $j);
+
+ &function_end("calc");
+
+ &asm_finish();
+
+The above example is very very unoptimised but gives an idea of how
+things work.
+
+There is also a cbc mode function generator in cbc.pl
+
+&cbc( $name,
+ $encrypt_function_name,
+ $decrypt_function_name,
+ $true_if_byte_swap_needed,
+ $parameter_number_for_iv,
+ $parameter_number_for_encrypt_flag,
+ $first_parameter_to_pass,
+ $second_parameter_to_pass,
+ $third_parameter_to_pass);
+
+So for example, given
+void BF_encrypt(BF_LONG *data,BF_KEY *key);
+void BF_decrypt(BF_LONG *data,BF_KEY *key);
+void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
+ BF_KEY *ks, unsigned char *iv, int enc);
+
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
+
+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
+
diff --git a/lib/libcrypto/perlasm/version b/lib/libcrypto/perlasm/version
new file mode 100644
index 000000000..5e62822b4
--- /dev/null
+++ b/lib/libcrypto/perlasm/version
@@ -0,0 +1,5 @@
+version,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
+
+This version of perlasm was copied from the openssl 0.9.6c distribution
+
+The license applying to it is enclose in the LICENSE file
diff --git a/lib/libcrypto/perlasm/x86asm.pl b/lib/libcrypto/perlasm/x86asm.pl
new file mode 100644
index 000000000..8af0fd17f
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86asm.pl
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+
+# require 'x86asm.pl';
+# &asm_init("cpp","des-586.pl");
+# XXX
+# XXX
+# main'asm_finish
+
+sub main'asm_finish
+ {
+ &file_end();
+ &asm_finish_cpp() if $cpp;
+ print &asm_get_output();
+ }
+
+sub main'asm_init
+ {
+ ($type,$fn,$i386)=@_;
+ $filename=$fn;
+
+ $cpp=$sol=$aout=$win32=$gaswin=0;
+ if ( ($type eq "elf"))
+ { require "x86unix.pl"; }
+ elsif ( ($type eq "a.out"))
+ { $aout=1; require "x86unix.pl"; }
+ elsif ( ($type eq "gaswin"))
+ { $gaswin=1; $aout=1; require "x86unix.pl"; }
+ elsif ( ($type eq "sol"))
+ { $sol=1; require "x86unix.pl"; }
+ elsif ( ($type eq "cpp"))
+ { $cpp=1; require "x86unix.pl"; }
+ elsif ( ($type eq "win32"))
+ { $win32=1; require "x86ms.pl"; }
+ elsif ( ($type eq "win32n"))
+ { $win32=1; require "x86nasm.pl"; }
+ else
+ {
+ print STDERR <<"EOF";
+Pick one target type from
+ elf - linux, FreeBSD etc
+ a.out - old linux
+ sol - x86 solaris
+ cpp - format so x86unix.cpp can be used
+ win32 - Windows 95/Windows NT
+ win32n - Windows 95/Windows NT NASM format
+EOF
+ exit(1);
+ }
+
+ &asm_init_output();
+
+&comment("Don't even think of reading this code");
+&comment("It was automatically generated by $filename");
+&comment("Which is a perl program used to generate the x86 assember for");
+&comment("any of elf, a.out, BSDI, Win32, gaswin (for GNU as on Win32) or Solaris");
+&comment("eric <eay\@cryptsoft.com>");
+&comment("");
+
+ $filename =~ s/\.pl$//;
+ &file($filename);
+ }
+
+sub asm_finish_cpp
+ {
+ return unless $cpp;
+
+ local($tmp,$i);
+ foreach $i (&get_labels())
+ {
+ $tmp.="#define $i _$i\n";
+ }
+ print <<"EOF";
+/* Run the C pre-processor over this file with one of the following defined
+ * ELF - elf object files,
+ * OUT - a.out object files,
+ * BSDI - BSDI style a.out object files
+ * SOL - Solaris style elf
+ */
+
+#define TYPE(a,b) .type a,b
+#define SIZE(a,b) .size a,b
+
+#if defined(OUT) || (defined(BSDI) && !defined(ELF))
+$tmp
+#endif
+
+#ifdef OUT
+#define OK 1
+#define ALIGN 4
+#endif
+
+#if defined(BSDI) && !defined(ELF)
+#define OK 1
+#define ALIGN 4
+#undef SIZE
+#undef TYPE
+#define SIZE(a,b)
+#define TYPE(a,b)
+#endif
+
+#if defined(ELF) || defined(SOL)
+#define OK 1
+#define ALIGN 16
+#endif
+
+#ifndef OK
+You need to define one of
+ELF - elf systems - linux-elf, NetBSD and DG-UX
+OUT - a.out systems - linux-a.out and FreeBSD
+SOL - solaris systems, which are elf with strange comment lines
+BSDI - a.out with a very primative version of as.
+#endif
+
+/* Let the Assembler begin :-) */
+EOF
+ }
+
+1;
diff --git a/lib/libcrypto/perlasm/x86ms.pl b/lib/libcrypto/perlasm/x86ms.pl
new file mode 100644
index 000000000..c6212f434
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86ms.pl
@@ -0,0 +1,365 @@
+#!/usr/bin/perl
+
+package x86ms;
+
+$label="L000";
+
+%lb=( 'eax', 'al',
+ 'ebx', 'bl',
+ 'ecx', 'cl',
+ 'edx', 'dl',
+ 'ax', 'al',
+ 'bx', 'bl',
+ 'cx', 'cl',
+ 'dx', 'dl',
+ );
+
+%hb=( 'eax', 'ah',
+ 'ebx', 'bh',
+ 'ecx', 'ch',
+ 'edx', 'dh',
+ 'ax', 'ah',
+ 'bx', 'bh',
+ 'cx', 'ch',
+ 'dx', 'dh',
+ );
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+sub main'LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main'HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main'BP
+ {
+ &get_mem("BYTE",@_);
+ }
+
+sub main'DWP
+ {
+ &get_mem("DWORD",@_);
+ }
+
+sub main'BC
+ {
+ return @_;
+ }
+
+sub main'DWC
+ {
+ return @_;
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main'sub("esp",$num*4);
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main'add("esp",$num*4);
+ }
+
+sub get_mem
+ {
+ local($size,$addr,$reg1,$reg2,$idx)=@_;
+ local($t,$post);
+ local($ret)="$size PTR ";
+
+ $addr =~ s/^\s+//;
+ if ($addr =~ /^(.+)\+(.+)$/)
+ {
+ $reg2=&conv($1);
+ $addr="_$2";
+ }
+ elsif ($addr =~ /^[_a-zA-Z]/)
+ {
+ $addr="_$addr";
+ }
+
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ if (($addr ne "") && ($addr ne 0))
+ {
+ if ($addr !~ /^-/)
+ { $ret.=$addr; }
+ else { $post=$addr; }
+ }
+ if ($reg2 ne "")
+ {
+ $t="";
+ $t="*$idx" if ($idx != 0);
+ $reg1="+".$reg1 if ("$reg1$post" ne "");
+ $ret.="[$reg2$t$reg1$post]";
+ }
+ else
+ {
+ $ret.="[$reg1$post]"
+ }
+ return($ret);
+ }
+
+sub main'mov { &out2("mov",@_); }
+sub main'movb { &out2("mov",@_); }
+sub main'and { &out2("and",@_); }
+sub main'or { &out2("or",@_); }
+sub main'shl { &out2("shl",@_); }
+sub main'shr { &out2("shr",@_); }
+sub main'xor { &out2("xor",@_); }
+sub main'xorb { &out2("xor",@_); }
+sub main'add { &out2("add",@_); }
+sub main'adc { &out2("adc",@_); }
+sub main'sub { &out2("sub",@_); }
+sub main'rotl { &out2("rol",@_); }
+sub main'rotr { &out2("ror",@_); }
+sub main'exch { &out2("xchg",@_); }
+sub main'cmp { &out2("cmp",@_); }
+sub main'lea { &out2("lea",@_); }
+sub main'mul { &out1("mul",@_); }
+sub main'div { &out1("div",@_); }
+sub main'dec { &out1("dec",@_); }
+sub main'inc { &out1("inc",@_); }
+sub main'jmp { &out1("jmp",@_); }
+sub main'jmp_ptr { &out1p("jmp",@_); }
+sub main'je { &out1("je",@_); }
+sub main'jle { &out1("jle",@_); }
+sub main'jz { &out1("jz",@_); }
+sub main'jge { &out1("jge",@_); }
+sub main'jl { &out1("jl",@_); }
+sub main'jb { &out1("jb",@_); }
+sub main'jc { &out1("jc",@_); }
+sub main'jnc { &out1("jnc",@_); }
+sub main'jnz { &out1("jnz",@_); }
+sub main'jne { &out1("jne",@_); }
+sub main'jno { &out1("jno",@_); }
+sub main'push { &out1("push",@_); $stack+=4; }
+sub main'pop { &out1("pop",@_); $stack-=4; }
+sub main'bswap { &out1("bswap",@_); &using486(); }
+sub main'not { &out1("not",@_); }
+sub main'call { &out1("call",'_'.$_[0]); }
+sub main'ret { &out0("ret"); }
+sub main'nop { &out0("nop"); }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t");
+ $t=&conv($p1).",";
+ $l=length($t);
+ push(@out,$t);
+ $l=4-($l+9)/8;
+ push(@out,"\t" x $l);
+ push(@out,&conv($p2));
+ push(@out,"\n");
+ }
+
+sub out0
+ {
+ local($name)=@_;
+
+ push(@out,"\t$name\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+ return $p;
+ }
+
+sub using486
+ {
+ return if $using486;
+ $using486++;
+ grep(s/\.386/\.486/,@out);
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ TITLE $file.asm
+ .386
+.model FLAT
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func,$extra)=@_;
+
+ push(@labels,$func);
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+ push ebp
+ push ebx
+ push esi
+ push edi
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main'function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+EOF
+ push(@out,$tmp);
+ $stack=4;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'file_end
+ {
+ push(@out,"END\n");
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ return(&main'DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main'swtmp
+ {
+ return(&main'DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'DWP(-(($num+1)*4),"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ push(@out,"\t; $_\n");
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="\$${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="${label}${_[0]}";
+ $label++;
+ }
+ if((defined $_[2]) && ($_[2] == 1))
+ {
+ push(@out,"$label{$_[0]}::\n");
+ }
+ else
+ {
+ push(@out,"$label{$_[0]}:\n");
+ }
+ }
+
+sub main'data_word
+ {
+ push(@out,"\tDD\t$_[0]\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t ".&conv($p1)."\n");
+ }
diff --git a/lib/libcrypto/perlasm/x86nasm.pl b/lib/libcrypto/perlasm/x86nasm.pl
new file mode 100644
index 000000000..90d27fca9
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86nasm.pl
@@ -0,0 +1,366 @@
+#!/usr/bin/perl
+
+package x86nasm;
+
+$label="L000";
+
+%lb=( 'eax', 'al',
+ 'ebx', 'bl',
+ 'ecx', 'cl',
+ 'edx', 'dl',
+ 'ax', 'al',
+ 'bx', 'bl',
+ 'cx', 'cl',
+ 'dx', 'dl',
+ );
+
+%hb=( 'eax', 'ah',
+ 'ebx', 'bh',
+ 'ecx', 'ch',
+ 'edx', 'dh',
+ 'ax', 'ah',
+ 'bx', 'bh',
+ 'cx', 'ch',
+ 'dx', 'dh',
+ );
+
+%regs=( 'eax', 'eax',
+ 'ebx', 'ebx',
+ 'ecx', 'ecx',
+ 'edx', 'edx',
+ 'esi', 'esi',
+ 'edi', 'edi',
+ 'ebp', 'ebp',
+ 'esp', 'esp',
+ 'mm0', 'mm0',
+ 'mm1', 'mm1',
+ );
+
+sub main::asm_init_output { @out=(); }
+sub main::asm_get_output { return(@out); }
+sub main::get_labels { return(@labels); }
+
+sub main::external_label
+{
+ push(@labels,@_);
+ foreach (@_) {
+ push(@out, "extern\t_$_\n");
+ }
+}
+
+sub main::LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main::HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main::BP
+ {
+ &get_mem("BYTE",@_);
+ }
+
+sub main::DWP
+ {
+ &get_mem("DWORD",@_);
+ }
+
+sub main::BC
+ {
+ return "BYTE @_";
+ }
+
+sub main::DWC
+ {
+ return "DWORD @_";
+ }
+
+sub main::stack_push
+ {
+ my($num)=@_;
+ $stack+=$num*4;
+ &main::sub("esp",$num*4);
+ }
+
+sub main::stack_pop
+ {
+ my($num)=@_;
+ $stack-=$num*4;
+ &main::add("esp",$num*4);
+ }
+
+sub get_mem
+ {
+ my($size,$addr,$reg1,$reg2,$idx)=@_;
+ my($t,$post);
+ my($ret)="[";
+ $addr =~ s/^\s+//;
+ if ($addr =~ /^(.+)\+(.+)$/)
+ {
+ if (defined($regs{$reg2})) {
+ $addr=join('+', &conv($1), "_$2");
+ } else {
+ $reg2=&conv($1);
+ $addr="_$2";
+ }
+ }
+ elsif ($addr =~ /^[_a-zA-Z]/)
+ {
+ $addr="_$addr";
+ }
+
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ if (($addr ne "") && ($addr ne 0))
+ {
+ if ($addr !~ /^-/)
+ { $ret.="${addr}+"; }
+ else { $post=$addr; }
+ }
+ if ($reg2 ne "")
+ {
+ $t="";
+ $t="*$idx" if ($idx != 0);
+ $reg1="+".$reg1 if ("$reg1$post" ne "");
+ $ret.="$reg2$t$reg1$post]";
+ }
+ else
+ {
+ $ret.="$reg1$post]"
+ }
+ return($ret);
+ }
+
+sub main::mov { &out2("mov",@_); }
+sub main::movb { &out2("mov",@_); }
+sub main::and { &out2("and",@_); }
+sub main::or { &out2("or",@_); }
+sub main::shl { &out2("shl",@_); }
+sub main::shr { &out2("shr",@_); }
+sub main::xor { &out2("xor",@_); }
+sub main::xorb { &out2("xor",@_); }
+sub main::add { &out2("add",@_); }
+sub main::adc { &out2("adc",@_); }
+sub main::sub { &out2("sub",@_); }
+sub main::rotl { &out2("rol",@_); }
+sub main::rotr { &out2("ror",@_); }
+sub main::exch { &out2("xchg",@_); }
+sub main::cmp { &out2("cmp",@_); }
+sub main::lea { &out2("lea",@_); }
+sub main::mul { &out1("mul",@_); }
+sub main::div { &out1("div",@_); }
+sub main::dec { &out1("dec",@_); }
+sub main::inc { &out1("inc",@_); }
+sub main::jmp { &out1("jmp",@_); }
+sub main::jmp_ptr { &out1p("jmp",@_); }
+
+# This is a bit of a kludge: declare all branches as NEAR.
+sub main::je { &out1("je NEAR",@_); }
+sub main::jle { &out1("jle NEAR",@_); }
+sub main::jz { &out1("jz NEAR",@_); }
+sub main::jge { &out1("jge NEAR",@_); }
+sub main::jl { &out1("jl NEAR",@_); }
+sub main::jb { &out1("jb NEAR",@_); }
+sub main::jc { &out1("jc NEAR",@_); }
+sub main::jnc { &out1("jnc NEAR",@_); }
+sub main::jnz { &out1("jnz NEAR",@_); }
+sub main::jne { &out1("jne NEAR",@_); }
+sub main::jno { &out1("jno NEAR",@_); }
+
+sub main::push { &out1("push",@_); $stack+=4; }
+sub main::pop { &out1("pop",@_); $stack-=4; }
+sub main::bswap { &out1("bswap",@_); &using486(); }
+sub main::not { &out1("not",@_); }
+sub main::call { &out1("call",'_'.$_[0]); }
+sub main::ret { &out0("ret"); }
+sub main::nop { &out0("nop"); }
+
+sub out2
+ {
+ my($name,$p1,$p2)=@_;
+ my($l,$t);
+
+ push(@out,"\t$name\t");
+ $t=&conv($p1).",";
+ $l=length($t);
+ push(@out,$t);
+ $l=4-($l+9)/8;
+ push(@out,"\t" x $l);
+ push(@out,&conv($p2));
+ push(@out,"\n");
+ }
+
+sub out0
+ {
+ my($name)=@_;
+
+ push(@out,"\t$name\n");
+ }
+
+sub out1
+ {
+ my($name,$p1)=@_;
+ my($l,$t);
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub conv
+ {
+ my($p)=@_;
+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+ return $p;
+ }
+
+sub using486
+ {
+ return if $using486;
+ $using486++;
+ grep(s/\.386/\.486/,@out);
+ }
+
+sub main::file
+ {
+ push(@out, "segment .text\n");
+ }
+
+sub main::function_begin
+ {
+ my($func,$extra)=@_;
+
+ push(@labels,$func);
+ my($tmp)=<<"EOF";
+global _$func
+_$func:
+ push ebp
+ push ebx
+ push esi
+ push edi
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main::function_begin_B
+ {
+ my($func,$extra)=@_;
+ my($tmp)=<<"EOF";
+global _$func
+_$func:
+EOF
+ push(@out,$tmp);
+ $stack=4;
+ }
+
+sub main::function_end
+ {
+ my($func)=@_;
+
+ my($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_B
+ {
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_A
+ {
+ my($func)=@_;
+
+ my($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main::file_end
+ {
+ }
+
+sub main::wparam
+ {
+ my($num)=@_;
+
+ return(&main::DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main::swtmp
+ {
+ return(&main::DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main::wtmp
+# {
+# my($num)=@_;
+#
+# return(&main::DWP(-(($num+1)*4),"esp","",0));
+# }
+
+sub main::comment
+ {
+ foreach (@_)
+ {
+ push(@out,"\t; $_\n");
+ }
+ }
+
+sub main::label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="\$${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main::set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="${label}${_[0]}";
+ $label++;
+ }
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main::data_word
+ {
+ push(@out,"\tDD\t$_[0]\n");
+ }
+
+sub out1p
+ {
+ my($name,$p1)=@_;
+ my($l,$t);
+
+ push(@out,"\t$name\t ".&conv($p1)."\n");
+ }
+
+##
+## Additional functions required for MMX and other ops
+##
+sub main::testb { &out2('test', @_) }
+sub main::movzx { &out2('movzx', @_) }
+sub main::movd { &out2('movd', @_) }
+sub main::emms { &out0('emms', @_) }
diff --git a/lib/libcrypto/perlasm/x86unix.pl b/lib/libcrypto/perlasm/x86unix.pl
new file mode 100644
index 000000000..f804b91c9
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86unix.pl
@@ -0,0 +1,472 @@
+#!/usr/bin/perl
+
+package x86unix;
+
+$label="L000";
+
+$align=($main::aout)?"4":"16";
+$under=($main::aout)?"_":"";
+$com_start=($main::sol)?"/":"#";
+
+sub main::asm_init_output { @out=(); }
+sub main::asm_get_output { return(@out); }
+sub main::get_labels { return(@labels); }
+sub main::external_label { push(@labels,@_); }
+
+if ($main::cpp)
+ {
+ $align="ALIGN";
+ $under="";
+ $com_start='/*';
+ $com_end='*/';
+ }
+
+%lb=( 'eax', '%al',
+ 'ebx', '%bl',
+ 'ecx', '%cl',
+ 'edx', '%dl',
+ 'ax', '%al',
+ 'bx', '%bl',
+ 'cx', '%cl',
+ 'dx', '%dl',
+ );
+
+%hb=( 'eax', '%ah',
+ 'ebx', '%bh',
+ 'ecx', '%ch',
+ 'edx', '%dh',
+ 'ax', '%ah',
+ 'bx', '%bh',
+ 'cx', '%ch',
+ 'dx', '%dh',
+ );
+
+%regs=( 'eax', '%eax',
+ 'ebx', '%ebx',
+ 'ecx', '%ecx',
+ 'edx', '%edx',
+ 'esi', '%esi',
+ 'edi', '%edi',
+ 'ebp', '%ebp',
+ 'esp', '%esp',
+ 'mm0', '%mm0',
+ 'mm1', '%mm1',
+ );
+
+%reg_val=(
+ 'eax', 0x00,
+ 'ebx', 0x03,
+ 'ecx', 0x01,
+ 'edx', 0x02,
+ 'esi', 0x06,
+ 'edi', 0x07,
+ 'ebp', 0x05,
+ 'esp', 0x04,
+ );
+
+sub main::LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main::HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main::DWP
+ {
+ local($addr,$reg1,$reg2,$idx)=@_;
+
+ $ret="";
+ $addr =~ s/(^|[+ \t])([A-Za-z_]+[A-Za-z0-9_]+)($|[+ \t])/$1$under$2$3/;
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ $ret.=$addr if ($addr ne "") && ($addr ne 0);
+ if ($reg2 ne "")
+ {
+ if($idx ne "")
+ { $ret.="($reg1,$reg2,$idx)"; }
+ else
+ { $ret.="($reg1,$reg2)"; }
+ }
+ else
+ { $ret.="($reg1)" }
+ return($ret);
+ }
+
+sub main::BP
+ {
+ return(&main::DWP(@_));
+ }
+
+sub main::BC
+ {
+ return @_;
+ }
+
+sub main::DWC
+ {
+ return @_;
+ }
+
+#sub main::BP
+# {
+# local($addr,$reg1,$reg2,$idx)=@_;
+#
+# $ret="";
+#
+# $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
+# $reg1="$regs{$reg1}" if defined($regs{$reg1});
+# $reg2="$regs{$reg2}" if defined($regs{$reg2});
+# $ret.=$addr if ($addr ne "") && ($addr ne 0);
+# if ($reg2 ne "")
+# { $ret.="($reg1,$reg2,$idx)"; }
+# else
+# { $ret.="($reg1)" }
+# return($ret);
+# }
+
+sub main::mov { &out2("movl",@_); }
+sub main::movb { &out2("movb",@_); }
+sub main::and { &out2("andl",@_); }
+sub main::or { &out2("orl",@_); }
+sub main::shl { &out2("sall",@_); }
+sub main::shr { &out2("shrl",@_); }
+sub main::xor { &out2("xorl",@_); }
+sub main::xorb { &out2("xorb",@_); }
+sub main::add { &out2("addl",@_); }
+sub main::adc { &out2("adcl",@_); }
+sub main::sub { &out2("subl",@_); }
+sub main::rotl { &out2("roll",@_); }
+sub main::rotr { &out2("rorl",@_); }
+sub main::exch { &out2("xchg",@_); }
+sub main::cmp { &out2("cmpl",@_); }
+sub main::lea { &out2("leal",@_); }
+sub main::mul { &out1("mull",@_); }
+sub main::div { &out1("divl",@_); }
+sub main::jmp { &out1("jmp",@_); }
+sub main::jmp_ptr { &out1p("jmp",@_); }
+sub main::je { &out1("je",@_); }
+sub main::jle { &out1("jle",@_); }
+sub main::jne { &out1("jne",@_); }
+sub main::jnz { &out1("jnz",@_); }
+sub main::jz { &out1("jz",@_); }
+sub main::jge { &out1("jge",@_); }
+sub main::jl { &out1("jl",@_); }
+sub main::jb { &out1("jb",@_); }
+sub main::jc { &out1("jc",@_); }
+sub main::jnc { &out1("jnc",@_); }
+sub main::jno { &out1("jno",@_); }
+sub main::dec { &out1("decl",@_); }
+sub main::inc { &out1("incl",@_); }
+sub main::push { &out1("pushl",@_); $stack+=4; }
+sub main::pop { &out1("popl",@_); $stack-=4; }
+sub main::not { &out1("notl",@_); }
+sub main::call { &out1("call",$under.$_[0]); }
+sub main::ret { &out0("ret"); }
+sub main::nop { &out0("nop"); }
+
+# The bswapl instruction is new for the 486. Emulate if i386.
+sub main::bswap
+ {
+ if ($main::i386)
+ {
+ &main::comment("bswapl @_");
+ &main::exch(main::HB(@_),main::LB(@_));
+ &main::rotr(@_,16);
+ &main::exch(main::HB(@_),main::LB(@_));
+ }
+ else
+ {
+ &out1("bswapl",@_);
+ }
+ }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$ll,$t);
+ local(%special)=( "roll",0xD1C0,"rorl",0xD1C8,
+ "rcll",0xD1D0,"rcrl",0xD1D8,
+ "shll",0xD1E0,"shrl",0xD1E8,
+ "sarl",0xD1F8);
+
+ if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
+ {
+ $op=$special{$name}|$reg_val{$p1};
+ $tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
+ $tmp2=sprintf(".byte %d\t",$op &0xff);
+ push(@out,$tmp1);
+ push(@out,$tmp2);
+
+ $p2=&conv($p2);
+ $p1=&conv($p1);
+ &main::comment("$name $p2 $p1");
+ return;
+ }
+
+ push(@out,"\t$name\t");
+ $t=&conv($p2).",";
+ $l=length($t);
+ push(@out,$t);
+ $ll=4-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+ push(@out,&conv($p1)."\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+ local(%special)=("bswapl",0x0FC8);
+
+ if ((defined($special{$name})) && defined($regs{$p1}))
+ {
+ $op=$special{$name}|$reg_val{$p1};
+ $tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
+ $tmp2=sprintf(".byte %d\t",$op &0xff);
+ push(@out,$tmp1);
+ push(@out,$tmp2);
+
+ $p2=&conv($p2);
+ $p1=&conv($p1);
+ &main::comment("$name $p2 $p1");
+ return;
+ }
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t*".&conv($p1)."\n");
+ }
+
+sub out0
+ {
+ push(@out,"\t$_[0]\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+# $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+
+ $p=$regs{$p} if (defined($regs{$p}));
+
+ $p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
+ $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
+ return $p;
+ }
+
+sub main::file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ .file "$file.s"
+ .version "01.01"
+EOF
+# Removed the next line from previous infile
+#gcc2_compiled.:
+ push(@out,$tmp);
+ }
+
+sub main::function_begin
+ {
+ local($func)=@_;
+
+ &main::external_label($func);
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
+ else { $tmp=push(@out,"\t.type\t$func,\@function\n"); }
+ push(@out,"$func:\n");
+ $tmp=<<"EOF";
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main::function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ &main::external_label($func);
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { push(@out,"\tTYPE($func,\@function)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
+ else { push(@out,"\t.type $func,\@function\n"); }
+ push(@out,"$func:\n");
+ $stack=4;
+ }
+
+sub main::function_end
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+.${func}_end:
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.align 4\n"); }
+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
+ push(@out,".ident \"$func\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main::function_end_B
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ push(@out,".L_${func}_end:\n");
+ if ($main::cpp)
+ { push(@out,"\tSIZE($func,.L_${func}_end-$func)\n"); }
+ elsif ($main::gaswin)
+ { push(@out,"\t.align 4\n"); }
+ else { push(@out,"\t.size\t$func,.L_${func}_end-$func\n"); }
+ push(@out,".ident \"desasm.pl\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main::wparam
+ {
+ local($num)=@_;
+
+ return(&main::DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main::stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main::sub("esp",$num*4);
+ }
+
+sub main::stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main::add("esp",$num*4);
+ }
+
+sub main::swtmp
+ {
+ return(&main::DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main::wtmp
+# {
+# local($num)=@_;
+#
+# return(&main::DWP(-($num+1)*4,"esp","",0));
+# }
+
+sub main::comment
+ {
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub main::label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main::set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ push(@out,".align $align\n") if ($_[1] != 0);
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main::file_end
+ {
+ }
+
+sub main::data_word
+ {
+ push(@out,"\t.long $_[0]\n");
+ }
+
+##
+## Additional functions required for MMX and other ops
+##
+sub main::testb { &out2('testb', @_) }
+sub main::movzx { &out2('movzx', @_) }
+sub main::movd { &out2('movd', @_) }
+sub main::emms { &out0('emms', @_) }