diff options
Diffstat (limited to 'lib/libcrypto/perlasm')
-rw-r--r-- | lib/libcrypto/perlasm/LICENSE | 127 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/alpha.pl | 434 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/cbc.pl | 342 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/readme | 124 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/version | 5 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/x86asm.pl | 118 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/x86ms.pl | 365 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/x86nasm.pl | 366 | ||||
-rw-r--r-- | lib/libcrypto/perlasm/x86unix.pl | 472 |
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', @_) } |