3 package x86unix; # GAS actually...
11 $align=($::aout)?"4":"16";
12 $under=($::aout or $::coff)?"_":"";
13 $dot=($::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 else { &::emit($opcode.$suffix,@arg);}
59 # opcodes not covered by ::generic above, mostly inconsistent namings...
61 sub ::movz { &::movzb(@_); }
62 sub ::pushf { &::pushfl; }
63 sub ::popf { &::popfl; }
64 sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
65 sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
67 sub ::call { &::emit("call",(&islabel($_[0]) or "$under$_[0]")); }
68 sub ::call_ptr { &::generic("call","*$_[0]"); }
69 sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
71 *::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
73 # chosen SSE instructions
75 { my($p1,$p2,$optimize)=@_;
76 if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
77 # movq between mmx registers can sink Intel CPUs
78 { &::pshufw($p1,$p2,0xe4); }
80 { &::generic("movq",@_); }
83 { my($dst,$src,$magic)=@_;
84 &::emit("pshufw","\$$magic","%$src","%$dst");
88 { my($addr,$reg1,$reg2,$idx)=@_;
92 # prepend global references with optional underscore
93 $addr =~ s/^([^\+\-0-9][^\+\-]*)/islabel($1) or "$under$1"/ige;
95 $reg1 = "%$reg1" if ($reg1);
96 $reg2 = "%$reg2" if ($reg2);
98 $ret .= $addr if (($addr ne "") && ($addr ne 0));
101 { $idx!= 0 or $idx=1;
102 $ret .= "($reg1,$reg2,$idx)";
105 { $ret .= "($reg1)"; }
109 sub ::QWP { &::DWP(@_); }
110 sub ::BP { &::DWP(@_); }
115 { push(@out,".file\t\"$_[0].s\"\n"); }
117 sub ::function_begin_B
118 { my($func,$extra)=@_;
121 &::external_label($func);
124 push(@out,".text\n.globl\t$func\n");
126 { push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
127 elsif ($::aout and !$::pic)
130 { push(@out,".type $func,\@function\n"); }
131 push(@out,".align\t$align\n");
132 push(@out,"$func:\n");
140 push(@out,"${dot}L_${func}_end:\n");
142 { push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); }
149 if (!defined($com_start) or $::elf)
150 { # Regarding $::elf above...
151 # GNU and SVR4 as'es use different comment delimiters,
152 push(@out,"\n"); # so we just skip ELF comments...
160 { push(@out,"\t$com_start $_ $com_end\n"); }
164 sub islabel # see is argument is a known label
166 foreach $i (%label) { return $label{$i} if ($label{$i} eq $_[0]); }
170 sub ::external_label { push(@labels,@_); }
173 { $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]}));
174 push(@out,".globl\t$label{$_[0]}\n");
178 { if (!defined($label{$_[0]}))
179 { $label{$_[0]}="${dot}${label}${_[0]}"; $label++; }
184 { my $label=&::label($_[0]);
185 &::align($_[1]) if ($_[1]>1);
186 push(@out,"$label:\n");
190 { # try to detect if SSE2 or MMX extensions were used on ELF platform...
191 if ($::elf && grep {/%[x]?mm[0-7]/i} @out){
194 push (@out,"\n.section\t.bss\n");
195 push (@out,".comm\t${under}OPENSSL_ia32cap_P,4,4\n");
197 push (@out,".section\t.init\n");
198 # One can argue that it's wasteful to craft every
199 # SSE/MMX module with this snippet... Well, it's 72
200 # bytes long and for the moment we have two modules.
201 # Let's argue when we have 7 modules or so...
203 # $1<<10 sets a reserved bit to signal that variable
204 # was initialized already...
205 &::picmeup("edx","OPENSSL_ia32cap_P");
238 { push(@out,".section .rodata\n");
244 sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
245 sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
248 { my $val=$_[0],$p2,$i;
250 { for ($p2=0;$val!=0;$val>>=1) { $p2++; }
254 push(@out,".align\t$val\n");
258 { my($dst,$sym,$base,$reflabel)=@_;
260 if ($::pic && ($::elf || $::aout))
261 { if (!defined($base))
262 { &::call(&::label("PIC_me_up"));
263 &::set_label("PIC_me_up");
265 &::add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-".
266 &::label("PIC_me_up") . "]");
269 { &::lea($dst,&::DWP("${under}_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
272 &::mov($dst,&::DWP($under.$sym."\@GOT",$dst));
275 { &::lea($dst,&::DWP($sym)); }
292 { $tmp=<<___; # applies to both Cygwin and Mingw
298 { $ctor="${under}_GLOBAL_\$I\$$f";
300 $tmp.=".type $ctor,\@function\n" if ($::pic);
301 $tmp.=<<___; # OpenBSD way...
308 push(@out,$tmp) if ($tmp);