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 ($opcode =~ m/^j/o && $#_==1)	{ &::emit($opcode,@arg);	}
     49     elsif ($opcode eq "call" && $#_==1)	{ &::emit($opcode,@arg);	}
     50     elsif ($opcode =~ m/^set/&& $#_==1)	{ &::emit($opcode,@arg);	}
     51     else				{ &::emit($opcode.$suffix,@arg);}
     52 
     53   1;
     54 }
     55 #
     56 # opcodes not covered by ::generic above, mostly inconsistent namings...
     57 #
     58 sub ::movzx	{ &::movzb(@_);			}
     59 sub ::pushfd	{ &::pushfl;			}
     60 sub ::popfd	{ &::popfl;			}
     61 sub ::cpuid	{ &::emit(".byte\t0x0f,0xa2");	}
     62 sub ::rdtsc	{ &::emit(".byte\t0x0f,0x31");	}
     63 
     64 sub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
     65 sub ::call_ptr	{ &::generic("call","*$_[0]");	}
     66 sub ::jmp_ptr	{ &::generic("jmp","*$_[0]");	}
     67 
     68 *::bswap = sub	{ &::emit("bswap","%$_[0]");	} if (!$::i386);
     69 
     70 sub ::DWP
     71 { my($addr,$reg1,$reg2,$idx)=@_;
     72   my $ret="";
     73 
     74     $addr =~ s/^\s+//;
     75     # prepend global references with optional underscore
     76     $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
     77 
     78     $reg1 = "%$reg1" if ($reg1);
     79     $reg2 = "%$reg2" if ($reg2);
     80 
     81     $ret .= $addr if (($addr ne "") && ($addr ne 0));
     82 
     83     if ($reg2)
     84     {	$idx!= 0 or $idx=1;
     85 	$ret .= "($reg1,$reg2,$idx)";
     86     }
     87     elsif ($reg1)
     88     {	$ret .= "($reg1)";	}
     89 
     90   $ret;
     91 }
     92 sub ::QWP	{ &::DWP(@_);	}
     93 sub ::BP	{ &::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 (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) {
    153 	my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,4";
    154 	if ($::elf)	{ push (@out,"$tmp,4\n"); }
    155 	else		{ push (@out,"$tmp\n"); }
    156     }
    157     if ($::macosx)
    158     {	if (%non_lazy_ptr)
    159     	{   push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
    160 	    foreach $i (keys %non_lazy_ptr)
    161 	    {	push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n");   }
    162 	}
    163     }
    164     push(@out,$initseg) if ($initseg);
    165 }
    166 
    167 sub ::data_byte	{   push(@out,".byte\t".join(',',@_)."\n");   }
    168 sub ::data_word {   push(@out,".long\t".join(',',@_)."\n");   }
    169 
    170 sub ::align
    171 { my $val=$_[0],$p2,$i;
    172     if ($::aout)
    173     {	for ($p2=0;$val!=0;$val>>=1) { $p2++; }
    174 	$val=$p2-1;
    175 	$val.=",0x90";
    176     }
    177     push(@out,".align\t$val\n");
    178 }
    179 
    180 sub ::picmeup
    181 { my($dst,$sym,$base,$reflabel)=@_;
    182 
    183     if ($::pic && ($::elf || $::aout))
    184     {	if (!defined($base))
    185 	{   &::call(&::label("PIC_me_up"));
    186 	    &::set_label("PIC_me_up");
    187 	    &::blindpop($dst);
    188 	    $base=$dst;
    189 	    $reflabel=&::label("PIC_me_up");
    190 	}
    191 	if ($::macosx)
    192 	{   my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr");
    193 	    &::mov($dst,&::DWP("$indirect-$reflabel",$base));
    194 	    $non_lazy_ptr{"$nmdecor$sym"}=$indirect;
    195 	}
    196 	else
    197 	{   &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
    198 			    $base));
    199 	    &::mov($dst,&::DWP("$sym\@GOT",$dst));
    200 	}
    201     }
    202     else
    203     {	&::lea($dst,&::DWP($sym));	}
    204 }
    205 
    206 sub ::initseg
    207 { my $f=$nmdecor.shift;
    208 
    209     if ($::elf)
    210     {	$initseg.=<<___;
    211 .section	.init
    212 	call	$f
    213 	jmp	.Linitalign
    214 .align	$align
    215 .Linitalign:
    216 ___
    217     }
    218     elsif ($::coff)
    219     {   $initseg.=<<___;	# applies to both Cygwin and Mingw
    220 .section	.ctors
    221 .long	$f
    222 ___
    223     }
    224     elsif ($::macosx)
    225     {	$initseg.=<<___;
    226 .mod_init_func
    227 .align 2
    228 .long   $f
    229 ___
    230     }
    231     elsif ($::aout)
    232     {	my $ctor="${nmdecor}_GLOBAL_\$I\$$f";
    233 	$initseg.=".text\n";
    234 	$initseg.=".type	$ctor,\@function\n" if ($::pic);
    235 	$initseg.=<<___;	# OpenBSD way...
    236 .globl	$ctor
    237 .align	2
    238 $ctor:
    239 	jmp	$f
    240 ___
    241     }
    242 }
    243 
    244 sub ::dataseg
    245 {   push(@out,".data\n");   }
    246 
    247 1;
    248