3 package x86unix; # GAS actually...
9 $align=($::aout)?"4":"16";
10 $under=($::aout or $::coff)?"_":"";
11 $dot=($::aout)?"":".";
12 $com_start="#" if ($::aout or $::coff);
16 if ($reg =~ m/^%e/o) { "l"; }
17 elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
18 elsif ($reg =~ m/^%[xm]/o) { undef; }
23 # expand opcode with size suffix;
24 # prefix numeric constants with $;
26 { my($opcode,$dst,$src)=@_;
27 my($tmp,$suffix,@arg);
30 { $src =~ s/^(e?[a-dsixphl]{2})$/%$1/o;
31 $src =~ s/^(x?mm[0-7])$/%$1/o;
32 $src =~ s/^(\-?[0-9]+)$/\$$1/o;
33 $src =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o;
37 { $dst =~ s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o;
38 $dst =~ s/^(x?mm[0-7])$/%$1/o;
39 $dst =~ s/^(\-?[0-9]+)$/\$$1/o if(!defined($src));
40 $dst =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o if(!defined($src));
44 if ($dst =~ m/^%/o) { $suffix=&opsize($dst); }
45 elsif ($src =~ m/^%/o) { $suffix=&opsize($src); }
47 undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
49 if ($#_==0) { &::emit($opcode); }
50 elsif ($opcode =~ m/^j/o && $#_==1) { &::emit($opcode,@arg); }
51 elsif ($opcode eq "call" && $#_==1) { &::emit($opcode,@arg); }
52 elsif ($opcode =~ m/^set/&& $#_==1) { &::emit($opcode,@arg); }
53 else { &::emit($opcode.$suffix,@arg);}
58 # opcodes not covered by ::generic above, mostly inconsistent namings...
60 sub ::movz { &::movzb(@_); }
61 sub ::pushf { &::pushfl; }
62 sub ::popf { &::popfl; }
63 sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
64 sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
66 sub ::call { &::emit("call",(&islabel($_[0]) or "$under$_[0]")); }
67 sub ::call_ptr { &::generic("call","*$_[0]"); }
68 sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
70 *::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
72 # chosen SSE instructions
74 { my($p1,$p2,$optimize)=@_;
75 if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
76 # movq between mmx registers can sink Intel CPUs
77 { &::pshufw($p1,$p2,0xe4); }
79 { &::generic("movq",@_); }
82 { my($dst,$src,$magic)=@_;
83 &::emit("pshufw","\$$magic","%$src","%$dst");
87 { my($addr,$reg1,$reg2,$idx)=@_;
91 # prepend global references with optional underscore
92 $addr =~ s/^([^\+\-0-9][^\+\-]*)/islabel($1) or "$under$1"/ige;
94 $reg1 = "%$reg1" if ($reg1);
95 $reg2 = "%$reg2" if ($reg2);
97 $ret .= $addr if (($addr ne "") && ($addr ne 0));
100 { $idx!= 0 or $idx=1;
101 $ret .= "($reg1,$reg2,$idx)";
104 { $ret .= "($reg1)"; }
108 sub ::QWP { &::DWP(@_); }
109 sub ::BP { &::DWP(@_); }
114 { push(@out,".file\t\"$_[0].s\"\n"); }
116 sub ::function_begin_B
117 { my($func,$extra)=@_;
120 &::external_label($func);
121 $label{$func} = $begin = "${dot}L_${func}_begin";
124 push(@out,".text\n");
125 push(@out,".globl\t$func\n") if ($func !~ /^${under}_/);
127 { push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
128 elsif ($::aout and !$::pic)
131 { push(@out,".type $func,\@function\n"); }
132 push(@out,".align\t$align\n");
133 push(@out,"$func:\n");
134 push(@out,"$begin:\n");
142 push(@out,"${dot}L_${func}_end:\n");
144 { push(@out,".size\t$under$func,${dot}L_${func}_end-${dot}L_${func}_begin\n"); }
146 foreach $i (keys %label) { delete $label{$i} if ($label{$i} =~ /^${dot}L[0-9]{3}/); }
151 if (!defined($com_start) or $::elf)
152 { # Regarding $::elf above...
153 # GNU and SVR4 as'es use different comment delimiters,
154 push(@out,"\n"); # so we just skip ELF comments...
162 { push(@out,"\t$com_start $_ $com_end\n"); }
166 sub islabel # see is argument is a known label
168 foreach $i (values %label) { return $i if ($i eq $_[0]); }
169 $label{$_[0]}; # can be undef
172 sub ::external_label { push(@labels,@_); }
175 { $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]}));
176 push(@out,".globl\t$label{$_[0]}\n");
180 { if (!defined($label{$_[0]}))
181 { $label{$_[0]}="${dot}${label}${_[0]}"; $label++; }
186 { my $label=&::label($_[0]);
187 &::align($_[1]) if ($_[1]>1);
188 push(@out,"$label:\n");
192 { # try to detect if SSE2 or MMX extensions were used on ELF platform...
193 if ($::elf && grep {/\b%[x]?mm[0-7]\b|OPENSSL_ia32cap_P\b/i} @out) {
195 push (@out,"\n.section\t.bss\n");
196 push (@out,".comm\t${under}OPENSSL_ia32cap_P,4,4\n");
198 return; # below is not needed in OpenSSL context
200 push (@out,".section\t.init\n");
201 &::picmeup("edx","OPENSSL_ia32cap_P");
202 # $1<<10 sets a reserved bit to signal that variable
203 # was initialized already...
226 cmpl $1970169159,%ebx
229 cmpl $1231384169,%edx
232 cmpl $1818588270,%ecx
248 andl $4026531839,%edx
262 sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
263 sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
266 { my $val=$_[0],$p2,$i;
268 { for ($p2=0;$val!=0;$val>>=1) { $p2++; }
272 push(@out,".align\t$val\n");
276 { my($dst,$sym,$base,$reflabel)=@_;
278 if ($::pic && ($::elf || $::aout))
279 { if (!defined($base))
280 { &::call(&::label("PIC_me_up"));
281 &::set_label("PIC_me_up");
283 &::add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-".
284 &::label("PIC_me_up") . "]");
287 { &::lea($dst,&::DWP("${under}_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
290 &::mov($dst,&::DWP($under.$sym."\@GOT",$dst));
293 { &::lea($dst,&::DWP($sym)); }
310 { $tmp=<<___; # applies to both Cygwin and Mingw
316 { $ctor="${under}_GLOBAL_\$I\$$f";
318 $tmp.=".type $ctor,\@function\n" if ($::pic);
319 $tmp.=<<___; # OpenBSD way...
326 push(@out,$tmp) if ($tmp);