1#!/usr/local/bin/perl
2
3package x86ms;
4
5$label="L000";
6
7%lb=(	'eax',	'al',
8	'ebx',	'bl',
9	'ecx',	'cl',
10	'edx',	'dl',
11	'ax',	'al',
12	'bx',	'bl',
13	'cx',	'cl',
14	'dx',	'dl',
15	);
16
17%hb=(	'eax',	'ah',
18	'ebx',	'bh',
19	'ecx',	'ch',
20	'edx',	'dh',
21	'ax',	'ah',
22	'bx',	'bh',
23	'cx',	'ch',
24	'dx',	'dh',
25	);
26
27sub main'asm_init_output { @out=(); }
28sub main'asm_get_output { return(@out); }
29sub main'get_labels { return(@labels); }
30sub main'external_label { push(@labels,@_); }
31
32sub main'LB
33	{
34	(defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
35	return($lb{$_[0]});
36	}
37
38sub main'HB
39	{
40	(defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
41	return($hb{$_[0]});
42	}
43
44sub main'BP
45	{
46	&get_mem("BYTE",@_);
47	}
48
49sub main'DWP
50	{
51	&get_mem("DWORD",@_);
52	}
53
54sub main'QWP
55	{
56	&get_mem("QWORD",@_);
57	}
58
59sub main'BC
60	{
61	return @_;
62	}
63
64sub main'DWC
65	{
66	return @_;
67	}
68
69sub main'stack_push
70	{
71	local($num)=@_;
72	$stack+=$num*4;
73	&main'sub("esp",$num*4);
74	}
75
76sub main'stack_pop
77	{
78	local($num)=@_;
79	$stack-=$num*4;
80	&main'add("esp",$num*4);
81	}
82
83sub get_mem
84	{
85	local($size,$addr,$reg1,$reg2,$idx)=@_;
86	local($t,$post);
87	local($ret)="$size PTR ";
88
89	$addr =~ s/^\s+//;
90	if ($addr =~ /^(.+)\+(.+)$/)
91		{
92		$reg2=&conv($1);
93		$addr="_$2";
94		}
95	elsif ($addr =~ /^[_a-z][_a-z0-9]*$/i)
96		{
97		$addr="_$addr";
98		}
99
100	if ($addr =~ /^.+\-.+$/) { $addr="($addr)"; }
101
102	$reg1="$regs{$reg1}" if defined($regs{$reg1});
103	$reg2="$regs{$reg2}" if defined($regs{$reg2});
104	if (($addr ne "") && ($addr ne 0))
105		{
106		if ($addr !~ /^-/)
107			{ $ret.=$addr; }
108		else	{ $post=$addr; }
109		}
110	if ($reg2 ne "")
111		{
112		$t="";
113		$t="*$idx" if ($idx != 0);
114		$reg1="+".$reg1 if ("$reg1$post" ne "");
115		$ret.="[$reg2$t$reg1$post]";
116		}
117	else
118		{
119		$ret.="[$reg1$post]"
120		}
121	$ret =~ s/\[\]//;	# in case $addr was the only argument
122	return($ret);
123	}
124
125sub main'mov	{ &out2("mov",@_); }
126sub main'movb	{ &out2("mov",@_); }
127sub main'and	{ &out2("and",@_); }
128sub main'or	{ &out2("or",@_); }
129sub main'shl	{ &out2("shl",@_); }
130sub main'shr	{ &out2("shr",@_); }
131sub main'xor	{ &out2("xor",@_); }
132sub main'xorb	{ &out2("xor",@_); }
133sub main'add	{ &out2("add",@_); }
134sub main'adc	{ &out2("adc",@_); }
135sub main'sub	{ &out2("sub",@_); }
136sub main'sbb	{ &out2("sbb",@_); }
137sub main'rotl	{ &out2("rol",@_); }
138sub main'rotr	{ &out2("ror",@_); }
139sub main'exch	{ &out2("xchg",@_); }
140sub main'cmp	{ &out2("cmp",@_); }
141sub main'lea	{ &out2("lea",@_); }
142sub main'mul	{ &out1("mul",@_); }
143sub main'div	{ &out1("div",@_); }
144sub main'dec	{ &out1("dec",@_); }
145sub main'inc	{ &out1("inc",@_); }
146sub main'jmp	{ &out1("jmp",@_); }
147sub main'jmp_ptr { &out1p("jmp",@_); }
148sub main'je	{ &out1("je",@_); }
149sub main'jle	{ &out1("jle",@_); }
150sub main'jz	{ &out1("jz",@_); }
151sub main'jge	{ &out1("jge",@_); }
152sub main'jl	{ &out1("jl",@_); }
153sub main'ja	{ &out1("ja",@_); }
154sub main'jae	{ &out1("jae",@_); }
155sub main'jb	{ &out1("jb",@_); }
156sub main'jbe	{ &out1("jbe",@_); }
157sub main'jc	{ &out1("jc",@_); }
158sub main'jnc	{ &out1("jnc",@_); }
159sub main'jnz	{ &out1("jnz",@_); }
160sub main'jne	{ &out1("jne",@_); }
161sub main'jno	{ &out1("jno",@_); }
162sub main'push	{ &out1("push",@_); $stack+=4; }
163sub main'pop	{ &out1("pop",@_); $stack-=4; }
164sub main'pushf	{ &out0("pushfd"); $stack+=4; }
165sub main'popf	{ &out0("popfd"); $stack-=4; }
166sub main'bswap	{ &out1("bswap",@_); &using486(); }
167sub main'not	{ &out1("not",@_); }
168sub main'call	{ &out1("call",($_[0]=~/^\$L/?'':'_').$_[0]); }
169sub main'ret	{ &out0("ret"); }
170sub main'nop	{ &out0("nop"); }
171sub main'test	{ &out2("test",@_); }
172sub main'bt	{ &out2("bt",@_); }
173sub main'leave	{ &out0("leave"); }
174sub main'cpuid  { &out0("DW\t0A20Fh"); }
175sub main'rdtsc  { &out0("DW\t0310Fh"); }
176sub main'halt	{ &out0("hlt"); }
177sub main'movz	{ &out2("movzx",@_); }
178sub main'neg	{ &out1("neg",@_); }
179sub main'cld	{ &out0("cld"); }
180
181# SSE2
182sub main'emms	{ &out0("emms"); }
183sub main'movd	{ &out2("movd",@_); }
184sub main'movq	{ &out2("movq",@_); }
185sub main'movdqu	{ &out2("movdqu",@_); }
186sub main'movdqa	{ &out2("movdqa",@_); }
187sub main'movdq2q{ &out2("movdq2q",@_); }
188sub main'movq2dq{ &out2("movq2dq",@_); }
189sub main'paddq	{ &out2("paddq",@_); }
190sub main'pmuludq{ &out2("pmuludq",@_); }
191sub main'psrlq	{ &out2("psrlq",@_); }
192sub main'psllq	{ &out2("psllq",@_); }
193sub main'pxor	{ &out2("pxor",@_); }
194sub main'por	{ &out2("por",@_); }
195sub main'pand	{ &out2("pand",@_); }
196
197sub out2
198	{
199	local($name,$p1,$p2)=@_;
200	local($l,$t);
201
202	push(@out,"\t$name\t");
203	$t=&conv($p1).",";
204	$l=length($t);
205	push(@out,$t);
206	$l=4-($l+9)/8;
207	push(@out,"\t" x $l);
208	push(@out,&conv($p2));
209	push(@out,"\n");
210	}
211
212sub out0
213	{
214	local($name)=@_;
215
216	push(@out,"\t$name\n");
217	}
218
219sub out1
220	{
221	local($name,$p1)=@_;
222	local($l,$t);
223
224	push(@out,"\t$name\t".&conv($p1)."\n");
225	}
226
227sub conv
228	{
229	local($p)=@_;
230
231	$p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
232	return $p;
233	}
234
235sub using486
236	{
237	return if $using486;
238	$using486++;
239	grep(s/\.386/\.486/,@out);
240	}
241
242sub main'file
243	{
244	local($file)=@_;
245
246	local($tmp)=<<"EOF";
247	TITLE	$file.asm
248        .386
249.model FLAT
250EOF
251	push(@out,$tmp);
252	}
253
254sub main'function_begin
255	{
256	local($func,$extra)=@_;
257
258	push(@labels,$func);
259
260	local($tmp)=<<"EOF";
261_TEXT\$	SEGMENT PAGE 'CODE'
262PUBLIC	_$func
263$extra
264_$func PROC NEAR
265	push	ebp
266	push	ebx
267	push	esi
268	push	edi
269EOF
270	push(@out,$tmp);
271	$stack=20;
272	}
273
274sub main'function_begin_B
275	{
276	local($func,$extra)=@_;
277
278	local($tmp)=<<"EOF";
279_TEXT\$	SEGMENT	PAGE 'CODE'
280PUBLIC	_$func
281$extra
282_$func PROC NEAR
283EOF
284	push(@out,$tmp);
285	$stack=4;
286	}
287
288sub main'function_end
289	{
290	local($func)=@_;
291
292	local($tmp)=<<"EOF";
293	pop	edi
294	pop	esi
295	pop	ebx
296	pop	ebp
297	ret
298_$func ENDP
299_TEXT\$	ENDS
300EOF
301	push(@out,$tmp);
302	$stack=0;
303	%label=();
304	}
305
306sub main'function_end_B
307	{
308	local($func)=@_;
309
310	local($tmp)=<<"EOF";
311_$func ENDP
312_TEXT\$	ENDS
313EOF
314	push(@out,$tmp);
315	$stack=0;
316	%label=();
317	}
318
319sub main'function_end_A
320	{
321	local($func)=@_;
322
323	local($tmp)=<<"EOF";
324	pop	edi
325	pop	esi
326	pop	ebx
327	pop	ebp
328	ret
329EOF
330	push(@out,$tmp);
331	}
332
333sub main'file_end
334	{
335	# try to detect if SSE2 or MMX extensions were used...
336	if (grep {/xmm[0-7]\s*,/i} @out) {
337		grep {s/\.[3-7]86/\.686\n\t\.XMM/} @out;
338		}
339	elsif (grep {/mm[0-7]\s*,/i} @out) {
340		grep {s/\.[3-7]86/\.686\n\t\.MMX/} @out;
341		}
342	push(@out,"END\n");
343	}
344
345sub main'wparam
346	{
347	local($num)=@_;
348
349	return(&main'DWP($stack+$num*4,"esp","",0));
350	}
351
352sub main'swtmp
353	{
354	return(&main'DWP($_[0]*4,"esp","",0));
355	}
356
357# Should use swtmp, which is above esp.  Linix can trash the stack above esp
358#sub main'wtmp
359#	{
360#	local($num)=@_;
361#
362#	return(&main'DWP(-(($num+1)*4),"esp","",0));
363#	}
364
365sub main'comment
366	{
367	foreach (@_)
368		{
369		push(@out,"\t; $_\n");
370		}
371	}
372
373sub main'public_label
374	{
375	$label{$_[0]}="_$_[0]"	if (!defined($label{$_[0]}));
376	push(@out,"PUBLIC\t$label{$_[0]}\n");
377	}
378
379sub main'label
380	{
381	if (!defined($label{$_[0]}))
382		{
383		$label{$_[0]}="\$${label}${_[0]}";
384		$label++;
385		}
386	return($label{$_[0]});
387	}
388
389sub main'set_label
390	{
391	if (!defined($label{$_[0]}))
392		{
393		$label{$_[0]}="\$${label}${_[0]}";
394		$label++;
395		}
396	if ($_[1]!=0 && $_[1]>1)
397		{
398		main'align($_[1]);
399		}
400	if((defined $_[2]) && ($_[2] == 1))
401		{
402		push(@out,"$label{$_[0]}::\n");
403		}
404	elsif ($label{$_[0]} !~ /^\$/)
405		{
406		push(@out,"$label{$_[0]}\tLABEL PTR\n");
407		}
408	else
409		{
410		push(@out,"$label{$_[0]}:\n");
411		}
412	}
413
414sub main'data_word
415	{
416	push(@out,"\tDD\t".join(',',@_)."\n");
417	}
418
419sub main'align
420	{
421	push(@out,"\tALIGN\t$_[0]\n");
422	}
423
424sub out1p
425	{
426	local($name,$p1)=@_;
427	local($l,$t);
428
429	push(@out,"\t$name\t ".&conv($p1)."\n");
430	}
431
432sub main'picmeup
433	{
434	local($dst,$sym)=@_;
435	&main'lea($dst,&main'DWP($sym));
436	}
437
438sub main'blindpop { &out1("pop",@_); }
439
440sub main'initseg
441	{
442	local($f)=@_;
443	local($tmp)=<<___;
444OPTION	DOTNAME
445.CRT\$XIU	SEGMENT DWORD PUBLIC 'DATA'
446EXTRN	_$f:NEAR
447DD	_$f
448.CRT\$XIU	ENDS
449___
450	push(@out,$tmp);
451	}
452
4531;
454