3 package x86unix; # GAS actually...
7 $lbdecor=$::aout?"L":".L"; # local label decoration
8 $nmdecor=($::aout or $::coff)?"_":""; # external name decoration
13 $align=log($align)/log(2) if ($::aout);
14 $com_start="#" if ($::aout or $::coff);
18 if ($reg =~ m/^%e/o) { "l"; }
19 elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
20 elsif ($reg =~ m/^%[xm]/o) { undef; }
25 # expand opcode with size suffix;
26 # prefix numeric constants with $;
28 { my($opcode,$dst,$src)=@_;
29 my($tmp,$suffix,@arg);
32 { $src =~ s/^(e?[a-dsixphl]{2})$/%$1/o;
33 $src =~ s/^(x?mm[0-7])$/%$1/o;
34 $src =~ s/^(\-?[0-9]+)$/\$$1/o;
35 $src =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o;
39 { $dst =~ s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o;
40 $dst =~ s/^(x?mm[0-7])$/%$1/o;
41 $dst =~ s/^(\-?[0-9]+)$/\$$1/o if(!defined($src));
42 $dst =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o if(!defined($src));
46 if ($dst =~ m/^%/o) { $suffix=&opsize($dst); }
47 elsif ($src =~ m/^%/o) { $suffix=&opsize($src); }
49 undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
51 if ($#_==0) { &::emit($opcode); }
52 elsif ($opcode =~ m/^j/o && $#_==1) { &::emit($opcode,@arg); }
53 elsif ($opcode eq "call" && $#_==1) { &::emit($opcode,@arg); }
54 elsif ($opcode =~ m/^set/&& $#_==1) { &::emit($opcode,@arg); }
55 else { &::emit($opcode.$suffix,@arg);}
60 # opcodes not covered by ::generic above, mostly inconsistent namings...
62 sub ::movz { &::movzb(@_); }
63 sub ::pushf { &::pushfl; }
64 sub ::popf { &::popfl; }
65 sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
66 sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
68 sub ::call { &::emit("call",(&islabel($_[0]) or "$nmdecor$_[0]")); }
69 sub ::call_ptr { &::generic("call","*$_[0]"); }
70 sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
72 *::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
74 # chosen SSE instructions
76 { my($p1,$p2,$optimize)=@_;
77 if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
78 # movq between mmx registers can sink Intel CPUs
79 { &::pshufw($p1,$p2,0xe4); }
81 { &::generic("movq",@_); }
84 { my($dst,$src,$magic)=@_;
85 &::emit("pshufw","\$$magic","%$src","%$dst");
89 { my($addr,$reg1,$reg2,$idx)=@_;
93 # prepend global references with optional underscore
94 $addr =~ s/^([^\+\-0-9][^\+\-]*)/islabel($1) or "$nmdecor$1"/ige;
96 $reg1 = "%$reg1" if ($reg1);
97 $reg2 = "%$reg2" if ($reg2);
99 $ret .= $addr if (($addr ne "") && ($addr ne 0));
102 { $idx!= 0 or $idx=1;
103 $ret .= "($reg1,$reg2,$idx)";
106 { $ret .= "($reg1)"; }
110 sub ::QWP { &::DWP(@_); }
111 sub ::BP { &::DWP(@_); }
116 { push(@out,".file\t\"$_[0].s\"\n"); }
118 sub ::function_begin_B
119 { my($func,$extra)=@_;
120 my $global=($func !~ /^_/);
121 my $begin="${lbdecor}_${func}_begin";
123 &::external_label($func);
124 $label{$func} = $global?"$begin":"$nmdecor$func";
125 $func=$nmdecor.$func;
127 push(@out,".text\n");
128 push(@out,".globl\t$func\n") if ($global);
130 { push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
131 elsif ($::aout and !$::pic)
134 { push(@out,".type $func,\@function\n"); }
135 push(@out,".align\t$align\n");
136 push(@out,"$func:\n");
137 push(@out,"$begin:\n") if ($global);
145 push(@out,".size\t$nmdecor$func,.-$label{$func}\n") if ($::elf);
146 foreach $i (keys %label)
147 { delete $label{$i} if ($label{$i} =~ /^${lbdecor}[0-9]{3}/); }
153 if (!defined($com_start) or $::elf)
154 { # Regarding $::elf above...
155 # GNU and SVR4 as'es use different comment delimiters,
156 push(@out,"\n"); # so we just skip ELF comments...
164 { push(@out,"\t$com_start $_ $com_end\n"); }
168 sub islabel # see is argument is a known label
170 foreach $i (values %label) { return $i if ($i eq $_[0]); }
171 $label{$_[0]}; # can be undef
174 sub ::external_label { push(@labels,@_); }
177 { $label{$_[0]}="${nmdecor}${_[0]}" if (!defined($label{$_[0]}));
178 push(@out,".globl\t$label{$_[0]}\n");
182 { if (!defined($label{$_[0]}))
183 { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; }
188 { my $label=&::label($_[0]);
189 &::align($_[1]) if ($_[1]>1);
190 push(@out,"$label:\n");
194 { # try to detect if SSE2 or MMX extensions were used on ELF platform...
195 if ($::elf && grep {/\b%[x]?mm[0-7]\b|OPENSSL_ia32cap_P\b/i} @out) {
197 push (@out,"\n.section\t.bss\n");
198 push (@out,".comm\t${nmdecor}OPENSSL_ia32cap_P,4,4\n");
200 return; # below is not needed in OpenSSL context
202 push (@out,".section\t.init\n");
203 &::picmeup("edx","OPENSSL_ia32cap_P");
204 # $1<<10 sets a reserved bit to signal that variable
205 # was initialized already...
228 cmpl $1970169159,%ebx
231 cmpl $1231384169,%edx
234 cmpl $1818588270,%ecx
250 andl $4026531839,%edx
264 sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
265 sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
268 { my $val=$_[0],$p2,$i;
270 { for ($p2=0;$val!=0;$val>>=1) { $p2++; }
274 push(@out,".align\t$val\n");
278 { my($dst,$sym,$base,$reflabel)=@_;
280 if ($::pic && ($::elf || $::aout))
281 { if (!defined($base))
282 { &::call(&::label("PIC_me_up"));
283 &::set_label("PIC_me_up");
285 &::add($dst,"\$${nmdecor}_GLOBAL_OFFSET_TABLE_+[.-".
286 &::label("PIC_me_up") . "]");
289 { &::lea($dst,&::DWP("${nmdecor}_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
292 &::mov($dst,&::DWP("$nmdecor$sym\@GOT",$dst));
295 { &::lea($dst,&::DWP($sym)); }
312 { $tmp=<<___; # applies to both Cygwin and Mingw
318 { $ctor="${nmdecor}_GLOBAL_\$I\$$f";
320 $tmp.=".type $ctor,\@function\n" if ($::pic);
321 $tmp.=<<___; # OpenBSD way...
328 push(@out,$tmp) if ($tmp);