1 | #! /usr/bin/env perl
|
---|
2 | # Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | #
|
---|
4 | # Licensed under the OpenSSL license (the "License"). You may not use
|
---|
5 | # this file except in compliance with the License. You can obtain a copy
|
---|
6 | # in the file LICENSE in the source distribution or at
|
---|
7 | # https://www.openssl.org/source/license.html
|
---|
8 |
|
---|
9 |
|
---|
10 | # require 'x86asm.pl';
|
---|
11 | # &asm_init(<flavor>[,$i386only]);
|
---|
12 | # &function_begin("foo");
|
---|
13 | # ...
|
---|
14 | # &function_end("foo");
|
---|
15 | # &asm_finish
|
---|
16 |
|
---|
17 | $out=();
|
---|
18 | $i386=0;
|
---|
19 |
|
---|
20 | # AUTOLOAD is this context has quite unpleasant side effect, namely
|
---|
21 | # that typos in function calls effectively go to assembler output,
|
---|
22 | # but on the pros side we don't have to implement one subroutine per
|
---|
23 | # each opcode...
|
---|
24 | sub ::AUTOLOAD
|
---|
25 | { my $opcode = $AUTOLOAD;
|
---|
26 |
|
---|
27 | die "more than 4 arguments passed to $opcode" if ($#_>3);
|
---|
28 |
|
---|
29 | $opcode =~ s/.*:://;
|
---|
30 | if ($opcode =~ /^push/) { $stack+=4; }
|
---|
31 | elsif ($opcode =~ /^pop/) { $stack-=4; }
|
---|
32 |
|
---|
33 | &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD";
|
---|
34 | }
|
---|
35 |
|
---|
36 | sub ::emit
|
---|
37 | { my $opcode=shift;
|
---|
38 |
|
---|
39 | if ($#_==-1) { push(@out,"\t$opcode\n"); }
|
---|
40 | else { push(@out,"\t$opcode\t".join(',',@_)."\n"); }
|
---|
41 | }
|
---|
42 |
|
---|
43 | sub ::LB
|
---|
44 | { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'";
|
---|
45 | $1."l";
|
---|
46 | }
|
---|
47 | sub ::HB
|
---|
48 | { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'";
|
---|
49 | $1."h";
|
---|
50 | }
|
---|
51 | sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); }
|
---|
52 | sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); }
|
---|
53 | sub ::blindpop { &pop($_[0]); $stack+=4; }
|
---|
54 | sub ::wparam { &DWP($stack+4*$_[0],"esp"); }
|
---|
55 | sub ::swtmp { &DWP(4*$_[0],"esp"); }
|
---|
56 |
|
---|
57 | sub ::bswap
|
---|
58 | { if ($i386) # emulate bswap for i386
|
---|
59 | { &comment("bswap @_");
|
---|
60 | &xchg(&HB(@_),&LB(@_));
|
---|
61 | &ror (@_,16);
|
---|
62 | &xchg(&HB(@_),&LB(@_));
|
---|
63 | }
|
---|
64 | else
|
---|
65 | { &generic("bswap",@_); }
|
---|
66 | }
|
---|
67 | # These are made-up opcodes introduced over the years essentially
|
---|
68 | # by ignorance, just alias them to real ones...
|
---|
69 | sub ::movb { &mov(@_); }
|
---|
70 | sub ::xorb { &xor(@_); }
|
---|
71 | sub ::rotl { &rol(@_); }
|
---|
72 | sub ::rotr { &ror(@_); }
|
---|
73 | sub ::exch { &xchg(@_); }
|
---|
74 | sub ::halt { &hlt; }
|
---|
75 | sub ::movz { &movzx(@_); }
|
---|
76 | sub ::pushf { &pushfd; }
|
---|
77 | sub ::popf { &popfd; }
|
---|
78 |
|
---|
79 | # 3 argument instructions
|
---|
80 | sub ::movq
|
---|
81 | { my($p1,$p2,$optimize)=@_;
|
---|
82 |
|
---|
83 | if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
|
---|
84 | # movq between mmx registers can sink Intel CPUs
|
---|
85 | { &::pshufw($p1,$p2,0xe4); }
|
---|
86 | else
|
---|
87 | { &::generic("movq",@_); }
|
---|
88 | }
|
---|
89 |
|
---|
90 | # SSE>2 instructions
|
---|
91 | my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3,
|
---|
92 | "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 );
|
---|
93 | sub ::pextrd
|
---|
94 | { my($dst,$src,$imm)=@_;
|
---|
95 | if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/)
|
---|
96 | { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); }
|
---|
97 | else
|
---|
98 | { &::generic("pextrd",@_); }
|
---|
99 | }
|
---|
100 |
|
---|
101 | sub ::pinsrd
|
---|
102 | { my($dst,$src,$imm)=@_;
|
---|
103 | if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/)
|
---|
104 | { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); }
|
---|
105 | else
|
---|
106 | { &::generic("pinsrd",@_); }
|
---|
107 | }
|
---|
108 |
|
---|
109 | sub ::pshufb
|
---|
110 | { my($dst,$src)=@_;
|
---|
111 | if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
---|
112 | { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); }
|
---|
113 | else
|
---|
114 | { &::generic("pshufb",@_); }
|
---|
115 | }
|
---|
116 |
|
---|
117 | sub ::palignr
|
---|
118 | { my($dst,$src,$imm)=@_;
|
---|
119 | if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
---|
120 | { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); }
|
---|
121 | else
|
---|
122 | { &::generic("palignr",@_); }
|
---|
123 | }
|
---|
124 |
|
---|
125 | sub ::pclmulqdq
|
---|
126 | { my($dst,$src,$imm)=@_;
|
---|
127 | if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
|
---|
128 | { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); }
|
---|
129 | else
|
---|
130 | { &::generic("pclmulqdq",@_); }
|
---|
131 | }
|
---|
132 |
|
---|
133 | sub ::rdrand
|
---|
134 | { my ($dst)=@_;
|
---|
135 | if ($dst =~ /(e[a-dsd][ixp])/)
|
---|
136 | { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); }
|
---|
137 | else
|
---|
138 | { &::generic("rdrand",@_); }
|
---|
139 | }
|
---|
140 |
|
---|
141 | sub ::rdseed
|
---|
142 | { my ($dst)=@_;
|
---|
143 | if ($dst =~ /(e[a-dsd][ixp])/)
|
---|
144 | { &::data_byte(0x0f,0xc7,0xf8|$regrm{$dst}); }
|
---|
145 | else
|
---|
146 | { &::generic("rdrand",@_); }
|
---|
147 | }
|
---|
148 |
|
---|
149 | sub rxb {
|
---|
150 | local *opcode=shift;
|
---|
151 | my ($dst,$src1,$src2,$rxb)=@_;
|
---|
152 |
|
---|
153 | $rxb|=0x7<<5;
|
---|
154 | $rxb&=~(0x04<<5) if($dst>=8);
|
---|
155 | $rxb&=~(0x01<<5) if($src1>=8);
|
---|
156 | $rxb&=~(0x02<<5) if($src2>=8);
|
---|
157 | push @opcode,$rxb;
|
---|
158 | }
|
---|
159 |
|
---|
160 | sub ::vprotd
|
---|
161 | { my $args=join(',',@_);
|
---|
162 | if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/)
|
---|
163 | { my @opcode=(0x8f);
|
---|
164 | rxb(\@opcode,$1,$2,-1,0x08);
|
---|
165 | push @opcode,0x78,0xc2;
|
---|
166 | push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M
|
---|
167 | my $c=$3;
|
---|
168 | push @opcode,$c=~/^0/?oct($c):$c;
|
---|
169 | &::data_byte(@opcode);
|
---|
170 | }
|
---|
171 | else
|
---|
172 | { &::generic("vprotd",@_); }
|
---|
173 | }
|
---|
174 |
|
---|
175 | sub ::endbranch
|
---|
176 | {
|
---|
177 | &::data_byte(0xf3,0x0f,0x1e,0xfb);
|
---|
178 | }
|
---|
179 |
|
---|
180 | # label management
|
---|
181 | $lbdecor="L"; # local label decoration, set by package
|
---|
182 | $label="000";
|
---|
183 |
|
---|
184 | sub ::islabel # see is argument is a known label
|
---|
185 | { my $i;
|
---|
186 | foreach $i (values %label) { return $i if ($i eq $_[0]); }
|
---|
187 | $label{$_[0]}; # can be undef
|
---|
188 | }
|
---|
189 |
|
---|
190 | sub ::label # instantiate a function-scope label
|
---|
191 | { if (!defined($label{$_[0]}))
|
---|
192 | { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; }
|
---|
193 | $label{$_[0]};
|
---|
194 | }
|
---|
195 |
|
---|
196 | sub ::LABEL # instantiate a file-scope label
|
---|
197 | { $label{$_[0]}=$_[1] if (!defined($label{$_[0]}));
|
---|
198 | $label{$_[0]};
|
---|
199 | }
|
---|
200 |
|
---|
201 | sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); }
|
---|
202 |
|
---|
203 | sub ::set_label_B { push(@out,"@_:\n"); }
|
---|
204 | sub ::set_label
|
---|
205 | { my $label=&::label($_[0]);
|
---|
206 | &::align($_[1]) if ($_[1]>1);
|
---|
207 | &::set_label_B($label);
|
---|
208 | $label;
|
---|
209 | }
|
---|
210 |
|
---|
211 | sub ::wipe_labels # wipes function-scope labels
|
---|
212 | { foreach $i (keys %label)
|
---|
213 | { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); }
|
---|
214 | }
|
---|
215 |
|
---|
216 | # subroutine management
|
---|
217 | sub ::function_begin
|
---|
218 | { &function_begin_B(@_);
|
---|
219 | $stack=4;
|
---|
220 | &push("ebp");
|
---|
221 | &push("ebx");
|
---|
222 | &push("esi");
|
---|
223 | &push("edi");
|
---|
224 | }
|
---|
225 |
|
---|
226 | sub ::function_end
|
---|
227 | { &pop("edi");
|
---|
228 | &pop("esi");
|
---|
229 | &pop("ebx");
|
---|
230 | &pop("ebp");
|
---|
231 | &ret();
|
---|
232 | &function_end_B(@_);
|
---|
233 | $stack=0;
|
---|
234 | &wipe_labels();
|
---|
235 | }
|
---|
236 |
|
---|
237 | sub ::function_end_A
|
---|
238 | { &pop("edi");
|
---|
239 | &pop("esi");
|
---|
240 | &pop("ebx");
|
---|
241 | &pop("ebp");
|
---|
242 | &ret();
|
---|
243 | $stack+=16; # readjust esp as if we didn't pop anything
|
---|
244 | }
|
---|
245 |
|
---|
246 | sub ::asciz
|
---|
247 | { my @str=unpack("C*",shift);
|
---|
248 | push @str,0;
|
---|
249 | while ($#str>15) {
|
---|
250 | &data_byte(@str[0..15]);
|
---|
251 | foreach (0..15) { shift @str; }
|
---|
252 | }
|
---|
253 | &data_byte(@str) if (@str);
|
---|
254 | }
|
---|
255 |
|
---|
256 | sub ::asm_finish
|
---|
257 | { &file_end();
|
---|
258 | print @out;
|
---|
259 | }
|
---|
260 |
|
---|
261 | sub ::asm_init
|
---|
262 | { my ($type,$cpu)=@_;
|
---|
263 |
|
---|
264 | $i386=$cpu;
|
---|
265 |
|
---|
266 | $elf=$cpp=$coff=$aout=$macosx=$win32=$mwerks=$android=0;
|
---|
267 | if (($type eq "elf"))
|
---|
268 | { $elf=1; require "x86gas.pl"; }
|
---|
269 | elsif (($type eq "elf-1"))
|
---|
270 | { $elf=-1; require "x86gas.pl"; }
|
---|
271 | elsif (($type eq "a\.out"))
|
---|
272 | { $aout=1; require "x86gas.pl"; }
|
---|
273 | elsif (($type eq "coff" or $type eq "gaswin"))
|
---|
274 | { $coff=1; require "x86gas.pl"; }
|
---|
275 | elsif (($type eq "win32n"))
|
---|
276 | { $win32=1; require "x86nasm.pl"; }
|
---|
277 | elsif (($type eq "win32"))
|
---|
278 | { $win32=1; require "x86masm.pl"; }
|
---|
279 | elsif (($type eq "macosx"))
|
---|
280 | { $aout=1; $macosx=1; require "x86gas.pl"; }
|
---|
281 | elsif (($type eq "android"))
|
---|
282 | { $elf=1; $android=1; require "x86gas.pl"; }
|
---|
283 | else
|
---|
284 | { print STDERR <<"EOF";
|
---|
285 | Pick one target type from
|
---|
286 | elf - Linux, FreeBSD, Solaris x86, etc.
|
---|
287 | a.out - DJGPP, elder OpenBSD, etc.
|
---|
288 | coff - GAS/COFF such as Win32 targets
|
---|
289 | win32n - Windows 95/Windows NT NASM format
|
---|
290 | macosx - Mac OS X
|
---|
291 | EOF
|
---|
292 | exit(1);
|
---|
293 | }
|
---|
294 |
|
---|
295 | $pic=0;
|
---|
296 | for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); }
|
---|
297 |
|
---|
298 | &file();
|
---|
299 | }
|
---|
300 |
|
---|
301 | sub ::hidden {}
|
---|
302 |
|
---|
303 | 1;
|
---|