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