1#!/usr/local/bin/perl
2
3package x86unix;
4
5$label="L000";
6$const="";
7$constl=0;
8
9$align=($main'aout)?"4":"16";
10$under=($main'aout)?"_":"";
11$com_start=($main'sol)?"/":"#";
12
13sub main'asm_init_output { @out=(); }
14sub main'asm_get_output { return(@out); }
15sub main'get_labels { return(@labels); }
16sub main'external_label { push(@labels,@_); }
17
18if ($main'cpp)
19	{
20	$align="ALIGN";
21	$under="";
22	$com_start='/*';
23	$com_end='*/';
24	}
25
26%lb=(	'eax',	'%al',
27	'ebx',	'%bl',
28	'ecx',	'%cl',
29	'edx',	'%dl',
30	'ax',	'%al',
31	'bx',	'%bl',
32	'cx',	'%cl',
33	'dx',	'%dl',
34	);
35
36%hb=(	'eax',	'%ah',
37	'ebx',	'%bh',
38	'ecx',	'%ch',
39	'edx',	'%dh',
40	'ax',	'%ah',
41	'bx',	'%bh',
42	'cx',	'%ch',
43	'dx',	'%dh',
44	);
45
46%regs=(	'eax',	'%eax',
47	'ebx',	'%ebx',
48	'ecx',	'%ecx',
49	'edx',	'%edx',
50	'esi',	'%esi',
51	'edi',	'%edi',
52	'ebp',	'%ebp',
53	'esp',	'%esp',
54	);
55
56%reg_val=(
57	'eax',	0x00,
58	'ebx',	0x03,
59	'ecx',	0x01,
60	'edx',	0x02,
61	'esi',	0x06,
62	'edi',	0x07,
63	'ebp',	0x05,
64	'esp',	0x04,
65	);
66
67sub main'LB
68	{
69	(defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
70	return($lb{$_[0]});
71	}
72
73sub main'HB
74	{
75	(defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
76	return($hb{$_[0]});
77	}
78
79sub main'DWP
80	{
81	local($addr,$reg1,$reg2,$idx)=@_;
82
83	$ret="";
84	$addr =~ s/(^|[+ \t])([A-Za-z_]+[A-Za-z0-9_]+)($|[+ \t])/$1$under$2$3/;
85	$reg1="$regs{$reg1}" if defined($regs{$reg1});
86	$reg2="$regs{$reg2}" if defined($regs{$reg2});
87	$ret.=$addr if ($addr ne "") && ($addr ne 0);
88	if ($reg2 ne "")
89		{
90		if($idx ne "" && $idx != 0)
91		    { $ret.="($reg1,$reg2,$idx)"; }
92		else
93		    { $ret.="($reg1,$reg2)"; }
94	        }
95	elsif ($reg1 ne "")
96		{ $ret.="($reg1)" }
97	return($ret);
98	}
99
100sub main'BP
101	{
102	return(&main'DWP(@_));
103	}
104
105sub main'BC
106	{
107	return @_;
108	}
109
110sub main'DWC
111	{
112	return @_;
113	}
114
115#sub main'BP
116#	{
117#	local($addr,$reg1,$reg2,$idx)=@_;
118#
119#	$ret="";
120#
121#	$addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
122#	$reg1="$regs{$reg1}" if defined($regs{$reg1});
123#	$reg2="$regs{$reg2}" if defined($regs{$reg2});
124#	$ret.=$addr if ($addr ne "") && ($addr ne 0);
125#	if ($reg2 ne "")
126#		{ $ret.="($reg1,$reg2,$idx)"; }
127#	else
128#		{ $ret.="($reg1)" }
129#	return($ret);
130#	}
131
132sub main'mov	{ &out2("movl",@_); }
133sub main'movb	{ &out2("movb",@_); }
134sub main'and	{ &out2("andl",@_); }
135sub main'or	{ &out2("orl",@_); }
136sub main'shl	{ &out2("sall",@_); }
137sub main'shr	{ &out2("shrl",@_); }
138sub main'xor	{ &out2("xorl",@_); }
139sub main'xorb	{ &out2("xorb",@_); }
140sub main'add	{ &out2($_[0]=~/%[a-d][lh]/?"addb":"addl",@_); }
141sub main'adc	{ &out2("adcl",@_); }
142sub main'sub	{ &out2("subl",@_); }
143sub main'rotl	{ &out2("roll",@_); }
144sub main'rotr	{ &out2("rorl",@_); }
145sub main'exch	{ &out2($_[0]=~/%[a-d][lh]/?"xchgb":"xchgl",@_); }
146sub main'cmp	{ &out2("cmpl",@_); }
147sub main'lea	{ &out2("leal",@_); }
148sub main'mul	{ &out1("mull",@_); }
149sub main'div	{ &out1("divl",@_); }
150sub main'jmp	{ &out1("jmp",@_); }
151sub main'jmp_ptr { &out1p("jmp",@_); }
152sub main'je	{ &out1("je",@_); }
153sub main'jle	{ &out1("jle",@_); }
154sub main'jne	{ &out1("jne",@_); }
155sub main'jnz	{ &out1("jnz",@_); }
156sub main'jz	{ &out1("jz",@_); }
157sub main'jge	{ &out1("jge",@_); }
158sub main'jl	{ &out1("jl",@_); }
159sub main'ja	{ &out1("ja",@_); }
160sub main'jae	{ &out1("jae",@_); }
161sub main'jb	{ &out1("jb",@_); }
162sub main'jbe	{ &out1("jbe",@_); }
163sub main'jc	{ &out1("jc",@_); }
164sub main'jnc	{ &out1("jnc",@_); }
165sub main'jno	{ &out1("jno",@_); }
166sub main'dec	{ &out1("decl",@_); }
167sub main'inc	{ &out1($_[0]=~/%[a-d][hl]/?"incb":"incl",@_); }
168sub main'push	{ &out1("pushl",@_); $stack+=4; }
169sub main'pop	{ &out1("popl",@_); $stack-=4; }
170sub main'pushf	{ &out0("pushf"); $stack+=4; }
171sub main'popf	{ &out0("popf"); $stack-=4; }
172sub main'not	{ &out1("notl",@_); }
173sub main'call	{ &out1("call",($_[0]=~/^\.L/?'':$under).$_[0]); }
174sub main'ret	{ &out0("ret"); }
175sub main'nop	{ &out0("nop"); }
176sub main'movz	{ &out2("movzbl",@_); }
177
178# The bswapl instruction is new for the 486. Emulate if i386.
179sub main'bswap
180	{
181	if ($main'i386)
182		{
183		&main'comment("bswapl @_");
184		&main'exch(main'HB(@_),main'LB(@_));
185		&main'rotr(@_,16);
186		&main'exch(main'HB(@_),main'LB(@_));
187		}
188	else
189		{
190		&out1("bswapl",@_);
191		}
192	}
193
194sub out2
195	{
196	local($name,$p1,$p2)=@_;
197	local($l,$ll,$t);
198	local(%special)=(	"roll",0xD1C0,"rorl",0xD1C8,
199				"rcll",0xD1D0,"rcrl",0xD1D8,
200				"shll",0xD1E0,"shrl",0xD1E8,
201				"sarl",0xD1F8);
202
203	if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
204		{
205		$op=$special{$name}|$reg_val{$p1};
206		$tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
207		$tmp2=sprintf(".byte %d\t",$op     &0xff);
208		push(@out,$tmp1);
209		push(@out,$tmp2);
210
211		$p2=&conv($p2);
212		$p1=&conv($p1);
213		&main'comment("$name $p2 $p1");
214		return;
215		}
216
217	push(@out,"\t$name\t");
218	$t=&conv($p2).",";
219	$l=length($t);
220	push(@out,$t);
221	$ll=4-($l+9)/8;
222	$tmp1=sprintf("\t" x $ll);
223	push(@out,$tmp1);
224	push(@out,&conv($p1)."\n");
225	}
226
227sub out1
228	{
229	local($name,$p1)=@_;
230	local($l,$t);
231	local(%special)=("bswapl",0x0FC8);
232
233	if ((defined($special{$name})) && defined($regs{$p1}))
234		{
235		$op=$special{$name}|$reg_val{$p1};
236		$tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
237		$tmp2=sprintf(".byte %d\t",$op     &0xff);
238		push(@out,$tmp1);
239		push(@out,$tmp2);
240
241		$p2=&conv($p2);
242		$p1=&conv($p1);
243		&main'comment("$name $p2 $p1");
244		return;
245		}
246
247	push(@out,"\t$name\t".&conv($p1)."\n");
248	}
249
250sub out1p
251	{
252	local($name,$p1)=@_;
253	local($l,$t);
254
255	push(@out,"\t$name\t*".&conv($p1)."\n");
256	}
257
258sub out0
259	{
260	push(@out,"\t$_[0]\n");
261	}
262
263sub conv
264	{
265	local($p)=@_;
266
267#	$p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
268
269	$p=$regs{$p} if (defined($regs{$p}));
270
271	$p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
272	$p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
273	return $p;
274	}
275
276sub main'file
277	{
278	local($file)=@_;
279
280	local($tmp)=<<"EOF";
281	.file	"$file.s"
282	.version	"01.01"
283gcc2_compiled.:
284EOF
285	push(@out,$tmp);
286	}
287
288sub main'function_begin
289	{
290	local($func)=@_;
291
292	&main'external_label($func);
293	$func=$under.$func;
294
295	local($tmp)=<<"EOF";
296.text
297	.align $align
298.globl $func
299EOF
300	push(@out,$tmp);
301	if ($main'cpp)
302		{ $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
303	elsif ($main'gaswin)
304		{ $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
305	else	{ $tmp=push(@out,"\t.type\t$func,\@function\n"); }
306	push(@out,"$func:\n");
307	$tmp=<<"EOF";
308	pushl	%ebp
309	pushl	%ebx
310	pushl	%esi
311	pushl	%edi
312
313EOF
314	push(@out,$tmp);
315	$stack=20;
316	}
317
318sub main'function_begin_B
319	{
320	local($func,$extra)=@_;
321
322	&main'external_label($func);
323	$func=$under.$func;
324
325	local($tmp)=<<"EOF";
326.text
327	.align $align
328.globl $func
329EOF
330	push(@out,$tmp);
331	if ($main'cpp)
332		{ push(@out,"\tTYPE($func,\@function)\n"); }
333	elsif ($main'gaswin)
334		{ $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
335	else	{ push(@out,"\t.type	$func,\@function\n"); }
336	push(@out,"$func:\n");
337	$stack=4;
338	}
339
340sub main'function_end
341	{
342	local($func)=@_;
343
344	$func=$under.$func;
345
346	local($tmp)=<<"EOF";
347	popl	%edi
348	popl	%esi
349	popl	%ebx
350	popl	%ebp
351	ret
352.L_${func}_end:
353EOF
354	push(@out,$tmp);
355
356	if ($main'cpp)
357		{ push(@out,"\tSIZE($func,.L_${func}_end-$func)\n"); }
358	elsif ($main'gaswin)
359                { $tmp=push(@out,"\t.align 4\n"); }
360	else	{ push(@out,"\t.size\t$func,.L_${func}_end-$func\n"); }
361	push(@out,".ident	\"$func\"\n");
362	$stack=0;
363	%label=();
364	}
365
366sub main'function_end_A
367	{
368	local($func)=@_;
369
370	local($tmp)=<<"EOF";
371	popl	%edi
372	popl	%esi
373	popl	%ebx
374	popl	%ebp
375	ret
376EOF
377	push(@out,$tmp);
378	}
379
380sub main'function_end_B
381	{
382	local($func)=@_;
383
384	$func=$under.$func;
385
386	push(@out,".L_${func}_end:\n");
387	if ($main'cpp)
388		{ push(@out,"\tSIZE($func,.L_${func}_end-$func)\n"); }
389        elsif ($main'gaswin)
390                { push(@out,"\t.align 4\n"); }
391	else	{ push(@out,"\t.size\t$func,.L_${func}_end-$func\n"); }
392	push(@out,".ident	\"desasm.pl\"\n");
393	$stack=0;
394	%label=();
395	}
396
397sub main'wparam
398	{
399	local($num)=@_;
400
401	return(&main'DWP($stack+$num*4,"esp","",0));
402	}
403
404sub main'stack_push
405	{
406	local($num)=@_;
407	$stack+=$num*4;
408	&main'sub("esp",$num*4);
409	}
410
411sub main'stack_pop
412	{
413	local($num)=@_;
414	$stack-=$num*4;
415	&main'add("esp",$num*4);
416	}
417
418sub main'swtmp
419	{
420	return(&main'DWP($_[0]*4,"esp","",0));
421	}
422
423# Should use swtmp, which is above esp.  Linix can trash the stack above esp
424#sub main'wtmp
425#	{
426#	local($num)=@_;
427#
428#	return(&main'DWP(-($num+1)*4,"esp","",0));
429#	}
430
431sub main'comment
432	{
433	if ($main'elf)	# GNU and SVR4 as'es use different comment delimiters,
434		{	# so we just skip comments...
435		push(@out,"\n");
436		return;
437		}
438	foreach (@_)
439		{
440		if (/^\s*$/)
441			{ push(@out,"\n"); }
442		else
443			{ push(@out,"\t$com_start $_ $com_end\n"); }
444		}
445	}
446
447sub main'label
448	{
449	if (!defined($label{$_[0]}))
450		{
451		$label{$_[0]}=".${label}${_[0]}";
452		$label++;
453		}
454	return($label{$_[0]});
455	}
456
457sub main'set_label
458	{
459	if (!defined($label{$_[0]}))
460		{
461		$label{$_[0]}=".${label}${_[0]}";
462		$label++;
463		}
464	push(@out,".align $align\n") if ($_[1] != 0);
465	push(@out,"$label{$_[0]}:\n");
466	}
467
468sub main'file_end
469	{
470	if ($const ne "")
471		{
472		push(@out,".section .rodata\n");
473		push(@out,$const);
474		$const="";
475		}
476	}
477
478sub main'data_word
479	{
480	push(@out,"\t.long $_[0]\n");
481	}
482
483# debug output functions: puts, putx, printf
484
485sub main'puts
486	{
487	&pushvars();
488	&main'push('$Lstring' . ++$constl);
489	&main'call('puts');
490	$stack-=4;
491	&main'add("esp",4);
492	&popvars();
493
494	$const .= "Lstring$constl:\n\t.string \"@_[0]\"\n";
495	}
496
497sub main'putx
498	{
499	&pushvars();
500	&main'push($_[0]);
501	&main'push('$Lstring' . ++$constl);
502	&main'call('printf');
503	&main'add("esp",8);
504	$stack-=8;
505	&popvars();
506
507	$const .= "Lstring$constl:\n\t.string \"\%X\"\n";
508	}
509
510sub main'printf
511	{
512	$ostack = $stack;
513	&pushvars();
514	for ($i = @_ - 1; $i >= 0; $i--)
515		{
516		if ($i == 0) # change this to support %s format strings
517			{
518			&main'push('$Lstring' . ++$constl);
519			$const .= "Lstring$constl:\n\t.string \"@_[$i]\"\n";
520			}
521		else
522			{
523			if ($_[$i] =~ /([0-9]*)\(%esp\)/)
524				{
525				&main'push(($1 + $stack - $ostack) . '(%esp)');
526				}
527			else
528				{
529				&main'push($_[$i]);
530				}
531			}
532		}
533	&main'call('printf');
534	$stack-=4*@_;
535	&main'add("esp",4*@_);
536	&popvars();
537	}
538
539sub pushvars
540	{
541	&main'pushf();
542	&main'push("edx");
543	&main'push("ecx");
544	&main'push("eax");
545	}
546
547sub popvars
548	{
549	&main'pop("eax");
550	&main'pop("ecx");
551	&main'pop("edx");
552	&main'popf();
553	}
554
555sub main'picmeup
556	{
557	local($dst,$sym)=@_;
558	if ($main'cpp)
559		{
560		local($tmp)=<<___;
561#if (defined(ELF) || defined(SOL)) && defined(PIC)
562	.align	8
563	call	1f
5641:	popl	$regs{$dst}
565	addl	\$_GLOBAL_OFFSET_TABLE_+[.-1b],$regs{$dst}
566	movl	$sym\@GOT($regs{$dst}),$regs{$dst}
567#else
568	leal	$sym,$regs{$dst}
569#endif
570___
571		push(@out,$tmp);
572		}
573	elsif ($main'pic && ($main'elf || $main'aout))
574		{
575		push(@out,"\t.align\t8\n");
576		&main'call(&main'label("PIC_me_up"));
577		&main'set_label("PIC_me_up");
578		&main'blindpop($dst);
579		&main'add($dst,"\$$under"."_GLOBAL_OFFSET_TABLE_+[.-".
580				&main'label("PIC_me_up") . "]");
581		&main'mov($dst,&main'DWP($sym."\@GOT",$dst));
582		}
583	else
584		{
585		&main'lea($dst,&main'DWP($sym));
586		}
587	}
588
589sub main'blindpop { &out1("popl",@_); }
590