25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

351 lines
8.4 KiB

  1. #! /usr/bin/env perl
  2. # Copyright 1995-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. # require 'x86asm.pl';
  9. # &asm_init(<flavor>[,$i386only]);
  10. # &function_begin("foo");
  11. # ...
  12. # &function_end("foo");
  13. # &asm_finish
  14. $out=();
  15. $i386=0;
  16. # AUTOLOAD is this context has quite unpleasant side effect, namely
  17. # that typos in function calls effectively go to assembler output,
  18. # but on the pros side we don't have to implement one subroutine per
  19. # each opcode...
  20. sub ::AUTOLOAD
  21. { my $opcode = $AUTOLOAD;
  22. die "more than 4 arguments passed to $opcode" if ($#_>3);
  23. $opcode =~ s/.*:://;
  24. if ($opcode =~ /^push/) { $stack+=4; }
  25. elsif ($opcode =~ /^pop/) { $stack-=4; }
  26. &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD";
  27. }
  28. # record_function_hit(int) writes a byte with value one to the given offset of
  29. # |BORINGSSL_function_hit|, but only if NDEBUG is not defined. This is used in
  30. # impl_dispatch_test.cc to test whether the expected assembly functions are
  31. # triggered by high-level API calls.
  32. sub ::record_function_hit
  33. { my($index)=@_;
  34. &preprocessor_ifndef("NDEBUG");
  35. &push("ebx");
  36. &push("edx");
  37. &call(&label("pic"));
  38. &set_label("pic");
  39. &blindpop("ebx");
  40. &lea("ebx",&DWP("BORINGSSL_function_hit+$index"."-".&label("pic"),"ebx"));
  41. &mov("edx", 1);
  42. &movb(&BP(0, "ebx"), "dl");
  43. &pop("edx");
  44. &pop("ebx");
  45. &preprocessor_endif();
  46. }
  47. sub ::emit
  48. { my $opcode=shift;
  49. if ($#_==-1) { push(@out,"\t$opcode\n"); }
  50. else { push(@out,"\t$opcode\t".join(',',@_)."\n"); }
  51. }
  52. sub ::LB
  53. { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'";
  54. $1."l";
  55. }
  56. sub ::HB
  57. { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'";
  58. $1."h";
  59. }
  60. sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); }
  61. sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); }
  62. sub ::blindpop { &pop($_[0]); $stack+=4; }
  63. sub ::wparam { &DWP($stack+4*$_[0],"esp"); }
  64. sub ::swtmp { &DWP(4*$_[0],"esp"); }
  65. sub ::bswap
  66. { if ($i386) # emulate bswap for i386
  67. { &comment("bswap @_");
  68. &xchg(&HB(@_),&LB(@_));
  69. &ror (@_,16);
  70. &xchg(&HB(@_),&LB(@_));
  71. }
  72. else
  73. { &generic("bswap",@_); }
  74. }
  75. # These are made-up opcodes introduced over the years essentially
  76. # by ignorance, just alias them to real ones...
  77. sub ::movb { &mov(@_); }
  78. sub ::xorb { &xor(@_); }
  79. sub ::rotl { &rol(@_); }
  80. sub ::rotr { &ror(@_); }
  81. sub ::exch { &xchg(@_); }
  82. sub ::halt { &hlt; }
  83. sub ::movz { &movzx(@_); }
  84. sub ::pushf { &pushfd; }
  85. sub ::popf { &popfd; }
  86. # 3 argument instructions
  87. sub ::movq
  88. { my($p1,$p2,$optimize)=@_;
  89. if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
  90. # movq between mmx registers can sink Intel CPUs
  91. { &::pshufw($p1,$p2,0xe4); }
  92. else
  93. { &::generic("movq",@_); }
  94. }
  95. # SSE>2 instructions
  96. my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3,
  97. "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 );
  98. sub ::pextrd
  99. { my($dst,$src,$imm)=@_;
  100. if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/)
  101. { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); }
  102. else
  103. { &::generic("pextrd",@_); }
  104. }
  105. sub ::pinsrd
  106. { my($dst,$src,$imm)=@_;
  107. if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/)
  108. { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); }
  109. else
  110. { &::generic("pinsrd",@_); }
  111. }
  112. sub ::pshufb
  113. { my($dst,$src)=@_;
  114. if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
  115. { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); }
  116. else
  117. { &::generic("pshufb",@_); }
  118. }
  119. sub ::palignr
  120. { my($dst,$src,$imm)=@_;
  121. if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
  122. { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); }
  123. else
  124. { &::generic("palignr",@_); }
  125. }
  126. sub ::pclmulqdq
  127. { my($dst,$src,$imm)=@_;
  128. if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
  129. { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); }
  130. else
  131. { &::generic("pclmulqdq",@_); }
  132. }
  133. sub ::rdrand
  134. { my ($dst)=@_;
  135. if ($dst =~ /(e[a-dsd][ixp])/)
  136. { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); }
  137. else
  138. { &::generic("rdrand",@_); }
  139. }
  140. sub ::rdseed
  141. { my ($dst)=@_;
  142. if ($dst =~ /(e[a-dsd][ixp])/)
  143. { &::data_byte(0x0f,0xc7,0xf8|$regrm{$dst}); }
  144. else
  145. { &::generic("rdrand",@_); }
  146. }
  147. sub rxb {
  148. local *opcode=shift;
  149. my ($dst,$src1,$src2,$rxb)=@_;
  150. $rxb|=0x7<<5;
  151. $rxb&=~(0x04<<5) if($dst>=8);
  152. $rxb&=~(0x01<<5) if($src1>=8);
  153. $rxb&=~(0x02<<5) if($src2>=8);
  154. push @opcode,$rxb;
  155. }
  156. sub ::vprotd
  157. { my $args=join(',',@_);
  158. if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/)
  159. { my @opcode=(0x8f);
  160. rxb(\@opcode,$1,$2,-1,0x08);
  161. push @opcode,0x78,0xc2;
  162. push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M
  163. my $c=$3;
  164. push @opcode,$c=~/^0/?oct($c):$c;
  165. &::data_byte(@opcode);
  166. }
  167. else
  168. { &::generic("vprotd",@_); }
  169. }
  170. sub ::endbranch
  171. {
  172. &::data_byte(0xf3,0x0f,0x1e,0xfb);
  173. }
  174. # label management
  175. $lbdecor="L"; # local label decoration, set by package
  176. $label="000";
  177. sub ::islabel # see is argument is a known label
  178. { my $i;
  179. foreach $i (values %label) { return $i if ($i eq $_[0]); }
  180. $label{$_[0]}; # can be undef
  181. }
  182. sub ::label # instantiate a function-scope label
  183. { if (!defined($label{$_[0]}))
  184. { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; }
  185. $label{$_[0]};
  186. }
  187. sub ::LABEL # instantiate a file-scope label
  188. { $label{$_[0]}=$_[1] if (!defined($label{$_[0]}));
  189. $label{$_[0]};
  190. }
  191. sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); }
  192. sub ::set_label_B { push(@out,"@_:\n"); }
  193. sub ::set_label
  194. { my $label=&::label($_[0]);
  195. &::align($_[1]) if ($_[1]>1);
  196. &::set_label_B($label);
  197. $label;
  198. }
  199. sub ::wipe_labels # wipes function-scope labels
  200. { foreach $i (keys %label)
  201. { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); }
  202. }
  203. # subroutine management
  204. sub ::function_begin
  205. { &function_begin_B(@_);
  206. $stack=4;
  207. &push("ebp");
  208. &push("ebx");
  209. &push("esi");
  210. &push("edi");
  211. }
  212. sub ::function_end
  213. { &pop("edi");
  214. &pop("esi");
  215. &pop("ebx");
  216. &pop("ebp");
  217. &ret();
  218. &function_end_B(@_);
  219. $stack=0;
  220. &wipe_labels();
  221. }
  222. sub ::function_end_A
  223. { &pop("edi");
  224. &pop("esi");
  225. &pop("ebx");
  226. &pop("ebp");
  227. &ret();
  228. $stack+=16; # readjust esp as if we didn't pop anything
  229. }
  230. sub ::asciz
  231. { my @str=unpack("C*",shift);
  232. push @str,0;
  233. while ($#str>15) {
  234. &data_byte(@str[0..15]);
  235. foreach (0..15) { shift @str; }
  236. }
  237. &data_byte(@str) if (@str);
  238. }
  239. sub ::asm_finish
  240. { &file_end();
  241. my $comment = "#";
  242. $comment = ";" if ($win32 || $netware);
  243. print <<___;
  244. $comment This file is generated from a similarly-named Perl script in the BoringSSL
  245. $comment source tree. Do not edit by hand.
  246. ___
  247. if ($win32 || $netware) {
  248. print <<___ unless $masm;
  249. %ifdef BORINGSSL_PREFIX
  250. %include "boringssl_prefix_symbols_nasm.inc"
  251. %endif
  252. ___
  253. } else {
  254. print <<___;
  255. #if defined(__i386__)
  256. #if defined(BORINGSSL_PREFIX)
  257. #include <boringssl_prefix_symbols_asm.h>
  258. #endif
  259. ___
  260. }
  261. print @out;
  262. print "#endif\n" unless ($win32 || $netware);
  263. }
  264. sub ::asm_init
  265. { my ($type,$cpu)=@_;
  266. $i386=$cpu;
  267. $elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0;
  268. if (($type eq "elf"))
  269. { $elf=1; require "x86gas.pl"; }
  270. elsif (($type eq "elf-1"))
  271. { $elf=-1; require "x86gas.pl"; }
  272. elsif (($type eq "a\.out"))
  273. { $aout=1; require "x86gas.pl"; }
  274. elsif (($type eq "coff" or $type eq "gaswin"))
  275. { $coff=1; require "x86gas.pl"; }
  276. elsif (($type eq "win32n"))
  277. { $win32=1; require "x86nasm.pl"; }
  278. elsif (($type eq "nw-nasm"))
  279. { $netware=1; require "x86nasm.pl"; }
  280. #elsif (($type eq "nw-mwasm"))
  281. #{ $netware=1; $mwerks=1; require "x86nasm.pl"; }
  282. elsif (($type eq "win32"))
  283. { $win32=1; $masm=1; require "x86masm.pl"; }
  284. elsif (($type eq "macosx"))
  285. { $aout=1; $macosx=1; require "x86gas.pl"; }
  286. elsif (($type eq "android"))
  287. { $elf=1; $android=1; require "x86gas.pl"; }
  288. else
  289. { print STDERR <<"EOF";
  290. Pick one target type from
  291. elf - Linux, FreeBSD, Solaris x86, etc.
  292. a.out - DJGPP, elder OpenBSD, etc.
  293. coff - GAS/COFF such as Win32 targets
  294. win32n - Windows 95/Windows NT NASM format
  295. nw-nasm - NetWare NASM format
  296. macosx - Mac OS X
  297. EOF
  298. exit(1);
  299. }
  300. $pic=0;
  301. for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); }
  302. &file();
  303. }
  304. sub ::hidden {}
  305. 1;