diff options
Diffstat (limited to 'usr/src/common/openssl/crypto/perlasm')
-rw-r--r-- | usr/src/common/openssl/crypto/perlasm/cbc.pl | 4 | ||||
-rwxr-xr-x | usr/src/common/openssl/crypto/perlasm/x86_64-xlate.pl | 506 | ||||
-rw-r--r-- | usr/src/common/openssl/crypto/perlasm/x86asm.pl | 23 | ||||
-rw-r--r-- | usr/src/common/openssl/crypto/perlasm/x86ms.pl | 86 | ||||
-rw-r--r-- | usr/src/common/openssl/crypto/perlasm/x86nasm.pl | 149 | ||||
-rw-r--r-- | usr/src/common/openssl/crypto/perlasm/x86unix.pl | 251 |
6 files changed, 927 insertions, 92 deletions
diff --git a/usr/src/common/openssl/crypto/perlasm/cbc.pl b/usr/src/common/openssl/crypto/perlasm/cbc.pl index 22149c680e..e43dc9ae15 100644 --- a/usr/src/common/openssl/crypto/perlasm/cbc.pl +++ b/usr/src/common/openssl/crypto/perlasm/cbc.pl @@ -322,7 +322,8 @@ sub cbc &function_end_A($name); - &set_label("cbc_enc_jmp_table",1); + &align(64); + &set_label("cbc_enc_jmp_table"); &data_word("0"); &data_word(&label("ej1")."-".&label("PIC_point")); &data_word(&label("ej2")."-".&label("PIC_point")); @@ -341,6 +342,7 @@ sub cbc #&data_word(&label("dj5")."-".&label("PIC_point")); #&data_word(&label("dj6")."-".&label("PIC_point")); #&data_word(&label("dj7")."-".&label("PIC_point")); + &align(64); &function_end_B($name); diff --git a/usr/src/common/openssl/crypto/perlasm/x86_64-xlate.pl b/usr/src/common/openssl/crypto/perlasm/x86_64-xlate.pl new file mode 100755 index 0000000000..ef1a4ce656 --- /dev/null +++ b/usr/src/common/openssl/crypto/perlasm/x86_64-xlate.pl @@ -0,0 +1,506 @@ +#!/usr/bin/env perl + +# Ascetic x86_64 AT&T to MASM assembler translator by <appro>. +# +# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T +# format is way easier to parse. Because it's simpler to "gear" from +# Unix ABI to Windows one [see cross-reference "card" at the end of +# file]. Because Linux targets were available first... +# +# In addition the script also "distills" code suitable for GNU +# assembler, so that it can be compiled with more rigid assemblers, +# such as Solaris /usr/ccs/bin/as. +# +# This translator is not designed to convert *arbitrary* assembler +# code from AT&T format to MASM one. It's designed to convert just +# enough to provide for dual-ABI OpenSSL modules development... +# There *are* limitations and you might have to modify your assembler +# code or this script to achieve the desired result... +# +# Currently recognized limitations: +# +# - can't use multiple ops per line; +# - indirect calls and jumps are not supported; +# +# Dual-ABI styling rules. +# +# 1. Adhere to Unix register and stack layout [see the end for +# explanation]. +# 2. Forget about "red zone," stick to more traditional blended +# stack frame allocation. If volatile storage is actually required +# that is. If not, just leave the stack as is. +# 3. Functions tagged with ".type name,@function" get crafted with +# unified Win64 prologue and epilogue automatically. If you want +# to take care of ABI differences yourself, tag functions as +# ".type name,@abi-omnipotent" instead. +# 4. To optimize the Win64 prologue you can specify number of input +# arguments as ".type name,@function,N." Keep in mind that if N is +# larger than 6, then you *have to* write "abi-omnipotent" code, +# because >6 cases can't be addressed with unified prologue. +# 5. Name local labels as .L*, do *not* use dynamic labels such as 1: +# (sorry about latter). +# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is +# required to identify the spots, where to inject Win64 epilogue! +# But on the pros, it's then prefixed with rep automatically:-) +# 7. Due to MASM limitations [and certain general counter-intuitivity +# of ip-relative addressing] generation of position-independent +# code is assisted by synthetic directive, .picmeup, which puts +# address of the *next* instruction into target register. +# +# Example 1: +# .picmeup %rax +# lea .Label-.(%rax),%rax +# Example 2: +# .picmeup %rcx +# .Lpic_point: +# ... +# lea .Label-.Lpic_point(%rcx),%rbp + +my $output = shift; +open STDOUT,">$output" || die "can't open $output: $!"; + +my $masm=1 if ($output =~ /\.asm/); + +my $current_segment; +my $current_function; + +{ package opcode; # pick up opcodes + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^([a-z]+)/i) { + $self->{op} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + undef $self->{sz}; + if ($self->{op} =~ /(movz)b.*/) { # movz is pain... + $self->{op} = $1; + $self->{sz} = "b"; + } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])/) { + $self->{op} = $1; + $self->{sz} = $2; + } + } + $ret; + } + sub size { + my $self = shift; + my $sz = shift; + $self->{sz} = $sz if (defined($sz) && !defined($self->{sz})); + $self->{sz}; + } + sub out { + my $self = shift; + if (!$masm) { + if ($self->{op} eq "movz") { # movz in pain... + sprintf "%s%s%s",$self->{op},$self->{sz},shift; + } elsif ($self->{op} eq "ret") { + ".byte 0xf3,0xc3"; + } else { + "$self->{op}$self->{sz}"; + } + } else { + $self->{op} =~ s/movz/movzx/; + if ($self->{op} eq "ret") { + $self->{op} = ""; + if ($current_function->{abi} eq "svr4") { + $self->{op} = "mov rdi,QWORD PTR 8[rsp]\t;WIN64 epilogue\n\t". + "mov rsi,QWORD PTR 16[rsp]\n\t"; + } + $self->{op} .= "DB\t0F3h,0C3h\t\t;repret"; + } + $self->{op}; + } + } +} +{ package const; # pick up constants, which start with $ + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^\$([^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub out { + my $self = shift; + + if (!$masm) { + sprintf "\$%s",$self->{value}; + } else { + $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig; + sprintf "%s",$self->{value}; + } + } +} +{ package ea; # pick up effective addresses: expr(%reg,%reg,scale) + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^([^\(,]*)\(([%\w,]+)\)/) { + $self->{label} = $1; + ($self->{base},$self->{index},$self->{scale})=split(/,/,$2); + $self->{scale} = 1 if (!defined($self->{scale})); + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{base} =~ s/^%//; + $self->{index} =~ s/^%// if (defined($self->{index})); + } + $ret; + } + sub size {} + sub out { + my $self = shift; + my $sz = shift; + + if (!$masm) { + # elder GNU assembler insists on 64-bit EAs:-( + # on pros side, this results in more compact code:-) + $self->{index} =~ s/^[er](.?[0-9xp])[d]?$/r\1/; + $self->{base} =~ s/^[er](.?[0-9xp])[d]?$/r\1/; + # Solaris /usr/ccs/bin/as can't handle multiplications + # in $self->{label} + $self->{label} =~ s/(?<![0-9a-f])(0[x0-9a-f]+)/oct($1)/eg; + $self->{label} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg; + + if (defined($self->{index})) { + sprintf "%s(%%%s,%%%s,%d)", + $self->{label},$self->{base}, + $self->{index},$self->{scale}; + } else { + sprintf "%s(%%%s)", $self->{label},$self->{base}; + } + } else { + %szmap = ( b=>"BYTE", w=>"WORD", l=>"DWORD", q=>"QWORD" ); + + $self->{label} =~ s/\./\$/g; + $self->{label} =~ s/0x([0-9a-f]+)/0$1h/ig; + $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); + + if (defined($self->{index})) { + sprintf "%s PTR %s[%s*%d+%s]",$szmap{$sz}, + $self->{label}, + $self->{index},$self->{scale}, + $self->{base}; + } else { + sprintf "%s PTR %s[%s]",$szmap{$sz}, + $self->{label},$self->{base}; + } + } + } +} +{ package register; # pick up registers, which start with %. + sub re { + my $class = shift; # muliple instances... + my $self = {}; + local *line = shift; + undef $ret; + + if ($line =~ /^%(\w+)/) { + bless $self,$class; + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub size { + my $self = shift; + undef $ret; + + if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; } + elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; } + elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; } + elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; } + elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; } + elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; } + + $ret; + } + sub out { + my $self = shift; + sprintf $masm?"%s":"%%%s",$self->{value}; + } +} +{ package label; # pick up labels, which end with : + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[\.\w]+\:)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/\.L/\$L/ if ($masm); + } + $ret; + } + sub out { + my $self = shift; + + if (!$masm) { + $self->{value}; + } elsif ($self->{value} ne "$current_function->{name}:") { + $self->{value}; + } elsif ($current_function->{abi} eq "svr4") { + my $func = "$current_function->{name} PROC\n". + " mov QWORD PTR 8[rsp],rdi\t;WIN64 prologue\n". + " mov QWORD PTR 16[rsp],rsi\n"; + my $narg = $current_function->{narg}; + $narg=6 if (!defined($narg)); + $func .= " mov rdi,rcx\n" if ($narg>0); + $func .= " mov rsi,rdx\n" if ($narg>1); + $func .= " mov rdx,r8\n" if ($narg>2); + $func .= " mov rcx,r9\n" if ($narg>3); + $func .= " mov r8,QWORD PTR 40[rsp]\n" if ($narg>4); + $func .= " mov r9,QWORD PTR 48[rsp]\n" if ($narg>5); + $func .= "\n"; + } else { + "$current_function->{name} PROC"; + } + } +} +{ package expr; # pick up expressioins + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/\.L/\$L/g if ($masm); + } + $ret; + } + sub out { + my $self = shift; + $self->{value}; + } +} +{ package directive; # pick up directives, which start with . + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + my $dir; + my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: + ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, + "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48, + "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48, + "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48, + "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c, + "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c, + "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, + "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); + + if ($line =~ /^\s*(\.\w+)/) { + if (!$masm) { + $self->{value} = $1; + $line =~ s/\@abi\-omnipotent/\@function/; + $line =~ s/\@function.*/\@function/; + if ($line =~ /\.picmeup\s+(%r[\w]+)/i) { + $self->{value} = sprintf "\t.long\t0x%x,0x90000000",$opcode{$1}; + } else { + $self->{value} = $line; + } + $line = ""; + return $self; + } + + $dir = $1; + $ret = $self; + undef $self->{value}; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + SWITCH: for ($dir) { + /\.(text)/ + && do { my $v=undef; + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = "_$1\$"; + $current_segment =~ tr/[a-z]/[A-Z]/; + $v.="$current_segment\tSEGMENT ALIGN(64) 'CODE'"; + $self->{value} = $v; + last; + }; + /\.globl/ && do { $self->{value} = "PUBLIC\t".$line; last; }; + /\.type/ && do { ($sym,$type,$narg) = split(',',$line); + if ($type eq "\@function") { + undef $current_function; + $current_function->{name} = $sym; + $current_function->{abi} = "svr4"; + $current_function->{narg} = $narg; + } elsif ($type eq "\@abi-omnipotent") { + undef $current_function; + $current_function->{name} = $sym; + } + last; + }; + /\.size/ && do { if (defined($current_function)) { + $self->{value}="$current_function->{name}\tENDP"; + undef $current_function; + } + last; + }; + /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; }; + /\.(byte|value|long|quad)/ + && do { my @arr = split(',',$line); + my $sz = substr($1,0,1); + my $last = pop(@arr); + + $sz =~ tr/bvlq/BWDQ/; + $self->{value} = "\tD$sz\t"; + for (@arr) { $self->{value} .= sprintf"0%Xh,",oct; } + $self->{value} .= sprintf"0%Xh",oct($last); + last; + }; + /\.picmeup/ && do { $self->{value} = sprintf"\tDD\t 0%Xh,090000000h",$opcode{$line}; + last; + }; + } + $line = ""; + } + + $ret; + } + sub out { + my $self = shift; + $self->{value}; + } +} + +while($line=<>) { + + chomp($line); + + $line =~ s|[#!].*$||; # get rid of asm-style comments... + $line =~ s|/\*.*\*/||; # ... and C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning + + undef $label; + undef $opcode; + undef $dst; + undef $src; + undef $sz; + + if ($label=label->re(\$line)) { print $label->out(); } + + if (directive->re(\$line)) { + printf "%s",directive->out(); + } elsif ($opcode=opcode->re(\$line)) { ARGUMENT: { + + if ($src=register->re(\$line)) { opcode->size($src->size()); } + elsif ($src=const->re(\$line)) { } + elsif ($src=ea->re(\$line)) { } + elsif ($src=expr->re(\$line)) { } + + last ARGUMENT if ($line !~ /^,/); + + $line = substr($line,1); $line =~ s/^\s+//; + + if ($dst=register->re(\$line)) { opcode->size($dst->size()); } + elsif ($dst=const->re(\$line)) { } + elsif ($dst=ea->re(\$line)) { } + + } # ARGUMENT: + + $sz=opcode->size(); + + if (defined($dst)) { + if (!$masm) { + printf "\t%s\t%s,%s", $opcode->out($dst->size()), + $src->out($sz),$dst->out($sz); + } else { + printf "\t%s\t%s,%s", $opcode->out(), + $dst->out($sz),$src->out($sz); + } + } elsif (defined($src)) { + printf "\t%s\t%s",$opcode->out(),$src->out($sz); + } else { + printf "\t%s",$opcode->out(); + } + } + + print $line,"\n"; +} + +print "\n$current_segment\tENDS\nEND\n" if ($masm); + +close STDOUT; + +################################################# +# Cross-reference x86_64 ABI "card" +# +# Unix Win64 +# %rax * * +# %rbx - - +# %rcx #4 #1 +# %rdx #3 #2 +# %rsi #2 - +# %rdi #1 - +# %rbp - - +# %rsp - - +# %r8 #5 #3 +# %r9 #6 #4 +# %r10 * * +# %r11 * * +# %r12 - - +# %r13 - - +# %r14 - - +# %r15 - - +# +# (*) volatile register +# (-) preserved by callee +# (#) Nth argument, volatile +# +# In Unix terms top of stack is argument transfer area for arguments +# which could not be accomodated in registers. Or in other words 7th +# [integer] argument resides at 8(%rsp) upon function entry point. +# 128 bytes above %rsp constitute a "red zone" which is not touched +# by signal handlers and can be used as temporal storage without +# allocating a frame. +# +# In Win64 terms N*8 bytes on top of stack is argument transfer area, +# which belongs to/can be overwritten by callee. N is the number of +# arguments passed to callee, *but* not less than 4! This means that +# upon function entry point 5th argument resides at 40(%rsp), as well +# as that 32 bytes from 8(%rsp) can always be used as temporal +# storage [without allocating a frame]. +# +# All the above means that if assembler programmer adheres to Unix +# register and stack layout, but disregards the "red zone" existense, +# it's possible to use following prologue and epilogue to "gear" from +# Unix to Win64 ABI in leaf functions with not more than 6 arguments. +# +# omnipotent_function: +# ifdef WIN64 +# movq %rdi,8(%rsp) +# movq %rsi,16(%rsp) +# movq %rcx,%rdi ; if 1st argument is actually present +# movq %rdx,%rsi ; if 2nd argument is actually ... +# movq %r8,%rdx ; if 3rd argument is ... +# movq %r9,%rcx ; if 4th argument ... +# movq 40(%rsp),%r8 ; if 5th ... +# movq 48(%rsp),%r9 ; if 6th ... +# endif +# ... +# ifdef WIN64 +# movq 8(%rsp),%rdi +# movq 16(%rsp),%rsi +# endif +# ret diff --git a/usr/src/common/openssl/crypto/perlasm/x86asm.pl b/usr/src/common/openssl/crypto/perlasm/x86asm.pl index 1cb96e914a..cf2aee40ec 100644 --- a/usr/src/common/openssl/crypto/perlasm/x86asm.pl +++ b/usr/src/common/openssl/crypto/perlasm/x86asm.pl @@ -18,31 +18,34 @@ sub main'asm_init ($type,$fn,$i386)=@_; $filename=$fn; - $elf=$cpp=$sol=$aout=$win32=$gaswin=0; + $elf=$cpp=$coff=$aout=$win32=$netware=$mwerks=0; if ( ($type eq "elf")) { $elf=1; 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 "coff" or $type eq "gaswin")) + { $coff=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"; } + elsif ( ($type eq "nw-nasm")) + { $netware=1; require "x86nasm.pl"; } + elsif ( ($type eq "nw-mwasm")) + { $netware=1; $mwerks=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 + elf - Linux, FreeBSD, Solaris x86, etc. + a.out - OpenBSD, DJGPP, etc. + coff - GAS/COFF such as Win32 targets win32 - Windows 95/Windows NT win32n - Windows 95/Windows NT NASM format + nw-nasm - NetWare NASM format + nw-mwasm- NetWare Metrowerks Assembler EOF exit(1); } @@ -55,7 +58,7 @@ EOF &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("any of ELF, a.out, COFF, Win32, ..."); &comment("eric <eay\@cryptsoft.com>"); &comment(""); diff --git a/usr/src/common/openssl/crypto/perlasm/x86ms.pl b/usr/src/common/openssl/crypto/perlasm/x86ms.pl index fbb4afb9bd..d1cb7ee0ac 100644 --- a/usr/src/common/openssl/crypto/perlasm/x86ms.pl +++ b/usr/src/common/openssl/crypto/perlasm/x86ms.pl @@ -51,6 +51,11 @@ sub main'DWP &get_mem("DWORD",@_); } +sub main'QWP + { + &get_mem("QWORD",@_); + } + sub main'BC { return @_; @@ -87,7 +92,7 @@ sub get_mem $reg2=&conv($1); $addr="_$2"; } - elsif ($addr =~ /^[_a-zA-Z]/) + elsif ($addr =~ /^[_a-z][_a-z0-9]*$/i) { $addr="_$addr"; } @@ -128,6 +133,7 @@ sub main'xorb { &out2("xor",@_); } sub main'add { &out2("add",@_); } sub main'adc { &out2("adc",@_); } sub main'sub { &out2("sub",@_); } +sub main'sbb { &out2("sbb",@_); } sub main'rotl { &out2("rol",@_); } sub main'rotr { &out2("ror",@_); } sub main'exch { &out2("xchg",@_); } @@ -155,11 +161,38 @@ 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'pushf { &out0("pushfd"); $stack+=4; } +sub main'popf { &out0("popfd"); $stack-=4; } sub main'bswap { &out1("bswap",@_); &using486(); } sub main'not { &out1("not",@_); } sub main'call { &out1("call",($_[0]=~/^\$L/?'':'_').$_[0]); } sub main'ret { &out0("ret"); } sub main'nop { &out0("nop"); } +sub main'test { &out2("test",@_); } +sub main'bt { &out2("bt",@_); } +sub main'leave { &out0("leave"); } +sub main'cpuid { &out0("DW\t0A20Fh"); } +sub main'rdtsc { &out0("DW\t0310Fh"); } +sub main'halt { &out0("hlt"); } +sub main'movz { &out2("movzx",@_); } +sub main'neg { &out1("neg",@_); } +sub main'cld { &out0("cld"); } + +# SSE2 +sub main'emms { &out0("emms"); } +sub main'movd { &out2("movd",@_); } +sub main'movq { &out2("movq",@_); } +sub main'movdqu { &out2("movdqu",@_); } +sub main'movdqa { &out2("movdqa",@_); } +sub main'movdq2q{ &out2("movdq2q",@_); } +sub main'movq2dq{ &out2("movq2dq",@_); } +sub main'paddq { &out2("paddq",@_); } +sub main'pmuludq{ &out2("pmuludq",@_); } +sub main'psrlq { &out2("psrlq",@_); } +sub main'psllq { &out2("psllq",@_); } +sub main'pxor { &out2("pxor",@_); } +sub main'por { &out2("por",@_); } +sub main'pand { &out2("pand",@_); } sub out2 { @@ -225,7 +258,7 @@ sub main'function_begin push(@labels,$func); local($tmp)=<<"EOF"; -_TEXT SEGMENT +_TEXT\$ SEGMENT PAGE 'CODE' PUBLIC _$func $extra _$func PROC NEAR @@ -243,7 +276,7 @@ sub main'function_begin_B local($func,$extra)=@_; local($tmp)=<<"EOF"; -_TEXT SEGMENT +_TEXT\$ SEGMENT PAGE 'CODE' PUBLIC _$func $extra _$func PROC NEAR @@ -263,7 +296,7 @@ sub main'function_end pop ebp ret _$func ENDP -_TEXT ENDS +_TEXT\$ ENDS EOF push(@out,$tmp); $stack=0; @@ -276,7 +309,7 @@ sub main'function_end_B local($tmp)=<<"EOF"; _$func ENDP -_TEXT ENDS +_TEXT\$ ENDS EOF push(@out,$tmp); $stack=0; @@ -299,6 +332,13 @@ EOF sub main'file_end { + # try to detect if SSE2 or MMX extensions were used... + if (grep {/xmm[0-7]\s*,/i} @out) { + grep {s/\.[3-7]86/\.686\n\t\.XMM/} @out; + } + elsif (grep {/mm[0-7]\s*,/i} @out) { + grep {s/\.[3-7]86/\.686\n\t\.MMX/} @out; + } push(@out,"END\n"); } @@ -330,6 +370,12 @@ sub main'comment } } +sub main'public_label + { + $label{$_[0]}="_$_[0]" if (!defined($label{$_[0]})); + push(@out,"PUBLIC\t$label{$_[0]}\n"); + } + sub main'label { if (!defined($label{$_[0]})) @@ -347,10 +393,18 @@ sub main'set_label $label{$_[0]}="\$${label}${_[0]}"; $label++; } + if ($_[1]!=0 && $_[1]>1) + { + main'align($_[1]); + } if((defined $_[2]) && ($_[2] == 1)) { push(@out,"$label{$_[0]}::\n"); } + elsif ($label{$_[0]} !~ /^\$/) + { + push(@out,"$label{$_[0]}\tLABEL PTR\n"); + } else { push(@out,"$label{$_[0]}:\n"); @@ -359,7 +413,12 @@ sub main'set_label sub main'data_word { - push(@out,"\tDD\t$_[0]\n"); + push(@out,"\tDD\t".join(',',@_)."\n"); + } + +sub main'align + { + push(@out,"\tALIGN\t$_[0]\n"); } sub out1p @@ -377,3 +436,18 @@ sub main'picmeup } sub main'blindpop { &out1("pop",@_); } + +sub main'initseg + { + local($f)=@_; + local($tmp)=<<___; +OPTION DOTNAME +.CRT\$XIU SEGMENT DWORD PUBLIC 'DATA' +EXTRN _$f:NEAR +DD _$f +.CRT\$XIU ENDS +___ + push(@out,$tmp); + } + +1; diff --git a/usr/src/common/openssl/crypto/perlasm/x86nasm.pl b/usr/src/common/openssl/crypto/perlasm/x86nasm.pl index 30346af4ea..331f18bb22 100644 --- a/usr/src/common/openssl/crypto/perlasm/x86nasm.pl +++ b/usr/src/common/openssl/crypto/perlasm/x86nasm.pl @@ -3,6 +3,7 @@ package x86nasm; $label="L000"; +$under=($main'netware)?'':'_'; %lb=( 'eax', 'al', 'ebx', 'bl', @@ -32,7 +33,8 @@ sub main'external_label { push(@labels,@_); foreach (@_) { - push(@out, "extern\t_$_\n"); + push(@out,".") if ($main'mwerks); + push(@out, "extern\t${under}$_\n"); } } @@ -58,14 +60,19 @@ sub main'DWP &get_mem("DWORD",@_); } +sub main'QWP + { + &get_mem("",@_); + } + sub main'BC { - return "BYTE @_"; + return (($main'mwerks)?"":"BYTE ")."@_"; } sub main'DWC { - return "DWORD @_"; + return (($main'mwerks)?"":"DWORD ")."@_"; } sub main'stack_push @@ -86,16 +93,22 @@ sub get_mem { my($size,$addr,$reg1,$reg2,$idx)=@_; my($t,$post); - my($ret)="["; + my($ret)=$size; + if ($ret ne "") + { + $ret .= " PTR" if ($main'mwerks); + $ret .= " "; + } + $ret .= "["; $addr =~ s/^\s+//; if ($addr =~ /^(.+)\+(.+)$/) { $reg2=&conv($1); - $addr="_$2"; + $addr="$under$2"; } - elsif ($addr =~ /^[_a-zA-Z]/) + elsif ($addr =~ /^[_a-z][_a-z0-9]*$/i) { - $addr="_$addr"; + $addr="$under$addr"; } if ($addr =~ /^.+\-.+$/) { $addr="($addr)"; } @@ -134,6 +147,7 @@ sub main'xorb { &out2("xor",@_); } sub main'add { &out2("add",@_); } sub main'adc { &out2("adc",@_); } sub main'sub { &out2("sub",@_); } +sub main'sbb { &out2("sbb",@_); } sub main'rotl { &out2("rol",@_); } sub main'rotr { &out2("ror",@_); } sub main'exch { &out2("xchg",@_); } @@ -147,28 +161,56 @@ 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'ja { &out1("ja NEAR",@_); } -sub main'jae { &out1("jae NEAR",@_); } -sub main'jb { &out1("jb NEAR",@_); } -sub main'jbe { &out1("jbe 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",@_); } +$near=($main'mwerks)?'':'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'ja { &out1("ja $near",@_); } +sub main'jae { &out1("jae $near",@_); } +sub main'jb { &out1("jb $near",@_); } +sub main'jbe { &out1("jbe $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'pushf { &out0("pushfd"); $stack+=4; } +sub main'popf { &out0("popfd"); $stack-=4; } sub main'bswap { &out1("bswap",@_); &using486(); } sub main'not { &out1("not",@_); } -sub main'call { &out1("call",($_[0]=~/^\$L/?'':'_').$_[0]); } +sub main'call { &out1("call",($_[0]=~/^\@L/?'':$under).$_[0]); } sub main'ret { &out0("ret"); } sub main'nop { &out0("nop"); } +sub main'test { &out2("test",@_); } +sub main'bt { &out2("bt",@_); } +sub main'leave { &out0("leave"); } +sub main'cpuid { &out0("cpuid"); } +sub main'rdtsc { &out0("rdtsc"); } +sub main'halt { &out0("hlt"); } +sub main'movz { &out2("movzx",@_); } +sub main'neg { &out1("neg",@_); } +sub main'cld { &out0("cld"); } + +# SSE2 +sub main'emms { &out0("emms"); } +sub main'movd { &out2("movd",@_); } +sub main'movq { &out2("movq",@_); } +sub main'movdqu { &out2("movdqu",@_); } +sub main'movdqa { &out2("movdqa",@_); } +sub main'movdq2q{ &out2("movdq2q",@_); } +sub main'movq2dq{ &out2("movq2dq",@_); } +sub main'paddq { &out2("paddq",@_); } +sub main'pmuludq{ &out2("pmuludq",@_); } +sub main'psrlq { &out2("psrlq",@_); } +sub main'psllq { &out2("psllq",@_); } +sub main'pxor { &out2("pxor",@_); } +sub main'por { &out2("por",@_); } +sub main'pand { &out2("pand",@_); } sub out2 { @@ -176,6 +218,11 @@ sub out2 my($l,$t); push(@out,"\t$name\t"); + if (!$main'mwerks and $name eq "lea") + { + $p1 =~ s/^[^\[]*\[/\[/; + $p2 =~ s/^[^\[]*\[/\[/; + } $t=&conv($p1).","; $l=length($t); push(@out,$t); @@ -215,7 +262,17 @@ sub using486 sub main'file { - push(@out, "segment .text use32\n"); + if ($main'mwerks) { push(@out,".section\t.text\n"); } + else { + local $tmp=<<___; +%ifdef __omf__ +section code use32 class=code +%else +section .text +%endif +___ + push(@out,$tmp); + } } sub main'function_begin @@ -224,8 +281,8 @@ sub main'function_begin push(@labels,$func); my($tmp)=<<"EOF"; -global _$func -_$func: +global $under$func +$under$func: push ebp push ebx push esi @@ -239,8 +296,8 @@ sub main'function_begin_B { my($func,$extra)=@_; my($tmp)=<<"EOF"; -global _$func -_$func: +global $under$func +$under$func: EOF push(@out,$tmp); $stack=4; @@ -314,11 +371,17 @@ sub main'comment } } +sub main'public_label + { + $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]})); + push(@out,"global\t$label{$_[0]}\n"); + } + sub main'label { if (!defined($label{$_[0]})) { - $label{$_[0]}="\$${label}${_[0]}"; + $label{$_[0]}="\@${label}${_[0]}"; $label++; } return($label{$_[0]}); @@ -328,15 +391,25 @@ sub main'set_label { if (!defined($label{$_[0]})) { - $label{$_[0]}="\$${label}${_[0]}"; + $label{$_[0]}="\@${label}${_[0]}"; $label++; } + if ($_[1]!=0 && $_[1]>1) + { + main'align($_[1]); + } push(@out,"$label{$_[0]}:\n"); } sub main'data_word { - push(@out,"\tDD\t$_[0]\n"); + push(@out,(($main'mwerks)?".long\t":"DD\t").join(',',@_)."\n"); + } + +sub main'align + { + push(@out,".") if ($main'mwerks); + push(@out,"align\t$_[0]\n"); } sub out1p @@ -354,3 +427,19 @@ sub main'picmeup } sub main'blindpop { &out1("pop",@_); } + +sub main'initseg + { + local($f)=@_; + if ($main'win32) + { + local($tmp)=<<___; +segment .CRT\$XIU data +extern $under$f +DD $under$f +___ + push(@out,$tmp); + } + } + +1; diff --git a/usr/src/common/openssl/crypto/perlasm/x86unix.pl b/usr/src/common/openssl/crypto/perlasm/x86unix.pl index 10b669bf04..9bc5c0e893 100644 --- a/usr/src/common/openssl/crypto/perlasm/x86unix.pl +++ b/usr/src/common/openssl/crypto/perlasm/x86unix.pl @@ -1,14 +1,15 @@ #!/usr/local/bin/perl -package x86unix; +package x86unix; # GAS actually... $label="L000"; $const=""; $constl=0; $align=($main'aout)?"4":"16"; -$under=($main'aout)?"_":""; -$com_start=($main'sol)?"/":"#"; +$under=($main'aout or $main'coff)?"_":""; +$dot=($main'aout)?"":"."; +$com_start="#" if ($main'aout or $main'coff); sub main'asm_init_output { @out=(); } sub main'asm_get_output { return(@out); } @@ -51,6 +52,24 @@ if ($main'cpp) 'edi', '%edi', 'ebp', '%ebp', 'esp', '%esp', + + 'mm0', '%mm0', + 'mm1', '%mm1', + 'mm2', '%mm2', + 'mm3', '%mm3', + 'mm4', '%mm4', + 'mm5', '%mm5', + 'mm6', '%mm6', + 'mm7', '%mm7', + + 'xmm0', '%xmm0', + 'xmm1', '%xmm1', + 'xmm2', '%xmm2', + 'xmm3', '%xmm3', + 'xmm4', '%xmm4', + 'xmm5', '%xmm5', + 'xmm6', '%xmm6', + 'xmm7', '%xmm7', ); %reg_val=( @@ -97,6 +116,11 @@ sub main'DWP return($ret); } +sub main'QWP + { + return(&main'DWP(@_)); + } + sub main'BP { return(&main'DWP(@_)); @@ -137,12 +161,13 @@ 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'add { &out2($_[0]=~/%[a-d][lh]/?"addb":"addl",@_); } sub main'adc { &out2("adcl",@_); } sub main'sub { &out2("subl",@_); } +sub main'sbb { &out2("sbbl",@_); } sub main'rotl { &out2("roll",@_); } sub main'rotr { &out2("rorl",@_); } -sub main'exch { &out2("xchg",@_); } +sub main'exch { &out2($_[0]=~/%[a-d][lh]/?"xchgb":"xchgl",@_); } sub main'cmp { &out2("cmpl",@_); } sub main'lea { &out2("leal",@_); } sub main'mul { &out1("mull",@_); } @@ -164,15 +189,44 @@ 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'inc { &out1($_[0]=~/%[a-d][hl]/?"incb":"incl",@_); } sub main'push { &out1("pushl",@_); $stack+=4; } sub main'pop { &out1("popl",@_); $stack-=4; } -sub main'pushf { &out0("pushf"); $stack+=4; } -sub main'popf { &out0("popf"); $stack-=4; } +sub main'pushf { &out0("pushfl"); $stack+=4; } +sub main'popf { &out0("popfl"); $stack-=4; } sub main'not { &out1("notl",@_); } -sub main'call { &out1("call",($_[0]=~/^\.L/?'':$under).$_[0]); } +sub main'call { my $pre=$under; + foreach $i (%label) + { if ($label{$i} eq $_[0]) { $pre=''; last; } } + &out1("call",$pre.$_[0]); + } sub main'ret { &out0("ret"); } sub main'nop { &out0("nop"); } +sub main'test { &out2("testl",@_); } +sub main'bt { &out2("btl",@_); } +sub main'leave { &out0("leave"); } +sub main'cpuid { &out0(".byte\t0x0f,0xa2"); } +sub main'rdtsc { &out0(".byte\t0x0f,0x31"); } +sub main'halt { &out0("hlt"); } +sub main'movz { &out2("movzbl",@_); } +sub main'neg { &out1("negl",@_); } +sub main'cld { &out0("cld"); } + +# SSE2 +sub main'emms { &out0("emms"); } +sub main'movd { &out2("movd",@_); } +sub main'movq { &out2("movq",@_); } +sub main'movdqu { &out2("movdqu",@_); } +sub main'movdqa { &out2("movdqa",@_); } +sub main'movdq2q{ &out2("movdq2q",@_); } +sub main'movq2dq{ &out2("movq2dq",@_); } +sub main'paddq { &out2("paddq",@_); } +sub main'pmuludq{ &out2("pmuludq",@_); } +sub main'psrlq { &out2("psrlq",@_); } +sub main'psllq { &out2("psllq",@_); } +sub main'pxor { &out2("pxor",@_); } +sub main'por { &out2("por",@_); } +sub main'pand { &out2("pand",@_); } # The bswapl instruction is new for the 486. Emulate if i386. sub main'bswap @@ -278,8 +332,6 @@ sub main'file local($tmp)=<<"EOF"; .file "$file.s" - .version "01.01" -gcc2_compiled.: EOF push(@out,$tmp); } @@ -293,15 +345,17 @@ sub main'function_begin local($tmp)=<<"EOF"; .text - .align $align -.globl $func +.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"); } + { $tmp=push(@out,"TYPE($func,\@function)\n"); } + elsif ($main'coff) + { $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); } + elsif ($main'aout and !$main'pic) + { } + else { $tmp=push(@out,".type\t$func,\@function\n"); } + push(@out,".align\t$align\n"); push(@out,"$func:\n"); $tmp=<<"EOF"; pushl %ebp @@ -323,15 +377,17 @@ sub main'function_begin_B local($tmp)=<<"EOF"; .text - .align $align -.globl $func +.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,"TYPE($func,\@function)\n"); } + elsif ($main'coff) + { $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); } + elsif ($main'aout and !$main'pic) + { } + else { push(@out,".type $func,\@function\n"); } + push(@out,".align\t$align\n"); push(@out,"$func:\n"); $stack=4; } @@ -348,15 +404,15 @@ sub main'function_end popl %ebx popl %ebp ret -.L_${func}_end: +${dot}L_${func}_end: EOF push(@out,$tmp); if ($main'cpp) - { push(@out,"\tSIZE($func,.L_${func}_end-$func)\n"); } - elsif ($main'gaswin) - { $tmp=push(@out,"\t.align 4\n"); } - else { push(@out,"\t.size\t$func,.L_${func}_end-$func\n"); } + { push(@out,"SIZE($func,${dot}L_${func}_end-$func)\n"); } + elsif ($main'coff or $main'aout) + { } + else { push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); } push(@out,".ident \"$func\"\n"); $stack=0; %label=(); @@ -382,13 +438,13 @@ sub main'function_end_B $func=$under.$func; - push(@out,".L_${func}_end:\n"); + push(@out,"${dot}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"); + { push(@out,"SIZE($func,${dot}L_${func}_end-$func)\n"); } + elsif ($main'coff or $main'aout) + { } + else { push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); } + push(@out,".ident \"$func\"\n"); $stack=0; %label=(); } @@ -429,9 +485,10 @@ sub main'swtmp sub main'comment { - if ($main'elf) # GNU and SVR4 as'es use different comment delimiters, - { # so we just skip comments... - push(@out,"\n"); + if (!defined($com_start) or $main'elf) + { # Regarding $main'elf above... + # GNU and SVR4 as'es use different comment delimiters, + push(@out,"\n"); # so we just skip ELF comments... return; } foreach (@_) @@ -443,11 +500,17 @@ sub main'comment } } +sub main'public_label + { + $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]})); + push(@out,".globl\t$label{$_[0]}\n"); + } + sub main'label { if (!defined($label{$_[0]})) { - $label{$_[0]}=".${label}${_[0]}"; + $label{$_[0]}="${dot}${label}${_[0]}"; $label++; } return($label{$_[0]}); @@ -457,15 +520,66 @@ sub main'set_label { if (!defined($label{$_[0]})) { - $label{$_[0]}=".${label}${_[0]}"; + $label{$_[0]}="${dot}${label}${_[0]}"; $label++; } - push(@out,".align $align\n") if ($_[1] != 0); + if ($_[1]!=0) + { + if ($_[1]>1) { main'align($_[1]); } + else { push(@out,".align $align\n"); } + } push(@out,"$label{$_[0]}:\n"); } sub main'file_end { + # try to detect if SSE2 or MMX extensions were used on ELF platform... + if ($main'elf && grep {/%[x]*mm[0-7]/i} @out) { + local($tmp); + + push (@out,"\n.section\t.bss\n"); + push (@out,".comm\t${under}OPENSSL_ia32cap_P,4,4\n"); + + push (@out,".section\t.init\n"); + # One can argue that it's wasteful to craft every + # SSE/MMX module with this snippet... Well, it's 72 + # bytes long and for the moment we have two modules. + # Let's argue when we have 7 modules or so... + # + # $1<<10 sets a reserved bit to signal that variable + # was initialized already... + &main'picmeup("edx","OPENSSL_ia32cap_P"); + $tmp=<<___; + cmpl \$0,(%edx) + jne 1f + movl \$1<<10,(%edx) + pushf + popl %eax + movl %eax,%ecx + xorl \$1<<21,%eax + pushl %eax + popf + pushf + popl %eax + xorl %ecx,%eax + btl \$21,%eax + jnc 1f + pushl %edi + pushl %ebx + movl %edx,%edi + movl \$1,%eax + .byte 0x0f,0xa2 + orl \$1<<10,%edx + movl %edx,0(%edi) + popl %ebx + popl %edi + jmp 1f + .align $align + 1: +___ + push (@out,$tmp); + } + if ($const ne "") { push(@out,".section .rodata\n"); @@ -476,7 +590,18 @@ sub main'file_end sub main'data_word { - push(@out,"\t.long $_[0]\n"); + push(@out,"\t.long\t".join(',',@_)."\n"); + } + +sub main'align + { + my $val=$_[0],$p2,$i; + if ($main'aout) { + for ($p2=0;$val!=0;$val>>=1) { $p2++; } + $val=$p2-1; + $val.=",0x90"; + } + push(@out,".align\t$val\n"); } # debug output functions: puts, putx, printf @@ -558,7 +683,6 @@ sub main'picmeup { local($tmp)=<<___; #if (defined(ELF) || defined(SOL)) && defined(PIC) - .align 8 call 1f 1: popl $regs{$dst} addl \$_GLOBAL_OFFSET_TABLE_+[.-1b],$regs{$dst} @@ -571,13 +695,12 @@ ___ } elsif ($main'pic && ($main'elf || $main'aout)) { - push(@out,"\t.align\t8\n"); &main'call(&main'label("PIC_me_up")); &main'set_label("PIC_me_up"); &main'blindpop($dst); - &main'add($dst,"\$$under"."_GLOBAL_OFFSET_TABLE_+[.-". + &main'add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-". &main'label("PIC_me_up") . "]"); - &main'mov($dst,&main'DWP($sym."\@GOT",$dst)); + &main'mov($dst,&main'DWP($under.$sym."\@GOT",$dst)); } else { @@ -586,3 +709,41 @@ ___ } sub main'blindpop { &out1("popl",@_); } + +sub main'initseg + { + local($f)=@_; + local($tmp); + if ($main'elf) + { + $tmp=<<___; +.section .init + call $under$f + jmp .Linitalign +.align $align +.Linitalign: +___ + } + elsif ($main'coff) + { + $tmp=<<___; # applies to both Cygwin and Mingw +.section .ctors +.long $under$f +___ + } + elsif ($main'aout) + { + local($ctor)="${under}_GLOBAL_\$I\$$f"; + $tmp=".text\n"; + $tmp.=".type $ctor,\@function\n" if ($main'pic); + $tmp.=<<___; # OpenBSD way... +.globl $ctor +.align 2 +$ctor: + jmp $under$f +___ + } + push(@out,$tmp) if ($tmp); + } + +1; |