mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
e0a651945c
Add copyright to most .pl files This does NOT cover any .pl file that has other copyright in it. Most of those are Andy's but some are public domain. Fix typo's in some existing files. Reviewed-by: Richard Levitte <levitte@openssl.org>
306 lines
7.2 KiB
Perl
306 lines
7.2 KiB
Perl
#! /usr/bin/env perl
|
|
# Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the OpenSSL license (the "License"). You may not use
|
|
# this file except in compliance with the License. You can obtain a copy
|
|
# in the file LICENSE in the source distribution or at
|
|
# https://www.openssl.org/source/license.html
|
|
|
|
|
|
# require 'x86asm.pl';
|
|
# &asm_init(<flavor>,"des-586.pl"[,$i386only]);
|
|
# &function_begin("foo");
|
|
# ...
|
|
# &function_end("foo");
|
|
# &asm_finish
|
|
|
|
$out=();
|
|
$i386=0;
|
|
|
|
# AUTOLOAD is this context has quite unpleasant side effect, namely
|
|
# that typos in function calls effectively go to assembler output,
|
|
# but on the pros side we don't have to implement one subroutine per
|
|
# each opcode...
|
|
sub ::AUTOLOAD
|
|
{ my $opcode = $AUTOLOAD;
|
|
|
|
die "more than 4 arguments passed to $opcode" if ($#_>3);
|
|
|
|
$opcode =~ s/.*:://;
|
|
if ($opcode =~ /^push/) { $stack+=4; }
|
|
elsif ($opcode =~ /^pop/) { $stack-=4; }
|
|
|
|
&generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD";
|
|
}
|
|
|
|
sub ::emit
|
|
{ my $opcode=shift;
|
|
|
|
if ($#_==-1) { push(@out,"\t$opcode\n"); }
|
|
else { push(@out,"\t$opcode\t".join(',',@_)."\n"); }
|
|
}
|
|
|
|
sub ::LB
|
|
{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'";
|
|
$1."l";
|
|
}
|
|
sub ::HB
|
|
{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'";
|
|
$1."h";
|
|
}
|
|
sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); }
|
|
sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); }
|
|
sub ::blindpop { &pop($_[0]); $stack+=4; }
|
|
sub ::wparam { &DWP($stack+4*$_[0],"esp"); }
|
|
sub ::swtmp { &DWP(4*$_[0],"esp"); }
|
|
|
|
sub ::bswap
|
|
{ if ($i386) # emulate bswap for i386
|
|
{ &comment("bswap @_");
|
|
&xchg(&HB(@_),&LB(@_));
|
|
&ror (@_,16);
|
|
&xchg(&HB(@_),&LB(@_));
|
|
}
|
|
else
|
|
{ &generic("bswap",@_); }
|
|
}
|
|
# These are made-up opcodes introduced over the years essentially
|
|
# by ignorance, just alias them to real ones...
|
|
sub ::movb { &mov(@_); }
|
|
sub ::xorb { &xor(@_); }
|
|
sub ::rotl { &rol(@_); }
|
|
sub ::rotr { &ror(@_); }
|
|
sub ::exch { &xchg(@_); }
|
|
sub ::halt { &hlt; }
|
|
sub ::movz { &movzx(@_); }
|
|
sub ::pushf { &pushfd; }
|
|
sub ::popf { &popfd; }
|
|
|
|
# 3 argument instructions
|
|
sub ::movq
|
|
{ my($p1,$p2,$optimize)=@_;
|
|
|
|
if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
|
|
# movq between mmx registers can sink Intel CPUs
|
|
{ &::pshufw($p1,$p2,0xe4); }
|
|
else
|
|
{ &::generic("movq",@_); }
|
|
}
|
|
|
|
# SSE>2 instructions
|
|
my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3,
|
|
"esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 );
|
|
sub ::pextrd
|
|
{ my($dst,$src,$imm)=@_;
|
|
if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/)
|
|
{ &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); }
|
|
else
|
|
{ &::generic("pextrd",@_); }
|
|
}
|
|
|
|
sub ::pinsrd
|
|
{ my($dst,$src,$imm)=@_;
|
|
if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/)
|
|
{ &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); }
|
|
else
|
|
{ &::generic("pinsrd",@_); }
|
|
}
|
|
|
|
sub ::pshufb
|
|
{ my($dst,$src)=@_;
|
|
if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
|
{ &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); }
|
|
else
|
|
{ &::generic("pshufb",@_); }
|
|
}
|
|
|
|
sub ::palignr
|
|
{ my($dst,$src,$imm)=@_;
|
|
if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
|
{ &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); }
|
|
else
|
|
{ &::generic("palignr",@_); }
|
|
}
|
|
|
|
sub ::pclmulqdq
|
|
{ my($dst,$src,$imm)=@_;
|
|
if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
|
{ &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); }
|
|
else
|
|
{ &::generic("pclmulqdq",@_); }
|
|
}
|
|
|
|
sub ::rdrand
|
|
{ my ($dst)=@_;
|
|
if ($dst =~ /(e[a-dsd][ixp])/)
|
|
{ &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); }
|
|
else
|
|
{ &::generic("rdrand",@_); }
|
|
}
|
|
|
|
sub ::rdseed
|
|
{ my ($dst)=@_;
|
|
if ($dst =~ /(e[a-dsd][ixp])/)
|
|
{ &::data_byte(0x0f,0xc7,0xf8|$regrm{$dst}); }
|
|
else
|
|
{ &::generic("rdrand",@_); }
|
|
}
|
|
|
|
sub rxb {
|
|
local *opcode=shift;
|
|
my ($dst,$src1,$src2,$rxb)=@_;
|
|
|
|
$rxb|=0x7<<5;
|
|
$rxb&=~(0x04<<5) if($dst>=8);
|
|
$rxb&=~(0x01<<5) if($src1>=8);
|
|
$rxb&=~(0x02<<5) if($src2>=8);
|
|
push @opcode,$rxb;
|
|
}
|
|
|
|
sub ::vprotd
|
|
{ my $args=join(',',@_);
|
|
if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/)
|
|
{ my @opcode=(0x8f);
|
|
rxb(\@opcode,$1,$2,-1,0x08);
|
|
push @opcode,0x78,0xc2;
|
|
push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M
|
|
my $c=$3;
|
|
push @opcode,$c=~/^0/?oct($c):$c;
|
|
&::data_byte(@opcode);
|
|
}
|
|
else
|
|
{ &::generic("vprotd",@_); }
|
|
}
|
|
|
|
# label management
|
|
$lbdecor="L"; # local label decoration, set by package
|
|
$label="000";
|
|
|
|
sub ::islabel # see is argument is a known label
|
|
{ my $i;
|
|
foreach $i (values %label) { return $i if ($i eq $_[0]); }
|
|
$label{$_[0]}; # can be undef
|
|
}
|
|
|
|
sub ::label # instantiate a function-scope label
|
|
{ if (!defined($label{$_[0]}))
|
|
{ $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; }
|
|
$label{$_[0]};
|
|
}
|
|
|
|
sub ::LABEL # instantiate a file-scope label
|
|
{ $label{$_[0]}=$_[1] if (!defined($label{$_[0]}));
|
|
$label{$_[0]};
|
|
}
|
|
|
|
sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); }
|
|
|
|
sub ::set_label_B { push(@out,"@_:\n"); }
|
|
sub ::set_label
|
|
{ my $label=&::label($_[0]);
|
|
&::align($_[1]) if ($_[1]>1);
|
|
&::set_label_B($label);
|
|
$label;
|
|
}
|
|
|
|
sub ::wipe_labels # wipes function-scope labels
|
|
{ foreach $i (keys %label)
|
|
{ delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); }
|
|
}
|
|
|
|
# subroutine management
|
|
sub ::function_begin
|
|
{ &function_begin_B(@_);
|
|
$stack=4;
|
|
&push("ebp");
|
|
&push("ebx");
|
|
&push("esi");
|
|
&push("edi");
|
|
}
|
|
|
|
sub ::function_end
|
|
{ &pop("edi");
|
|
&pop("esi");
|
|
&pop("ebx");
|
|
&pop("ebp");
|
|
&ret();
|
|
&function_end_B(@_);
|
|
$stack=0;
|
|
&wipe_labels();
|
|
}
|
|
|
|
sub ::function_end_A
|
|
{ &pop("edi");
|
|
&pop("esi");
|
|
&pop("ebx");
|
|
&pop("ebp");
|
|
&ret();
|
|
$stack+=16; # readjust esp as if we didn't pop anything
|
|
}
|
|
|
|
sub ::asciz
|
|
{ my @str=unpack("C*",shift);
|
|
push @str,0;
|
|
while ($#str>15) {
|
|
&data_byte(@str[0..15]);
|
|
foreach (0..15) { shift @str; }
|
|
}
|
|
&data_byte(@str) if (@str);
|
|
}
|
|
|
|
sub ::asm_finish
|
|
{ &file_end();
|
|
print @out;
|
|
}
|
|
|
|
sub ::asm_init
|
|
{ my ($type,$fn,$cpu)=@_;
|
|
|
|
$filename=$fn;
|
|
$i386=$cpu;
|
|
|
|
$elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0;
|
|
if (($type eq "elf"))
|
|
{ $elf=1; require "x86gas.pl"; }
|
|
elsif (($type eq "elf-1"))
|
|
{ $elf=-1; require "x86gas.pl"; }
|
|
elsif (($type eq "a\.out"))
|
|
{ $aout=1; require "x86gas.pl"; }
|
|
elsif (($type eq "coff" or $type eq "gaswin"))
|
|
{ $coff=1; require "x86gas.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"; }
|
|
elsif (($type eq "win32"))
|
|
{ $win32=1; require "x86masm.pl"; }
|
|
elsif (($type eq "macosx"))
|
|
{ $aout=1; $macosx=1; require "x86gas.pl"; }
|
|
elsif (($type eq "android"))
|
|
{ $elf=1; $android=1; require "x86gas.pl"; }
|
|
else
|
|
{ print STDERR <<"EOF";
|
|
Pick one target type from
|
|
elf - Linux, FreeBSD, Solaris x86, etc.
|
|
a.out - DJGPP, elder OpenBSD, etc.
|
|
coff - GAS/COFF such as Win32 targets
|
|
win32n - Windows 95/Windows NT NASM format
|
|
nw-nasm - NetWare NASM format
|
|
macosx - Mac OS X
|
|
EOF
|
|
exit(1);
|
|
}
|
|
|
|
$pic=0;
|
|
for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); }
|
|
|
|
$filename =~ s/\.pl$//;
|
|
&file($filename);
|
|
}
|
|
|
|
sub ::hidden {}
|
|
|
|
1;
|