1480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#!/usr/bin/env perl
2480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
3480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgpackage x86masm;
4480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
5480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org*out=\@::out;
6480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
7480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$::lbdecor="\$L";	# local label decoration
8480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$nmdecor="_";		# external name decoration
9480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
10480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$initseg="";
11480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$segment="";
12480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
13480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::generic
14480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my ($opcode,@arg)=@_;
15480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
16480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # fix hexadecimal constants
172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
18480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/)	# no []
202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    {	$opcode="mov";	}
212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    elsif ($opcode !~ /movq/)
22480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	# fix xmm references
23480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[1]=~/\bxmm[0-7]\b/i);
24480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$arg[1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i);
25480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
26480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
27480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &::emit($opcode,@arg);
28480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org  1;
29480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
30480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
31480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# opcodes not covered by ::generic above, mostly inconsistent namings...
32480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
33480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
34480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::call_ptr	{ &::emit("call",@_);	}
35480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::jmp_ptr	{ &::emit("jmp",@_);	}
367453c6c0666947e06d87565404f4397a4b387f91digit@chromium.orgsub ::lock	{ &::data_byte(0xf0);	}
37480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
38480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub get_mem
39480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my($size,$addr,$reg1,$reg2,$idx)=@_;
40480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org  my($post,$ret);
41480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
42480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $ret .= "$size PTR " if ($size ne "");
43480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
44480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $addr =~ s/^\s+//;
45480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # prepend global references with optional underscore
46480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
47480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # put address arithmetic expression in parenthesis
48480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
49480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
50480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if (($addr ne "") && ($addr ne 0))
51480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	if ($addr !~ /^-/)	{ $ret .= "$addr";  }
52480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	else			{ $post=$addr;      }
53480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
54480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $ret .= "[";
55480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
56480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if ($reg2 ne "")
57480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	$idx!=0 or $idx=1;
58480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$ret .= "$reg2*$idx";
59480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$ret .= "+$reg1" if ($reg1 ne "");
60480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
61480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    else
62480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	$ret .= "$reg1";   }
63480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
64480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $ret .= "$post]";
65480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $ret =~ s/\+\]/]/; # in case $addr was the only argument
66480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $ret =~ s/\[\s*\]//;
67480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
68480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org  $ret;
69480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
70480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::BP	{ &get_mem("BYTE",@_);  }
712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::WP	{ &get_mem("WORD",@_);	}
72480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::DWP	{ &get_mem("DWORD",@_); }
73480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::QWP	{ &get_mem("QWORD",@_); }
74480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::BC	{ "@_";  }
75480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::DWC	{ "@_"; }
76480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
77480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::file
78480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $tmp=<<___;
79480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgTITLE	$_[0].asm
80480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800
81480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgECHO MASM version 8.00 or later is strongly recommended.
82480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF
83480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.486
84480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.MODEL	FLAT
85480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgOPTION	DOTNAME
86480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800
87480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.text\$	SEGMENT PAGE 'CODE'
88480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgELSE
89480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.text\$	SEGMENT ALIGN(64) 'CODE'
90480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF
91480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
92480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push(@out,$tmp);
93480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $segment = ".text\$";
94480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
95480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
96480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::function_begin_B
97480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $func=shift;
98480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org  my $global=($func !~ /^_/);
99480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org  my $begin="${::lbdecor}_${func}_begin";
100480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
101480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &::LABEL($func,$global?"$begin":"$nmdecor$func");
102480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
103480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
104480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if ($global)    { $func.=" PUBLIC\n${begin}::\n"; }
105480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    else	    { $func.=" PRIVATE\n";            }
106480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push(@out,$func);
107480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $::stack=4;
108480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
109480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::function_end_B
110480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $func=shift;
111480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
112480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push(@out,"$nmdecor$func ENDP\n");
113480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $::stack=0;
114480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &::wipe_labels();
115480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
116480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
117480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::file_end
118480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $xmmheader=<<___;
119480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.686
120480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.XMM
121480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800
122480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgXMMWORD STRUCT 16
123480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgDQ	2 dup (?)
124480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgXMMWORD	ENDS
125480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF
126480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
127480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if (grep {/\b[x]?mm[0-7]\b/i} @out) {
128480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	grep {s/\.[3-7]86/$xmmheader/} @out;
129480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
130480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
131480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push(@out,"$segment	ENDS\n");
132480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
133480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
134480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	my $comm=<<___;
135480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.bss	SEGMENT 'BSS'
1362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgCOMM	${nmdecor}OPENSSL_ia32cap_P:QWORD
137480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.bss	ENDS
138480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
139480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	# comment out OPENSSL_ia32cap_P declarations
140480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
141480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	push (@out,$comm);
142480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
143480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push (@out,$initseg) if ($initseg);
144480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    push (@out,"END\n");
145480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
146480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
147480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::comment {   foreach (@_) { push(@out,"\t; $_\n"); }   }
148480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
149480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org*::set_label_B = sub
150480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };
151480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
152480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::external_label
153480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   foreach(@_)
154480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    {	push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n");   }
155480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
156480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
157480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::public_label
158480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }
159480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
160480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::data_byte
161480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   push(@out,("DB\t").join(',',@_)."\n");	}
162480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
1632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::data_short
1642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{   push(@out,("DW\t").join(',',@_)."\n");	}
1652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
166480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::data_word
167480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   push(@out,("DD\t").join(',',@_)."\n");	}
168480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
169480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::align
170480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   push(@out,"ALIGN\t$_[0]\n");	}
171480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
172480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::picmeup
173480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my($dst,$sym)=@_;
174480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &::lea($dst,&::DWP($sym));
175480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
176480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
177480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::initseg
178480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $f=$nmdecor.shift;
179480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
180480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $initseg.=<<___;
181480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.CRT\$XCU	SEGMENT DWORD PUBLIC 'DATA'
182480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgEXTERN	$f:NEAR
183480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgDD	$f
184480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.CRT\$XCU	ENDS
185480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
186480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
187480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
188480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::dataseg
189480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{   push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA";   }
190480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
1912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::safeseh
1922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{ my $nm=shift;
1932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    push(@out,"IF \@Version GE 710\n");
1942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    push(@out,".SAFESEH	".&::LABEL($nm,$nmdecor.$nm)."\n");
1952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    push(@out,"ENDIF\n");
1962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
1972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
198480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org1;
199