Home | History | Annotate | Download | only in perlasm
      1 #! /usr/bin/env perl
      2 # Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.
      3 #
      4 # Licensed under the OpenSSL license (the "License").  You may not use
      5 # this file except in compliance with the License.  You can obtain a copy
      6 # in the file LICENSE in the source distribution or at
      7 # https://www.openssl.org/source/license.html
      8 
      9 
     10 package x86gas;
     11 
     12 *out=\@::out;
     13 
     14 $::lbdecor=$::aout?"L":".L";		# local label decoration
     15 $nmdecor=($::aout or $::coff)?"_":"";	# external name decoration
     16 
     17 $initseg="";
     18 
     19 $align=16;
     20 $align=log($align)/log(2) if ($::aout);
     21 $com_start="#" if ($::aout or $::coff);
     22 
     23 sub opsize()
     24 { my $reg=shift;
     25     if    ($reg =~ m/^%e/o)		{ "l"; }
     26     elsif ($reg =~ m/^%[a-d][hl]$/o)	{ "b"; }
     27     elsif ($reg =~ m/^%[yxm]/o)		{ undef; }
     28     else				{ "w"; }
     29 }
     30 
     31 # swap arguments;
     32 # expand opcode with size suffix;
     33 # prefix numeric constants with $;
     34 sub ::generic
     35 { my($opcode,@arg)=@_;
     36   my($suffix,$dst,$src);
     37 
     38     @arg=reverse(@arg);
     39 
     40     for (@arg)
     41     {	s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o;	# gp registers
     42 	s/^([xy]?mm[0-7])$/%$1/o;		# xmm/mmx registers
     43 	s/^(\-?[0-9]+)$/\$$1/o;			# constants
     44 	s/^(\-?0x[0-9a-f]+)$/\$$1/o;		# constants
     45     }
     46 
     47     $dst = $arg[$#arg]		if ($#arg>=0);
     48     $src = $arg[$#arg-1]	if ($#arg>=1);
     49     if    ($dst =~ m/^%/o)	{ $suffix=&opsize($dst); }
     50     elsif ($src =~ m/^%/o)	{ $suffix=&opsize($src); }
     51     else			{ $suffix="l";           }
     52     undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
     53 
     54     if ($#_==0)				{ &::emit($opcode);		}
     55     elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o)
     56 					{ &::emit($opcode,@arg);	}
     57     else				{ &::emit($opcode.$suffix,@arg);}
     58 
     59   1;
     60 }
     61 #
     62 # opcodes not covered by ::generic above, mostly inconsistent namings...
     63 #
     64 sub ::movzx	{ &::movzb(@_);			}
     65 sub ::pushfd	{ &::pushfl;			}
     66 sub ::popfd	{ &::popfl;			}
     67 sub ::cpuid	{ &::emit(".byte\t0x0f,0xa2");	}
     68 sub ::rdtsc	{ &::emit(".byte\t0x0f,0x31");	}
     69 
     70 sub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
     71 sub ::call_ptr	{ &::generic("call","*$_[0]");	}
     72 sub ::jmp_ptr	{ &::generic("jmp","*$_[0]");	}
     73 
     74 *::bswap = sub	{ &::emit("bswap","%$_[0]");	} if (!$::i386);
     75 
     76 sub ::DWP
     77 { my($addr,$reg1,$reg2,$idx)=@_;
     78   my $ret="";
     79 
     80     if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
     81 
     82     $addr =~ s/^\s+//;
     83     # prepend global references with optional underscore
     84     $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
     85 
     86     $reg1 = "%$reg1" if ($reg1);
     87     $reg2 = "%$reg2" if ($reg2);
     88 
     89     $ret .= $addr if (($addr ne "") && ($addr ne 0));
     90 
     91     if ($reg2)
     92     {	$idx!= 0 or $idx=1;
     93 	$ret .= "($reg1,$reg2,$idx)";
     94     }
     95     elsif ($reg1)
     96     {	$ret .= "($reg1)";	}
     97 
     98   $ret;
     99 }
    100 sub ::QWP	{ &::DWP(@_);	}
    101 sub ::BP	{ &::DWP(@_);	}
    102 sub ::WP	{ &::DWP(@_);	}
    103 sub ::BC	{ @_;		}
    104 sub ::DWC	{ @_;		}
    105 
    106 sub ::file
    107 {   push(@out,".file\t\"$_[0].S\"\n.text\n");	}
    108 
    109 sub ::function_begin_B
    110 { my $func=shift;
    111   my $global=($func !~ /^_/);
    112   my $begin="${::lbdecor}_${func}_begin";
    113 
    114     &::LABEL($func,$global?"$begin":"$nmdecor$func");
    115     $func=$nmdecor.$func;
    116 
    117     push(@out,".globl\t$func\n")	if ($global);
    118     if ($::macosx) {
    119       push(@out,".private_extern\t$func\n");
    120     } else {
    121       push(@out,".hidden\t$func\n");
    122     }
    123     if ($::coff)
    124     {	push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); }
    125     elsif (($::aout and !$::pic) or $::macosx)
    126     { }
    127     else
    128     {	push(@out,".type	$func,\@function\n"); }
    129     push(@out,".align\t$align\n");
    130     push(@out,"$func:\n");
    131     push(@out,"$begin:\n")		if ($global);
    132     $::stack=4;
    133 }
    134 
    135 sub ::function_end_B
    136 { my $func=shift;
    137     push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf);
    138     $::stack=0;
    139     &::wipe_labels();
    140 }
    141 
    142 sub ::comment
    143 	{
    144 	if (!defined($com_start) or $::elf)
    145 		{	# Regarding $::elf above...
    146 			# GNU and SVR4 as'es use different comment delimiters,
    147 		push(@out,"\n");	# so we just skip ELF comments...
    148 		return;
    149 		}
    150 	foreach (@_)
    151 		{
    152 		if (/^\s*$/)
    153 			{ push(@out,"\n"); }
    154 		else
    155 			{ push(@out,"\t$com_start $_ $com_end\n"); }
    156 		}
    157 	}
    158 
    159 sub ::external_label
    160 {   foreach(@_) { &::LABEL($_,$nmdecor.$_); }   }
    161 
    162 sub ::public_label
    163 {   push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }
    164 
    165 sub ::file_end
    166 {   if ($::macosx)
    167     {	if (%non_lazy_ptr)
    168     	{   push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
    169 	    foreach $i (keys %non_lazy_ptr)
    170 	    {	push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n");   }
    171 	}
    172     }
    173     if (0 && grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) {
    174 	my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16";
    175 	if ($::macosx)	{ push (@out,"$tmp,2\n"); }
    176 	elsif ($::elf)	{ push (@out,"$tmp,4\n"); }
    177 	else		{ push (@out,"$tmp\n"); }
    178     }
    179     push(@out,$initseg) if ($initseg);
    180 }
    181 
    182 sub ::data_byte	{   push(@out,".byte\t".join(',',@_)."\n");   }
    183 sub ::data_short{   push(@out,".value\t".join(',',@_)."\n");  }
    184 sub ::data_word {   push(@out,".long\t".join(',',@_)."\n");   }
    185 
    186 sub ::align
    187 { my $val=$_[0];
    188     if ($::aout)
    189     {	$val=int(log($val)/log(2));
    190 	$val.=",0x90";
    191     }
    192     push(@out,".align\t$val\n");
    193 }
    194 
    195 sub ::picmeup
    196 { my($dst,$sym,$base,$reflabel)=@_;
    197 
    198     if (($::pic && ($::elf || $::aout)) || $::macosx)
    199     {	if (!defined($base))
    200 	{   &::call(&::label("PIC_me_up"));
    201 	    &::set_label("PIC_me_up");
    202 	    &::blindpop($dst);
    203 	    $base=$dst;
    204 	    $reflabel=&::label("PIC_me_up");
    205 	}
    206 	if ($::macosx)
    207 	{   my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr");
    208 	    &::mov($dst,&::DWP("$indirect-$reflabel",$base));
    209 	    $non_lazy_ptr{"$nmdecor$sym"}=$indirect;
    210 	}
    211 	elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0)
    212 	{   &::lea($dst,&::DWP("$sym-$reflabel",$base));   }
    213 	else
    214 	{   &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
    215 			    $base));
    216 	    &::mov($dst,&::DWP("$sym\@GOT",$dst));
    217 	}
    218     }
    219     else
    220     {	&::lea($dst,&::DWP($sym));	}
    221 }
    222 
    223 sub ::initseg
    224 { my $f=$nmdecor.shift;
    225 
    226     if ($::android)
    227     {	$initseg.=<<___;
    228 .section	.init_array
    229 .align	4
    230 .long	$f
    231 ___
    232     }
    233     elsif ($::elf)
    234     {	$initseg.=<<___;
    235 .section	.init
    236 	call	$f
    237 ___
    238     }
    239     elsif ($::coff)
    240     {   $initseg.=<<___;	# applies to both Cygwin and Mingw
    241 .section	.ctors
    242 .long	$f
    243 ___
    244     }
    245     elsif ($::macosx)
    246     {	$initseg.=<<___;
    247 .mod_init_func
    248 .align 2
    249 .long   $f
    250 ___
    251     }
    252     elsif ($::aout)
    253     {	my $ctor="${nmdecor}_GLOBAL_\$I\$$f";
    254 	$initseg.=".text\n";
    255 	$initseg.=".type	$ctor,\@function\n" if ($::pic);
    256 	$initseg.=<<___;	# OpenBSD way...
    257 .globl	$ctor
    258 .align	2
    259 $ctor:
    260 	jmp	$f
    261 ___
    262     }
    263 }
    264 
    265 sub ::dataseg
    266 {   push(@out,".data\n");   }
    267 
    268 *::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf);
    269 
    270 1;
    271