]>
Commit | Line | Data |
---|---|---|
e0a65194 RS |
1 | #! /usr/bin/env perl |
2 | # Copyright 2007-2016 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 | ||
43d8f27d AP |
9 | |
10 | package x86masm; | |
11 | ||
12 | *out=\@::out; | |
13 | ||
14 | $::lbdecor="\$L"; # local label decoration | |
15 | $nmdecor="_"; # external name decoration | |
16 | ||
17 | $initseg=""; | |
b94551e8 | 18 | $segment=""; |
43d8f27d AP |
19 | |
20 | sub ::generic | |
21 | { my ($opcode,@arg)=@_; | |
22 | ||
23 | # fix hexadecimal constants | |
d08eae1b | 24 | for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; } |
43d8f27d | 25 | |
ee743dca | 26 | if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/) # no [] |
0e1467a6 | 27 | { $opcode="mov"; } |
2f8d82d6 | 28 | elsif ($opcode !~ /mov[dq]$/) |
6c8b9259 | 29 | { # fix xmm references |
2f8d82d6 AP |
30 | $arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[-1]=~/\bxmm[0-7]\b/i); |
31 | $arg[-1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i); | |
6c8b9259 | 32 | } |
3a87756f | 33 | |
43d8f27d AP |
34 | &::emit($opcode,@arg); |
35 | 1; | |
36 | } | |
37 | # | |
38 | # opcodes not covered by ::generic above, mostly inconsistent namings... | |
39 | # | |
40 | sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); } | |
41 | sub ::call_ptr { &::emit("call",@_); } | |
42 | sub ::jmp_ptr { &::emit("jmp",@_); } | |
70d01a7f | 43 | sub ::lock { &::data_byte(0xf0); } |
43d8f27d AP |
44 | |
45 | sub get_mem | |
46 | { my($size,$addr,$reg1,$reg2,$idx)=@_; | |
47 | my($post,$ret); | |
48 | ||
c5cd28bd AP |
49 | if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; } |
50 | ||
43d8f27d AP |
51 | $ret .= "$size PTR " if ($size ne ""); |
52 | ||
53 | $addr =~ s/^\s+//; | |
54 | # prepend global references with optional underscore | |
55 | $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige; | |
56 | # put address arithmetic expression in parenthesis | |
57 | $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/); | |
58 | ||
59 | if (($addr ne "") && ($addr ne 0)) | |
60 | { if ($addr !~ /^-/) { $ret .= "$addr"; } | |
61 | else { $post=$addr; } | |
62 | } | |
63 | $ret .= "["; | |
64 | ||
65 | if ($reg2 ne "") | |
66 | { $idx!=0 or $idx=1; | |
67 | $ret .= "$reg2*$idx"; | |
68 | $ret .= "+$reg1" if ($reg1 ne ""); | |
69 | } | |
70 | else | |
71 | { $ret .= "$reg1"; } | |
72 | ||
73 | $ret .= "$post]"; | |
74 | $ret =~ s/\+\]/]/; # in case $addr was the only argument | |
75 | $ret =~ s/\[\s*\]//; | |
76 | ||
77 | $ret; | |
78 | } | |
79 | sub ::BP { &get_mem("BYTE",@_); } | |
d08eae1b | 80 | sub ::WP { &get_mem("WORD",@_); } |
43d8f27d AP |
81 | sub ::DWP { &get_mem("DWORD",@_); } |
82 | sub ::QWP { &get_mem("QWORD",@_); } | |
83 | sub ::BC { "@_"; } | |
84 | sub ::DWC { "@_"; } | |
85 | ||
86 | sub ::file | |
87 | { my $tmp=<<___; | |
88 | TITLE $_[0].asm | |
9960bdc6 AP |
89 | IF \@Version LT 800 |
90 | ECHO MASM version 8.00 or later is strongly recommended. | |
91 | ENDIF | |
43d8f27d AP |
92 | .486 |
93 | .MODEL FLAT | |
94 | OPTION DOTNAME | |
9960bdc6 | 95 | IF \@Version LT 800 |
e4662fdb | 96 | .text\$ SEGMENT PAGE 'CODE' |
9960bdc6 AP |
97 | ELSE |
98 | .text\$ SEGMENT ALIGN(64) 'CODE' | |
99 | ENDIF | |
43d8f27d AP |
100 | ___ |
101 | push(@out,$tmp); | |
b94551e8 | 102 | $segment = ".text\$"; |
43d8f27d AP |
103 | } |
104 | ||
105 | sub ::function_begin_B | |
106 | { my $func=shift; | |
107 | my $global=($func !~ /^_/); | |
108 | my $begin="${::lbdecor}_${func}_begin"; | |
109 | ||
110 | &::LABEL($func,$global?"$begin":"$nmdecor$func"); | |
e4662fdb | 111 | $func="ALIGN\t16\n".$nmdecor.$func."\tPROC"; |
43d8f27d AP |
112 | |
113 | if ($global) { $func.=" PUBLIC\n${begin}::\n"; } | |
114 | else { $func.=" PRIVATE\n"; } | |
115 | push(@out,$func); | |
116 | $::stack=4; | |
117 | } | |
118 | sub ::function_end_B | |
119 | { my $func=shift; | |
120 | ||
121 | push(@out,"$nmdecor$func ENDP\n"); | |
122 | $::stack=0; | |
123 | &::wipe_labels(); | |
124 | } | |
125 | ||
126 | sub ::file_end | |
127 | { my $xmmheader=<<___; | |
128 | .686 | |
129 | .XMM | |
130 | IF \@Version LT 800 | |
131 | XMMWORD STRUCT 16 | |
132 | DQ 2 dup (?) | |
133 | XMMWORD ENDS | |
134 | ENDIF | |
135 | ___ | |
136 | if (grep {/\b[x]?mm[0-7]\b/i} @out) { | |
137 | grep {s/\.[3-7]86/$xmmheader/} @out; | |
138 | } | |
139 | ||
b94551e8 | 140 | push(@out,"$segment ENDS\n"); |
43d8f27d AP |
141 | |
142 | if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) | |
143 | { my $comm=<<___; | |
55ff3aff | 144 | .bss SEGMENT 'BSS' |
c5cd28bd | 145 | COMM ${nmdecor}OPENSSL_ia32cap_P:DWORD:4 |
9960bdc6 | 146 | .bss ENDS |
43d8f27d AP |
147 | ___ |
148 | # comment out OPENSSL_ia32cap_P declarations | |
149 | grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out; | |
150 | push (@out,$comm); | |
151 | } | |
152 | push (@out,$initseg) if ($initseg); | |
153 | push (@out,"END\n"); | |
154 | } | |
155 | ||
156 | sub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } } | |
157 | ||
158 | *::set_label_B = sub | |
159 | { my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); }; | |
160 | ||
161 | sub ::external_label | |
3a87756f AP |
162 | { foreach(@_) |
163 | { push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n"); } | |
164 | } | |
43d8f27d AP |
165 | |
166 | sub ::public_label | |
167 | { push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); } | |
168 | ||
169 | sub ::data_byte | |
2f8d82d6 | 170 | { push(@out,("DB\t").join(',',splice(@_,0,16))."\n") while(@_); } |
43d8f27d | 171 | |
d08eae1b | 172 | sub ::data_short |
2f8d82d6 | 173 | { push(@out,("DW\t").join(',',splice(@_,0,8))."\n") while(@_); } |
d08eae1b | 174 | |
43d8f27d | 175 | sub ::data_word |
2f8d82d6 | 176 | { push(@out,("DD\t").join(',',splice(@_,0,4))."\n") while(@_); } |
43d8f27d AP |
177 | |
178 | sub ::align | |
179 | { push(@out,"ALIGN\t$_[0]\n"); } | |
180 | ||
181 | sub ::picmeup | |
182 | { my($dst,$sym)=@_; | |
183 | &::lea($dst,&::DWP($sym)); | |
184 | } | |
185 | ||
186 | sub ::initseg | |
187 | { my $f=$nmdecor.shift; | |
188 | ||
189 | $initseg.=<<___; | |
3a87756f | 190 | .CRT\$XCU SEGMENT DWORD PUBLIC 'DATA' |
43d8f27d AP |
191 | EXTERN $f:NEAR |
192 | DD $f | |
193 | .CRT\$XCU ENDS | |
194 | ___ | |
195 | } | |
196 | ||
b94551e8 AP |
197 | sub ::dataseg |
198 | { push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA"; } | |
199 | ||
ed28aef8 AP |
200 | sub ::safeseh |
201 | { my $nm=shift; | |
202 | push(@out,"IF \@Version GE 710\n"); | |
203 | push(@out,".SAFESEH ".&::LABEL($nm,$nmdecor.$nm)."\n"); | |
204 | push(@out,"ENDIF\n"); | |
205 | } | |
206 | ||
43d8f27d | 207 | 1; |