x86unix.pl 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #!/usr/bin/env perl
  2. package x86unix; # GAS actually...
  3. *out=\@::out;
  4. $label="L000";
  5. $align=($::aout)?"4":"16";
  6. $under=($::aout or $::coff)?"_":"";
  7. $dot=($::aout)?"":".";
  8. $com_start="#" if ($::aout or $::coff);
  9. sub opsize()
  10. { my $reg=shift;
  11. if ($reg =~ m/^%e/o) { "l"; }
  12. elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
  13. elsif ($reg =~ m/^%[xm]/o) { undef; }
  14. else { "w"; }
  15. }
  16. # swap arguments;
  17. # expand opcode with size suffix;
  18. # prefix numeric constants with $;
  19. sub ::generic
  20. { my($opcode,$dst,$src)=@_;
  21. my($tmp,$suffix,@arg);
  22. if (defined($src))
  23. { $src =~ s/^(e?[a-dsixphl]{2})$/%$1/o;
  24. $src =~ s/^(x?mm[0-7])$/%$1/o;
  25. $src =~ s/^(\-?[0-9]+)$/\$$1/o;
  26. $src =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o;
  27. push(@arg,$src);
  28. }
  29. if (defined($dst))
  30. { $dst =~ s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o;
  31. $dst =~ s/^(x?mm[0-7])$/%$1/o;
  32. $dst =~ s/^(\-?[0-9]+)$/\$$1/o if(!defined($src));
  33. $dst =~ s/^(\-?0x[0-9a-f]+)$/\$$1/o if(!defined($src));
  34. push(@arg,$dst);
  35. }
  36. if ($dst =~ m/^%/o) { $suffix=&opsize($dst); }
  37. elsif ($src =~ m/^%/o) { $suffix=&opsize($src); }
  38. else { $suffix="l"; }
  39. undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
  40. if ($#_==0) { &::emit($opcode); }
  41. elsif ($opcode =~ m/^j/o && $#_==1) { &::emit($opcode,@arg); }
  42. elsif ($opcode eq "call" && $#_==1) { &::emit($opcode,@arg); }
  43. elsif ($opcode =~ m/^set/&& $#_==1) { &::emit($opcode,@arg); }
  44. else { &::emit($opcode.$suffix,@arg);}
  45. 1;
  46. }
  47. #
  48. # opcodes not covered by ::generic above, mostly inconsistent namings...
  49. #
  50. sub ::movz { &::movzb(@_); }
  51. sub ::pushf { &::pushfl; }
  52. sub ::popf { &::popfl; }
  53. sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
  54. sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
  55. sub ::call { &::emit("call",(&islabel($_[0]) or "$under$_[0]")); }
  56. sub ::call_ptr { &::generic("call","*$_[0]"); }
  57. sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
  58. *::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
  59. # chosen SSE instructions
  60. sub ::movq
  61. { my($p1,$p2,$optimize)=@_;
  62. if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
  63. # movq between mmx registers can sink Intel CPUs
  64. { &::pshufw($p1,$p2,0xe4); }
  65. else
  66. { &::generic("movq",@_); }
  67. }
  68. sub ::pshufw
  69. { my($dst,$src,$magic)=@_;
  70. &::emit("pshufw","\$$magic","%$src","%$dst");
  71. }
  72. sub ::DWP
  73. { my($addr,$reg1,$reg2,$idx)=@_;
  74. my $ret="";
  75. $addr =~ s/^\s+//;
  76. # prepend global references with optional underscore
  77. $addr =~ s/^([^\+\-0-9][^\+\-]*)/islabel($1) or "$under$1"/ige;
  78. $reg1 = "%$reg1" if ($reg1);
  79. $reg2 = "%$reg2" if ($reg2);
  80. $ret .= $addr if (($addr ne "") && ($addr ne 0));
  81. if ($reg2)
  82. { $idx!= 0 or $idx=1;
  83. $ret .= "($reg1,$reg2,$idx)";
  84. }
  85. elsif ($reg1)
  86. { $ret .= "($reg1)"; }
  87. $ret;
  88. }
  89. sub ::QWP { &::DWP(@_); }
  90. sub ::BP { &::DWP(@_); }
  91. sub ::BC { @_; }
  92. sub ::DWC { @_; }
  93. sub ::file
  94. { push(@out,".file\t\"$_[0].s\"\n"); }
  95. sub ::function_begin_B
  96. { my($func,$extra)=@_;
  97. my $tmp;
  98. &::external_label($func);
  99. $func=$under.$func;
  100. push(@out,".text\n.globl\t$func\n");
  101. if ($::coff)
  102. { push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
  103. elsif ($::aout and !$::pic)
  104. { }
  105. else
  106. { push(@out,".type $func,\@function\n"); }
  107. push(@out,".align\t$align\n");
  108. push(@out,"$func:\n");
  109. $::stack=4;
  110. }
  111. sub ::function_end_B
  112. { my($func)=@_;
  113. $func=$under.$func;
  114. push(@out,"${dot}L_${func}_end:\n");
  115. if ($::elf)
  116. { push(@out,".size\t$func,${dot}L_${func}_end-$func\n"); }
  117. $::stack=0;
  118. %label=();
  119. }
  120. sub ::comment
  121. {
  122. if (!defined($com_start) or $::elf)
  123. { # Regarding $::elf above...
  124. # GNU and SVR4 as'es use different comment delimiters,
  125. push(@out,"\n"); # so we just skip ELF comments...
  126. return;
  127. }
  128. foreach (@_)
  129. {
  130. if (/^\s*$/)
  131. { push(@out,"\n"); }
  132. else
  133. { push(@out,"\t$com_start $_ $com_end\n"); }
  134. }
  135. }
  136. sub islabel # see is argument is a known label
  137. { my $i;
  138. foreach $i (%label) { return $label{$i} if ($label{$i} eq $_[0]); }
  139. undef;
  140. }
  141. sub ::external_label { push(@labels,@_); }
  142. sub ::public_label
  143. { $label{$_[0]}="${under}${_[0]}" if (!defined($label{$_[0]}));
  144. push(@out,".globl\t$label{$_[0]}\n");
  145. }
  146. sub ::label
  147. { if (!defined($label{$_[0]}))
  148. { $label{$_[0]}="${dot}${label}${_[0]}"; $label++; }
  149. $label{$_[0]};
  150. }
  151. sub ::set_label
  152. { my $label=&::label($_[0]);
  153. &::align($_[1]) if ($_[1]>1);
  154. push(@out,"$label:\n");
  155. }
  156. sub ::file_end
  157. { # try to detect if SSE2 or MMX extensions were used on ELF platform...
  158. if ($::elf && grep {/\b%[x]?mm[0-7]\b|OPENSSL_ia32cap_P\b/i} @out) {
  159. push (@out,"\n.section\t.bss\n");
  160. push (@out,".comm\t${under}OPENSSL_ia32cap_P,4,4\n");
  161. return; # below is not needed in OpenSSL context
  162. push (@out,".section\t.init\n");
  163. &::picmeup("edx","OPENSSL_ia32cap_P");
  164. # $1<<10 sets a reserved bit to signal that variable
  165. # was initialized already...
  166. my $code=<<___;
  167. cmpl \$0,(%edx)
  168. jne 3f
  169. movl \$1<<10,(%edx)
  170. pushf
  171. popl %eax
  172. movl %eax,%ecx
  173. xorl \$1<<21,%eax
  174. pushl %eax
  175. popf
  176. pushf
  177. popl %eax
  178. xorl %ecx,%eax
  179. btl \$21,%eax
  180. jnc 3f
  181. pushl %ebp
  182. pushl %edi
  183. pushl %ebx
  184. movl %edx,%edi
  185. xor %eax,%eax
  186. .byte 0x0f,0xa2
  187. xorl %eax,%eax
  188. cmpl $1970169159,%ebx
  189. setne %al
  190. movl %eax,%ebp
  191. cmpl $1231384169,%edx
  192. setne %al
  193. orl %eax,%ebp
  194. cmpl $1818588270,%ecx
  195. setne %al
  196. orl %eax,%ebp
  197. movl $1,%eax
  198. .byte 0x0f,0xa2
  199. cmpl $0,%ebp
  200. jne 1f
  201. andb $15,%ah
  202. cmpb $15,%ah
  203. jne 1f
  204. orl $1048576,%edx
  205. 1: btl $28,%edx
  206. jnc 2f
  207. shrl $16,%ebx
  208. cmpb $1,%bl
  209. ja 2f
  210. andl $4026531839,%edx
  211. 2: orl \$1<<10,%edx
  212. movl %edx,0(%edi)
  213. popl %ebx
  214. popl %edi
  215. popl %ebp
  216. jmp 3f
  217. .align $align
  218. 3:
  219. ___
  220. push (@out,$code);
  221. }
  222. }
  223. sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
  224. sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
  225. sub ::align
  226. { my $val=$_[0],$p2,$i;
  227. if ($::aout)
  228. { for ($p2=0;$val!=0;$val>>=1) { $p2++; }
  229. $val=$p2-1;
  230. $val.=",0x90";
  231. }
  232. push(@out,".align\t$val\n");
  233. }
  234. sub ::picmeup
  235. { my($dst,$sym,$base,$reflabel)=@_;
  236. if ($::pic && ($::elf || $::aout))
  237. { if (!defined($base))
  238. { &::call(&::label("PIC_me_up"));
  239. &::set_label("PIC_me_up");
  240. &::blindpop($dst);
  241. &::add($dst,"\$${under}_GLOBAL_OFFSET_TABLE_+[.-".
  242. &::label("PIC_me_up") . "]");
  243. }
  244. else
  245. { &::lea($dst,&::DWP("${under}_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
  246. $base));
  247. }
  248. &::mov($dst,&::DWP($under.$sym."\@GOT",$dst));
  249. }
  250. else
  251. { &::lea($dst,&::DWP($sym)); }
  252. }
  253. sub ::initseg
  254. { my($f)=@_;
  255. my($tmp,$ctor);
  256. if ($::elf)
  257. { $tmp=<<___;
  258. .section .init
  259. call $under$f
  260. jmp .Linitalign
  261. .align $align
  262. .Linitalign:
  263. ___
  264. }
  265. elsif ($::coff)
  266. { $tmp=<<___; # applies to both Cygwin and Mingw
  267. .section .ctors
  268. .long $under$f
  269. ___
  270. }
  271. elsif ($::aout)
  272. { $ctor="${under}_GLOBAL_\$I\$$f";
  273. $tmp=".text\n";
  274. $tmp.=".type $ctor,\@function\n" if ($::pic);
  275. $tmp.=<<___; # OpenBSD way...
  276. .globl $ctor
  277. .align 2
  278. $ctor:
  279. jmp $under$f
  280. ___
  281. }
  282. push(@out,$tmp) if ($tmp);
  283. }
  284. 1;