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 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 "$under$_[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 "$under$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)=@_;
122 &::external_label($func);
125 push(@out,".text\n.globl\t$func\n");
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");
141 push(@out,"${dot}L_${func}_end:\n");
143 { push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); }
150 if (!defined($com_start) or $::elf)
151 { # Regarding $::elf above...
152 # GNU and SVR4 as'es use different comment delimiters,
153 push(@out,"\n"); # so we just skip ELF comments...
161 { push(@out,"\t$com_start $_ $com_end\n"); }
165 sub islabel # see is argument is a known label
167 foreach $i (%label) { return $label{$i} if ($label{$i} eq $_[0]); }
171 sub ::external_label { push(@labels,@_); }
174 { $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]}));
175 push(@out,".globl\t$label{$_[0]}\n");
179 { if (!defined($label{$_[0]}))
180 { $label{$_[0]}="${dot}${label}${_[0]}"; $label++; }
185 { my $label=&::label($_[0]);
186 &::align($_[1]) if ($_[1]>1);
187 push(@out,"$label:\n");
191 { # try to detect if SSE2 or MMX extensions were used on ELF platform...
192 if ($::elf && grep {/%[x]?mm[0-7]/i} @out){
195 push (@out,"\n.section\t.bss\n");
196 push (@out,".comm\t${under}OPENSSL_ia32cap_P,4,4\n");
198 push (@out,".section\t.init\n");
199 # One can argue that it's wasteful to craft every
200 # SSE/MMX module with this snippet... Well, it's 72
201 # bytes long and for the moment we have two modules.
202 # Let's argue when we have 7 modules or so...
204 # $1<<10 sets a reserved bit to signal that variable
205 # was initialized already...
206 &::picmeup("edx","OPENSSL_ia32cap_P");
239 { push(@out,".section .rodata\n");
245 sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
246 sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
249 { my $val=$_[0],$p2,$i;
251 { for ($p2=0;$val!=0;$val>>=1) { $p2++; }
255 push(@out,".align\t$val\n");
259 { my($dst,$sym,$base,$reflabel)=@_;
261 if ($::pic && ($::elf || $::aout))
262 { if (!defined($base))
263 { &::call(&::label("PIC_me_up"));
264 &::set_label("PIC_me_up");
266 &::add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-".
267 &::label("PIC_me_up") . "]");
270 { &::lea($dst,&::DWP("${under}_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
273 &::mov($dst,&::DWP($under.$sym."\@GOT",$dst));
276 { &::lea($dst,&::DWP($sym)); }
293 { $tmp=<<___; # applies to both Cygwin and Mingw
299 { $ctor="${under}_GLOBAL_\$I\$$f";
301 $tmp.=".type $ctor,\@function\n" if ($::pic);
302 $tmp.=<<___; # OpenBSD way...
309 push(@out,$tmp) if ($tmp);