x86unix.pl 12.8 KB
Newer Older
1 2
#!/usr/local/bin/perl

3
package x86unix;	# GAS actually...
4 5

$label="L000";
6
$const="";
U
Ulf Möller 已提交
7
$constl=0;
8 9

$align=($main'aout)?"4":"16";
10 11
$under=($main'aout or $main'coff)?"_":"";
$com_start="#" if ($main'aout or $main'coff);
12

13 14 15 16 17
sub main'asm_init_output { @out=(); }
sub main'asm_get_output { return(@out); }
sub main'get_labels { return(@labels); }
sub main'external_label { push(@labels,@_); }

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
if ($main'cpp)
	{
	$align="ALIGN";
	$under="";
	$com_start='/*';
	$com_end='*/';
	}

%lb=(	'eax',	'%al',
	'ebx',	'%bl',
	'ecx',	'%cl',
	'edx',	'%dl',
	'ax',	'%al',
	'bx',	'%bl',
	'cx',	'%cl',
	'dx',	'%dl',
	);

%hb=(	'eax',	'%ah',
	'ebx',	'%bh',
	'ecx',	'%ch',
	'edx',	'%dh',
	'ax',	'%ah',
	'bx',	'%bh',
	'cx',	'%ch',
	'dx',	'%dh',
	);

%regs=(	'eax',	'%eax',
	'ebx',	'%ebx',
	'ecx',	'%ecx',
	'edx',	'%edx',
	'esi',	'%esi',
	'edi',	'%edi',
	'ebp',	'%ebp',
	'esp',	'%esp',
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

	'mm0',	'%mm0',
	'mm1',	'%mm1',
	'mm2',	'%mm2',
	'mm3',	'%mm3',
	'mm4',	'%mm4',
	'mm5',	'%mm5',
	'mm6',	'%mm6',
	'mm7',	'%mm7',

	'xmm0',	'%xmm0',
	'xmm1',	'%xmm1',
	'xmm2',	'%xmm2',
	'xmm3',	'%xmm3',
	'xmm4',	'%xmm4',
	'xmm5',	'%xmm5',
	'xmm6',	'%xmm6',
	'xmm7',	'%xmm7',
72 73
	);

74 75 76 77 78 79 80 81 82 83 84
%reg_val=(
	'eax',	0x00,
	'ebx',	0x03,
	'ecx',	0x01,
	'edx',	0x02,
	'esi',	0x06,
	'edi',	0x07,
	'ebp',	0x05,
	'esp',	0x04,
	);

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
sub main'LB
	{
	(defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
	return($lb{$_[0]});
	}

sub main'HB
	{
	(defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
	return($hb{$_[0]});
	}

sub main'DWP
	{
	local($addr,$reg1,$reg2,$idx)=@_;

	$ret="";
102
	$addr =~ s/(^|[+ \t])([A-Za-z_]+[A-Za-z0-9_]+)($|[+ \t])/$1$under$2$3/;
103 104 105 106
	$reg1="$regs{$reg1}" if defined($regs{$reg1});
	$reg2="$regs{$reg2}" if defined($regs{$reg2});
	$ret.=$addr if ($addr ne "") && ($addr ne 0);
	if ($reg2 ne "")
107
		{
108
		if($idx ne "" && $idx != 0)
109 110 111 112
		    { $ret.="($reg1,$reg2,$idx)"; }
		else
		    { $ret.="($reg1,$reg2)"; }
	        }
113
	elsif ($reg1 ne "")
114
		{ $ret.="($reg1)" }
115 116 117
	return($ret);
	}

118 119 120 121 122
sub main'QWP
	{
	return(&main'DWP(@_));
	}

123 124
sub main'BP
	{
125
	return(&main'DWP(@_));
126 127
	}

128 129 130 131 132 133 134 135 136 137
sub main'BC
	{
	return @_;
	}

sub main'DWC
	{
	return @_;
	}

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
#sub main'BP
#	{
#	local($addr,$reg1,$reg2,$idx)=@_;
#
#	$ret="";
#
#	$addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
#	$reg1="$regs{$reg1}" if defined($regs{$reg1});
#	$reg2="$regs{$reg2}" if defined($regs{$reg2});
#	$ret.=$addr if ($addr ne "") && ($addr ne 0);
#	if ($reg2 ne "")
#		{ $ret.="($reg1,$reg2,$idx)"; }
#	else
#		{ $ret.="($reg1)" }
#	return($ret);
#	}

155 156 157 158 159 160 161
sub main'mov	{ &out2("movl",@_); }
sub main'movb	{ &out2("movb",@_); }
sub main'and	{ &out2("andl",@_); }
sub main'or	{ &out2("orl",@_); }
sub main'shl	{ &out2("sall",@_); }
sub main'shr	{ &out2("shrl",@_); }
sub main'xor	{ &out2("xorl",@_); }
162
sub main'xorb	{ &out2("xorb",@_); }
163
sub main'add	{ &out2("addl",@_); }
164
sub main'adc	{ &out2("adcl",@_); }
165 166 167 168 169
sub main'sub	{ &out2("subl",@_); }
sub main'rotl	{ &out2("roll",@_); }
sub main'rotr	{ &out2("rorl",@_); }
sub main'exch	{ &out2("xchg",@_); }
sub main'cmp	{ &out2("cmpl",@_); }
170 171 172
sub main'lea	{ &out2("leal",@_); }
sub main'mul	{ &out1("mull",@_); }
sub main'div	{ &out1("divl",@_); }
173
sub main'jmp	{ &out1("jmp",@_); }
174
sub main'jmp_ptr { &out1p("jmp",@_); }
175
sub main'je	{ &out1("je",@_); }
176
sub main'jle	{ &out1("jle",@_); }
177 178 179
sub main'jne	{ &out1("jne",@_); }
sub main'jnz	{ &out1("jnz",@_); }
sub main'jz	{ &out1("jz",@_); }
180 181
sub main'jge	{ &out1("jge",@_); }
sub main'jl	{ &out1("jl",@_); }
182 183
sub main'ja	{ &out1("ja",@_); }
sub main'jae	{ &out1("jae",@_); }
184
sub main'jb	{ &out1("jb",@_); }
185
sub main'jbe	{ &out1("jbe",@_); }
186 187 188
sub main'jc	{ &out1("jc",@_); }
sub main'jnc	{ &out1("jnc",@_); }
sub main'jno	{ &out1("jno",@_); }
189
sub main'dec	{ &out1("decl",@_); }
190 191 192
sub main'inc	{ &out1("incl",@_); }
sub main'push	{ &out1("pushl",@_); $stack+=4; }
sub main'pop	{ &out1("popl",@_); $stack-=4; }
U
Ulf Möller 已提交
193 194
sub main'pushf	{ &out0("pushf"); $stack+=4; }
sub main'popf	{ &out0("popf"); $stack-=4; }
195
sub main'not	{ &out1("notl",@_); }
196
sub main'call	{ &out1("call",($_[0]=~/^\.L/?'':$under).$_[0]); }
197 198
sub main'ret	{ &out0("ret"); }
sub main'nop	{ &out0("nop"); }
199 200 201
sub main'test	{ &out2("testl",@_); }
sub main'bt	{ &out2("btl",@_); }
sub main'leave	{ &out0("leave"); }
202 203
sub main'cpuid	{ &out0(".word\t0xa20f"); }
sub main'rdtsc	{ &out0(".word\t0x310f"); }
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

# SSE2
sub main'emms	{ &out0("emms"); }
sub main'movd	{ &out2("movd",@_); }
sub main'movq	{ &out2("movq",@_); }
sub main'movdqu	{ &out2("movdqu",@_); }
sub main'movdqa	{ &out2("movdqa",@_); }
sub main'movdq2q{ &out2("movdq2q",@_); }
sub main'movq2dq{ &out2("movq2dq",@_); }
sub main'paddq	{ &out2("paddq",@_); }
sub main'pmuludq{ &out2("pmuludq",@_); }
sub main'psrlq	{ &out2("psrlq",@_); }
sub main'psllq	{ &out2("psllq",@_); }
sub main'pxor	{ &out2("pxor",@_); }
sub main'por	{ &out2("por",@_); }
sub main'pand	{ &out2("pand",@_); }
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
# The bswapl instruction is new for the 486. Emulate if i386.
sub main'bswap
	{
	if ($main'i386)
		{
		&main'comment("bswapl @_");
		&main'exch(main'HB(@_),main'LB(@_));
		&main'rotr(@_,16);
		&main'exch(main'HB(@_),main'LB(@_));
		}
	else
		{
		&out1("bswapl",@_);
		}
	}

237 238 239 240
sub out2
	{
	local($name,$p1,$p2)=@_;
	local($l,$ll,$t);
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
	local(%special)=(	"roll",0xD1C0,"rorl",0xD1C8,
				"rcll",0xD1D0,"rcrl",0xD1D8,
				"shll",0xD1E0,"shrl",0xD1E8,
				"sarl",0xD1F8);
	
	if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
		{
		$op=$special{$name}|$reg_val{$p1};
		$tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
		$tmp2=sprintf(".byte %d\t",$op     &0xff);
		push(@out,$tmp1);
		push(@out,$tmp2);

		$p2=&conv($p2);
		$p1=&conv($p1);
		&main'comment("$name $p2 $p1");
		return;
		}
259

260
	push(@out,"\t$name\t");
261 262
	$t=&conv($p2).",";
	$l=length($t);
263
	push(@out,$t);
264
	$ll=4-($l+9)/8;
265 266 267
	$tmp1=sprintf("\t" x $ll);
	push(@out,$tmp1);
	push(@out,&conv($p1)."\n");
268 269 270 271 272 273
	}

sub out1
	{
	local($name,$p1)=@_;
	local($l,$t);
274
	local(%special)=("bswapl",0x0FC8);
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	if ((defined($special{$name})) && defined($regs{$p1}))
		{
		$op=$special{$name}|$reg_val{$p1};
		$tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
		$tmp2=sprintf(".byte %d\t",$op     &0xff);
		push(@out,$tmp1);
		push(@out,$tmp2);

		$p2=&conv($p2);
		$p1=&conv($p1);
		&main'comment("$name $p2 $p1");
		return;
		}

	push(@out,"\t$name\t".&conv($p1)."\n");
	}

sub out1p
	{
	local($name,$p1)=@_;
	local($l,$t);

	push(@out,"\t$name\t*".&conv($p1)."\n");
	}

sub out0
	{
	push(@out,"\t$_[0]\n");
304 305 306 307 308 309 310 311 312 313
	}

sub conv
	{
	local($p)=@_;

#	$p =~ s/0x([0-9A-Fa-f]+)/0$1h/;

	$p=$regs{$p} if (defined($regs{$p}));

314
	$p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
315 316 317 318 319 320 321 322
	$p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
	return $p;
	}

sub main'file
	{
	local($file)=@_;

323
	local($tmp)=<<"EOF";
324 325
	.file	"$file.s"
EOF
326
	push(@out,$tmp);
327 328 329 330
	}

sub main'function_begin
	{
331
	local($func)=@_;
332

333
	&main'external_label($func);
334 335
	$func=$under.$func;

336
	local($tmp)=<<"EOF";
337
.text
338
.align $align
339 340
.globl $func
EOF
341
	push(@out,$tmp);
342
	if ($main'cpp)
343 344 345 346 347 348
		{ $tmp=push(@out,"TYPE($func,\@function)\n"); }
	elsif ($main'coff)
		{ $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
	elsif ($main'aout)
		{ }
	else	{ $tmp=push(@out,".type\t$func,\@function\n"); }
349 350
	push(@out,"$func:\n");
	$tmp=<<"EOF";
351 352 353 354 355 356
	pushl	%ebp
	pushl	%ebx
	pushl	%esi
	pushl	%edi

EOF
357
	push(@out,$tmp);
358 359 360
	$stack=20;
	}

361 362 363 364 365 366 367 368 369
sub main'function_begin_B
	{
	local($func,$extra)=@_;

	&main'external_label($func);
	$func=$under.$func;

	local($tmp)=<<"EOF";
.text
370
.align $align
371 372 373 374
.globl $func
EOF
	push(@out,$tmp);
	if ($main'cpp)
375 376 377 378 379 380
		{ push(@out,"TYPE($func,\@function)\n"); }
	elsif ($main'coff)
		{ $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
	elsif ($main'aout)
		{ }
	else	{ push(@out,".type	$func,\@function\n"); }
381 382 383 384
	push(@out,"$func:\n");
	$stack=4;
	}

385 386 387 388 389 390
sub main'function_end
	{
	local($func)=@_;

	$func=$under.$func;

391
	local($tmp)=<<"EOF";
392 393 394 395 396
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret
397
.L_${func}_end:
398
EOF
399
	push(@out,$tmp);
400

401
	if ($main'cpp)
402 403 404 405
		{ push(@out,"SIZE($func,.L_${func}_end-$func)\n"); }
	elsif ($main'coff or $main'aout)
                { $tmp=push(@out,".align $align\n"); }
	else	{ push(@out,".size\t$func,.L_${func}_end-$func\n"); }
406
	push(@out,".ident	\"$func\"\n");
407 408 409 410 411 412 413 414
	$stack=0;
	%label=();
	}

sub main'function_end_A
	{
	local($func)=@_;

415
	local($tmp)=<<"EOF";
416 417 418 419 420 421
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret
EOF
422
	push(@out,$tmp);
423 424 425 426 427 428 429 430
	}

sub main'function_end_B
	{
	local($func)=@_;

	$func=$under.$func;

431
	push(@out,".L_${func}_end:\n");
432
	if ($main'cpp)
433 434 435 436
		{ push(@out,"SIZE($func,.L_${func}_end-$func)\n"); }
        elsif ($main'coff or $main'aout)
                { push(@out,".align $align\n"); }
	else	{ push(@out,".size\t$func,.L_${func}_end-$func\n"); }
437
	push(@out,".ident	\"$func\"\n");
438 439 440 441 442 443 444 445 446 447 448
	$stack=0;
	%label=();
	}

sub main'wparam
	{
	local($num)=@_;

	return(&main'DWP($stack+$num*4,"esp","",0));
	}

449
sub main'stack_push
450
	{
451 452 453
	local($num)=@_;
	$stack+=$num*4;
	&main'sub("esp",$num*4);
454 455
	}

456
sub main'stack_pop
457 458
	{
	local($num)=@_;
459 460 461
	$stack-=$num*4;
	&main'add("esp",$num*4);
	}
462

463 464 465
sub main'swtmp
	{
	return(&main'DWP($_[0]*4,"esp","",0));
466 467
	}

468 469 470 471 472 473 474 475
# Should use swtmp, which is above esp.  Linix can trash the stack above esp
#sub main'wtmp
#	{
#	local($num)=@_;
#
#	return(&main'DWP(-($num+1)*4,"esp","",0));
#	}

476 477
sub main'comment
	{
478
	return if (!defined($com_start);
479 480 481 482 483
	if ($main'elf)	# GNU and SVR4 as'es use different comment delimiters,
		{	# so we just skip comments...
		push(@out,"\n");
		return;
		}
484 485 486
	foreach (@_)
		{
		if (/^\s*$/)
487
			{ push(@out,"\n"); }
488
		else
489
			{ push(@out,"\t$com_start $_ $com_end\n"); }
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
		}
	}

sub main'label
	{
	if (!defined($label{$_[0]}))
		{
		$label{$_[0]}=".${label}${_[0]}";
		$label++;
		}
	return($label{$_[0]});
	}

sub main'set_label
	{
	if (!defined($label{$_[0]}))
		{
		$label{$_[0]}=".${label}${_[0]}";
		$label++;
		}
510 511
	push(@out,".align $align\n") if ($_[1] != 0);
	push(@out,"$label{$_[0]}:\n");
512 513 514 515
	}

sub main'file_end
	{
516 517 518 519 520 521 522 523 524 525 526
	# try to detect if SSE2 or MMX extensions were used on ELF platform...
	if ($main'elf && grep {/%[x]*mm[0-7]/i} @out) {
		local($tmp);

		push (@out,"\n.comm\t".$under."OPENSSL_ia32cap,8,4\n");

		push (@out,".section\t.init\n");
		# One can argue that it's wasteful to craft every
		# SSE/MMX module with this snippet... Well, it's 72
		# bytes long and for the moment we have two modules.
		# Let's argue when we have 7 modules or so...
527 528 529
		#
		# $1<<10 sets a reserved bit to signal that variable
		# was initialized already...
530 531 532 533
		&main'picmeup("edx","OPENSSL_ia32cap");
		$tmp=<<___;
		cmpl	\$0,(%edx)
		jne	1f
534
		movl	\$1<<10,(%edx)
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
		pushf
		popl	%eax
		movl	%eax,%ecx
		xorl	\$1<<21,%eax
		pushl	%eax
		popf
		pushf
		popl	%eax
		xorl	%ecx,%eax
		bt	\$21,%eax
		jnc	1f
		pushl	%edi
		pushl	%ebx
		movl	%edx,%edi
		movl	\$1,%eax
550 551
		.word	0xa20f
		orl	\$1<<10,%edx
552 553 554 555
		movl	%edx,0(%edi)
		movl	%ecx,4(%edi)
		popl	%ebx
		popl	%edi
556
	.align	4
557 558 559 560 561
	1:
___
		push (@out,$tmp);
	}

562 563 564 565 566 567
	if ($const ne "")
		{
		push(@out,".section .rodata\n");
		push(@out,$const);
		$const="";
		}
568
	}
569 570 571

sub main'data_word
	{
572 573 574 575 576
	push(@out,"\t.long\t".join(',',@_)."\n");
	}

sub main'align
	{
577 578 579 580 581 582 583
	my $val=$_[0],$p2,$i;
	if ($main'aout) {
		for ($p2=0;$val!=0;$val>>=1) { $p2++; }
		$val=$p2-1;
		$val.=",0x90";
	}
	push(@out,".align $val\n");
584
	}
585

586 587
# debug output functions: puts, putx, printf

588 589
sub main'puts
	{
590
	&pushvars();
591 592 593 594
	&main'push('$Lstring' . ++$constl);
	&main'call('puts');
	$stack-=4;
	&main'add("esp",4);
595
	&popvars();
596

597
	$const .= "Lstring$constl:\n\t.string \"@_[0]\"\n";
598 599 600 601
	}

sub main'putx
	{
602
	&pushvars();
603 604 605 606
	&main'push($_[0]);
	&main'push('$Lstring' . ++$constl);
	&main'call('printf');
	&main'add("esp",8);
U
Ulf Möller 已提交
607
	$stack-=8;
608
	&popvars();
609

610 611 612 613 614 615
	$const .= "Lstring$constl:\n\t.string \"\%X\"\n";
	}

sub main'printf
	{
	$ostack = $stack;
616
	&pushvars();
617 618 619 620
	for ($i = @_ - 1; $i >= 0; $i--)
		{
		if ($i == 0) # change this to support %s format strings
			{
U
Ulf Möller 已提交
621
			&main'push('$Lstring' . ++$constl);
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
			$const .= "Lstring$constl:\n\t.string \"@_[$i]\"\n";
			}
		else
			{
			if ($_[$i] =~ /([0-9]*)\(%esp\)/)
				{
				&main'push(($1 + $stack - $ostack) . '(%esp)');
				}
			else
				{
				&main'push($_[$i]);
				}
			}
		}
	&main'call('printf');
637
	$stack-=4*@_;
638
	&main'add("esp",4*@_);
U
Ulf Möller 已提交
639
	&popvars();
640
	}
641 642 643

sub pushvars
	{
U
Ulf Möller 已提交
644
	&main'pushf();
645 646 647 648 649 650 651 652 653 654
	&main'push("edx");
	&main'push("ecx");
	&main'push("eax");
	}

sub popvars
	{
	&main'pop("eax");
	&main'pop("ecx");
	&main'pop("edx");
U
Ulf Möller 已提交
655
	&main'popf();
656
	}
657 658 659 660

sub main'picmeup
	{
	local($dst,$sym)=@_;
661 662 663
	if ($main'cpp)
		{
		local($tmp)=<<___;
664
#if (defined(ELF) || defined(SOL)) && defined(PIC)
665
	.align	4
666 667 668 669 670
	call	1f
1:	popl	$regs{$dst}
	addl	\$_GLOBAL_OFFSET_TABLE_+[.-1b],$regs{$dst}
	movl	$sym\@GOT($regs{$dst}),$regs{$dst}
#else
671
	leal	$sym,$regs{$dst}
672 673
#endif
___
674 675
		push(@out,$tmp);
		}
676
	elsif ($main'pic && ($main'elf || $main'aout))
677 678 679 680
		{
		&main'call(&main'label("PIC_me_up"));
		&main'set_label("PIC_me_up");
		&main'blindpop($dst);
681
		&main'add($dst,"\$$under"."_GLOBAL_OFFSET_TABLE_+[.-".
682
				&main'label("PIC_me_up") . "]");
683
		&main'mov($dst,&main'DWP($sym."\@GOT",$dst));
684 685 686
		}
	else
		{
687
		&main'lea($dst,&main'DWP($sym));
688
		}
689 690 691
	}

sub main'blindpop { &out1("popl",@_); }
692 693 694 695 696 697 698 699 700 701 702 703 704 705

sub main'initseg
	{
	local($f)=@_;
	if ($main'elf)
		{
		local($tmp)=<<___;
.pushsection	.init
	call	$under$f
.popsection
___
		push(@out,$tmp);
		}
	}