armv4-mont.pl 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #!/usr/bin/env perl
  2. # ====================================================================
  3. # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
  4. # project. The module is, however, dual licensed under OpenSSL and
  5. # CRYPTOGAMS licenses depending on where you obtain it. For further
  6. # details see http://www.openssl.org/~appro/cryptogams/.
  7. # ====================================================================
  8. # January 2007.
  9. # Montgomery multiplication for ARMv4.
  10. #
  11. # Performance improvement naturally varies among CPU implementations
  12. # and compilers. The code was observed to provide +65-35% improvement
  13. # [depending on key length, less for longer keys] on ARM920T, and
  14. # +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
  15. # base and compiler generated code with in-lined umull and even umlal
  16. # instructions. The latter means that this code didn't really have an
  17. # "advantage" of utilizing some "secret" instruction.
  18. #
  19. # The code is interoperable with Thumb ISA and is rather compact, less
  20. # than 1/2KB. Windows CE port would be trivial, as it's exclusively
  21. # about decorations, ABI and instruction syntax are identical.
  22. $flavour = shift;
  23. if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
  24. else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
  25. if ($flavour && $flavour ne "void") {
  26. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  27. ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
  28. ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
  29. die "can't locate arm-xlate.pl";
  30. open STDOUT,"| \"$^X\" $xlate $flavour $output";
  31. } else {
  32. open STDOUT,">$output";
  33. }
  34. $num="r0"; # starts as num argument, but holds &tp[num-1]
  35. $ap="r1";
  36. $bp="r2"; $bi="r2"; $rp="r2";
  37. $np="r3";
  38. $tp="r4";
  39. $aj="r5";
  40. $nj="r6";
  41. $tj="r7";
  42. $n0="r8";
  43. ########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer
  44. $alo="r10"; # sl, gcc uses it to keep @GOT
  45. $ahi="r11"; # fp
  46. $nlo="r12"; # ip
  47. ########### # r13 is stack pointer
  48. $nhi="r14"; # lr
  49. ########### # r15 is program counter
  50. #### argument block layout relative to &tp[num-1], a.k.a. $num
  51. $_rp="$num,#12*4";
  52. # ap permanently resides in r1
  53. $_bp="$num,#13*4";
  54. # np permanently resides in r3
  55. $_n0="$num,#14*4";
  56. $_num="$num,#15*4"; $_bpend=$_num;
  57. $code=<<___;
  58. .text
  59. .global bn_mul_mont
  60. .type bn_mul_mont,%function
  61. .align 2
  62. bn_mul_mont:
  63. stmdb sp!,{r0,r2} @ sp points at argument block
  64. ldr $num,[sp,#3*4] @ load num
  65. cmp $num,#2
  66. movlt r0,#0
  67. addlt sp,sp,#2*4
  68. blt .Labrt
  69. stmdb sp!,{r4-r12,lr} @ save 10 registers
  70. mov $num,$num,lsl#2 @ rescale $num for byte count
  71. sub sp,sp,$num @ alloca(4*num)
  72. sub sp,sp,#4 @ +extra dword
  73. sub $num,$num,#4 @ "num=num-1"
  74. add $tp,$bp,$num @ &bp[num-1]
  75. add $num,sp,$num @ $num to point at &tp[num-1]
  76. ldr $n0,[$_n0] @ &n0
  77. ldr $bi,[$bp] @ bp[0]
  78. ldr $aj,[$ap],#4 @ ap[0],ap++
  79. ldr $nj,[$np],#4 @ np[0],np++
  80. ldr $n0,[$n0] @ *n0
  81. str $tp,[$_bpend] @ save &bp[num]
  82. umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0]
  83. str $n0,[$_n0] @ save n0 value
  84. mul $n0,$alo,$n0 @ "tp[0]"*n0
  85. mov $nlo,#0
  86. umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]"
  87. mov $tp,sp
  88. .L1st:
  89. ldr $aj,[$ap],#4 @ ap[j],ap++
  90. mov $alo,$ahi
  91. ldr $nj,[$np],#4 @ np[j],np++
  92. mov $ahi,#0
  93. umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0]
  94. mov $nhi,#0
  95. umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
  96. adds $nlo,$nlo,$alo
  97. str $nlo,[$tp],#4 @ tp[j-1]=,tp++
  98. adc $nlo,$nhi,#0
  99. cmp $tp,$num
  100. bne .L1st
  101. adds $nlo,$nlo,$ahi
  102. ldr $tp,[$_bp] @ restore bp
  103. mov $nhi,#0
  104. ldr $n0,[$_n0] @ restore n0
  105. adc $nhi,$nhi,#0
  106. str $nlo,[$num] @ tp[num-1]=
  107. str $nhi,[$num,#4] @ tp[num]=
  108. .Louter:
  109. sub $tj,$num,sp @ "original" $num-1 value
  110. sub $ap,$ap,$tj @ "rewind" ap to &ap[1]
  111. ldr $bi,[$tp,#4]! @ *(++bp)
  112. sub $np,$np,$tj @ "rewind" np to &np[1]
  113. ldr $aj,[$ap,#-4] @ ap[0]
  114. ldr $alo,[sp] @ tp[0]
  115. ldr $nj,[$np,#-4] @ np[0]
  116. ldr $tj,[sp,#4] @ tp[1]
  117. mov $ahi,#0
  118. umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0]
  119. str $tp,[$_bp] @ save bp
  120. mul $n0,$alo,$n0
  121. mov $nlo,#0
  122. umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]"
  123. mov $tp,sp
  124. .Linner:
  125. ldr $aj,[$ap],#4 @ ap[j],ap++
  126. adds $alo,$ahi,$tj @ +=tp[j]
  127. ldr $nj,[$np],#4 @ np[j],np++
  128. mov $ahi,#0
  129. umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i]
  130. mov $nhi,#0
  131. umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
  132. adc $ahi,$ahi,#0
  133. ldr $tj,[$tp,#8] @ tp[j+1]
  134. adds $nlo,$nlo,$alo
  135. str $nlo,[$tp],#4 @ tp[j-1]=,tp++
  136. adc $nlo,$nhi,#0
  137. cmp $tp,$num
  138. bne .Linner
  139. adds $nlo,$nlo,$ahi
  140. mov $nhi,#0
  141. ldr $tp,[$_bp] @ restore bp
  142. adc $nhi,$nhi,#0
  143. ldr $n0,[$_n0] @ restore n0
  144. adds $nlo,$nlo,$tj
  145. ldr $tj,[$_bpend] @ restore &bp[num]
  146. adc $nhi,$nhi,#0
  147. str $nlo,[$num] @ tp[num-1]=
  148. str $nhi,[$num,#4] @ tp[num]=
  149. cmp $tp,$tj
  150. bne .Louter
  151. ldr $rp,[$_rp] @ pull rp
  152. add $num,$num,#4 @ $num to point at &tp[num]
  153. sub $aj,$num,sp @ "original" num value
  154. mov $tp,sp @ "rewind" $tp
  155. mov $ap,$tp @ "borrow" $ap
  156. sub $np,$np,$aj @ "rewind" $np to &np[0]
  157. subs $tj,$tj,$tj @ "clear" carry flag
  158. .Lsub: ldr $tj,[$tp],#4
  159. ldr $nj,[$np],#4
  160. sbcs $tj,$tj,$nj @ tp[j]-np[j]
  161. str $tj,[$rp],#4 @ rp[j]=
  162. teq $tp,$num @ preserve carry
  163. bne .Lsub
  164. sbcs $nhi,$nhi,#0 @ upmost carry
  165. mov $tp,sp @ "rewind" $tp
  166. sub $rp,$rp,$aj @ "rewind" $rp
  167. and $ap,$tp,$nhi
  168. bic $np,$rp,$nhi
  169. orr $ap,$ap,$np @ ap=borrow?tp:rp
  170. .Lcopy: ldr $tj,[$ap],#4 @ copy or in-place refresh
  171. str sp,[$tp],#4 @ zap tp
  172. str $tj,[$rp],#4
  173. cmp $tp,$num
  174. bne .Lcopy
  175. add sp,$num,#4 @ skip over tp[num+1]
  176. ldmia sp!,{r4-r12,lr} @ restore registers
  177. add sp,sp,#2*4 @ skip over {r0,r2}
  178. mov r0,#1
  179. .Labrt: tst lr,#1
  180. moveq pc,lr @ be binary compatible with V4, yet
  181. bx lr @ interoperable with Thumb ISA:-)
  182. .size bn_mul_mont,.-bn_mul_mont
  183. .asciz "Montgomery multiplication for ARMv4, CRYPTOGAMS by <appro\@openssl.org>"
  184. .align 2
  185. ___
  186. $code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
  187. print $code;
  188. close STDOUT;