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