x86unix.pl 13.7 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
$under=($main'aout or $main'coff)?"_":"";
11
$dot=($main'aout)?"":".";
12
$com_start="#" if ($main'aout or $main'coff);
13

14 15 16 17 18
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,@_); }

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 54
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',
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

	'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',
73 74
	);

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

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
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="";
103
	$addr =~ s/(^|[+ \t])([A-Za-z_]+[A-Za-z0-9_]+)($|[+ \t])/$1$under$2$3/;
104 105 106 107
	$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 "")
108
		{
109
		if($idx ne "" && $idx != 0)
110 111 112 113
		    { $ret.="($reg1,$reg2,$idx)"; }
		else
		    { $ret.="($reg1,$reg2)"; }
	        }
114
	elsif ($reg1 ne "")
115
		{ $ret.="($reg1)" }
116 117 118
	return($ret);
	}

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

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

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

sub main'DWC
	{
	return @_;
	}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
#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);
#	}

156 157 158 159 160 161 162
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",@_); }
163
sub main'xorb	{ &out2("xorb",@_); }
164
sub main'add	{ &out2($_[0]=~/%[a-d][lh]/?"addb":"addl",@_); }
165
sub main'adc	{ &out2("adcl",@_); }
166
sub main'sub	{ &out2("subl",@_); }
167
sub main'sbb	{ &out2("sbbl",@_); }
168 169
sub main'rotl	{ &out2("roll",@_); }
sub main'rotr	{ &out2("rorl",@_); }
A
Andy Polyakov 已提交
170
sub main'exch	{ &out2($_[0]=~/%[a-d][lh]/?"xchgb":"xchgl",@_); }
171
sub main'cmp	{ &out2("cmpl",@_); }
172 173 174
sub main'lea	{ &out2("leal",@_); }
sub main'mul	{ &out1("mull",@_); }
sub main'div	{ &out1("divl",@_); }
175
sub main'jmp	{ &out1("jmp",@_); }
176
sub main'jmp_ptr { &out1p("jmp",@_); }
177
sub main'je	{ &out1("je",@_); }
178
sub main'jle	{ &out1("jle",@_); }
179 180 181
sub main'jne	{ &out1("jne",@_); }
sub main'jnz	{ &out1("jnz",@_); }
sub main'jz	{ &out1("jz",@_); }
182 183
sub main'jge	{ &out1("jge",@_); }
sub main'jl	{ &out1("jl",@_); }
184 185
sub main'ja	{ &out1("ja",@_); }
sub main'jae	{ &out1("jae",@_); }
186
sub main'jb	{ &out1("jb",@_); }
187
sub main'jbe	{ &out1("jbe",@_); }
188 189 190
sub main'jc	{ &out1("jc",@_); }
sub main'jnc	{ &out1("jnc",@_); }
sub main'jno	{ &out1("jno",@_); }
191
sub main'dec	{ &out1("decl",@_); }
192
sub main'inc	{ &out1($_[0]=~/%[a-d][hl]/?"incb":"incl",@_); }
193 194
sub main'push	{ &out1("pushl",@_); $stack+=4; }
sub main'pop	{ &out1("popl",@_); $stack-=4; }
195 196
sub main'pushf	{ &out0("pushfl"); $stack+=4; }
sub main'popf	{ &out0("popfl"); $stack-=4; }
197
sub main'not	{ &out1("notl",@_); }
198 199 200 201 202
sub main'call	{	my $pre=$under;
			foreach $i (%label)
			{ if ($label{$i} eq $_[0]) { $pre=''; last; } }
			&out1("call",$pre.$_[0]);
		}
203 204
sub main'ret	{ &out0("ret"); }
sub main'nop	{ &out0("nop"); }
205 206 207
sub main'test	{ &out2("testl",@_); }
sub main'bt	{ &out2("btl",@_); }
sub main'leave	{ &out0("leave"); }
208 209
sub main'cpuid	{ &out0(".byte\t0x0f,0xa2"); }
sub main'rdtsc	{ &out0(".byte\t0x0f,0x31"); }
210
sub main'halt	{ &out0("hlt"); }
A
Andy Polyakov 已提交
211
sub main'movz	{ &out2("movzbl",@_); }
212
sub main'neg	{ &out1("negl",@_); }
213
sub main'cld	{ &out0("cld"); }
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229

# 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",@_); }
230

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
# 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",@_);
		}
	}

247 248 249 250
sub out2
	{
	local($name,$p1,$p2)=@_;
	local($l,$ll,$t);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	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;
		}
269

270
	push(@out,"\t$name\t");
271 272
	$t=&conv($p2).",";
	$l=length($t);
273
	push(@out,$t);
274
	$ll=4-($l+9)/8;
275 276 277
	$tmp1=sprintf("\t" x $ll);
	push(@out,$tmp1);
	push(@out,&conv($p1)."\n");
278 279 280 281 282 283
	}

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

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
	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");
314 315 316 317 318 319 320 321 322 323
	}

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

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

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

324
	$p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
325 326 327 328 329 330 331 332
	$p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
	return $p;
	}

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

333
	local($tmp)=<<"EOF";
334 335
	.file	"$file.s"
EOF
336
	push(@out,$tmp);
337 338 339 340
	}

sub main'function_begin
	{
341
	local($func)=@_;
342

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

346
	local($tmp)=<<"EOF";
347
.text
348
.globl	$func
349
EOF
350
	push(@out,$tmp);
351
	if ($main'cpp)
352 353 354
		{ $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"); }
355
	elsif ($main'aout and !$main'pic)
356 357
		{ }
	else	{ $tmp=push(@out,".type\t$func,\@function\n"); }
358
	push(@out,".align\t$align\n");
359 360
	push(@out,"$func:\n");
	$tmp=<<"EOF";
361 362 363 364 365 366
	pushl	%ebp
	pushl	%ebx
	pushl	%esi
	pushl	%edi

EOF
367
	push(@out,$tmp);
368 369 370
	$stack=20;
	}

371 372 373 374 375 376 377 378 379
sub main'function_begin_B
	{
	local($func,$extra)=@_;

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

	local($tmp)=<<"EOF";
.text
380
.globl	$func
381 382 383
EOF
	push(@out,$tmp);
	if ($main'cpp)
384 385 386
		{ push(@out,"TYPE($func,\@function)\n"); }
	elsif ($main'coff)
		{ $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
387
	elsif ($main'aout and !$main'pic)
388 389
		{ }
	else	{ push(@out,".type	$func,\@function\n"); }
390
	push(@out,".align\t$align\n");
391 392 393 394
	push(@out,"$func:\n");
	$stack=4;
	}

395 396 397 398 399 400
sub main'function_end
	{
	local($func)=@_;

	$func=$under.$func;

401
	local($tmp)=<<"EOF";
402 403 404 405 406
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret
407
${dot}L_${func}_end:
408
EOF
409
	push(@out,$tmp);
410

411
	if ($main'cpp)
412
		{ push(@out,"SIZE($func,${dot}L_${func}_end-$func)\n"); }
413
	elsif ($main'coff or $main'aout)
414
                { }
415
	else	{ push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); }
416
	push(@out,".ident	\"$func\"\n");
417 418 419 420 421 422 423 424
	$stack=0;
	%label=();
	}

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

425
	local($tmp)=<<"EOF";
426 427 428 429 430 431
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret
EOF
432
	push(@out,$tmp);
433 434 435 436 437 438 439 440
	}

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

	$func=$under.$func;

441
	push(@out,"${dot}L_${func}_end:\n");
442
	if ($main'cpp)
443
		{ push(@out,"SIZE($func,${dot}L_${func}_end-$func)\n"); }
444
        elsif ($main'coff or $main'aout)
445
                { }
446
	else	{ push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); }
447
	push(@out,".ident	\"$func\"\n");
448 449 450 451 452 453 454 455 456 457 458
	$stack=0;
	%label=();
	}

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

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

459
sub main'stack_push
460
	{
461 462 463
	local($num)=@_;
	$stack+=$num*4;
	&main'sub("esp",$num*4);
464 465
	}

466
sub main'stack_pop
467 468
	{
	local($num)=@_;
469 470 471
	$stack-=$num*4;
	&main'add("esp",$num*4);
	}
472

473 474 475
sub main'swtmp
	{
	return(&main'DWP($_[0]*4,"esp","",0));
476 477
	}

478 479 480 481 482 483 484 485
# 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));
#	}

486 487
sub main'comment
	{
488 489 490 491
	if (!defined($com_start) or $main'elf)
		{	# Regarding $main'elf above...
			# GNU and SVR4 as'es use different comment delimiters,
		push(@out,"\n");	# so we just skip ELF comments...
492 493
		return;
		}
494 495 496
	foreach (@_)
		{
		if (/^\s*$/)
497
			{ push(@out,"\n"); }
498
		else
499
			{ push(@out,"\t$com_start $_ $com_end\n"); }
500 501 502
		}
	}

503 504 505 506 507 508
sub main'public_label
	{
	$label{$_[0]}="${under}${_[0]}"	if (!defined($label{$_[0]}));
	push(@out,".globl\t$label{$_[0]}\n");
	}

509 510 511 512
sub main'label
	{
	if (!defined($label{$_[0]}))
		{
513
		$label{$_[0]}="${dot}${label}${_[0]}";
514 515 516 517 518 519 520 521 522
		$label++;
		}
	return($label{$_[0]});
	}

sub main'set_label
	{
	if (!defined($label{$_[0]}))
		{
523
		$label{$_[0]}="${dot}${label}${_[0]}";
524 525
		$label++;
		}
526 527 528 529 530
	if ($_[1]!=0)
		{
		if ($_[1]>1)	{ main'align($_[1]);		}
		else		{ push(@out,".align $align\n");	}
		}
531
	push(@out,"$label{$_[0]}:\n");
532 533 534 535
	}

sub main'file_end
	{
536 537 538 539
	# 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);

540
		push (@out,"\n.comm\t${under}OPENSSL_ia32cap_P,4,4\n");
541 542 543 544 545 546

		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...
547 548 549
		#
		# $1<<10 sets a reserved bit to signal that variable
		# was initialized already...
550
		&main'picmeup("edx","OPENSSL_ia32cap_P");
551 552 553
		$tmp=<<___;
		cmpl	\$0,(%edx)
		jne	1f
554
		movl	\$1<<10,(%edx)
555 556 557 558 559 560 561 562 563
		pushf
		popl	%eax
		movl	%eax,%ecx
		xorl	\$1<<21,%eax
		pushl	%eax
		popf
		pushf
		popl	%eax
		xorl	%ecx,%eax
564
		btl	\$21,%eax
565 566 567 568 569
		jnc	1f
		pushl	%edi
		pushl	%ebx
		movl	%edx,%edi
		movl	\$1,%eax
570
		.byte	0x0f,0xa2
571
		orl	\$1<<10,%edx
572 573 574 575 576 577 578 579
		movl	%edx,0(%edi)
		popl	%ebx
		popl	%edi
	1:
___
		push (@out,$tmp);
	}

580 581 582 583 584 585
	if ($const ne "")
		{
		push(@out,".section .rodata\n");
		push(@out,$const);
		$const="";
		}
586
	}
587 588 589

sub main'data_word
	{
590 591 592 593 594
	push(@out,"\t.long\t".join(',',@_)."\n");
	}

sub main'align
	{
595 596 597 598 599 600
	my $val=$_[0],$p2,$i;
	if ($main'aout) {
		for ($p2=0;$val!=0;$val>>=1) { $p2++; }
		$val=$p2-1;
		$val.=",0x90";
	}
601
	push(@out,".align\t$val\n");
602
	}
603

604 605
# debug output functions: puts, putx, printf

606 607
sub main'puts
	{
608
	&pushvars();
609 610 611 612
	&main'push('$Lstring' . ++$constl);
	&main'call('puts');
	$stack-=4;
	&main'add("esp",4);
613
	&popvars();
614

615
	$const .= "Lstring$constl:\n\t.string \"@_[0]\"\n";
616 617 618 619
	}

sub main'putx
	{
620
	&pushvars();
621 622 623 624
	&main'push($_[0]);
	&main'push('$Lstring' . ++$constl);
	&main'call('printf');
	&main'add("esp",8);
U
Ulf Möller 已提交
625
	$stack-=8;
626
	&popvars();
627

628 629 630 631 632 633
	$const .= "Lstring$constl:\n\t.string \"\%X\"\n";
	}

sub main'printf
	{
	$ostack = $stack;
634
	&pushvars();
635 636 637 638
	for ($i = @_ - 1; $i >= 0; $i--)
		{
		if ($i == 0) # change this to support %s format strings
			{
U
Ulf Möller 已提交
639
			&main'push('$Lstring' . ++$constl);
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
			$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');
655
	$stack-=4*@_;
656
	&main'add("esp",4*@_);
U
Ulf Möller 已提交
657
	&popvars();
658
	}
659 660 661

sub pushvars
	{
U
Ulf Möller 已提交
662
	&main'pushf();
663 664 665 666 667 668 669 670 671 672
	&main'push("edx");
	&main'push("ecx");
	&main'push("eax");
	}

sub popvars
	{
	&main'pop("eax");
	&main'pop("ecx");
	&main'pop("edx");
U
Ulf Möller 已提交
673
	&main'popf();
674
	}
675 676 677 678

sub main'picmeup
	{
	local($dst,$sym)=@_;
679 680 681
	if ($main'cpp)
		{
		local($tmp)=<<___;
682 683 684 685 686 687
#if (defined(ELF) || defined(SOL)) && defined(PIC)
	call	1f
1:	popl	$regs{$dst}
	addl	\$_GLOBAL_OFFSET_TABLE_+[.-1b],$regs{$dst}
	movl	$sym\@GOT($regs{$dst}),$regs{$dst}
#else
688
	leal	$sym,$regs{$dst}
689 690
#endif
___
691 692
		push(@out,$tmp);
		}
693
	elsif ($main'pic && ($main'elf || $main'aout))
694 695 696 697
		{
		&main'call(&main'label("PIC_me_up"));
		&main'set_label("PIC_me_up");
		&main'blindpop($dst);
698
		&main'add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-".
699
				&main'label("PIC_me_up") . "]");
700
		&main'mov($dst,&main'DWP($under.$sym."\@GOT",$dst));
701 702 703
		}
	else
		{
704
		&main'lea($dst,&main'DWP($sym));
705
		}
706 707 708
	}

sub main'blindpop { &out1("popl",@_); }
709 710 711 712

sub main'initseg
	{
	local($f)=@_;
713
	local($tmp);
714 715
	if ($main'elf)
		{
716 717
		$tmp=<<___;
.section	.init
718 719 720
	call	$under$f
___
		}
721 722 723 724 725 726 727 728 729
	elsif ($main'coff)
		{
		$tmp=<<___;	# applies to both Cygwin and Mingw
.section	.ctors
.long	$under$f
___
		}
	elsif ($main'aout)
		{
730 731 732 733 734
		local($ctor)="${under}_GLOBAL_\$I\$$f";
		$tmp=".text\n";
		$tmp.=".type	$ctor,\@function\n" if ($main'pic);
		$tmp.=<<___;	# OpenBSD way...
.globl	$ctor
735
.align	2
736
$ctor:
737 738 739 740
	jmp	$under$f
___
		}
	push(@out,$tmp) if ($tmp);
741
	}
742 743

1;