1480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#!/usr/bin/env perl 2480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 3480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgpackage x86masm; 4480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 5480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org*out=\@::out; 6480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 7480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$::lbdecor="\$L"; # local label decoration 8480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$nmdecor="_"; # external name decoration 9480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 10480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$initseg=""; 11480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$segment=""; 12480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 13480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::generic 14480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my ($opcode,@arg)=@_; 15480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 16480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org # fix hexadecimal constants 172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; } 18480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/) # no [] 202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org { $opcode="mov"; } 212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org elsif ($opcode !~ /movq/) 22480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { # fix xmm references 23480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[1]=~/\bxmm[0-7]\b/i); 24480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $arg[1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i); 25480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org } 26480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 27480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org &::emit($opcode,@arg); 28480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 1; 29480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 30480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 31480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# opcodes not covered by ::generic above, mostly inconsistent namings... 32480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 33480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); } 34480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::call_ptr { &::emit("call",@_); } 35480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::jmp_ptr { &::emit("jmp",@_); } 367453c6c0666947e06d87565404f4397a4b387f91digit@chromium.orgsub ::lock { &::data_byte(0xf0); } 37480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 38480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub get_mem 39480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my($size,$addr,$reg1,$reg2,$idx)=@_; 40480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org my($post,$ret); 41480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 42480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret .= "$size PTR " if ($size ne ""); 43480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 44480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $addr =~ s/^\s+//; 45480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org # prepend global references with optional underscore 46480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige; 47480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org # put address arithmetic expression in parenthesis 48480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/); 49480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 50480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org if (($addr ne "") && ($addr ne 0)) 51480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { if ($addr !~ /^-/) { $ret .= "$addr"; } 52480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org else { $post=$addr; } 53480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org } 54480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret .= "["; 55480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 56480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org if ($reg2 ne "") 57480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { $idx!=0 or $idx=1; 58480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret .= "$reg2*$idx"; 59480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret .= "+$reg1" if ($reg1 ne ""); 60480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org } 61480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org else 62480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { $ret .= "$reg1"; } 63480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 64480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret .= "$post]"; 65480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret =~ s/\+\]/]/; # in case $addr was the only argument 66480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret =~ s/\[\s*\]//; 67480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 68480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $ret; 69480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 70480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::BP { &get_mem("BYTE",@_); } 712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::WP { &get_mem("WORD",@_); } 72480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::DWP { &get_mem("DWORD",@_); } 73480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::QWP { &get_mem("QWORD",@_); } 74480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::BC { "@_"; } 75480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::DWC { "@_"; } 76480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 77480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::file 78480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $tmp=<<___; 79480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgTITLE $_[0].asm 80480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800 81480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgECHO MASM version 8.00 or later is strongly recommended. 82480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF 83480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.486 84480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.MODEL FLAT 85480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgOPTION DOTNAME 86480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800 87480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.text\$ SEGMENT PAGE 'CODE' 88480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgELSE 89480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.text\$ SEGMENT ALIGN(64) 'CODE' 90480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF 91480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___ 92480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push(@out,$tmp); 93480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $segment = ".text\$"; 94480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 95480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 96480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::function_begin_B 97480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $func=shift; 98480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org my $global=($func !~ /^_/); 99480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org my $begin="${::lbdecor}_${func}_begin"; 100480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 101480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org &::LABEL($func,$global?"$begin":"$nmdecor$func"); 102480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $func="ALIGN\t16\n".$nmdecor.$func."\tPROC"; 103480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 104480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org if ($global) { $func.=" PUBLIC\n${begin}::\n"; } 105480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org else { $func.=" PRIVATE\n"; } 106480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push(@out,$func); 107480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $::stack=4; 108480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 109480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::function_end_B 110480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $func=shift; 111480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 112480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push(@out,"$nmdecor$func ENDP\n"); 113480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $::stack=0; 114480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org &::wipe_labels(); 115480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 116480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 117480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::file_end 118480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $xmmheader=<<___; 119480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.686 120480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.XMM 121480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgIF \@Version LT 800 122480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgXMMWORD STRUCT 16 123480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgDQ 2 dup (?) 124480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgXMMWORD ENDS 125480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgENDIF 126480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___ 127480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org if (grep {/\b[x]?mm[0-7]\b/i} @out) { 128480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org grep {s/\.[3-7]86/$xmmheader/} @out; 129480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org } 130480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 131480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push(@out,"$segment ENDS\n"); 132480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 133480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) 134480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { my $comm=<<___; 135480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.bss SEGMENT 'BSS' 1362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgCOMM ${nmdecor}OPENSSL_ia32cap_P:QWORD 137480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.bss ENDS 138480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___ 139480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org # comment out OPENSSL_ia32cap_P declarations 140480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out; 141480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push (@out,$comm); 142480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org } 143480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push (@out,$initseg) if ($initseg); 144480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org push (@out,"END\n"); 145480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 146480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 147480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } } 148480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 149480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org*::set_label_B = sub 150480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); }; 151480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 152480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::external_label 153480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ foreach(@_) 154480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org { push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n"); } 155480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 156480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 157480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::public_label 158480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); } 159480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 160480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::data_byte 161480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ push(@out,("DB\t").join(',',@_)."\n"); } 162480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 1632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::data_short 1642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{ push(@out,("DW\t").join(',',@_)."\n"); } 1652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org 166480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::data_word 167480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ push(@out,("DD\t").join(',',@_)."\n"); } 168480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 169480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::align 170480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ push(@out,"ALIGN\t$_[0]\n"); } 171480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 172480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::picmeup 173480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my($dst,$sym)=@_; 174480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org &::lea($dst,&::DWP($sym)); 175480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 176480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 177480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::initseg 178480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ my $f=$nmdecor.shift; 179480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 180480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org $initseg.=<<___; 181480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.CRT\$XCU SEGMENT DWORD PUBLIC 'DATA' 182480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgEXTERN $f:NEAR 183480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgDD $f 184480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.CRT\$XCU ENDS 185480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___ 186480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org} 187480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 188480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub ::dataseg 189480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org{ push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA"; } 190480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org 1912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsub ::safeseh 1922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{ my $nm=shift; 1932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org push(@out,"IF \@Version GE 710\n"); 1942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org push(@out,".SAFESEH ".&::LABEL($nm,$nmdecor.$nm)."\n"); 1952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org push(@out,"ENDIF\n"); 1962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org} 1972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org 198480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org1; 199