11cb0ef41Sopenharmony_ci#! /usr/bin/env perl
21cb0ef41Sopenharmony_ci# Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci#
41cb0ef41Sopenharmony_ci# Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci# this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci# in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci# https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cipackage x86masm;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci*out=\@::out;
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci$::lbdecor="\$L";	# local label decoration
151cb0ef41Sopenharmony_ci$nmdecor="_";		# external name decoration
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci$initseg="";
181cb0ef41Sopenharmony_ci$segment="";
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cisub ::generic
211cb0ef41Sopenharmony_ci{ my ($opcode,@arg)=@_;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci    # fix hexadecimal constants
241cb0ef41Sopenharmony_ci    for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci    if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/)	# no []
271cb0ef41Sopenharmony_ci    {	$opcode="mov";	}
281cb0ef41Sopenharmony_ci    elsif ($opcode !~ /mov[dq]$/)
291cb0ef41Sopenharmony_ci    {	# fix xmm references
301cb0ef41Sopenharmony_ci	$arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[-1]=~/\bxmm[0-7]\b/i);
311cb0ef41Sopenharmony_ci	$arg[-1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i);
321cb0ef41Sopenharmony_ci    }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    &::emit($opcode,@arg);
351cb0ef41Sopenharmony_ci  1;
361cb0ef41Sopenharmony_ci}
371cb0ef41Sopenharmony_ci#
381cb0ef41Sopenharmony_ci# opcodes not covered by ::generic above, mostly inconsistent namings...
391cb0ef41Sopenharmony_ci#
401cb0ef41Sopenharmony_cisub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
411cb0ef41Sopenharmony_cisub ::call_ptr	{ &::emit("call",@_);	}
421cb0ef41Sopenharmony_cisub ::jmp_ptr	{ &::emit("jmp",@_);	}
431cb0ef41Sopenharmony_cisub ::lock	{ &::data_byte(0xf0);	}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_cisub get_mem
461cb0ef41Sopenharmony_ci{ my($size,$addr,$reg1,$reg2,$idx)=@_;
471cb0ef41Sopenharmony_ci  my($post,$ret);
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci    if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci    $ret .= "$size PTR " if ($size ne "");
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci    $addr =~ s/^\s+//;
541cb0ef41Sopenharmony_ci    # prepend global references with optional underscore
551cb0ef41Sopenharmony_ci    $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
561cb0ef41Sopenharmony_ci    # put address arithmetic expression in parenthesis
571cb0ef41Sopenharmony_ci    $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci    if (($addr ne "") && ($addr ne 0))
601cb0ef41Sopenharmony_ci    {	if ($addr !~ /^-/)	{ $ret .= "$addr";  }
611cb0ef41Sopenharmony_ci	else			{ $post=$addr;      }
621cb0ef41Sopenharmony_ci    }
631cb0ef41Sopenharmony_ci    $ret .= "[";
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci    if ($reg2 ne "")
661cb0ef41Sopenharmony_ci    {	$idx!=0 or $idx=1;
671cb0ef41Sopenharmony_ci	$ret .= "$reg2*$idx";
681cb0ef41Sopenharmony_ci	$ret .= "+$reg1" if ($reg1 ne "");
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci    else
711cb0ef41Sopenharmony_ci    {	$ret .= "$reg1";   }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci    $ret .= "$post]";
741cb0ef41Sopenharmony_ci    $ret =~ s/\+\]/]/; # in case $addr was the only argument
751cb0ef41Sopenharmony_ci    $ret =~ s/\[\s*\]//;
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  $ret;
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_cisub ::BP	{ &get_mem("BYTE",@_);  }
801cb0ef41Sopenharmony_cisub ::WP	{ &get_mem("WORD",@_);	}
811cb0ef41Sopenharmony_cisub ::DWP	{ &get_mem("DWORD",@_); }
821cb0ef41Sopenharmony_cisub ::QWP	{ &get_mem("QWORD",@_); }
831cb0ef41Sopenharmony_cisub ::BC	{ "@_";  }
841cb0ef41Sopenharmony_cisub ::DWC	{ "@_"; }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cisub ::file
871cb0ef41Sopenharmony_ci{ my $tmp=<<___;
881cb0ef41Sopenharmony_ciIF \@Version LT 800
891cb0ef41Sopenharmony_ciECHO MASM version 8.00 or later is strongly recommended.
901cb0ef41Sopenharmony_ciENDIF
911cb0ef41Sopenharmony_ci.686
921cb0ef41Sopenharmony_ci.MODEL	FLAT
931cb0ef41Sopenharmony_ciOPTION	DOTNAME
941cb0ef41Sopenharmony_ciIF \@Version LT 800
951cb0ef41Sopenharmony_ci.text\$	SEGMENT PAGE 'CODE'
961cb0ef41Sopenharmony_ciELSE
971cb0ef41Sopenharmony_ci.text\$	SEGMENT ALIGN(64) 'CODE'
981cb0ef41Sopenharmony_ciENDIF
991cb0ef41Sopenharmony_ci___
1001cb0ef41Sopenharmony_ci    push(@out,$tmp);
1011cb0ef41Sopenharmony_ci    $segment = ".text\$";
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_cisub ::function_begin_B
1051cb0ef41Sopenharmony_ci{ my $func=shift;
1061cb0ef41Sopenharmony_ci  my $global=($func !~ /^_/);
1071cb0ef41Sopenharmony_ci  my $begin="${::lbdecor}_${func}_begin";
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci    &::LABEL($func,$global?"$begin":"$nmdecor$func");
1101cb0ef41Sopenharmony_ci    $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci    if ($global)    { $func.=" PUBLIC\n${begin}::\n"; }
1131cb0ef41Sopenharmony_ci    else	    { $func.=" PRIVATE\n";            }
1141cb0ef41Sopenharmony_ci    push(@out,$func);
1151cb0ef41Sopenharmony_ci    $::stack=4;
1161cb0ef41Sopenharmony_ci}
1171cb0ef41Sopenharmony_cisub ::function_end_B
1181cb0ef41Sopenharmony_ci{ my $func=shift;
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    push(@out,"$nmdecor$func ENDP\n");
1211cb0ef41Sopenharmony_ci    $::stack=0;
1221cb0ef41Sopenharmony_ci    &::wipe_labels();
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_cisub ::file_end
1261cb0ef41Sopenharmony_ci{ my $xmmheader=<<___;
1271cb0ef41Sopenharmony_ci.686
1281cb0ef41Sopenharmony_ci.XMM
1291cb0ef41Sopenharmony_ciIF \@Version LT 800
1301cb0ef41Sopenharmony_ciXMMWORD STRUCT 16
1311cb0ef41Sopenharmony_ciDQ	2 dup (?)
1321cb0ef41Sopenharmony_ciXMMWORD	ENDS
1331cb0ef41Sopenharmony_ciENDIF
1341cb0ef41Sopenharmony_ci___
1351cb0ef41Sopenharmony_ci    if (grep {/\b[x]?mm[0-7]\b/i} @out) {
1361cb0ef41Sopenharmony_ci	grep {s/\.[3-7]86/$xmmheader/} @out;
1371cb0ef41Sopenharmony_ci    }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci    push(@out,"$segment	ENDS\n");
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
1421cb0ef41Sopenharmony_ci    {	my $comm=<<___;
1431cb0ef41Sopenharmony_ci.bss	SEGMENT 'BSS'
1441cb0ef41Sopenharmony_ciCOMM	${nmdecor}OPENSSL_ia32cap_P:DWORD:4
1451cb0ef41Sopenharmony_ci.bss	ENDS
1461cb0ef41Sopenharmony_ci___
1471cb0ef41Sopenharmony_ci	# comment out OPENSSL_ia32cap_P declarations
1481cb0ef41Sopenharmony_ci	grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
1491cb0ef41Sopenharmony_ci	push (@out,$comm);
1501cb0ef41Sopenharmony_ci    }
1511cb0ef41Sopenharmony_ci    push (@out,$initseg) if ($initseg);
1521cb0ef41Sopenharmony_ci    push (@out,"END\n");
1531cb0ef41Sopenharmony_ci}
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_cisub ::comment {   foreach (@_) { push(@out,"\t; $_\n"); }   }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci*::set_label_B = sub
1581cb0ef41Sopenharmony_ci{ my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_cisub ::external_label
1611cb0ef41Sopenharmony_ci{   foreach(@_)
1621cb0ef41Sopenharmony_ci    {	push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n");   }
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_cisub ::public_label
1661cb0ef41Sopenharmony_ci{   push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_cisub ::data_byte
1691cb0ef41Sopenharmony_ci{   push(@out,("DB\t").join(',',splice(@_,0,16))."\n") while(@_);	}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cisub ::data_short
1721cb0ef41Sopenharmony_ci{   push(@out,("DW\t").join(',',splice(@_,0,8))."\n") while(@_);	}
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_cisub ::data_word
1751cb0ef41Sopenharmony_ci{   push(@out,("DD\t").join(',',splice(@_,0,4))."\n") while(@_);	}
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_cisub ::align
1781cb0ef41Sopenharmony_ci{   push(@out,"ALIGN\t$_[0]\n");	}
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_cisub ::picmeup
1811cb0ef41Sopenharmony_ci{ my($dst,$sym)=@_;
1821cb0ef41Sopenharmony_ci    &::lea($dst,&::DWP($sym));
1831cb0ef41Sopenharmony_ci}
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_cisub ::initseg
1861cb0ef41Sopenharmony_ci{ my $f=$nmdecor.shift;
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci    $initseg.=<<___;
1891cb0ef41Sopenharmony_ci.CRT\$XCU	SEGMENT DWORD PUBLIC 'DATA'
1901cb0ef41Sopenharmony_ciEXTERN	$f:NEAR
1911cb0ef41Sopenharmony_ciDD	$f
1921cb0ef41Sopenharmony_ci.CRT\$XCU	ENDS
1931cb0ef41Sopenharmony_ci___
1941cb0ef41Sopenharmony_ci}
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_cisub ::dataseg
1971cb0ef41Sopenharmony_ci{   push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA";   }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_cisub ::safeseh
2001cb0ef41Sopenharmony_ci{ my $nm=shift;
2011cb0ef41Sopenharmony_ci    push(@out,"IF \@Version GE 710\n");
2021cb0ef41Sopenharmony_ci    push(@out,".SAFESEH	".&::LABEL($nm,$nmdecor.$nm)."\n");
2031cb0ef41Sopenharmony_ci    push(@out,"ENDIF\n");
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci1;
207