x86masm.pl 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #! /usr/bin/env perl
  2. # Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the OpenSSL license (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. package x86masm;
  9. *out=\@::out;
  10. $::lbdecor="\$L"; # local label decoration
  11. $nmdecor="_"; # external name decoration
  12. $initseg="";
  13. $segment="";
  14. sub ::generic
  15. { my ($opcode,@arg)=@_;
  16. # fix hexadecimal constants
  17. for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
  18. if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/) # no []
  19. { $opcode="mov"; }
  20. elsif ($opcode !~ /mov[dq]$/)
  21. { # fix xmm references
  22. $arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[-1]=~/\bxmm[0-7]\b/i);
  23. $arg[-1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i);
  24. }
  25. &::emit($opcode,@arg);
  26. 1;
  27. }
  28. #
  29. # opcodes not covered by ::generic above, mostly inconsistent namings...
  30. #
  31. sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
  32. sub ::call_ptr { &::emit("call",@_); }
  33. sub ::jmp_ptr { &::emit("jmp",@_); }
  34. sub ::lock { &::data_byte(0xf0); }
  35. sub get_mem
  36. { my($size,$addr,$reg1,$reg2,$idx)=@_;
  37. my($post,$ret);
  38. if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
  39. $ret .= "$size PTR " if ($size ne "");
  40. $addr =~ s/^\s+//;
  41. # prepend global references with optional underscore
  42. $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
  43. # put address arithmetic expression in parenthesis
  44. $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
  45. if (($addr ne "") && ($addr ne 0))
  46. { if ($addr !~ /^-/) { $ret .= "$addr"; }
  47. else { $post=$addr; }
  48. }
  49. $ret .= "[";
  50. if ($reg2 ne "")
  51. { $idx!=0 or $idx=1;
  52. $ret .= "$reg2*$idx";
  53. $ret .= "+$reg1" if ($reg1 ne "");
  54. }
  55. else
  56. { $ret .= "$reg1"; }
  57. $ret .= "$post]";
  58. $ret =~ s/\+\]/]/; # in case $addr was the only argument
  59. $ret =~ s/\[\s*\]//;
  60. $ret;
  61. }
  62. sub ::BP { &get_mem("BYTE",@_); }
  63. sub ::WP { &get_mem("WORD",@_); }
  64. sub ::DWP { &get_mem("DWORD",@_); }
  65. sub ::QWP { &get_mem("QWORD",@_); }
  66. sub ::BC { "@_"; }
  67. sub ::DWC { "@_"; }
  68. sub ::file
  69. { my $tmp=<<___;
  70. TITLE $_[0].asm
  71. IF \@Version LT 800
  72. ECHO MASM version 8.00 or later is strongly recommended.
  73. ENDIF
  74. .686
  75. .MODEL FLAT
  76. OPTION DOTNAME
  77. IF \@Version LT 800
  78. .text\$ SEGMENT PAGE 'CODE'
  79. ELSE
  80. .text\$ SEGMENT ALIGN(64) 'CODE'
  81. ENDIF
  82. ___
  83. push(@out,$tmp);
  84. $segment = ".text\$";
  85. }
  86. sub ::function_begin_B
  87. { my $func=shift;
  88. my $global=($func !~ /^_/);
  89. my $begin="${::lbdecor}_${func}_begin";
  90. &::LABEL($func,$global?"$begin":"$nmdecor$func");
  91. $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
  92. if ($global) { $func.=" PUBLIC\n${begin}::\n"; }
  93. else { $func.=" PRIVATE\n"; }
  94. push(@out,$func);
  95. $::stack=4;
  96. }
  97. sub ::function_end_B
  98. { my $func=shift;
  99. push(@out,"$nmdecor$func ENDP\n");
  100. $::stack=0;
  101. &::wipe_labels();
  102. }
  103. sub ::file_end
  104. { my $xmmheader=<<___;
  105. .686
  106. .XMM
  107. IF \@Version LT 800
  108. XMMWORD STRUCT 16
  109. DQ 2 dup (?)
  110. XMMWORD ENDS
  111. ENDIF
  112. ___
  113. if (grep {/\b[x]?mm[0-7]\b/i} @out) {
  114. grep {s/\.[3-7]86/$xmmheader/} @out;
  115. }
  116. push(@out,"$segment ENDS\n");
  117. if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
  118. { my $comm=<<___;
  119. .bss SEGMENT 'BSS'
  120. COMM ${nmdecor}OPENSSL_ia32cap_P:DWORD:4
  121. .bss ENDS
  122. ___
  123. # comment out OPENSSL_ia32cap_P declarations
  124. grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
  125. push (@out,$comm);
  126. }
  127. push (@out,$initseg) if ($initseg);
  128. push (@out,"END\n");
  129. }
  130. sub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } }
  131. *::set_label_B = sub
  132. { my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };
  133. sub ::external_label
  134. { foreach(@_)
  135. { push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n"); }
  136. }
  137. sub ::public_label
  138. { push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); }
  139. sub ::data_byte
  140. { push(@out,("DB\t").join(',',splice(@_,0,16))."\n") while(@_); }
  141. sub ::data_short
  142. { push(@out,("DW\t").join(',',splice(@_,0,8))."\n") while(@_); }
  143. sub ::data_word
  144. { push(@out,("DD\t").join(',',splice(@_,0,4))."\n") while(@_); }
  145. sub ::align
  146. { push(@out,"ALIGN\t$_[0]\n"); }
  147. sub ::picmeup
  148. { my($dst,$sym)=@_;
  149. &::lea($dst,&::DWP($sym));
  150. }
  151. sub ::initseg
  152. { my $f=$nmdecor.shift;
  153. $initseg.=<<___;
  154. .CRT\$XCU SEGMENT DWORD PUBLIC 'DATA'
  155. EXTERN $f:NEAR
  156. DD $f
  157. .CRT\$XCU ENDS
  158. ___
  159. }
  160. sub ::dataseg
  161. { push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA"; }
  162. sub ::safeseh
  163. { my $nm=shift;
  164. push(@out,"IF \@Version GE 710\n");
  165. push(@out,".SAFESEH ".&::LABEL($nm,$nmdecor.$nm)."\n");
  166. push(@out,"ENDIF\n");
  167. }
  168. 1;