perlasm/x86masm.pl: make it work.
[openssl.git] / crypto / perlasm / x86masm.pl
index 7a0f4aa5bb1b2b045c5d99439a046543e00a19f3..917d0f8b8e1982621b3a06cd8c1fe1cebd17f71f 100644 (file)
@@ -8,13 +8,21 @@ $::lbdecor="\$L";     # local label decoration
 $nmdecor="_";          # external name decoration
 
 $initseg="";
+$segment="";
 
 sub ::generic
 { my ($opcode,@arg)=@_;
 
     # fix hexadecimal constants
-    $arg[0] =~ s/0x([0-9a-f]+)/0$1h/oi if (defined($arg[0]));
-    $arg[1] =~ s/0x([0-9a-f]+)/0$1h/oi if (defined($arg[1]));
+    for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
+
+    if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/) # no []
+    {  $opcode="mov";  }
+    elsif ($opcode !~ /mov[dq]$/)
+    {  # 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);
+    }
 
     &::emit($opcode,@arg);
   1;
@@ -25,11 +33,14 @@ sub ::generic
 sub ::call     { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
 sub ::call_ptr { &::emit("call",@_);   }
 sub ::jmp_ptr  { &::emit("jmp",@_);    }
+sub ::lock     { &::data_byte(0xf0);   }
 
 sub get_mem
 { my($size,$addr,$reg1,$reg2,$idx)=@_;
   my($post,$ret);
 
+    if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
+
     $ret .= "$size PTR " if ($size ne "");
 
     $addr =~ s/^\s+//;
@@ -59,6 +70,7 @@ sub get_mem
   $ret;
 }
 sub ::BP       { &get_mem("BYTE",@_);  }
+sub ::WP       { &get_mem("WORD",@_);  }
 sub ::DWP      { &get_mem("DWORD",@_); }
 sub ::QWP      { &get_mem("QWORD",@_); }
 sub ::BC       { "@_";  }
@@ -67,12 +79,20 @@ sub ::DWC   { "@_"; }
 sub ::file
 { my $tmp=<<___;
 TITLE  $_[0].asm
+IF \@Version LT 800
+ECHO MASM version 8.00 or later is strongly recommended.
+ENDIF
 .486
 .MODEL FLAT
 OPTION DOTNAME
-.TEXT\$        SEGMENT PAGE 'CODE'
+IF \@Version LT 800
+.text\$        SEGMENT PAGE 'CODE'
+ELSE
+.text\$        SEGMENT ALIGN(64) 'CODE'
+ENDIF
 ___
     push(@out,$tmp);
+    $segment = ".text\$";
 }
 
 sub ::function_begin_B
@@ -81,7 +101,7 @@ sub ::function_begin_B
   my $begin="${::lbdecor}_${func}_begin";
 
     &::LABEL($func,$global?"$begin":"$nmdecor$func");
-    $func=$nmdecor.$func."\tPROC";
+    $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
 
     if ($global)    { $func.=" PUBLIC\n${begin}::\n"; }
     else           { $func.=" PRIVATE\n";            }
@@ -110,13 +130,13 @@ ___
        grep {s/\.[3-7]86/$xmmheader/} @out;
     }
 
-    push(@out,".TEXT\$ ENDS\n");
+    push(@out,"$segment        ENDS\n");
 
     if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
     {  my $comm=<<___;
-_DATA  SEGMENT
-COMM   ${nmdecor}OPENSSL_ia32cap_P:DWORD
-_DATA  ENDS
+.bss   SEGMENT 'BSS'
+COMM   ${nmdecor}OPENSSL_ia32cap_P:DWORD:4
+.bss   ENDS
 ___
        # comment out OPENSSL_ia32cap_P declarations
        grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
@@ -132,16 +152,21 @@ sub ::comment {   foreach (@_) { push(@out,"\t; $_\n"); }   }
 { my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };
 
 sub ::external_label
-{   push(@out, "EXTERN\t".&::LABEL($_[0],$nmdecor.$_[0]).":NEAR\n");   }
+{   foreach(@_)
+    {  push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n");   }
+}
 
 sub ::public_label
 {   push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }
 
 sub ::data_byte
-{   push(@out,("DB\t").join(',',@_)."\n");     }
+{   push(@out,("DB\t").join(',',splice(@_,0,16))."\n") while(@_);      }
+
+sub ::data_short
+{   push(@out,("DW\t").join(',',splice(@_,0,8))."\n") while(@_);       }
 
 sub ::data_word
-{   push(@out,("DD\t").join(',',@_)."\n");     }
+{   push(@out,("DD\t").join(',',splice(@_,0,4))."\n") while(@_);       }
 
 sub ::align
 {   push(@out,"ALIGN\t$_[0]\n");       }
@@ -155,11 +180,21 @@ sub ::initseg
 { my $f=$nmdecor.shift;
 
     $initseg.=<<___;
-.CRT\$XCU      SEGMENT DWORD PUBLIC DATA
+.CRT\$XCU      SEGMENT DWORD PUBLIC 'DATA'
 EXTERN $f:NEAR
 DD     $f
 .CRT\$XCU      ENDS
 ___
 }
 
+sub ::dataseg
+{   push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA";   }
+
+sub ::safeseh
+{ my $nm=shift;
+    push(@out,"IF \@Version GE 710\n");
+    push(@out,".SAFESEH        ".&::LABEL($nm,$nmdecor.$nm)."\n");
+    push(@out,"ENDIF\n");
+}
+
 1;