ring-native 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +3 -0
  4. data/README.md +22 -0
  5. data/Rakefile +1 -0
  6. data/ext/ring/extconf.rb +29 -0
  7. data/lib/ring/native.rb +8 -0
  8. data/lib/ring/native/version.rb +5 -0
  9. data/ring-native.gemspec +25 -0
  10. data/vendor/ring/BUILDING.md +40 -0
  11. data/vendor/ring/Cargo.toml +43 -0
  12. data/vendor/ring/LICENSE +185 -0
  13. data/vendor/ring/Makefile +35 -0
  14. data/vendor/ring/PORTING.md +163 -0
  15. data/vendor/ring/README.md +113 -0
  16. data/vendor/ring/STYLE.md +197 -0
  17. data/vendor/ring/appveyor.yml +27 -0
  18. data/vendor/ring/build.rs +108 -0
  19. data/vendor/ring/crypto/aes/aes.c +1142 -0
  20. data/vendor/ring/crypto/aes/aes_test.Windows.vcxproj +25 -0
  21. data/vendor/ring/crypto/aes/aes_test.cc +93 -0
  22. data/vendor/ring/crypto/aes/asm/aes-586.pl +2368 -0
  23. data/vendor/ring/crypto/aes/asm/aes-armv4.pl +1249 -0
  24. data/vendor/ring/crypto/aes/asm/aes-x86_64.pl +2246 -0
  25. data/vendor/ring/crypto/aes/asm/aesni-x86.pl +1318 -0
  26. data/vendor/ring/crypto/aes/asm/aesni-x86_64.pl +2084 -0
  27. data/vendor/ring/crypto/aes/asm/aesv8-armx.pl +675 -0
  28. data/vendor/ring/crypto/aes/asm/bsaes-armv7.pl +1364 -0
  29. data/vendor/ring/crypto/aes/asm/bsaes-x86_64.pl +1565 -0
  30. data/vendor/ring/crypto/aes/asm/vpaes-x86.pl +841 -0
  31. data/vendor/ring/crypto/aes/asm/vpaes-x86_64.pl +1116 -0
  32. data/vendor/ring/crypto/aes/internal.h +87 -0
  33. data/vendor/ring/crypto/aes/mode_wrappers.c +61 -0
  34. data/vendor/ring/crypto/bn/add.c +394 -0
  35. data/vendor/ring/crypto/bn/asm/armv4-mont.pl +694 -0
  36. data/vendor/ring/crypto/bn/asm/armv8-mont.pl +1503 -0
  37. data/vendor/ring/crypto/bn/asm/bn-586.pl +774 -0
  38. data/vendor/ring/crypto/bn/asm/co-586.pl +287 -0
  39. data/vendor/ring/crypto/bn/asm/rsaz-avx2.pl +1882 -0
  40. data/vendor/ring/crypto/bn/asm/x86-mont.pl +592 -0
  41. data/vendor/ring/crypto/bn/asm/x86_64-gcc.c +599 -0
  42. data/vendor/ring/crypto/bn/asm/x86_64-mont.pl +1393 -0
  43. data/vendor/ring/crypto/bn/asm/x86_64-mont5.pl +3507 -0
  44. data/vendor/ring/crypto/bn/bn.c +352 -0
  45. data/vendor/ring/crypto/bn/bn_asn1.c +74 -0
  46. data/vendor/ring/crypto/bn/bn_test.Windows.vcxproj +25 -0
  47. data/vendor/ring/crypto/bn/bn_test.cc +1696 -0
  48. data/vendor/ring/crypto/bn/cmp.c +200 -0
  49. data/vendor/ring/crypto/bn/convert.c +433 -0
  50. data/vendor/ring/crypto/bn/ctx.c +311 -0
  51. data/vendor/ring/crypto/bn/div.c +594 -0
  52. data/vendor/ring/crypto/bn/exponentiation.c +1335 -0
  53. data/vendor/ring/crypto/bn/gcd.c +711 -0
  54. data/vendor/ring/crypto/bn/generic.c +1019 -0
  55. data/vendor/ring/crypto/bn/internal.h +316 -0
  56. data/vendor/ring/crypto/bn/montgomery.c +516 -0
  57. data/vendor/ring/crypto/bn/mul.c +888 -0
  58. data/vendor/ring/crypto/bn/prime.c +829 -0
  59. data/vendor/ring/crypto/bn/random.c +334 -0
  60. data/vendor/ring/crypto/bn/rsaz_exp.c +262 -0
  61. data/vendor/ring/crypto/bn/rsaz_exp.h +53 -0
  62. data/vendor/ring/crypto/bn/shift.c +276 -0
  63. data/vendor/ring/crypto/bytestring/bytestring_test.Windows.vcxproj +25 -0
  64. data/vendor/ring/crypto/bytestring/bytestring_test.cc +421 -0
  65. data/vendor/ring/crypto/bytestring/cbb.c +399 -0
  66. data/vendor/ring/crypto/bytestring/cbs.c +227 -0
  67. data/vendor/ring/crypto/bytestring/internal.h +46 -0
  68. data/vendor/ring/crypto/chacha/chacha_generic.c +140 -0
  69. data/vendor/ring/crypto/chacha/chacha_vec.c +323 -0
  70. data/vendor/ring/crypto/chacha/chacha_vec_arm.S +1447 -0
  71. data/vendor/ring/crypto/chacha/chacha_vec_arm_generate.go +153 -0
  72. data/vendor/ring/crypto/cipher/cipher_test.Windows.vcxproj +25 -0
  73. data/vendor/ring/crypto/cipher/e_aes.c +390 -0
  74. data/vendor/ring/crypto/cipher/e_chacha20poly1305.c +208 -0
  75. data/vendor/ring/crypto/cipher/internal.h +173 -0
  76. data/vendor/ring/crypto/cipher/test/aes_128_gcm_tests.txt +543 -0
  77. data/vendor/ring/crypto/cipher/test/aes_128_key_wrap_tests.txt +9 -0
  78. data/vendor/ring/crypto/cipher/test/aes_256_gcm_tests.txt +475 -0
  79. data/vendor/ring/crypto/cipher/test/aes_256_key_wrap_tests.txt +23 -0
  80. data/vendor/ring/crypto/cipher/test/chacha20_poly1305_old_tests.txt +422 -0
  81. data/vendor/ring/crypto/cipher/test/chacha20_poly1305_tests.txt +484 -0
  82. data/vendor/ring/crypto/cipher/test/cipher_test.txt +100 -0
  83. data/vendor/ring/crypto/constant_time_test.Windows.vcxproj +25 -0
  84. data/vendor/ring/crypto/constant_time_test.c +304 -0
  85. data/vendor/ring/crypto/cpu-arm-asm.S +32 -0
  86. data/vendor/ring/crypto/cpu-arm.c +199 -0
  87. data/vendor/ring/crypto/cpu-intel.c +261 -0
  88. data/vendor/ring/crypto/crypto.c +151 -0
  89. data/vendor/ring/crypto/curve25519/asm/x25519-arm.S +2118 -0
  90. data/vendor/ring/crypto/curve25519/curve25519.c +4888 -0
  91. data/vendor/ring/crypto/curve25519/x25519_test.cc +128 -0
  92. data/vendor/ring/crypto/digest/md32_common.h +181 -0
  93. data/vendor/ring/crypto/ec/asm/p256-x86_64-asm.pl +2725 -0
  94. data/vendor/ring/crypto/ec/ec.c +193 -0
  95. data/vendor/ring/crypto/ec/ec_curves.c +61 -0
  96. data/vendor/ring/crypto/ec/ec_key.c +228 -0
  97. data/vendor/ring/crypto/ec/ec_montgomery.c +114 -0
  98. data/vendor/ring/crypto/ec/example_mul.Windows.vcxproj +25 -0
  99. data/vendor/ring/crypto/ec/internal.h +243 -0
  100. data/vendor/ring/crypto/ec/oct.c +253 -0
  101. data/vendor/ring/crypto/ec/p256-64.c +1794 -0
  102. data/vendor/ring/crypto/ec/p256-x86_64-table.h +9548 -0
  103. data/vendor/ring/crypto/ec/p256-x86_64.c +509 -0
  104. data/vendor/ring/crypto/ec/simple.c +1007 -0
  105. data/vendor/ring/crypto/ec/util-64.c +183 -0
  106. data/vendor/ring/crypto/ec/wnaf.c +508 -0
  107. data/vendor/ring/crypto/ecdh/ecdh.c +155 -0
  108. data/vendor/ring/crypto/ecdsa/ecdsa.c +304 -0
  109. data/vendor/ring/crypto/ecdsa/ecdsa_asn1.c +193 -0
  110. data/vendor/ring/crypto/ecdsa/ecdsa_test.Windows.vcxproj +25 -0
  111. data/vendor/ring/crypto/ecdsa/ecdsa_test.cc +327 -0
  112. data/vendor/ring/crypto/header_removed.h +17 -0
  113. data/vendor/ring/crypto/internal.h +495 -0
  114. data/vendor/ring/crypto/libring.Windows.vcxproj +101 -0
  115. data/vendor/ring/crypto/mem.c +98 -0
  116. data/vendor/ring/crypto/modes/asm/aesni-gcm-x86_64.pl +1045 -0
  117. data/vendor/ring/crypto/modes/asm/ghash-armv4.pl +517 -0
  118. data/vendor/ring/crypto/modes/asm/ghash-x86.pl +1393 -0
  119. data/vendor/ring/crypto/modes/asm/ghash-x86_64.pl +1741 -0
  120. data/vendor/ring/crypto/modes/asm/ghashv8-armx.pl +422 -0
  121. data/vendor/ring/crypto/modes/ctr.c +226 -0
  122. data/vendor/ring/crypto/modes/gcm.c +1206 -0
  123. data/vendor/ring/crypto/modes/gcm_test.Windows.vcxproj +25 -0
  124. data/vendor/ring/crypto/modes/gcm_test.c +348 -0
  125. data/vendor/ring/crypto/modes/internal.h +299 -0
  126. data/vendor/ring/crypto/perlasm/arm-xlate.pl +170 -0
  127. data/vendor/ring/crypto/perlasm/readme +100 -0
  128. data/vendor/ring/crypto/perlasm/x86_64-xlate.pl +1164 -0
  129. data/vendor/ring/crypto/perlasm/x86asm.pl +292 -0
  130. data/vendor/ring/crypto/perlasm/x86gas.pl +263 -0
  131. data/vendor/ring/crypto/perlasm/x86masm.pl +200 -0
  132. data/vendor/ring/crypto/perlasm/x86nasm.pl +187 -0
  133. data/vendor/ring/crypto/poly1305/poly1305.c +331 -0
  134. data/vendor/ring/crypto/poly1305/poly1305_arm.c +301 -0
  135. data/vendor/ring/crypto/poly1305/poly1305_arm_asm.S +2015 -0
  136. data/vendor/ring/crypto/poly1305/poly1305_test.Windows.vcxproj +25 -0
  137. data/vendor/ring/crypto/poly1305/poly1305_test.cc +80 -0
  138. data/vendor/ring/crypto/poly1305/poly1305_test.txt +52 -0
  139. data/vendor/ring/crypto/poly1305/poly1305_vec.c +892 -0
  140. data/vendor/ring/crypto/rand/asm/rdrand-x86_64.pl +75 -0
  141. data/vendor/ring/crypto/rand/internal.h +32 -0
  142. data/vendor/ring/crypto/rand/rand.c +189 -0
  143. data/vendor/ring/crypto/rand/urandom.c +219 -0
  144. data/vendor/ring/crypto/rand/windows.c +56 -0
  145. data/vendor/ring/crypto/refcount_c11.c +66 -0
  146. data/vendor/ring/crypto/refcount_lock.c +53 -0
  147. data/vendor/ring/crypto/refcount_test.Windows.vcxproj +25 -0
  148. data/vendor/ring/crypto/refcount_test.c +58 -0
  149. data/vendor/ring/crypto/rsa/blinding.c +462 -0
  150. data/vendor/ring/crypto/rsa/internal.h +108 -0
  151. data/vendor/ring/crypto/rsa/padding.c +300 -0
  152. data/vendor/ring/crypto/rsa/rsa.c +450 -0
  153. data/vendor/ring/crypto/rsa/rsa_asn1.c +261 -0
  154. data/vendor/ring/crypto/rsa/rsa_impl.c +944 -0
  155. data/vendor/ring/crypto/rsa/rsa_test.Windows.vcxproj +25 -0
  156. data/vendor/ring/crypto/rsa/rsa_test.cc +437 -0
  157. data/vendor/ring/crypto/sha/asm/sha-armv8.pl +436 -0
  158. data/vendor/ring/crypto/sha/asm/sha-x86_64.pl +2390 -0
  159. data/vendor/ring/crypto/sha/asm/sha256-586.pl +1275 -0
  160. data/vendor/ring/crypto/sha/asm/sha256-armv4.pl +735 -0
  161. data/vendor/ring/crypto/sha/asm/sha256-armv8.pl +14 -0
  162. data/vendor/ring/crypto/sha/asm/sha256-x86_64.pl +14 -0
  163. data/vendor/ring/crypto/sha/asm/sha512-586.pl +911 -0
  164. data/vendor/ring/crypto/sha/asm/sha512-armv4.pl +666 -0
  165. data/vendor/ring/crypto/sha/asm/sha512-armv8.pl +14 -0
  166. data/vendor/ring/crypto/sha/asm/sha512-x86_64.pl +14 -0
  167. data/vendor/ring/crypto/sha/sha1.c +271 -0
  168. data/vendor/ring/crypto/sha/sha256.c +204 -0
  169. data/vendor/ring/crypto/sha/sha512.c +355 -0
  170. data/vendor/ring/crypto/test/file_test.cc +326 -0
  171. data/vendor/ring/crypto/test/file_test.h +181 -0
  172. data/vendor/ring/crypto/test/malloc.cc +150 -0
  173. data/vendor/ring/crypto/test/scoped_types.h +95 -0
  174. data/vendor/ring/crypto/test/test.Windows.vcxproj +35 -0
  175. data/vendor/ring/crypto/test/test_util.cc +46 -0
  176. data/vendor/ring/crypto/test/test_util.h +41 -0
  177. data/vendor/ring/crypto/thread_none.c +55 -0
  178. data/vendor/ring/crypto/thread_pthread.c +165 -0
  179. data/vendor/ring/crypto/thread_test.Windows.vcxproj +25 -0
  180. data/vendor/ring/crypto/thread_test.c +200 -0
  181. data/vendor/ring/crypto/thread_win.c +282 -0
  182. data/vendor/ring/examples/checkdigest.rs +103 -0
  183. data/vendor/ring/include/openssl/aes.h +121 -0
  184. data/vendor/ring/include/openssl/arm_arch.h +129 -0
  185. data/vendor/ring/include/openssl/base.h +156 -0
  186. data/vendor/ring/include/openssl/bn.h +794 -0
  187. data/vendor/ring/include/openssl/buffer.h +18 -0
  188. data/vendor/ring/include/openssl/bytestring.h +235 -0
  189. data/vendor/ring/include/openssl/chacha.h +37 -0
  190. data/vendor/ring/include/openssl/cmac.h +76 -0
  191. data/vendor/ring/include/openssl/cpu.h +184 -0
  192. data/vendor/ring/include/openssl/crypto.h +43 -0
  193. data/vendor/ring/include/openssl/curve25519.h +88 -0
  194. data/vendor/ring/include/openssl/ec.h +225 -0
  195. data/vendor/ring/include/openssl/ec_key.h +129 -0
  196. data/vendor/ring/include/openssl/ecdh.h +110 -0
  197. data/vendor/ring/include/openssl/ecdsa.h +156 -0
  198. data/vendor/ring/include/openssl/err.h +201 -0
  199. data/vendor/ring/include/openssl/mem.h +101 -0
  200. data/vendor/ring/include/openssl/obj_mac.h +71 -0
  201. data/vendor/ring/include/openssl/opensslfeatures.h +68 -0
  202. data/vendor/ring/include/openssl/opensslv.h +18 -0
  203. data/vendor/ring/include/openssl/ossl_typ.h +18 -0
  204. data/vendor/ring/include/openssl/poly1305.h +51 -0
  205. data/vendor/ring/include/openssl/rand.h +70 -0
  206. data/vendor/ring/include/openssl/rsa.h +399 -0
  207. data/vendor/ring/include/openssl/thread.h +133 -0
  208. data/vendor/ring/include/openssl/type_check.h +71 -0
  209. data/vendor/ring/mk/Common.props +63 -0
  210. data/vendor/ring/mk/Windows.props +42 -0
  211. data/vendor/ring/mk/WindowsTest.props +18 -0
  212. data/vendor/ring/mk/appveyor.bat +62 -0
  213. data/vendor/ring/mk/bottom_of_makefile.mk +54 -0
  214. data/vendor/ring/mk/ring.mk +266 -0
  215. data/vendor/ring/mk/top_of_makefile.mk +214 -0
  216. data/vendor/ring/mk/travis.sh +40 -0
  217. data/vendor/ring/mk/update-travis-yml.py +229 -0
  218. data/vendor/ring/ring.sln +153 -0
  219. data/vendor/ring/src/aead.rs +682 -0
  220. data/vendor/ring/src/agreement.rs +248 -0
  221. data/vendor/ring/src/c.rs +129 -0
  222. data/vendor/ring/src/constant_time.rs +37 -0
  223. data/vendor/ring/src/der.rs +96 -0
  224. data/vendor/ring/src/digest.rs +690 -0
  225. data/vendor/ring/src/digest_tests.txt +57 -0
  226. data/vendor/ring/src/ecc.rs +28 -0
  227. data/vendor/ring/src/ecc_build.rs +279 -0
  228. data/vendor/ring/src/ecc_curves.rs +117 -0
  229. data/vendor/ring/src/ed25519_tests.txt +2579 -0
  230. data/vendor/ring/src/exe_tests.rs +46 -0
  231. data/vendor/ring/src/ffi.rs +29 -0
  232. data/vendor/ring/src/file_test.rs +187 -0
  233. data/vendor/ring/src/hkdf.rs +153 -0
  234. data/vendor/ring/src/hkdf_tests.txt +59 -0
  235. data/vendor/ring/src/hmac.rs +414 -0
  236. data/vendor/ring/src/hmac_tests.txt +97 -0
  237. data/vendor/ring/src/input.rs +312 -0
  238. data/vendor/ring/src/lib.rs +41 -0
  239. data/vendor/ring/src/pbkdf2.rs +265 -0
  240. data/vendor/ring/src/pbkdf2_tests.txt +113 -0
  241. data/vendor/ring/src/polyfill.rs +57 -0
  242. data/vendor/ring/src/rand.rs +28 -0
  243. data/vendor/ring/src/signature.rs +314 -0
  244. data/vendor/ring/third-party/NIST/README.md +9 -0
  245. data/vendor/ring/third-party/NIST/SHAVS/SHA1LongMsg.rsp +263 -0
  246. data/vendor/ring/third-party/NIST/SHAVS/SHA1Monte.rsp +309 -0
  247. data/vendor/ring/third-party/NIST/SHAVS/SHA1ShortMsg.rsp +267 -0
  248. data/vendor/ring/third-party/NIST/SHAVS/SHA224LongMsg.rsp +263 -0
  249. data/vendor/ring/third-party/NIST/SHAVS/SHA224Monte.rsp +309 -0
  250. data/vendor/ring/third-party/NIST/SHAVS/SHA224ShortMsg.rsp +267 -0
  251. data/vendor/ring/third-party/NIST/SHAVS/SHA256LongMsg.rsp +263 -0
  252. data/vendor/ring/third-party/NIST/SHAVS/SHA256Monte.rsp +309 -0
  253. data/vendor/ring/third-party/NIST/SHAVS/SHA256ShortMsg.rsp +267 -0
  254. data/vendor/ring/third-party/NIST/SHAVS/SHA384LongMsg.rsp +519 -0
  255. data/vendor/ring/third-party/NIST/SHAVS/SHA384Monte.rsp +309 -0
  256. data/vendor/ring/third-party/NIST/SHAVS/SHA384ShortMsg.rsp +523 -0
  257. data/vendor/ring/third-party/NIST/SHAVS/SHA512LongMsg.rsp +519 -0
  258. data/vendor/ring/third-party/NIST/SHAVS/SHA512Monte.rsp +309 -0
  259. data/vendor/ring/third-party/NIST/SHAVS/SHA512ShortMsg.rsp +523 -0
  260. data/vendor/ring/third-party/NIST/sha256sums.txt +1 -0
  261. metadata +333 -0
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env perl
2
+
3
+ # ARM assembler distiller by <appro>.
4
+
5
+ my $flavour = shift;
6
+ my $output = shift;
7
+ open STDOUT,">$output" || die "can't open $output: $!";
8
+
9
+ $flavour = "linux32" if (!$flavour or $flavour eq "void");
10
+
11
+ my %GLOBALS;
12
+ my $dotinlocallabels=($flavour=~/linux/)?1:0;
13
+
14
+ ################################################################
15
+ # directives which need special treatment on different platforms
16
+ ################################################################
17
+ my $arch = sub {
18
+ if ($flavour =~ /linux/) { ".arch\t".join(',',@_); }
19
+ else { ""; }
20
+ };
21
+ my $fpu = sub {
22
+ if ($flavour =~ /linux/) { ".fpu\t".join(',',@_); }
23
+ else { ""; }
24
+ };
25
+ my $hidden = sub {
26
+ if ($flavour =~ /ios/) { ".private_extern\t".join(',',@_); }
27
+ else { ".hidden\t".join(',',@_); }
28
+ };
29
+ my $comm = sub {
30
+ my @args = split(/,\s*/,shift);
31
+ my $name = @args[0];
32
+ my $global = \$GLOBALS{$name};
33
+ my $ret;
34
+
35
+ if ($flavour =~ /ios32/) {
36
+ $ret = ".comm\t_$name,@args[1]\n";
37
+ $ret .= ".non_lazy_symbol_pointer\n";
38
+ $ret .= "$name:\n";
39
+ $ret .= ".indirect_symbol\t_$name\n";
40
+ $ret .= ".long\t0";
41
+ $name = "_$name";
42
+ } else { $ret = ".comm\t".join(',',@args); }
43
+
44
+ $$global = $name;
45
+ $ret;
46
+ };
47
+ my $globl = sub {
48
+ my $name = shift;
49
+ my $global = \$GLOBALS{$name};
50
+ my $ret;
51
+
52
+ SWITCH: for ($flavour) {
53
+ /ios/ && do { $name = "_$name";
54
+ last;
55
+ };
56
+ }
57
+
58
+ $ret = ".globl $name" if (!$ret);
59
+ $$global = $name;
60
+ $ret;
61
+ };
62
+ my $global = $globl;
63
+ my $extern = sub {
64
+ &$globl(@_);
65
+ return; # return nothing
66
+ };
67
+ my $type = sub {
68
+ if ($flavour =~ /linux/) { ".type\t".join(',',@_); }
69
+ else { ""; }
70
+ };
71
+ my $size = sub {
72
+ if ($flavour =~ /linux/) { ".size\t".join(',',@_); }
73
+ else { ""; }
74
+ };
75
+ my $inst = sub {
76
+ if ($flavour =~ /linux/) { ".inst\t".join(',',@_); }
77
+ else { ".long\t".join(',',@_); }
78
+ };
79
+ my $asciz = sub {
80
+ my $line = join(",",@_);
81
+ if ($line =~ /^"(.*)"$/)
82
+ { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; }
83
+ else
84
+ { ""; }
85
+ };
86
+
87
+ sub range {
88
+ my ($r,$sfx,$start,$end) = @_;
89
+
90
+ join(",",map("$r$_$sfx",($start..$end)));
91
+ }
92
+
93
+ sub expand_line {
94
+ my $line = shift;
95
+ my @ret = ();
96
+
97
+ pos($line)=0;
98
+
99
+ while ($line =~ m/\G[^@\/\{\"]*/g) {
100
+ if ($line =~ m/\G(@|\/\/|$)/gc) {
101
+ last;
102
+ }
103
+ elsif ($line =~ m/\G\{/gc) {
104
+ my $saved_pos = pos($line);
105
+ $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e;
106
+ pos($line) = $saved_pos;
107
+ $line =~ m/\G[^\}]*\}/g;
108
+ }
109
+ elsif ($line =~ m/\G\"/gc) {
110
+ $line =~ m/\G[^\"]*\"/g;
111
+ }
112
+ }
113
+
114
+ $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge;
115
+
116
+ return $line;
117
+ }
118
+
119
+ print "#if defined(__arm__)\n" if ($flavour eq "linux32");
120
+ print "#if defined(__aarch64__)\n" if ($flavour eq "linux64");
121
+
122
+ while($line=<>) {
123
+
124
+ if ($line =~ m/^\s*(#|@|\/\/)/) { print $line; next; }
125
+
126
+ $line =~ s|/\*.*\*/||; # get rid of C-style comments...
127
+ $line =~ s|^\s+||; # ... and skip white spaces in beginning...
128
+ $line =~ s|\s+$||; # ... and at the end
129
+
130
+ {
131
+ $line =~ s|[\b\.]L(\w{2,})|L$1|g; # common denominator for Locallabel
132
+ $line =~ s|\bL(\w{2,})|\.L$1|g if ($dotinlocallabels);
133
+ }
134
+
135
+ {
136
+ $line =~ s|(^[\.\w]+)\:\s*||;
137
+ my $label = $1;
138
+ if ($label) {
139
+ printf "%s:",($GLOBALS{$label} or $label);
140
+ }
141
+ }
142
+
143
+ if ($line !~ m/^[#@]/) {
144
+ $line =~ s|^\s*(\.?)(\S+)\s*||;
145
+ my $c = $1; $c = "\t" if ($c eq "");
146
+ my $mnemonic = $2;
147
+ my $opcode;
148
+ if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) {
149
+ $opcode = eval("\$$1_$2");
150
+ } else {
151
+ $opcode = eval("\$$mnemonic");
152
+ }
153
+
154
+ my $arg=expand_line($line);
155
+
156
+ if (ref($opcode) eq 'CODE') {
157
+ $line = &$opcode($arg);
158
+ } elsif ($mnemonic) {
159
+ $line = $c.$mnemonic;
160
+ $line.= "\t$arg" if ($arg ne "");
161
+ }
162
+ }
163
+
164
+ print $line if ($line);
165
+ print "\n";
166
+ }
167
+
168
+ print "#endif" if ($flavour eq "linux32" || $flavour eq "linux64");
169
+
170
+ close STDOUT;
@@ -0,0 +1,100 @@
1
+ The perl scripts in this directory are my 'hack' to generate
2
+ multiple different assembler formats via the one origional script.
3
+
4
+ The way to use this library is to start with adding the path to this directory
5
+ and then include it.
6
+
7
+ push(@INC,"perlasm","../../perlasm");
8
+ require "x86asm.pl";
9
+
10
+ The first thing we do is setup the file and type of assember
11
+
12
+ &asm_init($ARGV[0],$0);
13
+
14
+ The first argument is the 'type'. Currently
15
+ 'cpp', 'sol', 'a.out', 'elf' or 'win32'.
16
+ Argument 2 is the file name.
17
+
18
+ The reciprocal function is
19
+ &asm_finish() which should be called at the end.
20
+
21
+ There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
22
+ and x86unix.pl which is the unix (gas) version.
23
+
24
+ Functions of interest are:
25
+ &external_label("des_SPtrans"); declare and external variable
26
+ &LB(reg); Low byte for a register
27
+ &HB(reg); High byte for a register
28
+ &BP(off,base,index,scale) Byte pointer addressing
29
+ &DWP(off,base,index,scale) Word pointer addressing
30
+ &stack_push(num) Basically a 'sub esp, num*4' with extra
31
+ &stack_pop(num) inverse of stack_push
32
+ &function_begin(name,extra) Start a function with pushing of
33
+ edi, esi, ebx and ebp. extra is extra win32
34
+ external info that may be required.
35
+ &function_begin_B(name,extra) Same as norma function_begin but no pushing.
36
+ &function_end(name) Call at end of function.
37
+ &function_end_A(name) Standard pop and ret, for use inside functions
38
+ &function_end_B(name) Call at end but with poping or 'ret'.
39
+ &swtmp(num) Address on stack temp word.
40
+ &wparam(num) Parameter number num, that was push
41
+ in C convention. This all works over pushes
42
+ and pops.
43
+ &comment("hello there") Put in a comment.
44
+ &label("loop") Refer to a label, normally a jmp target.
45
+ &set_label("loop") Set a label at this point.
46
+ &data_word(word) Put in a word of data.
47
+
48
+ So how does this all hold together? Given
49
+
50
+ int calc(int len, int *data)
51
+ {
52
+ int i,j=0;
53
+
54
+ for (i=0; i<len; i++)
55
+ {
56
+ j+=other(data[i]);
57
+ }
58
+ }
59
+
60
+ So a very simple version of this function could be coded as
61
+
62
+ push(@INC,"perlasm","../../perlasm");
63
+ require "x86asm.pl";
64
+
65
+ &asm_init($ARGV[0],"cacl.pl");
66
+
67
+ &external_label("other");
68
+
69
+ $tmp1= "eax";
70
+ $j= "edi";
71
+ $data= "esi";
72
+ $i= "ebp";
73
+
74
+ &comment("a simple function");
75
+ &function_begin("calc");
76
+ &mov( $data, &wparam(1)); # data
77
+ &xor( $j, $j);
78
+ &xor( $i, $i);
79
+
80
+ &set_label("loop");
81
+ &cmp( $i, &wparam(0));
82
+ &jge( &label("end"));
83
+
84
+ &mov( $tmp1, &DWP(0,$data,$i,4));
85
+ &push( $tmp1);
86
+ &call( "other");
87
+ &add( $j, "eax");
88
+ &pop( $tmp1);
89
+ &inc( $i);
90
+ &jmp( &label("loop"));
91
+
92
+ &set_label("end");
93
+ &mov( "eax", $j);
94
+
95
+ &function_end("calc");
96
+
97
+ &asm_finish();
98
+
99
+ The above example is very very unoptimised but gives an idea of how
100
+ things work.
@@ -0,0 +1,1164 @@
1
+ #!/usr/bin/env perl
2
+
3
+ # Ascetic x86_64 AT&T to MASM/NASM assembler translator by <appro>.
4
+ #
5
+ # Why AT&T to MASM and not vice versa? Several reasons. Because AT&T
6
+ # format is way easier to parse. Because it's simpler to "gear" from
7
+ # Unix ABI to Windows one [see cross-reference "card" at the end of
8
+ # file]. Because Linux targets were available first...
9
+ #
10
+ # In addition the script also "distills" code suitable for GNU
11
+ # assembler, so that it can be compiled with more rigid assemblers,
12
+ # such as Solaris /usr/ccs/bin/as.
13
+ #
14
+ # This translator is not designed to convert *arbitrary* assembler
15
+ # code from AT&T format to MASM one. It's designed to convert just
16
+ # enough to provide for dual-ABI OpenSSL modules development...
17
+ # There *are* limitations and you might have to modify your assembler
18
+ # code or this script to achieve the desired result...
19
+ #
20
+ # Currently recognized limitations:
21
+ #
22
+ # - can't use multiple ops per line;
23
+ #
24
+ # Dual-ABI styling rules.
25
+ #
26
+ # 1. Adhere to Unix register and stack layout [see cross-reference
27
+ # ABI "card" at the end for explanation].
28
+ # 2. Forget about "red zone," stick to more traditional blended
29
+ # stack frame allocation. If volatile storage is actually required
30
+ # that is. If not, just leave the stack as is.
31
+ # 3. Functions tagged with ".type name,@function" get crafted with
32
+ # unified Win64 prologue and epilogue automatically. If you want
33
+ # to take care of ABI differences yourself, tag functions as
34
+ # ".type name,@abi-omnipotent" instead.
35
+ # 4. To optimize the Win64 prologue you can specify number of input
36
+ # arguments as ".type name,@function,N." Keep in mind that if N is
37
+ # larger than 6, then you *have to* write "abi-omnipotent" code,
38
+ # because >6 cases can't be addressed with unified prologue.
39
+ # 5. Name local labels as .L*, do *not* use dynamic labels such as 1:
40
+ # (sorry about latter).
41
+ # 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is
42
+ # required to identify the spots, where to inject Win64 epilogue!
43
+ # But on the pros, it's then prefixed with rep automatically:-)
44
+ # 7. Stick to explicit ip-relative addressing. If you have to use
45
+ # GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??.
46
+ # Both are recognized and translated to proper Win64 addressing
47
+ # modes. To support legacy code a synthetic directive, .picmeup,
48
+ # is implemented. It puts address of the *next* instruction into
49
+ # target register, e.g.:
50
+ #
51
+ # .picmeup %rax
52
+ # lea .Label-.(%rax),%rax
53
+ #
54
+ # 8. In order to provide for structured exception handling unified
55
+ # Win64 prologue copies %rsp value to %rax. For further details
56
+ # see SEH paragraph at the end.
57
+ # 9. .init segment is allowed to contain calls to functions only.
58
+ # a. If function accepts more than 4 arguments *and* >4th argument
59
+ # is declared as non 64-bit value, do clear its upper part.
60
+
61
+ my $flavour = shift;
62
+ my $output = shift;
63
+ if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
64
+
65
+ open STDOUT,">$output" || die "can't open $output: $!"
66
+ if (defined($output));
67
+
68
+ my $gas=1; $gas=0 if ($output =~ /\.asm$/);
69
+ my $elf=1; $elf=0 if (!$gas);
70
+ my $win64=0;
71
+ my $prefix="";
72
+ my $decor=".L";
73
+
74
+ my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005
75
+ my $masm=0;
76
+ my $PTR=" PTR";
77
+
78
+ my $nasmref=2.03;
79
+ my $nasm=0;
80
+
81
+ if ($flavour eq "mingw64") { $gas=1; $elf=0; $win64=1;
82
+ # TODO(davidben): Before supporting the
83
+ # mingw64 perlasm flavour, do away with this
84
+ # environment variable check.
85
+ die "mingw64 not supported";
86
+ $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`;
87
+ chomp($prefix);
88
+ }
89
+ elsif ($flavour eq "macosx") { $gas=1; $elf=0; $prefix="_"; $decor="L\$"; }
90
+ elsif ($flavour eq "masm") { $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; }
91
+ elsif ($flavour eq "nasm") { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; }
92
+ elsif (!$gas) { die "unknown flavour $flavour"; }
93
+
94
+ my $current_segment;
95
+ my $current_function;
96
+ my %globals;
97
+
98
+ { package opcode; # pick up opcodes
99
+ sub re {
100
+ my $self = shift; # single instance in enough...
101
+ local *line = shift;
102
+ undef $ret;
103
+
104
+ if ($line =~ /^([a-z][a-z0-9]*)/i) {
105
+ $self->{op} = $1;
106
+ $ret = $self;
107
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
108
+
109
+ undef $self->{sz};
110
+ if ($self->{op} =~ /^(movz)x?([bw]).*/) { # movz is pain...
111
+ $self->{op} = $1;
112
+ $self->{sz} = $2;
113
+ } elsif ($self->{op} =~ /call|jmp/) {
114
+ $self->{sz} = "";
115
+ } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn
116
+ $self->{sz} = "";
117
+ } elsif ($self->{op} =~ /^v/) { # VEX
118
+ $self->{sz} = "";
119
+ } elsif ($self->{op} =~ /mov[dq]/ && $line =~ /%xmm/) {
120
+ $self->{sz} = "";
121
+ } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
122
+ $self->{op} = $1;
123
+ $self->{sz} = $2;
124
+ }
125
+ }
126
+ $ret;
127
+ }
128
+ sub size {
129
+ my $self = shift;
130
+ my $sz = shift;
131
+ $self->{sz} = $sz if (defined($sz) && !defined($self->{sz}));
132
+ $self->{sz};
133
+ }
134
+ sub out {
135
+ my $self = shift;
136
+ if ($gas) {
137
+ if ($self->{op} eq "movz") { # movz is pain...
138
+ sprintf "%s%s%s",$self->{op},$self->{sz},shift;
139
+ } elsif ($self->{op} =~ /^set/) {
140
+ "$self->{op}";
141
+ } elsif ($self->{op} eq "ret") {
142
+ my $epilogue = "";
143
+ if ($win64 && $current_function->{abi} eq "svr4") {
144
+ $epilogue = "movq 8(%rsp),%rdi\n\t" .
145
+ "movq 16(%rsp),%rsi\n\t";
146
+ }
147
+ $epilogue . ".byte 0xf3,0xc3";
148
+ } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") {
149
+ ".p2align\t3\n\t.quad";
150
+ } else {
151
+ "$self->{op}$self->{sz}";
152
+ }
153
+ } else {
154
+ $self->{op} =~ s/^movz/movzx/;
155
+ if ($self->{op} eq "ret") {
156
+ $self->{op} = "";
157
+ if ($win64 && $current_function->{abi} eq "svr4") {
158
+ $self->{op} = "mov rdi,QWORD${PTR}[8+rsp]\t;WIN64 epilogue\n\t".
159
+ "mov rsi,QWORD${PTR}[16+rsp]\n\t";
160
+ }
161
+ $self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
162
+ } elsif ($self->{op} =~ /^(pop|push)f/) {
163
+ $self->{op} .= $self->{sz};
164
+ } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") {
165
+ $self->{op} = "\tDQ";
166
+ }
167
+ $self->{op};
168
+ }
169
+ }
170
+ sub mnemonic {
171
+ my $self=shift;
172
+ my $op=shift;
173
+ $self->{op}=$op if (defined($op));
174
+ $self->{op};
175
+ }
176
+ }
177
+ { package const; # pick up constants, which start with $
178
+ sub re {
179
+ my $self = shift; # single instance in enough...
180
+ local *line = shift;
181
+ undef $ret;
182
+
183
+ if ($line =~ /^\$([^,]+)/) {
184
+ $self->{value} = $1;
185
+ $ret = $self;
186
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
187
+ }
188
+ $ret;
189
+ }
190
+ sub out {
191
+ my $self = shift;
192
+
193
+ if ($gas) {
194
+ # Solaris /usr/ccs/bin/as can't handle multiplications
195
+ # in $self->{value}
196
+ $self->{value} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
197
+ $self->{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
198
+ sprintf "\$%s",$self->{value};
199
+ } else {
200
+ $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig;
201
+ $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
202
+ sprintf "%s",$self->{value};
203
+ }
204
+ }
205
+ }
206
+ { package ea; # pick up effective addresses: expr(%reg,%reg,scale)
207
+ sub re {
208
+ my $self = shift; # single instance in enough...
209
+ local *line = shift;
210
+ undef $ret;
211
+
212
+ # optional * ---vvv--- appears in indirect jmp/call
213
+ if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) {
214
+ $self->{asterisk} = $1;
215
+ $self->{label} = $2;
216
+ ($self->{base},$self->{index},$self->{scale})=split(/,/,$3);
217
+ $self->{scale} = 1 if (!defined($self->{scale}));
218
+ $ret = $self;
219
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
220
+
221
+ if ($win64 && $self->{label} =~ s/\@GOTPCREL//) {
222
+ die if (opcode->mnemonic() ne "mov");
223
+ opcode->mnemonic("lea");
224
+ }
225
+ $self->{base} =~ s/^%//;
226
+ $self->{index} =~ s/^%// if (defined($self->{index}));
227
+ }
228
+ $ret;
229
+ }
230
+ sub size {}
231
+ sub out {
232
+ my $self = shift;
233
+ my $sz = shift;
234
+
235
+ $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
236
+ $self->{label} =~ s/\.L/$decor/g;
237
+
238
+ # Silently convert all EAs to 64-bit. This is required for
239
+ # elder GNU assembler and results in more compact code,
240
+ # *but* most importantly AES module depends on this feature!
241
+ $self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
242
+ $self->{base} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
243
+
244
+ # Solaris /usr/ccs/bin/as can't handle multiplications
245
+ # in $self->{label}, new gas requires sign extension...
246
+ use integer;
247
+ $self->{label} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
248
+ $self->{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg;
249
+ $self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg;
250
+
251
+ if (!$self->{label} && $self->{index} && $self->{scale}==1 &&
252
+ $self->{base} =~ /(rbp|r13)/) {
253
+ $self->{base} = $self->{index}; $self->{index} = $1;
254
+ }
255
+
256
+ if ($gas) {
257
+ $self->{label} =~ s/^___imp_/__imp__/ if ($flavour eq "mingw64");
258
+
259
+ if (defined($self->{index})) {
260
+ sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk},
261
+ $self->{label},
262
+ $self->{base}?"%$self->{base}":"",
263
+ $self->{index},$self->{scale};
264
+ } else {
265
+ sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base};
266
+ }
267
+ } else {
268
+ %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR",
269
+ l=>"DWORD$PTR", d=>"DWORD$PTR",
270
+ q=>"QWORD$PTR", o=>"OWORD$PTR",
271
+ x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" );
272
+
273
+ $self->{label} =~ s/\./\$/g;
274
+ $self->{label} =~ s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/ig;
275
+ $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
276
+
277
+ ($self->{asterisk}) && ($sz="q") ||
278
+ (opcode->mnemonic() =~ /^v?mov([qd])$/) && ($sz=$1) ||
279
+ (opcode->mnemonic() =~ /^v?pinsr([qdwb])$/) && ($sz=$1) ||
280
+ (opcode->mnemonic() =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) ||
281
+ (opcode->mnemonic() =~ /^vinsert[fi]128$/) && ($sz="x");
282
+
283
+ if (defined($self->{index})) {
284
+ sprintf "%s[%s%s*%d%s]",$szmap{$sz},
285
+ $self->{label}?"$self->{label}+":"",
286
+ $self->{index},$self->{scale},
287
+ $self->{base}?"+$self->{base}":"";
288
+ } elsif ($self->{base} eq "rip") {
289
+ sprintf "%s[%s]",$szmap{$sz},$self->{label};
290
+ } else {
291
+ sprintf "%s[%s%s]",$szmap{$sz},
292
+ $self->{label}?"$self->{label}+":"",
293
+ $self->{base};
294
+ }
295
+ }
296
+ }
297
+ }
298
+ { package register; # pick up registers, which start with %.
299
+ sub re {
300
+ my $class = shift; # muliple instances...
301
+ my $self = {};
302
+ local *line = shift;
303
+ undef $ret;
304
+
305
+ # optional * ---vvv--- appears in indirect jmp/call
306
+ if ($line =~ /^(\*?)%(\w+)/) {
307
+ bless $self,$class;
308
+ $self->{asterisk} = $1;
309
+ $self->{value} = $2;
310
+ $ret = $self;
311
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
312
+ }
313
+ $ret;
314
+ }
315
+ sub size {
316
+ my $self = shift;
317
+ undef $ret;
318
+
319
+ if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; }
320
+ elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; }
321
+ elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; }
322
+ elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; }
323
+ elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; }
324
+ elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; }
325
+ elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; }
326
+ elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; }
327
+
328
+ $ret;
329
+ }
330
+ sub out {
331
+ my $self = shift;
332
+ if ($gas) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; }
333
+ else { $self->{value}; }
334
+ }
335
+ }
336
+ { package label; # pick up labels, which end with :
337
+ sub re {
338
+ my $self = shift; # single instance is enough...
339
+ local *line = shift;
340
+ undef $ret;
341
+
342
+ if ($line =~ /(^[\.\w]+)\:/) {
343
+ $self->{value} = $1;
344
+ $ret = $self;
345
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
346
+
347
+ $self->{value} =~ s/^\.L/$decor/;
348
+ }
349
+ $ret;
350
+ }
351
+ sub out {
352
+ my $self = shift;
353
+
354
+ if ($gas) {
355
+ my $func = ($globals{$self->{value}} or $self->{value}) . ":";
356
+ if ($win64 &&
357
+ $current_function->{name} eq $self->{value} &&
358
+ $current_function->{abi} eq "svr4") {
359
+ $func .= "\n";
360
+ $func .= " movq %rdi,8(%rsp)\n";
361
+ $func .= " movq %rsi,16(%rsp)\n";
362
+ $func .= " movq %rsp,%rax\n";
363
+ $func .= "${decor}SEH_begin_$current_function->{name}:\n";
364
+ my $narg = $current_function->{narg};
365
+ $narg=6 if (!defined($narg));
366
+ $func .= " movq %rcx,%rdi\n" if ($narg>0);
367
+ $func .= " movq %rdx,%rsi\n" if ($narg>1);
368
+ $func .= " movq %r8,%rdx\n" if ($narg>2);
369
+ $func .= " movq %r9,%rcx\n" if ($narg>3);
370
+ $func .= " movq 40(%rsp),%r8\n" if ($narg>4);
371
+ $func .= " movq 48(%rsp),%r9\n" if ($narg>5);
372
+ }
373
+ $func;
374
+ } elsif ($self->{value} ne "$current_function->{name}") {
375
+ $self->{value} .= ":" if ($masm && $ret!~m/^\$/);
376
+ $self->{value} . ":";
377
+ } elsif ($win64 && $current_function->{abi} eq "svr4") {
378
+ my $func = "$current_function->{name}" .
379
+ ($nasm ? ":" : "\tPROC $current_function->{scope}") .
380
+ "\n";
381
+ $func .= " mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n";
382
+ $func .= " mov QWORD${PTR}[16+rsp],rsi\n";
383
+ $func .= " mov rax,rsp\n";
384
+ $func .= "${decor}SEH_begin_$current_function->{name}:";
385
+ $func .= ":" if ($masm);
386
+ $func .= "\n";
387
+ my $narg = $current_function->{narg};
388
+ $narg=6 if (!defined($narg));
389
+ $func .= " mov rdi,rcx\n" if ($narg>0);
390
+ $func .= " mov rsi,rdx\n" if ($narg>1);
391
+ $func .= " mov rdx,r8\n" if ($narg>2);
392
+ $func .= " mov rcx,r9\n" if ($narg>3);
393
+ $func .= " mov r8,QWORD${PTR}[40+rsp]\n" if ($narg>4);
394
+ $func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5);
395
+ $func .= "\n";
396
+ } else {
397
+ "$current_function->{name}".
398
+ ($nasm ? ":" : "\tPROC $current_function->{scope}");
399
+ }
400
+ }
401
+ }
402
+ { package expr; # pick up expressioins
403
+ sub re {
404
+ my $self = shift; # single instance is enough...
405
+ local *line = shift;
406
+ undef $ret;
407
+
408
+ if ($line =~ /(^[^,]+)/) {
409
+ $self->{value} = $1;
410
+ $ret = $self;
411
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
412
+
413
+ $self->{value} =~ s/\@PLT// if (!$elf);
414
+ $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
415
+ $self->{value} =~ s/\.L/$decor/g;
416
+ }
417
+ $ret;
418
+ }
419
+ sub out {
420
+ my $self = shift;
421
+ if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) {
422
+ "NEAR ".$self->{value};
423
+ } else {
424
+ $self->{value};
425
+ }
426
+ }
427
+ }
428
+ { package directive; # pick up directives, which start with .
429
+ sub re {
430
+ my $self = shift; # single instance is enough...
431
+ local *line = shift;
432
+ undef $ret;
433
+ my $dir;
434
+ my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2:
435
+ ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48,
436
+ "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48,
437
+ "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48,
438
+ "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48,
439
+ "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c,
440
+ "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c,
441
+ "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c,
442
+ "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c );
443
+
444
+ if ($line =~ /^\s*(\.\w+)/) {
445
+ $dir = $1;
446
+ $ret = $self;
447
+ undef $self->{value};
448
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
449
+
450
+ SWITCH: for ($dir) {
451
+ /\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) {
452
+ $dir="\t.long";
453
+ $line=sprintf "0x%x,0x90000000",$opcode{$1};
454
+ }
455
+ last;
456
+ };
457
+ /\.global|\.globl|\.extern/
458
+ && do { $globals{$line} = $prefix . $line;
459
+ $line = $globals{$line} if ($prefix);
460
+ last;
461
+ };
462
+ /\.type/ && do { ($sym,$type,$narg) = split(',',$line);
463
+ if ($type eq "\@function") {
464
+ undef $current_function;
465
+ $current_function->{name} = $sym;
466
+ $current_function->{abi} = "svr4";
467
+ $current_function->{narg} = $narg;
468
+ $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
469
+ } elsif ($type eq "\@abi-omnipotent") {
470
+ undef $current_function;
471
+ $current_function->{name} = $sym;
472
+ $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
473
+ }
474
+ $line =~ s/\@abi\-omnipotent/\@function/;
475
+ $line =~ s/\@function.*/\@function/;
476
+ last;
477
+ };
478
+ /\.asciz/ && do { if ($line =~ /^"(.*)"$/) {
479
+ $dir = ".byte";
480
+ $line = join(",",unpack("C*",$1),0);
481
+ }
482
+ last;
483
+ };
484
+ /\.rva|\.long|\.quad/
485
+ && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
486
+ $line =~ s/\.L/$decor/g;
487
+ last;
488
+ };
489
+ }
490
+
491
+ if ($gas) {
492
+ $self->{value} = $dir . "\t" . $line;
493
+
494
+ if ($dir =~ /\.extern/) {
495
+ if ($flavour eq "elf") {
496
+ $self->{value} .= "\n.hidden $line";
497
+ } else {
498
+ $self->{value} = "";
499
+ }
500
+ } elsif (!$elf && $dir =~ /\.type/) {
501
+ $self->{value} = "";
502
+ $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" .
503
+ (defined($globals{$1})?".scl 2;":".scl 3;") .
504
+ "\t.type 32;\t.endef"
505
+ if ($win64 && $line =~ /([^,]+),\@function/);
506
+ } elsif (!$elf && $dir =~ /\.size/) {
507
+ $self->{value} = "";
508
+ if (defined($current_function)) {
509
+ $self->{value} .= "${decor}SEH_end_$current_function->{name}:"
510
+ if ($win64 && $current_function->{abi} eq "svr4");
511
+ undef $current_function;
512
+ }
513
+ } elsif (!$elf && $dir =~ /\.align/) {
514
+ $self->{value} = ".p2align\t" . (log($line)/log(2));
515
+ } elsif ($dir eq ".section") {
516
+ $current_segment=$line;
517
+ if (!$elf && $current_segment eq ".init") {
518
+ if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; }
519
+ elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; }
520
+ }
521
+ } elsif ($dir =~ /\.(text|data)/) {
522
+ $current_segment=".$1";
523
+ } elsif ($dir =~ /\.global|\.globl|\.extern/) {
524
+ if ($flavour eq "macosx") {
525
+ $self->{value} .= "\n.private_extern $line";
526
+ } else {
527
+ $self->{value} .= "\n.hidden $line";
528
+ }
529
+ } elsif ($dir =~ /\.hidden/) {
530
+ if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$line"; }
531
+ elsif ($flavour eq "mingw64") { $self->{value} = ""; }
532
+ } elsif ($dir =~ /\.comm/) {
533
+ $self->{value} = "$dir\t$prefix$line";
534
+ $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx");
535
+ }
536
+ $line = "";
537
+ return $self;
538
+ }
539
+
540
+ # non-gas case or nasm/masm
541
+ SWITCH: for ($dir) {
542
+ /\.text/ && do { my $v=undef;
543
+ if ($nasm) {
544
+ $v="section .text code align=64\n";
545
+ } else {
546
+ $v="$current_segment\tENDS\n" if ($current_segment);
547
+ $current_segment = ".text\$";
548
+ $v.="$current_segment\tSEGMENT ";
549
+ $v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE";
550
+ $v.=" 'CODE'";
551
+ }
552
+ $self->{value} = $v;
553
+ last;
554
+ };
555
+ /\.data/ && do { my $v=undef;
556
+ if ($nasm) {
557
+ $v="section .data data align=8\n";
558
+ } else {
559
+ $v="$current_segment\tENDS\n" if ($current_segment);
560
+ $current_segment = "_DATA";
561
+ $v.="$current_segment\tSEGMENT";
562
+ }
563
+ $self->{value} = $v;
564
+ last;
565
+ };
566
+ /\.section/ && do { my $v=undef;
567
+ $line =~ s/([^,]*).*/$1/;
568
+ $line = ".CRT\$XCU" if ($line eq ".init");
569
+ if ($nasm) {
570
+ $v="section $line";
571
+ if ($line=~/\.([px])data/) {
572
+ $v.=" rdata align=";
573
+ $v.=$1 eq "p"? 4 : 8;
574
+ } elsif ($line=~/\.CRT\$/i) {
575
+ $v.=" rdata align=8";
576
+ }
577
+ } else {
578
+ $v="$current_segment\tENDS\n" if ($current_segment);
579
+ $v.="$line\tSEGMENT";
580
+ if ($line=~/\.([px])data/) {
581
+ $v.=" READONLY";
582
+ $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
583
+ } elsif ($line=~/\.CRT\$/i) {
584
+ $v.=" READONLY ";
585
+ $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD";
586
+ }
587
+ }
588
+ $current_segment = $line;
589
+ $self->{value} = $v;
590
+ last;
591
+ };
592
+ /\.extern/ && do { $self->{value} = "EXTERN\t".$line;
593
+ $self->{value} .= ":NEAR" if ($masm);
594
+ last;
595
+ };
596
+ /\.globl|.global/
597
+ && do { $self->{value} = $masm?"PUBLIC":"global";
598
+ $self->{value} .= "\t".$line;
599
+ last;
600
+ };
601
+ /\.size/ && do { if (defined($current_function)) {
602
+ undef $self->{value};
603
+ if ($current_function->{abi} eq "svr4") {
604
+ $self->{value}="${decor}SEH_end_$current_function->{name}:";
605
+ $self->{value}.=":\n" if($masm);
606
+ }
607
+ $self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name});
608
+ undef $current_function;
609
+ }
610
+ last;
611
+ };
612
+ /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; };
613
+ /\.(value|long|rva|quad)/
614
+ && do { my $sz = substr($1,0,1);
615
+ my @arr = split(/,\s*/,$line);
616
+ my $last = pop(@arr);
617
+ my $conv = sub { my $var=shift;
618
+ $var=~s/^(0b[0-1]+)/oct($1)/eig;
619
+ $var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm);
620
+ if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva"))
621
+ { $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
622
+ $var;
623
+ };
624
+
625
+ $sz =~ tr/bvlrq/BWDDQ/;
626
+ $self->{value} = "\tD$sz\t";
627
+ for (@arr) { $self->{value} .= &$conv($_).","; }
628
+ $self->{value} .= &$conv($last);
629
+ last;
630
+ };
631
+ /\.byte/ && do { my @str=split(/,\s*/,$line);
632
+ map(s/(0b[0-1]+)/oct($1)/eig,@str);
633
+ map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm);
634
+ while ($#str>15) {
635
+ $self->{value}.="DB\t"
636
+ .join(",",@str[0..15])."\n";
637
+ foreach (0..15) { shift @str; }
638
+ }
639
+ $self->{value}.="DB\t"
640
+ .join(",",@str) if (@str);
641
+ last;
642
+ };
643
+ /\.comm/ && do { my @str=split(/,\s*/,$line);
644
+ my $v=undef;
645
+ if ($nasm) {
646
+ $v.="common $prefix@str[0] @str[1]";
647
+ } else {
648
+ $v="$current_segment\tENDS\n" if ($current_segment);
649
+ $current_segment = "_DATA";
650
+ $v.="$current_segment\tSEGMENT\n";
651
+ $v.="COMM @str[0]:DWORD:".@str[1]/4;
652
+ }
653
+ $self->{value} = $v;
654
+ last;
655
+ };
656
+ }
657
+ $line = "";
658
+ }
659
+
660
+ $ret;
661
+ }
662
+ sub out {
663
+ my $self = shift;
664
+ $self->{value};
665
+ }
666
+ }
667
+
668
+ sub rex {
669
+ local *opcode=shift;
670
+ my ($dst,$src,$rex)=@_;
671
+
672
+ $rex|=0x04 if($dst>=8);
673
+ $rex|=0x01 if($src>=8);
674
+ push @opcode,($rex|0x40) if ($rex);
675
+ }
676
+
677
+ # older gas and ml64 don't handle SSE>2 instructions
678
+ my %regrm = ( "%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3,
679
+ "%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7 );
680
+
681
+ my $movq = sub { # elderly gas can't handle inter-register movq
682
+ my $arg = shift;
683
+ my @opcode=(0x66);
684
+ if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) {
685
+ my ($src,$dst)=($1,$2);
686
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
687
+ rex(\@opcode,$src,$dst,0x8);
688
+ push @opcode,0x0f,0x7e;
689
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
690
+ @opcode;
691
+ } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) {
692
+ my ($src,$dst)=($2,$1);
693
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
694
+ rex(\@opcode,$src,$dst,0x8);
695
+ push @opcode,0x0f,0x6e;
696
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
697
+ @opcode;
698
+ } else {
699
+ ();
700
+ }
701
+ };
702
+
703
+ my $pextrd = sub {
704
+ if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) {
705
+ my @opcode=(0x66);
706
+ $imm=$1;
707
+ $src=$2;
708
+ $dst=$3;
709
+ if ($dst =~ /%r([0-9]+)d/) { $dst = $1; }
710
+ elsif ($dst =~ /%e/) { $dst = $regrm{$dst}; }
711
+ rex(\@opcode,$src,$dst);
712
+ push @opcode,0x0f,0x3a,0x16;
713
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
714
+ push @opcode,$imm;
715
+ @opcode;
716
+ } else {
717
+ ();
718
+ }
719
+ };
720
+
721
+ my $pinsrd = sub {
722
+ if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) {
723
+ my @opcode=(0x66);
724
+ $imm=$1;
725
+ $src=$2;
726
+ $dst=$3;
727
+ if ($src =~ /%r([0-9]+)/) { $src = $1; }
728
+ elsif ($src =~ /%e/) { $src = $regrm{$src}; }
729
+ rex(\@opcode,$dst,$src);
730
+ push @opcode,0x0f,0x3a,0x22;
731
+ push @opcode,0xc0|(($dst&7)<<3)|($src&7); # ModR/M
732
+ push @opcode,$imm;
733
+ @opcode;
734
+ } else {
735
+ ();
736
+ }
737
+ };
738
+
739
+ my $pshufb = sub {
740
+ if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
741
+ my @opcode=(0x66);
742
+ rex(\@opcode,$2,$1);
743
+ push @opcode,0x0f,0x38,0x00;
744
+ push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M
745
+ @opcode;
746
+ } else {
747
+ ();
748
+ }
749
+ };
750
+
751
+ my $palignr = sub {
752
+ if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
753
+ my @opcode=(0x66);
754
+ rex(\@opcode,$3,$2);
755
+ push @opcode,0x0f,0x3a,0x0f;
756
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
757
+ push @opcode,$1;
758
+ @opcode;
759
+ } else {
760
+ ();
761
+ }
762
+ };
763
+
764
+ my $pclmulqdq = sub {
765
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
766
+ my @opcode=(0x66);
767
+ rex(\@opcode,$3,$2);
768
+ push @opcode,0x0f,0x3a,0x44;
769
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
770
+ my $c=$1;
771
+ push @opcode,$c=~/^0/?oct($c):$c;
772
+ @opcode;
773
+ } else {
774
+ ();
775
+ }
776
+ };
777
+
778
+ my $rdrand = sub {
779
+ if (shift =~ /%[er](\w+)/) {
780
+ my @opcode=();
781
+ my $dst=$1;
782
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
783
+ rex(\@opcode,0,$1,8);
784
+ push @opcode,0x0f,0xc7,0xf0|($dst&7);
785
+ @opcode;
786
+ } else {
787
+ ();
788
+ }
789
+ };
790
+
791
+ my $rdseed = sub {
792
+ if (shift =~ /%[er](\w+)/) {
793
+ my @opcode=();
794
+ my $dst=$1;
795
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
796
+ rex(\@opcode,0,$1,8);
797
+ push @opcode,0x0f,0xc7,0xf8|($dst&7);
798
+ @opcode;
799
+ } else {
800
+ ();
801
+ }
802
+ };
803
+
804
+ sub rxb {
805
+ local *opcode=shift;
806
+ my ($dst,$src1,$src2,$rxb)=@_;
807
+
808
+ $rxb|=0x7<<5;
809
+ $rxb&=~(0x04<<5) if($dst>=8);
810
+ $rxb&=~(0x01<<5) if($src1>=8);
811
+ $rxb&=~(0x02<<5) if($src2>=8);
812
+ push @opcode,$rxb;
813
+ }
814
+
815
+ my $vprotd = sub {
816
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
817
+ my @opcode=(0x8f);
818
+ rxb(\@opcode,$3,$2,-1,0x08);
819
+ push @opcode,0x78,0xc2;
820
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
821
+ my $c=$1;
822
+ push @opcode,$c=~/^0/?oct($c):$c;
823
+ @opcode;
824
+ } else {
825
+ ();
826
+ }
827
+ };
828
+
829
+ my $vprotq = sub {
830
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
831
+ my @opcode=(0x8f);
832
+ rxb(\@opcode,$3,$2,-1,0x08);
833
+ push @opcode,0x78,0xc3;
834
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
835
+ my $c=$1;
836
+ push @opcode,$c=~/^0/?oct($c):$c;
837
+ @opcode;
838
+ } else {
839
+ ();
840
+ }
841
+ };
842
+
843
+ if ($nasm) {
844
+ print <<___;
845
+ default rel
846
+ %define XMMWORD
847
+ %define YMMWORD
848
+ %define ZMMWORD
849
+ ___
850
+ } elsif ($masm) {
851
+ print <<___;
852
+ OPTION DOTNAME
853
+ ___
854
+ }
855
+
856
+ print STDOUT "#if defined(__x86_64__)\n" if ($gas);
857
+
858
+ while($line=<>) {
859
+
860
+ chomp($line);
861
+
862
+ $line =~ s|[#!].*$||; # get rid of asm-style comments...
863
+ $line =~ s|/\*.*\*/||; # ... and C-style comments...
864
+ $line =~ s|^\s+||; # ... and skip white spaces in beginning
865
+ $line =~ s|\s+$||; # ... and at the end
866
+
867
+ undef $label;
868
+ undef $opcode;
869
+ undef @args;
870
+
871
+ if ($label=label->re(\$line)) { print $label->out(); }
872
+
873
+ if (directive->re(\$line)) {
874
+ printf "%s",directive->out();
875
+ } elsif ($opcode=opcode->re(\$line)) {
876
+ my $asm = eval("\$".$opcode->mnemonic());
877
+ undef @bytes;
878
+
879
+ if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) {
880
+ print $gas?".byte\t":"DB\t",join(',',@bytes),"\n";
881
+ next;
882
+ }
883
+
884
+ ARGUMENT: while (1) {
885
+ my $arg;
886
+
887
+ if ($arg=register->re(\$line)) { opcode->size($arg->size()); }
888
+ elsif ($arg=const->re(\$line)) { }
889
+ elsif ($arg=ea->re(\$line)) { }
890
+ elsif ($arg=expr->re(\$line)) { }
891
+ else { last ARGUMENT; }
892
+
893
+ push @args,$arg;
894
+
895
+ last ARGUMENT if ($line !~ /^,/);
896
+
897
+ $line =~ s/^,\s*//;
898
+ } # ARGUMENT:
899
+
900
+ if ($#args>=0) {
901
+ my $insn;
902
+ my $sz=opcode->size();
903
+
904
+ if ($gas) {
905
+ $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz);
906
+ @args = map($_->out($sz),@args);
907
+ printf "\t%s\t%s",$insn,join(",",@args);
908
+ } else {
909
+ $insn = $opcode->out();
910
+ foreach (@args) {
911
+ my $arg = $_->out();
912
+ # $insn.=$sz compensates for movq, pinsrw, ...
913
+ if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; }
914
+ if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; }
915
+ if ($arg =~ /^zmm[0-9]+$/) { $insn.=$sz; $sz="z" if(!$sz); last; }
916
+ if ($arg =~ /^mm[0-9]+$/) { $insn.=$sz; $sz="q" if(!$sz); last; }
917
+ }
918
+ @args = reverse(@args);
919
+ undef $sz if ($nasm && $opcode->mnemonic() eq "lea");
920
+
921
+ if ($insn eq "movq" && $#args == 1 && $args[0]->out($sz) eq "xmm0" && $args[1]->out($sz) eq "rax") {
922
+ # I have no clue why MASM can't parse this instruction.
923
+ printf "DB 66h, 48h, 0fh, 6eh, 0c0h";
924
+ } else {
925
+ printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args));
926
+ }
927
+ }
928
+ } else {
929
+ printf "\t%s",$opcode->out();
930
+ }
931
+ }
932
+
933
+ print $line,"\n";
934
+ }
935
+
936
+ print "\n$current_segment\tENDS\n" if ($current_segment && $masm);
937
+ print "END\n" if ($masm);
938
+ print "#endif\n" if ($gas);
939
+
940
+
941
+ close STDOUT;
942
+
943
+ #################################################
944
+ # Cross-reference x86_64 ABI "card"
945
+ #
946
+ # Unix Win64
947
+ # %rax * *
948
+ # %rbx - -
949
+ # %rcx #4 #1
950
+ # %rdx #3 #2
951
+ # %rsi #2 -
952
+ # %rdi #1 -
953
+ # %rbp - -
954
+ # %rsp - -
955
+ # %r8 #5 #3
956
+ # %r9 #6 #4
957
+ # %r10 * *
958
+ # %r11 * *
959
+ # %r12 - -
960
+ # %r13 - -
961
+ # %r14 - -
962
+ # %r15 - -
963
+ #
964
+ # (*) volatile register
965
+ # (-) preserved by callee
966
+ # (#) Nth argument, volatile
967
+ #
968
+ # In Unix terms top of stack is argument transfer area for arguments
969
+ # which could not be accomodated in registers. Or in other words 7th
970
+ # [integer] argument resides at 8(%rsp) upon function entry point.
971
+ # 128 bytes above %rsp constitute a "red zone" which is not touched
972
+ # by signal handlers and can be used as temporal storage without
973
+ # allocating a frame.
974
+ #
975
+ # In Win64 terms N*8 bytes on top of stack is argument transfer area,
976
+ # which belongs to/can be overwritten by callee. N is the number of
977
+ # arguments passed to callee, *but* not less than 4! This means that
978
+ # upon function entry point 5th argument resides at 40(%rsp), as well
979
+ # as that 32 bytes from 8(%rsp) can always be used as temporal
980
+ # storage [without allocating a frame]. One can actually argue that
981
+ # one can assume a "red zone" above stack pointer under Win64 as well.
982
+ # Point is that at apparently no occasion Windows kernel would alter
983
+ # the area above user stack pointer in true asynchronous manner...
984
+ #
985
+ # All the above means that if assembler programmer adheres to Unix
986
+ # register and stack layout, but disregards the "red zone" existense,
987
+ # it's possible to use following prologue and epilogue to "gear" from
988
+ # Unix to Win64 ABI in leaf functions with not more than 6 arguments.
989
+ #
990
+ # omnipotent_function:
991
+ # ifdef WIN64
992
+ # movq %rdi,8(%rsp)
993
+ # movq %rsi,16(%rsp)
994
+ # movq %rcx,%rdi ; if 1st argument is actually present
995
+ # movq %rdx,%rsi ; if 2nd argument is actually ...
996
+ # movq %r8,%rdx ; if 3rd argument is ...
997
+ # movq %r9,%rcx ; if 4th argument ...
998
+ # movq 40(%rsp),%r8 ; if 5th ...
999
+ # movq 48(%rsp),%r9 ; if 6th ...
1000
+ # endif
1001
+ # ...
1002
+ # ifdef WIN64
1003
+ # movq 8(%rsp),%rdi
1004
+ # movq 16(%rsp),%rsi
1005
+ # endif
1006
+ # ret
1007
+ #
1008
+ #################################################
1009
+ # Win64 SEH, Structured Exception Handling.
1010
+ #
1011
+ # Unlike on Unix systems(*) lack of Win64 stack unwinding information
1012
+ # has undesired side-effect at run-time: if an exception is raised in
1013
+ # assembler subroutine such as those in question (basically we're
1014
+ # referring to segmentation violations caused by malformed input
1015
+ # parameters), the application is briskly terminated without invoking
1016
+ # any exception handlers, most notably without generating memory dump
1017
+ # or any user notification whatsoever. This poses a problem. It's
1018
+ # possible to address it by registering custom language-specific
1019
+ # handler that would restore processor context to the state at
1020
+ # subroutine entry point and return "exception is not handled, keep
1021
+ # unwinding" code. Writing such handler can be a challenge... But it's
1022
+ # doable, though requires certain coding convention. Consider following
1023
+ # snippet:
1024
+ #
1025
+ # .type function,@function
1026
+ # function:
1027
+ # movq %rsp,%rax # copy rsp to volatile register
1028
+ # pushq %r15 # save non-volatile registers
1029
+ # pushq %rbx
1030
+ # pushq %rbp
1031
+ # movq %rsp,%r11
1032
+ # subq %rdi,%r11 # prepare [variable] stack frame
1033
+ # andq $-64,%r11
1034
+ # movq %rax,0(%r11) # check for exceptions
1035
+ # movq %r11,%rsp # allocate [variable] stack frame
1036
+ # movq %rax,0(%rsp) # save original rsp value
1037
+ # magic_point:
1038
+ # ...
1039
+ # movq 0(%rsp),%rcx # pull original rsp value
1040
+ # movq -24(%rcx),%rbp # restore non-volatile registers
1041
+ # movq -16(%rcx),%rbx
1042
+ # movq -8(%rcx),%r15
1043
+ # movq %rcx,%rsp # restore original rsp
1044
+ # ret
1045
+ # .size function,.-function
1046
+ #
1047
+ # The key is that up to magic_point copy of original rsp value remains
1048
+ # in chosen volatile register and no non-volatile register, except for
1049
+ # rsp, is modified. While past magic_point rsp remains constant till
1050
+ # the very end of the function. In this case custom language-specific
1051
+ # exception handler would look like this:
1052
+ #
1053
+ # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1054
+ # CONTEXT *context,DISPATCHER_CONTEXT *disp)
1055
+ # { ULONG64 *rsp = (ULONG64 *)context->Rax;
1056
+ # if (context->Rip >= magic_point)
1057
+ # { rsp = ((ULONG64 **)context->Rsp)[0];
1058
+ # context->Rbp = rsp[-3];
1059
+ # context->Rbx = rsp[-2];
1060
+ # context->R15 = rsp[-1];
1061
+ # }
1062
+ # context->Rsp = (ULONG64)rsp;
1063
+ # context->Rdi = rsp[1];
1064
+ # context->Rsi = rsp[2];
1065
+ #
1066
+ # memcpy (disp->ContextRecord,context,sizeof(CONTEXT));
1067
+ # RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase,
1068
+ # dips->ControlPc,disp->FunctionEntry,disp->ContextRecord,
1069
+ # &disp->HandlerData,&disp->EstablisherFrame,NULL);
1070
+ # return ExceptionContinueSearch;
1071
+ # }
1072
+ #
1073
+ # It's appropriate to implement this handler in assembler, directly in
1074
+ # function's module. In order to do that one has to know members'
1075
+ # offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant
1076
+ # values. Here they are:
1077
+ #
1078
+ # CONTEXT.Rax 120
1079
+ # CONTEXT.Rcx 128
1080
+ # CONTEXT.Rdx 136
1081
+ # CONTEXT.Rbx 144
1082
+ # CONTEXT.Rsp 152
1083
+ # CONTEXT.Rbp 160
1084
+ # CONTEXT.Rsi 168
1085
+ # CONTEXT.Rdi 176
1086
+ # CONTEXT.R8 184
1087
+ # CONTEXT.R9 192
1088
+ # CONTEXT.R10 200
1089
+ # CONTEXT.R11 208
1090
+ # CONTEXT.R12 216
1091
+ # CONTEXT.R13 224
1092
+ # CONTEXT.R14 232
1093
+ # CONTEXT.R15 240
1094
+ # CONTEXT.Rip 248
1095
+ # CONTEXT.Xmm6 512
1096
+ # sizeof(CONTEXT) 1232
1097
+ # DISPATCHER_CONTEXT.ControlPc 0
1098
+ # DISPATCHER_CONTEXT.ImageBase 8
1099
+ # DISPATCHER_CONTEXT.FunctionEntry 16
1100
+ # DISPATCHER_CONTEXT.EstablisherFrame 24
1101
+ # DISPATCHER_CONTEXT.TargetIp 32
1102
+ # DISPATCHER_CONTEXT.ContextRecord 40
1103
+ # DISPATCHER_CONTEXT.LanguageHandler 48
1104
+ # DISPATCHER_CONTEXT.HandlerData 56
1105
+ # UNW_FLAG_NHANDLER 0
1106
+ # ExceptionContinueSearch 1
1107
+ #
1108
+ # In order to tie the handler to the function one has to compose
1109
+ # couple of structures: one for .xdata segment and one for .pdata.
1110
+ #
1111
+ # UNWIND_INFO structure for .xdata segment would be
1112
+ #
1113
+ # function_unwind_info:
1114
+ # .byte 9,0,0,0
1115
+ # .rva handler
1116
+ #
1117
+ # This structure designates exception handler for a function with
1118
+ # zero-length prologue, no stack frame or frame register.
1119
+ #
1120
+ # To facilitate composing of .pdata structures, auto-generated "gear"
1121
+ # prologue copies rsp value to rax and denotes next instruction with
1122
+ # .LSEH_begin_{function_name} label. This essentially defines the SEH
1123
+ # styling rule mentioned in the beginning. Position of this label is
1124
+ # chosen in such manner that possible exceptions raised in the "gear"
1125
+ # prologue would be accounted to caller and unwound from latter's frame.
1126
+ # End of function is marked with respective .LSEH_end_{function_name}
1127
+ # label. To summarize, .pdata segment would contain
1128
+ #
1129
+ # .rva .LSEH_begin_function
1130
+ # .rva .LSEH_end_function
1131
+ # .rva function_unwind_info
1132
+ #
1133
+ # Reference to functon_unwind_info from .xdata segment is the anchor.
1134
+ # In case you wonder why references are 32-bit .rvas and not 64-bit
1135
+ # .quads. References put into these two segments are required to be
1136
+ # *relative* to the base address of the current binary module, a.k.a.
1137
+ # image base. No Win64 module, be it .exe or .dll, can be larger than
1138
+ # 2GB and thus such relative references can be and are accommodated in
1139
+ # 32 bits.
1140
+ #
1141
+ # Having reviewed the example function code, one can argue that "movq
1142
+ # %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix
1143
+ # rax would contain an undefined value. If this "offends" you, use
1144
+ # another register and refrain from modifying rax till magic_point is
1145
+ # reached, i.e. as if it was a non-volatile register. If more registers
1146
+ # are required prior [variable] frame setup is completed, note that
1147
+ # nobody says that you can have only one "magic point." You can
1148
+ # "liberate" non-volatile registers by denoting last stack off-load
1149
+ # instruction and reflecting it in finer grade unwind logic in handler.
1150
+ # After all, isn't it why it's called *language-specific* handler...
1151
+ #
1152
+ # Attentive reader can notice that exceptions would be mishandled in
1153
+ # auto-generated "gear" epilogue. Well, exception effectively can't
1154
+ # occur there, because if memory area used by it was subject to
1155
+ # segmentation violation, then it would be raised upon call to the
1156
+ # function (and as already mentioned be accounted to caller, which is
1157
+ # not a problem). If you're still not comfortable, then define tail
1158
+ # "magic point" just prior ret instruction and have handler treat it...
1159
+ #
1160
+ # (*) Note that we're talking about run-time, not debug-time. Lack of
1161
+ # unwind information makes debugging hard on both Windows and
1162
+ # Unix. "Unlike" referes to the fact that on Unix signal handler
1163
+ # will always be invoked, core dumped and appropriate exit code
1164
+ # returned to parent (for user notification).