x86masm.pl 4.3 KB
Newer Older
A
Andy Polyakov 已提交
1 2 3 4 5 6 7 8 9 10
#!/usr/bin/env perl

package x86masm;

*out=\@::out;

$::lbdecor="\$L";	# local label decoration
$nmdecor="_";		# external name decoration

$initseg="";
11
$segment="";
A
Andy Polyakov 已提交
12 13 14 15 16

sub ::generic
{ my ($opcode,@arg)=@_;

    # fix hexadecimal constants
17
    for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
A
Andy Polyakov 已提交
18

19
    if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/)	# no []
20 21
    {	$opcode="mov";	}
    elsif ($opcode !~ /movq/)
A
Andy Polyakov 已提交
22 23 24 25
    {	# fix xmm references
	$arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[1]=~/\bxmm[0-7]\b/i);
	$arg[1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i);
    }
A
Andy Polyakov 已提交
26

A
Andy Polyakov 已提交
27 28 29 30 31 32 33 34 35
    &::emit($opcode,@arg);
  1;
}
#
# opcodes not covered by ::generic above, mostly inconsistent namings...
#
sub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
sub ::call_ptr	{ &::emit("call",@_);	}
sub ::jmp_ptr	{ &::emit("jmp",@_);	}
36
sub ::lock	{ &::data_byte(0xf0);	}
A
Andy Polyakov 已提交
37 38 39 40 41

sub get_mem
{ my($size,$addr,$reg1,$reg2,$idx)=@_;
  my($post,$ret);

42 43
    if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }

A
Andy Polyakov 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    $ret .= "$size PTR " if ($size ne "");

    $addr =~ s/^\s+//;
    # prepend global references with optional underscore
    $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
    # put address arithmetic expression in parenthesis
    $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);

    if (($addr ne "") && ($addr ne 0))
    {	if ($addr !~ /^-/)	{ $ret .= "$addr";  }
	else			{ $post=$addr;      }
    }
    $ret .= "[";

    if ($reg2 ne "")
    {	$idx!=0 or $idx=1;
	$ret .= "$reg2*$idx";
	$ret .= "+$reg1" if ($reg1 ne "");
    }
    else
    {	$ret .= "$reg1";   }

    $ret .= "$post]";
    $ret =~ s/\+\]/]/; # in case $addr was the only argument
    $ret =~ s/\[\s*\]//;

  $ret;
}
sub ::BP	{ &get_mem("BYTE",@_);  }
73
sub ::WP	{ &get_mem("WORD",@_);	}
A
Andy Polyakov 已提交
74 75 76 77 78 79 80 81
sub ::DWP	{ &get_mem("DWORD",@_); }
sub ::QWP	{ &get_mem("QWORD",@_); }
sub ::BC	{ "@_";  }
sub ::DWC	{ "@_"; }

sub ::file
{ my $tmp=<<___;
TITLE	$_[0].asm
A
Andy Polyakov 已提交
82 83 84
IF \@Version LT 800
ECHO MASM version 8.00 or later is strongly recommended.
ENDIF
A
Andy Polyakov 已提交
85 86 87
.486
.MODEL	FLAT
OPTION	DOTNAME
A
Andy Polyakov 已提交
88
IF \@Version LT 800
89
.text\$	SEGMENT PAGE 'CODE'
A
Andy Polyakov 已提交
90 91 92
ELSE
.text\$	SEGMENT ALIGN(64) 'CODE'
ENDIF
A
Andy Polyakov 已提交
93 94
___
    push(@out,$tmp);
95
    $segment = ".text\$";
A
Andy Polyakov 已提交
96 97 98 99 100 101 102 103
}

sub ::function_begin_B
{ my $func=shift;
  my $global=($func !~ /^_/);
  my $begin="${::lbdecor}_${func}_begin";

    &::LABEL($func,$global?"$begin":"$nmdecor$func");
104
    $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
A
Andy Polyakov 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

    if ($global)    { $func.=" PUBLIC\n${begin}::\n"; }
    else	    { $func.=" PRIVATE\n";            }
    push(@out,$func);
    $::stack=4;
}
sub ::function_end_B
{ my $func=shift;

    push(@out,"$nmdecor$func ENDP\n");
    $::stack=0;
    &::wipe_labels();
}

sub ::file_end
{ my $xmmheader=<<___;
.686
.XMM
IF \@Version LT 800
XMMWORD STRUCT 16
DQ	2 dup (?)
XMMWORD	ENDS
ENDIF
___
    if (grep {/\b[x]?mm[0-7]\b/i} @out) {
	grep {s/\.[3-7]86/$xmmheader/} @out;
    }

133
    push(@out,"$segment	ENDS\n");
A
Andy Polyakov 已提交
134 135 136

    if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
    {	my $comm=<<___;
137
.bss	SEGMENT 'BSS'
138
COMM	${nmdecor}OPENSSL_ia32cap_P:DWORD:4
A
Andy Polyakov 已提交
139
.bss	ENDS
A
Andy Polyakov 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
___
	# comment out OPENSSL_ia32cap_P declarations
	grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
	push (@out,$comm);
    }
    push (@out,$initseg) if ($initseg);
    push (@out,"END\n");
}

sub ::comment {   foreach (@_) { push(@out,"\t; $_\n"); }   }

*::set_label_B = sub
{ my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };

sub ::external_label
A
Andy Polyakov 已提交
155 156 157
{   foreach(@_)
    {	push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n");   }
}
A
Andy Polyakov 已提交
158 159 160 161 162 163 164

sub ::public_label
{   push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }

sub ::data_byte
{   push(@out,("DB\t").join(',',@_)."\n");	}

165 166 167
sub ::data_short
{   push(@out,("DW\t").join(',',@_)."\n");	}

A
Andy Polyakov 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
sub ::data_word
{   push(@out,("DD\t").join(',',@_)."\n");	}

sub ::align
{   push(@out,"ALIGN\t$_[0]\n");	}

sub ::picmeup
{ my($dst,$sym)=@_;
    &::lea($dst,&::DWP($sym));
}

sub ::initseg
{ my $f=$nmdecor.shift;

    $initseg.=<<___;
A
Andy Polyakov 已提交
183
.CRT\$XCU	SEGMENT DWORD PUBLIC 'DATA'
A
Andy Polyakov 已提交
184 185 186 187 188 189
EXTERN	$f:NEAR
DD	$f
.CRT\$XCU	ENDS
___
}

190 191 192
sub ::dataseg
{   push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA";   }

193 194 195 196 197 198 199
sub ::safeseh
{ my $nm=shift;
    push(@out,"IF \@Version GE 710\n");
    push(@out,".SAFESEH	".&::LABEL($nm,$nmdecor.$nm)."\n");
    push(@out,"ENDIF\n");
}

A
Andy Polyakov 已提交
200
1;