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