- import of strongswan-2.7.0

- applied patch for charon
This commit is contained in:
Martin Willi
2006-04-28 07:14:48 +00:00
parent 52923c9acb
commit 997358a6c4
2043 changed files with 346842 additions and 0 deletions
+342
View File
@@ -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;
+124
View File
@@ -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);
@@ -0,0 +1,111 @@
#!/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)=@_;
$filename=$fn;
$cpp=$sol=$aout=$win32=0;
if ( ($type eq "elf"))
{ require "x86unix.pl"; }
elsif ( ($type eq "a.out"))
{ $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"; }
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
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, 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)
$tmp
#endif
#ifdef OUT
#define OK 1
#define ALIGN 4
#endif
#ifdef BSDI
#define OK 1
#define ALIGN 4
#undef SIZE
#undef TYPE
#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;
@@ -0,0 +1,345 @@
#!/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'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'jnz { &out1("jnz",@_); }
sub main'jne { &out1("jne",@_); }
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++;
}
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");
}
@@ -0,0 +1,403 @@
#!/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',
);
%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_]+)($|[+ \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'BP
{
return(&main'DWP(@_));
}
#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'dec { &out1("decl",@_); }
sub main'inc { &out1("incl",@_); }
sub main'push { &out1("pushl",@_); $stack+=4; }
sub main'pop { &out1("popl",@_); $stack-=4; }
sub main'bswap { &out1("bswapl",@_); }
sub main'not { &out1("notl",@_); }
sub main'call { &out1("call",$under.$_[0]); }
sub main'ret { &out0("ret"); }
sub main'nop { &out0("nop"); }
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);
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"
gcc2_compiled.:
EOF
push(@out,$tmp);
}
sub main'function_begin
{
local($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"); }
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)=@_;
$func=$under.$func;
local($tmp)=<<"EOF";
.text
.align $align
.globl $func
EOF
push(@out,$tmp);
if ($main'cpp)
{ push(@out,"\tTYPE($func,\@function)\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"); }
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,".${func}_end:\n");
if ($main'cpp)
{ push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
else { push(@out,"\t.size\t$func,.${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");
}