x86nasm.pl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #!/usr/bin/env perl
  2. package x86nasm;
  3. *out=\@::out;
  4. $lprfx="\@L";
  5. $label="000";
  6. $under=($::netware)?'':'_';
  7. $initseg="";
  8. sub ::generic
  9. { my $opcode=shift;
  10. my $tmp;
  11. if (!$::mwerks)
  12. { if ($opcode =~ m/^j/o && $#_==0) # optimize jumps
  13. { $_[0] = "NEAR $_[0]"; }
  14. elsif ($opcode eq "lea" && $#_==1)# wipe storage qualifier from lea
  15. { $_[1] =~ s/^[^\[]*\[/\[/o; }
  16. }
  17. &::emit($opcode,@_);
  18. 1;
  19. }
  20. #
  21. # opcodes not covered by ::generic above, mostly inconsistent namings...
  22. #
  23. sub ::movz { &::movzx(@_); }
  24. sub ::pushf { &::pushfd; }
  25. sub ::popf { &::popfd; }
  26. sub ::call { &::emit("call",(&islabel($_[0]) or "$under$_[0]")); }
  27. sub ::call_ptr { &::emit("call",@_); }
  28. sub ::jmp_ptr { &::emit("jmp",@_); }
  29. # chosen SSE instructions
  30. sub ::movq
  31. { my($p1,$p2,$optimize)=@_;
  32. if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
  33. # movq between mmx registers can sink Intel CPUs
  34. { &::pshufw($p1,$p2,0xe4); }
  35. else
  36. { &::emit("movq",@_); }
  37. }
  38. sub ::pshufw { &::emit("pshufw",@_); }
  39. sub get_mem
  40. { my($size,$addr,$reg1,$reg2,$idx)=@_;
  41. my($post,$ret);
  42. if ($size ne "")
  43. { $ret .= "$size";
  44. $ret .= " PTR" if ($::mwerks);
  45. $ret .= " ";
  46. }
  47. $ret .= "[";
  48. $addr =~ s/^\s+//;
  49. # prepend global references with optional underscore
  50. $addr =~ s/^([^\+\-0-9][^\+\-]*)/islabel($1) or "$under$1"/ige;
  51. # put address arithmetic expression in parenthesis
  52. $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
  53. if (($addr ne "") && ($addr ne 0))
  54. { if ($addr !~ /^-/) { $ret .= "$addr+"; }
  55. else { $post=$addr; }
  56. }
  57. if ($reg2 ne "")
  58. { $idx!=0 or $idx=1;
  59. $ret .= "$reg2*$idx";
  60. $ret .= "+$reg1" if ($reg1 ne "");
  61. }
  62. else
  63. { $ret .= "$reg1"; }
  64. $ret .= "$post]";
  65. $ret =~ s/\+\]/]/; # in case $addr was the only argument
  66. $ret;
  67. }
  68. sub ::BP { &get_mem("BYTE",@_); }
  69. sub ::DWP { &get_mem("DWORD",@_); }
  70. sub ::QWP { &get_mem("",@_); }
  71. sub ::BC { (($::mwerks)?"":"BYTE ")."@_"; }
  72. sub ::DWC { (($::mwerks)?"":"DWORD ")."@_"; }
  73. sub ::file
  74. { if ($::mwerks) { push(@out,".section\t.text\n"); }
  75. else
  76. { my $tmp=<<___;
  77. %ifdef __omf__
  78. section code use32 class=code align=64
  79. %else
  80. section .text code align=64
  81. %endif
  82. ___
  83. push(@out,$tmp);
  84. }
  85. }
  86. sub ::function_begin_B
  87. { my $func=$under.shift;
  88. my $tmp=<<___;
  89. global $func
  90. align 16
  91. $func:
  92. ___
  93. push(@out,$tmp);
  94. $::stack=4;
  95. }
  96. sub ::function_end_B
  97. { my $i;
  98. foreach $i (%label) { undef $label{$i} if ($label{$i} =~ /^$prfx/); }
  99. $::stack=0;
  100. }
  101. sub ::file_end
  102. { # try to detect if SSE2 or MMX extensions were used on Win32...
  103. if ($::win32 && grep {/\b[x]?mm[0-7]\b|OPENSSL_ia32cap_P\b/i} @out)
  104. { # $1<<10 sets a reserved bit to signal that variable
  105. # was initialized already...
  106. my $code=<<___;
  107. align 16
  108. ${lprfx}OPENSSL_ia32cap_init:
  109. lea edx,[${under}OPENSSL_ia32cap_P]
  110. cmp DWORD [edx],0
  111. jne NEAR ${lprfx}nocpuid
  112. mov DWORD [edx],1<<10
  113. pushfd
  114. pop eax
  115. mov ecx,eax
  116. xor eax,1<<21
  117. push eax
  118. popfd
  119. pushfd
  120. pop eax
  121. xor eax,ecx
  122. bt eax,21
  123. jnc NEAR ${lprfx}nocpuid
  124. push ebp
  125. push edi
  126. push ebx
  127. mov edi,edx
  128. xor eax,eax
  129. cpuid
  130. xor eax,eax
  131. cmp ebx,'Genu'
  132. setne al
  133. mov ebp,eax
  134. cmp edx,'ineI'
  135. setne al
  136. or ebp,eax
  137. cmp eax,'ntel'
  138. setne al
  139. or ebp,eax
  140. mov eax,1
  141. cpuid
  142. cmp ebp,0
  143. jne ${lprfx}notP4
  144. and ah,15
  145. cmp ah,15
  146. jne ${lprfx}notP4
  147. or edx,1<<20
  148. ${lprfx}notP4:
  149. bt edx,28
  150. jnc ${lprfx}done
  151. shr ebx,16
  152. cmp bl,1
  153. ja ${lprfx}done
  154. and edx,0xefffffff
  155. ${lprfx}done:
  156. or edx,1<<10
  157. mov DWORD [edi],edx
  158. pop ebx
  159. pop edi
  160. pop ebp
  161. ${lprfx}nocpuid:
  162. ret
  163. segment .CRT\$XCU data align=4
  164. dd ${lprfx}OPENSSL_ia32cap_init
  165. ___
  166. my $data=<<___;
  167. segment .bss
  168. common ${under}OPENSSL_ia32cap_P 4
  169. ___
  170. #<not needed in OpenSSL context>#push (@out,$code);
  171. # comment out OPENSSL_ia32cap_P declarations
  172. grep {s/(^extern\s+${under}OPENSSL_ia32cap_P)/\;$1/} @out;
  173. push (@out,$data)
  174. }
  175. push (@out,$initseg) if ($initseg);
  176. }
  177. sub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } }
  178. sub islabel # see is argument is known label
  179. { my $i;
  180. foreach $i (%label) { return $label{$i} if ($label{$i} eq $_[0]); }
  181. undef;
  182. }
  183. sub ::external_label
  184. { push(@labels,@_);
  185. foreach (@_)
  186. { push(@out,".") if ($::mwerks);
  187. push(@out, "extern\t${under}$_\n");
  188. }
  189. }
  190. sub ::public_label
  191. { $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]}));
  192. push(@out,"global\t$label{$_[0]}\n");
  193. }
  194. sub ::label
  195. { if (!defined($label{$_[0]}))
  196. { $label{$_[0]}="${lprfx}${label}${_[0]}"; $label++; }
  197. $label{$_[0]};
  198. }
  199. sub ::set_label
  200. { my $label=&::label($_[0]);
  201. &::align($_[1]) if ($_[1]>1);
  202. push(@out,"$label{$_[0]}:\n");
  203. }
  204. sub ::data_byte
  205. { push(@out,(($::mwerks)?".byte\t":"db\t").join(',',@_)."\n"); }
  206. sub ::data_word
  207. { push(@out,(($::mwerks)?".long\t":"dd\t").join(',',@_)."\n"); }
  208. sub ::align
  209. { push(@out,".") if ($::mwerks); push(@out,"align\t$_[0]\n"); }
  210. sub ::picmeup
  211. { my($dst,$sym)=@_;
  212. &::lea($dst,&::DWP($sym));
  213. }
  214. sub ::initseg
  215. { my($f)=$under.shift;
  216. if ($::win32)
  217. { $initseg=<<___;
  218. segment .CRT\$XCU data align=4
  219. extern $f
  220. dd $f
  221. ___
  222. }
  223. }
  224. 1;