195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#!/usr/bin/env perl
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Ascetic x86_64 AT&T to MASM/NASM assembler translator by <appro>.
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# format is way easier to parse. Because it's simpler to "gear" from
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Unix ABI to Windows one [see cross-reference "card" at the end of
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# file]. Because Linux targets were available first...
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# In addition the script also "distills" code suitable for GNU
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# assembler, so that it can be compiled with more rigid assemblers,
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# such as Solaris /usr/ccs/bin/as.
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# This translator is not designed to convert *arbitrary* assembler
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# code from AT&T format to MASM one. It's designed to convert just
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# enough to provide for dual-ABI OpenSSL modules development...
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# There *are* limitations and you might have to modify your assembler
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# code or this script to achieve the desired result...
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Currently recognized limitations:
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# - can't use multiple ops per line;
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Dual-ABI styling rules.
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 1. Adhere to Unix register and stack layout [see cross-reference
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    ABI "card" at the end for explanation].
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 2. Forget about "red zone," stick to more traditional blended
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    stack frame allocation. If volatile storage is actually required
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    that is. If not, just leave the stack as is.
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 3. Functions tagged with ".type name,@function" get crafted with
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    unified Win64 prologue and epilogue automatically. If you want
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    to take care of ABI differences yourself, tag functions as
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    ".type name,@abi-omnipotent" instead.
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 4. To optimize the Win64 prologue you can specify number of input
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    arguments as ".type name,@function,N." Keep in mind that if N is
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    larger than 6, then you *have to* write "abi-omnipotent" code,
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    because >6 cases can't be addressed with unified prologue.
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 5. Name local labels as .L*, do *not* use dynamic labels such as 1:
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    (sorry about latter).
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    required to identify the spots, where to inject Win64 epilogue!
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    But on the pros, it's then prefixed with rep automatically:-)
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 7. Stick to explicit ip-relative addressing. If you have to use
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??.
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    Both are recognized and translated to proper Win64 addressing
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    modes. To support legacy code a synthetic directive, .picmeup,
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    is implemented. It puts address of the *next* instruction into
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    target register, e.g.:
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#		.picmeup	%rax
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#		lea		.Label-.(%rax),%rax
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 8. In order to provide for structured exception handling unified
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    Win64 prologue copies %rsp value to %rax. For further details
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    see SEH paragraph at the end.
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 9. .init segment is allowed to contain calls to functions only.
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# a. If function accepts more than 4 arguments *and* >4th argument
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#    is declared as non 64-bit value, do clear its upper part.
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $flavour = shift;
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $output  = shift;
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyif ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyopen STDOUT,">$output" || die "can't open $output: $!"
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if (defined($output));
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $gas=1;	$gas=0 if ($output =~ /\.asm$/);
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $elf=1;	$elf=0 if (!$gas);
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $win64=0;
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $prefix="";
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $decor=".L";
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $masmref=8 + 50727*2**-32;	# 8.00.50727 shipped with VS2005
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $masm=0;
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $PTR=" PTR";
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $nasmref=2.03;
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $nasm=0;
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyif    ($flavour eq "mingw64")	{ $gas=1; $elf=0; $win64=1;
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`;
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  chomp($prefix);
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				}
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyelsif ($flavour eq "macosx")	{ $gas=1; $elf=0; $prefix="_"; $decor="L\$"; }
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyelsif ($flavour eq "masm")	{ $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; }
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyelsif ($flavour eq "nasm")	{ $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; }
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyelsif (!$gas)
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{   if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i)
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    {	$nasm = $1 + $2*0.01; $PTR="";  }
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/)
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    {	$masm = $1 + $2*2**-16 + $4*2**-32;   }
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    die "no assembler found on %PATH" if (!($nasm || $masm));
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $win64=1;
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $elf=0;
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $decor="\$L\$";
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $current_segment;
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $current_function;
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy %globals;
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package opcode;	# pick up opcodes
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance in enough...
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /^([a-z][a-z0-9]*)/i) {
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{op} = $1;
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    undef $self->{sz};
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($self->{op} =~ /^(movz)x?([bw]).*/) {	# movz is pain...
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} = $1;
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = $2;
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /call|jmp/) {
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = "";
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = "";
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /^v/) { # VEX
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = "";
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /movq/ && $line =~ /%xmm/) {
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = "";
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} = $1;
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{sz} = $2;
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub size {
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self = shift;
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $sz   = shift;
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{sz} = $sz if (defined($sz) && !defined($self->{sz}));
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{sz};
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self = shift;
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($gas) {
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($self->{op} eq "movz") {	# movz is pain...
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s%s%s",$self->{op},$self->{sz},shift;
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /^set/) {
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		"$self->{op}";
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} eq "ret") {
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		my $epilogue = "";
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		if ($win64 && $current_function->{abi} eq "svr4") {
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $epilogue = "movq	8(%rsp),%rdi\n\t" .
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				"movq	16(%rsp),%rsi\n\t";
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		}
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    	$epilogue . ".byte	0xf3,0xc3";
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") {
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		".p2align\t3\n\t.quad";
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } else {
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		"$self->{op}$self->{sz}";
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{op} =~ s/^movz/movzx/;
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($self->{op} eq "ret") {
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} = "";
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		if ($win64 && $current_function->{abi} eq "svr4") {
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{op} = "mov	rdi,QWORD${PTR}[8+rsp]\t;WIN64 epilogue\n\t".
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  "mov	rsi,QWORD${PTR}[16+rsp]\n\t";
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    	}
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} =~ /^(pop|push)f/) {
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} .= $self->{sz};
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") {
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{op} = "\tDQ";
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{op};
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub mnemonic {
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self=shift;
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $op=shift;
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{op}=$op if (defined($op));
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{op};
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package const;	# pick up constants, which start with $
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance in enough...
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /^\$([^,]+)/) {
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} = $1;
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    	my $self = shift;
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($gas) {
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    # Solaris /usr/ccs/bin/as can't handle multiplications
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    # in $self->{value}
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    sprintf "\$%s",$self->{value};
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig;
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    sprintf "%s",$self->{value};
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package ea;		# pick up effective addresses: expr(%reg,%reg,scale)
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance in enough...
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# optional * ---vvv--- appears in indirect jmp/call
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) {
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{asterisk} = $1;
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{label} = $2;
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    ($self->{base},$self->{index},$self->{scale})=split(/,/,$3);
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{scale} = 1 if (!defined($self->{scale}));
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($win64 && $self->{label} =~ s/\@GOTPCREL//) {
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		die if (opcode->mnemonic() ne "mov");
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		opcode->mnemonic("lea");
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{base}  =~ s/^%//;
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{index} =~ s/^%// if (defined($self->{index}));
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub size {}
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    	my $self = shift;
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $sz = shift;
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{label} =~ s/\.L/$decor/g;
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# Silently convert all EAs to 64-bit. This is required for
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# elder GNU assembler and results in more compact code,
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# *but* most importantly AES module depends on this feature!
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{base}  =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# Solaris /usr/ccs/bin/as can't handle multiplications
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# in $self->{label}, new gas requires sign extension...
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	use integer;
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{label} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg;
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg;
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if (!$self->{label} && $self->{index} && $self->{scale}==1 &&
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{base} =~ /(rbp|r13)/) {
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{base} = $self->{index}; $self->{index} = $1;
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($gas) {
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{label} =~ s/^___imp_/__imp__/   if ($flavour eq "mingw64");
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if (defined($self->{index})) {
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk},
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{label},
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{base}?"%$self->{base}":"",
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{index},$self->{scale};
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } else {
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s%s(%%%s)",	$self->{asterisk},$self->{label},$self->{base};
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
2734b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    %szmap = (	b=>"BYTE$PTR",  w=>"WORD$PTR",
2744b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley			l=>"DWORD$PTR", d=>"DWORD$PTR",
2754b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    		q=>"QWORD$PTR", o=>"OWORD$PTR",
2764b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley			x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" );
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{label} =~ s/\./\$/g;
27995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{label} =~ s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/ig;
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
2814b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley
2824b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    ($self->{asterisk})					&& ($sz="q") ||
2834b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    (opcode->mnemonic() =~ /^v?mov([qd])$/)		&& ($sz=$1)  ||
2844b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    (opcode->mnemonic() =~ /^v?pinsr([qdwb])$/)		&& ($sz=$1)  ||
2854b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    (opcode->mnemonic() =~ /^vpbroadcast([qdwb])$/)	&& ($sz=$1)  ||
2864b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	    (opcode->mnemonic() =~ /^vinsert[fi]128$/)		&& ($sz="x");
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if (defined($self->{index})) {
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s[%s%s*%d%s]",$szmap{$sz},
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{label}?"$self->{label}+":"",
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{index},$self->{scale},
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{base}?"+$self->{base}":"";
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } elsif ($self->{base} eq "rip") {
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s[%s]",$szmap{$sz},$self->{label};
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } else {
29695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		sprintf "%s[%s%s]",$szmap{$sz},
29795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{label}?"$self->{label}+":"",
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{base};
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package register;	# pick up registers, which start with %.
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$class = shift;	# muliple instances...
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = {};
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	# optional * ---vvv--- appears in indirect jmp/call
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /^(\*?)%(\w+)/) {
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    bless $self,$class;
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{asterisk} = $1;
31495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} = $2;
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
31795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub size {
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if    ($self->{value} =~ /^r[\d]+b$/i)	{ $ret="b"; }
32595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^r[\d]+w$/i)	{ $ret="w"; }
32695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^r[\d]+d$/i)	{ $ret="l"; }
32795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^r[\w]+$/i)	{ $ret="q"; }
32895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; }
32995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^[\w]{2}l$/i)	{ $ret="b"; }
33095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^[\w]{2}$/i)	{ $ret="w"; }
33195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; }
33295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
33495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
33595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
33695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    	my $self = shift;
33795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($gas)	{ sprintf "%s%%%s",$self->{asterisk},$self->{value}; }
33895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	else		{ $self->{value}; }
33995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
34095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
34195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package label;	# pick up labels, which end with :
34295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
34395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance is enough...
34495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
34595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
34695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /(^[\.\w]+)\:/) {
34895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} = $1;
34995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
35095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
35195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/^\.L/$decor/;
35395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
35495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
35595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
35695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
35795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self = shift;
35895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($gas) {
36095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    my $func = ($globals{$self->{value}} or $self->{value}) . ":";
36195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($win64	&&
36295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			$current_function->{name} eq $self->{value} &&
36395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			$current_function->{abi} eq "svr4") {
36495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "\n";
36595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%rdi,8(%rsp)\n";
36695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%rsi,16(%rsp)\n";
36795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%rsp,%rax\n";
36895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "${decor}SEH_begin_$current_function->{name}:\n";
36995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		my $narg = $current_function->{narg};
37095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$narg=6 if (!defined($narg));
37195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%rcx,%rdi\n" if ($narg>0);
37295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%rdx,%rsi\n" if ($narg>1);
37395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%r8,%rdx\n"  if ($narg>2);
37495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	%r9,%rcx\n"  if ($narg>3);
37595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	40(%rsp),%r8\n" if ($narg>4);
37695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$func .= "	movq	48(%rsp),%r9\n" if ($narg>5);
37795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
37895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func;
37995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} elsif ($self->{value} ne "$current_function->{name}") {
38095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} .= ":" if ($masm && $ret!~m/^\$/);
38195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} . ":";
38295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} elsif ($win64 && $current_function->{abi} eq "svr4") {
38395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    my $func =	"$current_function->{name}" .
38495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			($nasm ? ":" : "\tPROC $current_function->{scope}") .
38595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"\n";
38695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n";
38795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	QWORD${PTR}[16+rsp],rsi\n";
38895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	rax,rsp\n";
38995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "${decor}SEH_begin_$current_function->{name}:";
39095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= ":" if ($masm);
39195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "\n";
39295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    my $narg = $current_function->{narg};
39395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $narg=6 if (!defined($narg));
39495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	rdi,rcx\n" if ($narg>0);
39595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	rsi,rdx\n" if ($narg>1);
39695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	rdx,r8\n"  if ($narg>2);
39795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	rcx,r9\n"  if ($narg>3);
39895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	r8,QWORD${PTR}[40+rsp]\n" if ($narg>4);
39995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "	mov	r9,QWORD${PTR}[48+rsp]\n" if ($narg>5);
40095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $func .= "\n";
40195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
40295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	   "$current_function->{name}".
40395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			($nasm ? ":" : "\tPROC $current_function->{scope}");
40495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
40595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
40695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
40795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package expr;		# pick up expressioins
40895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
40995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance is enough...
41095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
41195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
41295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
41395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /(^[^,]+)/) {
41495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} = $1;
41595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
41695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
41795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
41895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/\@PLT// if (!$elf);
41995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
42095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value} =~ s/\.L/$decor/g;
42195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
42295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
42395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
42495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
42595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self = shift;
42695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) {
42795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    "NEAR ".$self->{value};
42895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
42995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $self->{value};
43095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
43195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
43295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
43395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{ package directive;	# pick up directives, which start with .
43495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub re {
43595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$self = shift;	# single instance is enough...
43695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	local	*line = shift;
43795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef	$ret;
43895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	$dir;
43995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my	%opcode =	# lea 2f-1f(%rip),%dst; 1: nop; 2:
44095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		(	"%rax"=>0x01058d48,	"%rcx"=>0x010d8d48,
44195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%rdx"=>0x01158d48,	"%rbx"=>0x011d8d48,
44295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%rsp"=>0x01258d48,	"%rbp"=>0x012d8d48,
44395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%rsi"=>0x01358d48,	"%rdi"=>0x013d8d48,
44495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%r8" =>0x01058d4c,	"%r9" =>0x010d8d4c,
44595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%r10"=>0x01158d4c,	"%r11"=>0x011d8d4c,
44695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%r12"=>0x01258d4c,	"%r13"=>0x012d8d4c,
44795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			"%r14"=>0x01358d4c,	"%r15"=>0x013d8d4c	);
44895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
44995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($line =~ /^\s*(\.\w+)/) {
45095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $dir = $1;
45195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $ret = $self;
45295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    undef $self->{value};
45395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = substr($line,@+[0]); $line =~ s/^\s+//;
45495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
45595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    SWITCH: for ($dir) {
45695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) {
45795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			    		$dir="\t.long";
45895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$line=sprintf "0x%x,0x90000000",$opcode{$1};
45995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
46095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
46195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
46295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.global|\.globl|\.extern/
46395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			    && do { $globals{$line} = $prefix . $line;
46495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line = $globals{$line} if ($prefix);
46595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
46695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
46795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.type/    && do { ($sym,$type,$narg) = split(',',$line);
46895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    if ($type eq "\@function") {
46995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					undef $current_function;
47095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{name} = $sym;
47195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{abi}  = "svr4";
47295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{narg} = $narg;
47395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
47495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    } elsif ($type eq "\@abi-omnipotent") {
47595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					undef $current_function;
47695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{name} = $sym;
47795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
47895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
47995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line =~ s/\@abi\-omnipotent/\@function/;
48095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line =~ s/\@function.*/\@function/;
48195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
48295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
48395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.asciz/   && do { if ($line =~ /^"(.*)"$/) {
48495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$dir  = ".byte";
48595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$line = join(",",unpack("C*",$1),0);
48695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
48795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
48895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
48995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.rva|\.long|\.quad/
49095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			    && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
49195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line =~ s/\.L/$decor/g;
49295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
49395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
49495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
49595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
49695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($gas) {
49795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$self->{value} = $dir . "\t" . $line;
49895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
49995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		if ($dir =~ /\.extern/) {
50095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = ""; # swallow extern
50195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif (!$elf && $dir =~ /\.type/) {
50295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = "";
50395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" .
50495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				(defined($globals{$1})?".scl 2;":".scl 3;") .
50595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				"\t.type 32;\t.endef"
50695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				if ($win64 && $line =~ /([^,]+),\@function/);
50795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif (!$elf && $dir =~ /\.size/) {
50895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = "";
50995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if (defined($current_function)) {
51095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			$self->{value} .= "${decor}SEH_end_$current_function->{name}:"
51195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				if ($win64 && $current_function->{abi} eq "svr4");
51295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			undef $current_function;
51395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    }
51495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif (!$elf && $dir =~ /\.align/) {
51595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = ".p2align\t" . (log($line)/log(2));
51695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif ($dir eq ".section") {
51795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $current_segment=$line;
51895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if (!$elf && $current_segment eq ".init") {
51995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			if	($flavour eq "macosx")	{ $self->{value} = ".mod_init_func"; }
52095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			elsif	($flavour eq "mingw64")	{ $self->{value} = ".section\t.ctors"; }
52195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    }
52295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif ($dir =~ /\.(text|data)/) {
52395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $current_segment=".$1";
524eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		} elsif ($dir =~ /\.global|\.globl|\.extern/) {
525eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		    if ($flavour eq "macosx") {
526eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		        $self->{value} .= "\n.private_extern $line";
527eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		    } else {
528eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		        $self->{value} .= "\n.hidden $line";
529eb7d2ed1fe8a33b3e3871502ba7e12efaf94360cAdam Langley		    }
53095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif ($dir =~ /\.hidden/) {
53195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if    ($flavour eq "macosx")  { $self->{value} = ".private_extern\t$prefix$line"; }
53295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    elsif ($flavour eq "mingw64") { $self->{value} = ""; }
53395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		} elsif ($dir =~ /\.comm/) {
53495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} = "$dir\t$prefix$line";
53595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx");
53695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		}
53795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$line = "";
53895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		return $self;
53995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
54095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
54195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    # non-gas case or nasm/masm
54295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    SWITCH: for ($dir) {
54395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.text/    && do { my $v=undef;
54495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    if ($nasm) {
54595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="section	.text code align=64\n";
54695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    } else {
54795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="$current_segment\tENDS\n" if ($current_segment);
54895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_segment = ".text\$";
54995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="$current_segment\tSEGMENT ";
5504b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley					$v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE";
55195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.=" 'CODE'";
55295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
55395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} = $v;
55495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
55595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
55695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.data/    && do { my $v=undef;
55795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    if ($nasm) {
55895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="section	.data data align=8\n";
55995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    } else {
56095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="$current_segment\tENDS\n" if ($current_segment);
56195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_segment = "_DATA";
56295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="$current_segment\tSEGMENT";
56395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
56495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} = $v;
56595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
56695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
56795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.section/ && do { my $v=undef;
56895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line =~ s/([^,]*).*/$1/;
56995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $line = ".CRT\$XCU" if ($line eq ".init");
57095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    if ($nasm) {
57195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="section	$line";
57295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					if ($line=~/\.([px])data/) {
57395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=" rdata align=";
57495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=$1 eq "p"? 4 : 8;
57595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					} elsif ($line=~/\.CRT\$/i) {
57695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=" rdata align=8";
57795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					}
57895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    } else {
57995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="$current_segment\tENDS\n" if ($current_segment);
58095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="$line\tSEGMENT";
58195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					if ($line=~/\.([px])data/) {
58295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=" READONLY";
58395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
58495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					} elsif ($line=~/\.CRT\$/i) {
58595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=" READONLY ";
58695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD";
58795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					}
58895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
58995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $current_segment = $line;
59095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} = $v;
59195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
59295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
59395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.extern/  && do { $self->{value}  = "EXTERN\t".$line;
59495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} .= ":NEAR" if ($masm);
59595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
59695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
59795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.globl|.global/
59895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			    && do { $self->{value}  = $masm?"PUBLIC":"global";
59995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} .= "\t".$line;
60095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
60195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
60295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.size/    && do { if (defined($current_function)) {
60395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					undef $self->{value};
60495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					if ($current_function->{abi} eq "svr4") {
60595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $self->{value}="${decor}SEH_end_$current_function->{name}:";
60695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					    $self->{value}.=":\n" if($masm);
60795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					}
60895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name});
60995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					undef $current_function;
61095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
61195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
61295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
61395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.align/   && do { $self->{value} = "ALIGN\t".$line; last; };
61495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.(value|long|rva|quad)/
61595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			    && do { my $sz  = substr($1,0,1);
61695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    my @arr = split(/,\s*/,$line);
61795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    my $last = pop(@arr);
61895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    my $conv = sub  {	my $var=shift;
61995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley							$var=~s/^(0b[0-1]+)/oct($1)/eig;
62095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley							$var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm);
62195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley							if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva"))
62295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley							{ $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
62395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley							$var;
62495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley						    };
62595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
62695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $sz =~ tr/bvlrq/BWDDQ/;
62795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} = "\tD$sz\t";
62895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    for (@arr) { $self->{value} .= &$conv($_).","; }
62995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} .= &$conv($last);
63095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
63195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
63295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.byte/    && do { my @str=split(/,\s*/,$line);
63395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    map(s/(0b[0-1]+)/oct($1)/eig,@str);
63495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm);
63595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    while ($#str>15) {
63695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$self->{value}.="DB\t"
63795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley						.join(",",@str[0..15])."\n";
63895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					foreach (0..15) { shift @str; }
63995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
64095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value}.="DB\t"
64195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley						.join(",",@str) if (@str);
64295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
64395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
64495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		/\.comm/    && do { my @str=split(/,\s*/,$line);
64595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    my $v=undef;
64695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    if ($nasm) {
64795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="common	$prefix@str[0] @str[1]";
64895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    } else {
64995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v="$current_segment\tENDS\n" if ($current_segment);
65095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$current_segment = "_DATA";
65195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="$current_segment\tSEGMENT\n";
65295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley					$v.="COMM	@str[0]:DWORD:".@str[1]/4;
65395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    }
65495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    $self->{value} = $v;
65595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				    last;
65695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley				  };
65795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
65895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    $line = "";
65995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
66095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
66195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$ret;
66295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
66395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    sub out {
66495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $self = shift;
66595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$self->{value};
66695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
66795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
66895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
66995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleysub rex {
67095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley local *opcode=shift;
67195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley my ($dst,$src,$rex)=@_;
67295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
67395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rex|=0x04 if($dst>=8);
67495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rex|=0x01 if($src>=8);
67595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   push @opcode,($rex|0x40) if ($rex);
67695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
67795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
67895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# older gas and ml64 don't handle SSE>2 instructions
67995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy %regrm = (	"%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3,
68095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		"%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7	);
68195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
68295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $movq = sub {	# elderly gas can't handle inter-register movq
68395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  my $arg = shift;
68495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  my @opcode=(0x66);
68595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) {
68695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my ($src,$dst)=($1,$2);
68795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($dst !~ /[0-9]+/)	{ $dst = $regrm{"%e$dst"}; }
68895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$src,$dst,0x8);
68995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x7e;
69095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
69195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
69295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) {
69395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my ($src,$dst)=($2,$1);
69495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($dst !~ /[0-9]+/)	{ $dst = $regrm{"%e$dst"}; }
69595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$src,$dst,0x8);
69695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x6e;
69795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
69895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
69995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
70095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
70195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
70295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
70395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
70495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $pextrd = sub {
70595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) {
70695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x66);
70795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$imm=$1;
70895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$src=$2;
70995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$dst=$3;
71095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($dst =~ /%r([0-9]+)d/)	{ $dst = $1; }
71195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($dst =~ /%e/)		{ $dst = $regrm{$dst}; }
71295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$src,$dst);
71395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x3a,0x16;
71495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
71595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$imm;
71695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
71795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
71895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
71995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
72095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
72195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
72295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $pinsrd = sub {
72395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) {
72495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x66);
72595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$imm=$1;
72695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$src=$2;
72795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$dst=$3;
72895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($src =~ /%r([0-9]+)/)	{ $src = $1; }
72995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($src =~ /%e/)		{ $src = $regrm{$src}; }
73095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$dst,$src);
73195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x3a,0x22;
73295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|(($dst&7)<<3)|($src&7);	# ModR/M
73395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$imm;
73495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
73595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
73695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
73795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
73895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
73995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
74095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $pshufb = sub {
74195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
74295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x66);
74395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$2,$1);
74495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x38,0x00;
74595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
74695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
74795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
74895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
74995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
75095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
75195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
75295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $palignr = sub {
75395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
75495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x66);
75595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$3,$2);
75695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x3a,0x0f;
75795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
75895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$1;
75995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
76095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
76195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
76295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
76395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
76495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
76595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $pclmulqdq = sub {
76695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
76795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x66);
76895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,$3,$2);
76995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0x3a,0x44;
77095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
77195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $c=$1;
77295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$c=~/^0/?oct($c):$c;
77395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
77495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
77595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
77695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
77795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
77895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
77995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $rdrand = sub {
78095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /%[er](\w+)/) {
78195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=();
78295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my $dst=$1;
78395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
78495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rex(\@opcode,0,$1,8);
78595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x0f,0xc7,0xf0|($dst&7);
78695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
78795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
78895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
78995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
79095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
79195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7924b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langleymy $rdseed = sub {
7934b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley    if (shift =~ /%[er](\w+)/) {
7944b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley      my @opcode=();
7954b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley      my $dst=$1;
7964b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
7974b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	rex(\@opcode,0,$1,8);
7984b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	push @opcode,0x0f,0xc7,0xf8|($dst&7);
7994b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	@opcode;
8004b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley    } else {
8014b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley	();
8024b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley    }
8034b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley};
8044b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley
80595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleysub rxb {
80695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley local *opcode=shift;
80795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley my ($dst,$src1,$src2,$rxb)=@_;
80895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
80995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rxb|=0x7<<5;
81095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rxb&=~(0x04<<5) if($dst>=8);
81195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rxb&=~(0x01<<5) if($src1>=8);
81295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   $rxb&=~(0x02<<5) if($src2>=8);
81395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   push @opcode,$rxb;
81495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
81595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
81695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $vprotd = sub {
81795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
81895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x8f);
81995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rxb(\@opcode,$3,$2,-1,0x08);
82095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x78,0xc2;
82195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
82295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $c=$1;
82395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$c=~/^0/?oct($c):$c;
82495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
82595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
82695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
82795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
82895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
82995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
83095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleymy $vprotq = sub {
83195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
83295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      my @opcode=(0x8f);
83395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rxb(\@opcode,$3,$2,-1,0x08);
83495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0x78,0xc3;
83595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
83695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $c=$1;
83795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @opcode,$c=~/^0/?oct($c):$c;
83895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	@opcode;
83995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
84095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	();
84195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
84295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
84395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
84495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyif ($nasm) {
84595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    print <<___;
84695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleydefault	rel
84795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley%define XMMWORD
8484b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley%define YMMWORD
8494b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley%define ZMMWORD
85095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley___
85195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley} elsif ($masm) {
85295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    print <<___;
85395c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyOPTION	DOTNAME
85495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley___
85595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
85695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
85795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyprint STDOUT "#if defined(__x86_64__)\n" if ($gas);
85895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
85995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleywhile($line=<>) {
86095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
86195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    chomp($line);
86295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
86395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $line =~ s|[#!].*$||;	# get rid of asm-style comments...
86495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $line =~ s|/\*.*\*/||;	# ... and C-style comments...
86595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $line =~ s|^\s+||;		# ... and skip white spaces in beginning
86695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    $line =~ s|\s+$||;		# ... and at the end
86795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
86895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    undef $label;
86995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    undef $opcode;
87095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    undef @args;
87195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
87295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if ($label=label->re(\$line))	{ print $label->out(); }
87395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
87495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (directive->re(\$line)) {
87595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	printf "%s",directive->out();
87695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } elsif ($opcode=opcode->re(\$line)) {
87795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $asm = eval("\$".$opcode->mnemonic());
87895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	undef @bytes;
87995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
88095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) {
88195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    print $gas?".byte\t":"DB\t",join(',',@bytes),"\n";
88295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    next;
88395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
88495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
88595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	ARGUMENT: while (1) {
88695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	my $arg;
88795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
88895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($arg=register->re(\$line))	{ opcode->size($arg->size()); }
88995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($arg=const->re(\$line))	{ }
89095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($arg=ea->re(\$line))	{ }
89195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	elsif ($arg=expr->re(\$line))	{ }
89295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	else				{ last ARGUMENT; }
89395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
89495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	push @args,$arg;
89595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
89695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	last ARGUMENT if ($line !~ /^,/);
89795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
89895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	$line =~ s/^,\s*//;
89995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} # ARGUMENT:
90095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
90195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ($#args>=0) {
90295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    my $insn;
90395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    my $sz=opcode->size();
90495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
90595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    if ($gas) {
90695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$insn = $opcode->out($#args>=1?$args[$#args]->size():$sz);
90795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		@args = map($_->out($sz),@args);
90895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		printf "\t%s\t%s",$insn,join(",",@args);
90995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    } else {
91095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		$insn = $opcode->out();
91195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		foreach (@args) {
91295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    my $arg = $_->out();
91395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    # $insn.=$sz compensates for movq, pinsrw, ...
91495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; }
91595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; }
9164b5979b3fa02446964fdc1cff7ff972fa796e17dAdam Langley		    if ($arg =~ /^zmm[0-9]+$/) { $insn.=$sz; $sz="z" if(!$sz); last; }
91795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		    if ($arg =~ /^mm[0-9]+$/)  { $insn.=$sz; $sz="q" if(!$sz); last; }
91895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		}
91995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		@args = reverse(@args);
92095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		undef $sz if ($nasm && $opcode->mnemonic() eq "lea");
921ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley
922ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		if ($insn eq "movq" && $#args == 1 && $args[0]->out($sz) eq "xmm0" && $args[1]->out($sz) eq "rax") {
923ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		    # I have no clue why MASM can't parse this instruction.
924ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		    printf "DB 66h, 48h, 0fh, 6eh, 0c0h";
925ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		} else {
926ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		    printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args));
927ded93581f1674f81faa0dba4b15a842756066ab2Adam Langley		}
92895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    }
92995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
93095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	    printf "\t%s",$opcode->out();
93195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
93295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
93395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
93495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    print $line,"\n";
93595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
93695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
93795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyprint "\n$current_segment\tENDS\n"	if ($current_segment && $masm);
93895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyprint "END\n"				if ($masm);
9391195796045e1f8bbd1ed311b2cbd8b9d87f2074aDavid Benjaminprint "#endif\n"			if ($gas);
94095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
94195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
94295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyclose STDOUT;
94395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
94495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#################################################
94595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Cross-reference x86_64 ABI "card"
94695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
94795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 		Unix		Win64
94895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rax		*		*
94995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rbx		-		-
95095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rcx		#4		#1
95195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rdx		#3		#2
95295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rsi		#2		-
95395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rdi		#1		-
95495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rbp		-		-
95595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rsp		-		-
95695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r8		#5		#3
95795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r9		#6		#4
95895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r10		*		*
95995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r11		*		*
96095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r12		-		-
96195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r13		-		-
96295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r14		-		-
96395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %r15		-		-
96495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
96595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# (*)	volatile register
96695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# (-)	preserved by callee
96795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# (#)	Nth argument, volatile
96895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
96995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# In Unix terms top of stack is argument transfer area for arguments
97095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# which could not be accomodated in registers. Or in other words 7th
97195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# [integer] argument resides at 8(%rsp) upon function entry point.
97295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 128 bytes above %rsp constitute a "red zone" which is not touched
97395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# by signal handlers and can be used as temporal storage without
97495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# allocating a frame.
97595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
97695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# In Win64 terms N*8 bytes on top of stack is argument transfer area,
97795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# which belongs to/can be overwritten by callee. N is the number of
97895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# arguments passed to callee, *but* not less than 4! This means that
97995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# upon function entry point 5th argument resides at 40(%rsp), as well
98095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# as that 32 bytes from 8(%rsp) can always be used as temporal
98195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# storage [without allocating a frame]. One can actually argue that
98295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# one can assume a "red zone" above stack pointer under Win64 as well.
98395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Point is that at apparently no occasion Windows kernel would alter
98495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# the area above user stack pointer in true asynchronous manner...
98595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
98695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# All the above means that if assembler programmer adheres to Unix
98795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# register and stack layout, but disregards the "red zone" existense,
98895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# it's possible to use following prologue and epilogue to "gear" from
98995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Unix to Win64 ABI in leaf functions with not more than 6 arguments.
99095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
99195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# omnipotent_function:
99295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# ifdef WIN64
99395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rdi,8(%rsp)
99495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rsi,16(%rsp)
99595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rcx,%rdi	; if 1st argument is actually present
99695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rdx,%rsi	; if 2nd argument is actually ...
99795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%r8,%rdx	; if 3rd argument is ...
99895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%r9,%rcx	; if 4th argument ...
99995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	40(%rsp),%r8	; if 5th ...
100095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	48(%rsp),%r9	; if 6th ...
100195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# endif
100295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	...
100395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# ifdef WIN64
100495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	8(%rsp),%rdi
100595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	16(%rsp),%rsi
100695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# endif
100795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	ret
100895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
100995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#################################################
101095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Win64 SEH, Structured Exception Handling.
101195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
101295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Unlike on Unix systems(*) lack of Win64 stack unwinding information
101395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# has undesired side-effect at run-time: if an exception is raised in
101495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# assembler subroutine such as those in question (basically we're
101595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# referring to segmentation violations caused by malformed input
101695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# parameters), the application is briskly terminated without invoking
101795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# any exception handlers, most notably without generating memory dump
101895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# or any user notification whatsoever. This poses a problem. It's
101995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# possible to address it by registering custom language-specific
102095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# handler that would restore processor context to the state at
102195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# subroutine entry point and return "exception is not handled, keep
102295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# unwinding" code. Writing such handler can be a challenge... But it's
102395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# doable, though requires certain coding convention. Consider following
102495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# snippet:
102595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
102695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# .type	function,@function
102795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# function:
102895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rsp,%rax	# copy rsp to volatile register
102995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	pushq	%r15		# save non-volatile registers
103095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	pushq	%rbx
103195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	pushq	%rbp
103295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rsp,%r11
103395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	subq	%rdi,%r11	# prepare [variable] stack frame
103495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	andq	$-64,%r11
103595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rax,0(%r11)	# check for exceptions
103695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%r11,%rsp	# allocate [variable] stack frame
103795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rax,0(%rsp)	# save original rsp value
103895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# magic_point:
103995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	...
104095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	0(%rsp),%rcx	# pull original rsp value
104195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	-24(%rcx),%rbp	# restore non-volatile registers
104295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	-16(%rcx),%rbx
104395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	-8(%rcx),%r15
104495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	movq	%rcx,%rsp	# restore original rsp
104595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	ret
104695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# .size function,.-function
104795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
104895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# The key is that up to magic_point copy of original rsp value remains
104995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# in chosen volatile register and no non-volatile register, except for
105095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# rsp, is modified. While past magic_point rsp remains constant till
105195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# the very end of the function. In this case custom language-specific
105295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# exception handler would look like this:
105395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
105495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
105595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
105695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# {	ULONG64 *rsp = (ULONG64 *)context->Rax;
105795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	if (context->Rip >= magic_point)
105895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	{   rsp = ((ULONG64 **)context->Rsp)[0];
105995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	    context->Rbp = rsp[-3];
106095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	    context->Rbx = rsp[-2];
106195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	    context->R15 = rsp[-1];
106295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	}
106395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	context->Rsp = (ULONG64)rsp;
106495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	context->Rdi = rsp[1];
106595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	context->Rsi = rsp[2];
106695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
106795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	memcpy (disp->ContextRecord,context,sizeof(CONTEXT));
106895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase,
106995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#		dips->ControlPc,disp->FunctionEntry,disp->ContextRecord,
107095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#		&disp->HandlerData,&disp->EstablisherFrame,NULL);
107195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	return ExceptionContinueSearch;
107295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# }
107395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
107495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# It's appropriate to implement this handler in assembler, directly in
107595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# function's module. In order to do that one has to know members'
107695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant
107795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# values. Here they are:
107895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
107995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rax				120
108095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rcx				128
108195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rdx				136
108295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rbx				144
108395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rsp				152
108495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rbp				160
108595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rsi				168
108695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rdi				176
108795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R8				184
108895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R9				192
108995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R10				200
109095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R11				208
109195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R12				216
109295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R13				224
109395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R14				232
109495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.R15				240
109595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Rip				248
109695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	CONTEXT.Xmm6				512
109795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	sizeof(CONTEXT)				1232
109895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.ControlPc		0
109995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.ImageBase		8
110095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.FunctionEntry	16
110195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.EstablisherFrame	24
110295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.TargetIp		32
110395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.ContextRecord	40
110495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.LanguageHandler	48
110595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	DISPATCHER_CONTEXT.HandlerData		56
110695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	UNW_FLAG_NHANDLER			0
110795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	ExceptionContinueSearch			1
110895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
110995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# In order to tie the handler to the function one has to compose
111095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# couple of structures: one for .xdata segment and one for .pdata.
111195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
111295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# UNWIND_INFO structure for .xdata segment would be
111395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
111495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# function_unwind_info:
111595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	.byte	9,0,0,0
111695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	.rva	handler
111795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
111895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# This structure designates exception handler for a function with
111995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# zero-length prologue, no stack frame or frame register.
112095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
112195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# To facilitate composing of .pdata structures, auto-generated "gear"
112295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# prologue copies rsp value to rax and denotes next instruction with
112395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# .LSEH_begin_{function_name} label. This essentially defines the SEH
112495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# styling rule mentioned in the beginning. Position of this label is
112595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# chosen in such manner that possible exceptions raised in the "gear"
112695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# prologue would be accounted to caller and unwound from latter's frame.
112795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# End of function is marked with respective .LSEH_end_{function_name}
112895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# label. To summarize, .pdata segment would contain
112995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
113095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	.rva	.LSEH_begin_function
113195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	.rva	.LSEH_end_function
113295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	.rva	function_unwind_info
113395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
113495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Reference to functon_unwind_info from .xdata segment is the anchor.
113595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# In case you wonder why references are 32-bit .rvas and not 64-bit
113695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# .quads. References put into these two segments are required to be
113795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# *relative* to the base address of the current binary module, a.k.a.
113895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# image base. No Win64 module, be it .exe or .dll, can be larger than
113995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 2GB and thus such relative references can be and are accommodated in
114095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# 32 bits.
114195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
114295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Having reviewed the example function code, one can argue that "movq
114395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix
114495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# rax would contain an undefined value. If this "offends" you, use
114595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# another register and refrain from modifying rax till magic_point is
114695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# reached, i.e. as if it was a non-volatile register. If more registers
114795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# are required prior [variable] frame setup is completed, note that
114895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# nobody says that you can have only one "magic point." You can
114995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# "liberate" non-volatile registers by denoting last stack off-load
115095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# instruction and reflecting it in finer grade unwind logic in handler.
115195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# After all, isn't it why it's called *language-specific* handler...
115295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
115395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# Attentive reader can notice that exceptions would be mishandled in
115495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# auto-generated "gear" epilogue. Well, exception effectively can't
115595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# occur there, because if memory area used by it was subject to
115695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# segmentation violation, then it would be raised upon call to the
115795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# function (and as already mentioned be accounted to caller, which is
115895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# not a problem). If you're still not comfortable, then define tail
115995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# "magic point" just prior ret instruction and have handler treat it...
116095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#
116195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# (*)	Note that we're talking about run-time, not debug-time. Lack of
116295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	unwind information makes debugging hard on both Windows and
116395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	Unix. "Unlike" referes to the fact that on Unix signal handler
116495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	will always be invoked, core dumped and appropriate exit code
116595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#	returned to parent (for user notification).
1166