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