ecc: Fix ec_mulm_25519.
[libgcrypt.git] / cipher / sha512-arm.S
1 /* sha512-arm.S  -  ARM assembly implementation of SHA-512 transform
2  *
3  * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi>
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20 #include <config.h>
21
22 #if defined(__ARMEL__)
23 #ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
24
25 .text
26
27 .syntax unified
28 .arm
29
30 /* structure of SHA512_CONTEXT */
31 #define hd_a 0
32 #define hd_b ((hd_a) + 8)
33 #define hd_c ((hd_b) + 8)
34 #define hd_d ((hd_c) + 8)
35 #define hd_e ((hd_d) + 8)
36 #define hd_f ((hd_e) + 8)
37 #define hd_g ((hd_f) + 8)
38 #define hd_h ((hd_g) + 8)
39
40 /* register macros */
41 #define RK    %r2
42
43 #define RElo %r0
44 #define REhi %r1
45
46 #define RT1lo %r3
47 #define RT1hi %r4
48 #define RT2lo %r5
49 #define RT2hi %r6
50 #define RWlo  %r7
51 #define RWhi  %r8
52 #define RT3lo %r9
53 #define RT3hi %r10
54 #define RT4lo %r11
55 #define RT4hi %ip
56
57 #define RRND  %lr
58
59 /* variable offsets in stack */
60 #define ctx (0)
61 #define data ((ctx) + 4)
62 #define nblks ((data) + 4)
63 #define _a ((nblks) + 4)
64 #define _b ((_a) + 8)
65 #define _c ((_b) + 8)
66 #define _d ((_c) + 8)
67 #define _e ((_d) + 8)
68 #define _f ((_e) + 8)
69 #define _g ((_f) + 8)
70 #define _h ((_g) + 8)
71
72 #define w(i) ((_h) + 8 + ((i) % 16) * 8)
73
74 #define STACK_MAX (w(15) + 8)
75
76 /* helper macros */
77 #define ldr_unaligned_be(rout, rsrc, offs, rtmp) \
78     ldrb rout, [rsrc, #((offs) + 3)]; \
79     ldrb rtmp, [rsrc, #((offs) + 2)]; \
80     orr rout, rout, rtmp, lsl #8; \
81     ldrb rtmp, [rsrc, #((offs) + 1)]; \
82     orr rout, rout, rtmp, lsl #16; \
83     ldrb rtmp, [rsrc, #((offs) + 0)]; \
84     orr rout, rout, rtmp, lsl #24;
85
86 #ifdef __ARMEL__
87     /* bswap on little-endian */
88 #ifdef HAVE_ARM_ARCH_V6
89     #define be_to_host(reg, rtmp) \
90         rev reg, reg;
91 #else
92     #define be_to_host(reg, rtmp) \
93         eor rtmp, reg, reg, ror #16; \
94         mov rtmp, rtmp, lsr #8; \
95         bic rtmp, rtmp, #65280; \
96         eor reg, rtmp, reg, ror #8;
97 #endif
98 #else
99     /* nop on big-endian */
100     #define be_to_host(reg, rtmp) /*_*/
101 #endif
102
103 #define host_to_host(x, y) /*_*/
104
105 #define read_u64_aligned_4(rin, offs, lo0, hi0, lo1, hi1, lo2, hi2, lo3, hi3, convert, rtmp) \
106     ldr lo0, [rin, #((offs) + 0 * 8 + 4)]; \
107     ldr hi0, [rin, #((offs) + 0 * 8 + 0)]; \
108     ldr lo1, [rin, #((offs) + 1 * 8 + 4)]; \
109     ldr hi1, [rin, #((offs) + 1 * 8 + 0)]; \
110     ldr lo2, [rin, #((offs) + 2 * 8 + 4)]; \
111     convert(lo0, rtmp); \
112     ldr hi2, [rin, #((offs) + 2 * 8 + 0)]; \
113     convert(hi0, rtmp); \
114     ldr lo3, [rin, #((offs) + 3 * 8 + 4)]; \
115     convert(lo1, rtmp); \
116     ldr hi3, [rin, #((offs) + 3 * 8 + 0)]; \
117     convert(hi1, rtmp); \
118     convert(lo2, rtmp); \
119     convert(hi2, rtmp); \
120     convert(lo3, rtmp); \
121     convert(hi3, rtmp);
122
123 #define read_be64_aligned_4(rin, offs, lo0, hi0, lo1, hi1, lo2, hi2, lo3, hi3, rtmp0) \
124     read_u64_aligned_4(rin, offs, lo0, hi0, lo1, hi1, lo2, hi2, lo3, hi3, be_to_host, rtmp0)
125
126 /* need to handle unaligned reads by byte reads */
127 #define read_be64_unaligned_4(rin, offs, lo0, hi0, lo1, hi1, lo2, hi2, lo3, hi3, rtmp0) \
128     ldr_unaligned_be(lo0, rin, (offs) + 0 * 8 + 4, rtmp0); \
129     ldr_unaligned_be(hi0, rin, (offs) + 0 * 8 + 0, rtmp0); \
130     ldr_unaligned_be(lo1, rin, (offs) + 1 * 8 + 4, rtmp0); \
131     ldr_unaligned_be(hi1, rin, (offs) + 1 * 8 + 0, rtmp0); \
132     ldr_unaligned_be(lo2, rin, (offs) + 2 * 8 + 4, rtmp0); \
133     ldr_unaligned_be(hi2, rin, (offs) + 2 * 8 + 0, rtmp0); \
134     ldr_unaligned_be(lo3, rin, (offs) + 3 * 8 + 4, rtmp0); \
135     ldr_unaligned_be(hi3, rin, (offs) + 3 * 8 + 0, rtmp0);
136
137 /***********************************************************************
138  * ARM assembly implementation of sha512 transform
139  ***********************************************************************/
140
141 /* Round function */
142
143 #define R(_a,_b,_c,_d,_e,_f,_g,_h,W,wi) \
144     /* Message expansion, t1 = _h + w[i] */ \
145     W(_a,_h,wi); \
146     \
147     /* w = Sum1(_e) */ \
148     mov RWlo, RElo, lsr#14; \
149     ldm RK!, {RT2lo-RT2hi}; \
150     mov RWhi, REhi, lsr#14; \
151     eor RWlo, RWlo, RElo, lsr#18; \
152     eor RWhi, RWhi, REhi, lsr#18; \
153     ldr RT3lo, [%sp, #(_f)]; \
154     adds RT1lo, RT2lo; /* t1 += K */ \
155     ldr RT3hi, [%sp, #(_f) + 4]; \
156     adc RT1hi, RT2hi; \
157     ldr RT4lo, [%sp, #(_g)]; \
158     eor RWlo, RWlo, RElo, lsl#23; \
159     ldr RT4hi, [%sp, #(_g) + 4]; \
160     eor RWhi, RWhi, REhi, lsl#23; \
161     eor RWlo, RWlo, REhi, lsl#18; \
162     eor RWhi, RWhi, RElo, lsl#18; \
163     eor RWlo, RWlo, REhi, lsl#14; \
164     eor RWhi, RWhi, RElo, lsl#14; \
165     eor RWlo, RWlo, REhi, lsr#9; \
166     eor RWhi, RWhi, RElo, lsr#9; \
167     \
168     /* Cho(_e,_f,_g) => (_e & _f) ^ (~_e & _g) */ \
169     adds RT1lo, RWlo; /* t1 += Sum1(_e) */ \
170     and RT3lo, RT3lo, RElo; \
171     adc RT1hi, RWhi; \
172     and RT3hi, RT3hi, REhi; \
173     bic RT4lo, RT4lo, RElo; \
174     bic RT4hi, RT4hi, REhi; \
175     eor RT3lo, RT3lo, RT4lo; \
176     eor RT3hi, RT3hi, RT4hi; \
177     \
178     /* Load D */ \
179     /* t1 += Cho(_e,_f,_g) */ \
180     ldr RElo, [%sp, #(_d)]; \
181     adds RT1lo, RT3lo; \
182     ldr REhi, [%sp, #(_d) + 4]; \
183     adc RT1hi, RT3hi; \
184     \
185     /* Load A */ \
186     ldr RT3lo, [%sp, #(_a)]; \
187     \
188     /* _d += t1 */ \
189     adds RElo, RT1lo; \
190     ldr RT3hi, [%sp, #(_a) + 4]; \
191     adc REhi, RT1hi; \
192     \
193     /* Store D */ \
194     str RElo, [%sp, #(_d)]; \
195     \
196     /* t2 = Sum0(_a) */ \
197     mov RT2lo, RT3lo, lsr#28; \
198     str REhi, [%sp, #(_d) + 4]; \
199     mov RT2hi, RT3hi, lsr#28; \
200     ldr RWlo, [%sp, #(_b)]; \
201     eor RT2lo, RT2lo, RT3lo, lsl#30; \
202     ldr RWhi, [%sp, #(_b) + 4]; \
203     eor RT2hi, RT2hi, RT3hi, lsl#30; \
204     eor RT2lo, RT2lo, RT3lo, lsl#25; \
205     eor RT2hi, RT2hi, RT3hi, lsl#25; \
206     eor RT2lo, RT2lo, RT3hi, lsl#4; \
207     eor RT2hi, RT2hi, RT3lo, lsl#4; \
208     eor RT2lo, RT2lo, RT3hi, lsr#2; \
209     eor RT2hi, RT2hi, RT3lo, lsr#2; \
210     eor RT2lo, RT2lo, RT3hi, lsr#7; \
211     eor RT2hi, RT2hi, RT3lo, lsr#7; \
212     \
213     /* t2 += t1 */ \
214     adds RT2lo, RT1lo; \
215     ldr RT1lo, [%sp, #(_c)]; \
216     adc RT2hi, RT1hi; \
217     \
218     /* Maj(_a,_b,_c) => ((_a & _b) ^ (_c & (_a ^ _b))) */ \
219     ldr RT1hi, [%sp, #(_c) + 4]; \
220     and RT4lo, RWlo, RT3lo; \
221     and RT4hi, RWhi, RT3hi; \
222     eor RWlo, RWlo, RT3lo; \
223     eor RWhi, RWhi, RT3hi; \
224     and RWlo, RWlo, RT1lo; \
225     and RWhi, RWhi, RT1hi; \
226     eor RWlo, RWlo, RT4lo; \
227     eor RWhi, RWhi, RT4hi; \
228
229 /* Message expansion */
230
231 #define W_0_63(_a,_h,i) \
232     ldr RT3lo, [%sp, #(w(i-2))]; \
233     adds RT2lo, RWlo; /* _h = t2 + Maj(_a,_b,_c) */ \
234     ldr RT3hi, [%sp, #(w(i-2)) + 4]; \
235     adc RT2hi, RWhi; \
236     /* nw = S1(w[i-2]) */ \
237     ldr RT1lo, [%sp, #(_h)]; /* Load H */ \
238     mov RWlo, RT3lo, lsr#19; \
239     str RT2lo, [%sp, #(_a)]; \
240     eor RWlo, RWlo, RT3lo, lsl#3; \
241     ldr RT1hi, [%sp, #(_h) + 4]; \
242     mov RWhi, RT3hi, lsr#19; \
243     ldr RT2lo, [%sp, #(w(i-7))]; \
244     eor RWhi, RWhi, RT3hi, lsl#3; \
245     str RT2hi, [%sp, #(_a) + 4]; \
246     eor RWlo, RWlo, RT3lo, lsr#6; \
247     ldr RT2hi, [%sp, #(w(i-7)) + 4]; \
248     eor RWhi, RWhi, RT3hi, lsr#6; \
249     eor RWlo, RWlo, RT3hi, lsl#13; \
250     eor RWhi, RWhi, RT3lo, lsl#13; \
251     eor RWlo, RWlo, RT3hi, lsr#29; \
252     eor RWhi, RWhi, RT3lo, lsr#29; \
253     ldr RT3lo, [%sp, #(w(i-15))]; \
254     eor RWlo, RWlo, RT3hi, lsl#26; \
255     ldr RT3hi, [%sp, #(w(i-15)) + 4]; \
256     \
257     adds RT2lo, RWlo; /* nw += w[i-7] */ \
258     ldr RWlo, [%sp, #(w(i-16))]; \
259     adc RT2hi, RWhi; \
260     mov RT4lo, RT3lo, lsr#1; /* S0(w[i-15]) */ \
261     ldr RWhi, [%sp, #(w(i-16)) + 4]; \
262     mov RT4hi, RT3hi, lsr#1; \
263     adds RT2lo, RWlo; /* nw += w[i-16] */ \
264     eor RT4lo, RT4lo, RT3lo, lsr#8; \
265     eor RT4hi, RT4hi, RT3hi, lsr#8; \
266     eor RT4lo, RT4lo, RT3lo, lsr#7; \
267     eor RT4hi, RT4hi, RT3hi, lsr#7; \
268     eor RT4lo, RT4lo, RT3hi, lsl#31; \
269     eor RT4hi, RT4hi, RT3lo, lsl#31; \
270     eor RT4lo, RT4lo, RT3hi, lsl#24; \
271     eor RT4hi, RT4hi, RT3lo, lsl#24; \
272     eor RT4lo, RT4lo, RT3hi, lsl#25; \
273     adc RT2hi, RWhi; \
274     \
275     /* nw += S0(w[i-15]) */ \
276     adds RT2lo, RT4lo; \
277     adc RT2hi, RT4hi; \
278     \
279     /* w[0] = nw */ \
280     str RT2lo, [%sp, #(w(i))]; \
281     adds RT1lo, RWlo; \
282     str RT2hi, [%sp, #(w(i)) + 4]; \
283     adc RT1hi, RWhi;
284
285 #define W_64_79(_a,_h,i) \
286     adds RT2lo, RWlo; /* _h = t2 + Maj(_a,_b,_c) */ \
287     ldr RWlo, [%sp, #(w(i-16))]; \
288     adc RT2hi, RWhi; \
289     ldr RWhi, [%sp, #(w(i-16)) + 4]; \
290     ldr RT1lo, [%sp, #(_h)]; /* Load H */ \
291     ldr RT1hi, [%sp, #(_h) + 4]; \
292     str RT2lo, [%sp, #(_a)]; \
293     str RT2hi, [%sp, #(_a) + 4]; \
294     adds RT1lo, RWlo; \
295     adc RT1hi, RWhi;
296
297 .align 3
298 .globl _gcry_sha512_transform_arm
299 .type  _gcry_sha512_transform_arm,%function;
300
301 _gcry_sha512_transform_arm:
302         /* Input:
303          *      %r0: SHA512_CONTEXT
304          *      %r1: data
305          *      %r2: u64 k[] constants
306          *      %r3: nblks
307          */
308         push {%r4-%r11, %ip, %lr};
309         sub %sp, %sp, #STACK_MAX;
310         movs RWlo, %r3;
311         str %r0, [%sp, #(ctx)];
312
313         beq .Ldone;
314
315 .Loop_blocks:
316         str RWlo, [%sp, #nblks];
317
318         /* Load context to stack */
319         add RWhi, %sp, #(_a);
320         ldm %r0!,  {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
321         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
322         ldm %r0,  {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
323         stm RWhi, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
324
325         /* Load input to w[16] */
326
327         /* test if data is unaligned */
328         tst %r1, #3;
329         beq 1f;
330
331         /* unaligned load */
332         add RWhi, %sp, #(w(0));
333         read_be64_unaligned_4(%r1, 0 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
334         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
335
336         read_be64_unaligned_4(%r1, 4 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
337         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
338
339         read_be64_unaligned_4(%r1, 8 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
340         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
341
342         read_be64_unaligned_4(%r1, 12 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
343         b 2f;
344 1:
345         /* aligned load */
346         add RWhi, %sp, #(w(0));
347         read_be64_aligned_4(%r1, 0 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
348         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
349
350         read_be64_aligned_4(%r1, 4 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
351         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
352
353         read_be64_aligned_4(%r1, 8 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
354         stm RWhi!, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
355
356         read_be64_aligned_4(%r1, 12 * 8, RT1lo, RT1hi, RT2lo, RT2hi, RT3lo, RT3hi, RT4lo, RT4hi, RWlo);
357 2:
358         add %r1, #(16 * 8);
359         stm RWhi, {RT1lo,RT1hi,RT2lo,RT2hi,RT3lo,RT3hi,RT4lo,RT4hi}
360         str %r1, [%sp, #(data)];
361
362         /* preload E & A */
363         ldr RElo, [%sp, #(_e)];
364         ldr REhi, [%sp, #(_e) + 4];
365         mov RWlo, #0;
366         ldr RT2lo, [%sp, #(_a)];
367         mov RRND, #(80-16);
368         ldr RT2hi, [%sp, #(_a) + 4];
369         mov RWhi, #0;
370
371 .Loop_rounds:
372         R(_a, _b, _c, _d, _e, _f, _g, _h, W_0_63, 16);
373         R(_h, _a, _b, _c, _d, _e, _f, _g, W_0_63, 17);
374         R(_g, _h, _a, _b, _c, _d, _e, _f, W_0_63, 18);
375         R(_f, _g, _h, _a, _b, _c, _d, _e, W_0_63, 19);
376         R(_e, _f, _g, _h, _a, _b, _c, _d, W_0_63, 20);
377         R(_d, _e, _f, _g, _h, _a, _b, _c, W_0_63, 21);
378         R(_c, _d, _e, _f, _g, _h, _a, _b, W_0_63, 22);
379         R(_b, _c, _d, _e, _f, _g, _h, _a, W_0_63, 23);
380         R(_a, _b, _c, _d, _e, _f, _g, _h, W_0_63, 24);
381         R(_h, _a, _b, _c, _d, _e, _f, _g, W_0_63, 25);
382         R(_g, _h, _a, _b, _c, _d, _e, _f, W_0_63, 26);
383         R(_f, _g, _h, _a, _b, _c, _d, _e, W_0_63, 27);
384         R(_e, _f, _g, _h, _a, _b, _c, _d, W_0_63, 28);
385         R(_d, _e, _f, _g, _h, _a, _b, _c, W_0_63, 29);
386         R(_c, _d, _e, _f, _g, _h, _a, _b, W_0_63, 30);
387         R(_b, _c, _d, _e, _f, _g, _h, _a, W_0_63, 31);
388
389         subs RRND, #16;
390         bne .Loop_rounds;
391
392         R(_a, _b, _c, _d, _e, _f, _g, _h, W_64_79, 16);
393         R(_h, _a, _b, _c, _d, _e, _f, _g, W_64_79, 17);
394         R(_g, _h, _a, _b, _c, _d, _e, _f, W_64_79, 18);
395         R(_f, _g, _h, _a, _b, _c, _d, _e, W_64_79, 19);
396         R(_e, _f, _g, _h, _a, _b, _c, _d, W_64_79, 20);
397         R(_d, _e, _f, _g, _h, _a, _b, _c, W_64_79, 21);
398         R(_c, _d, _e, _f, _g, _h, _a, _b, W_64_79, 22);
399         R(_b, _c, _d, _e, _f, _g, _h, _a, W_64_79, 23);
400         R(_a, _b, _c, _d, _e, _f, _g, _h, W_64_79, 24);
401         R(_h, _a, _b, _c, _d, _e, _f, _g, W_64_79, 25);
402         R(_g, _h, _a, _b, _c, _d, _e, _f, W_64_79, 26);
403         R(_f, _g, _h, _a, _b, _c, _d, _e, W_64_79, 27);
404         R(_e, _f, _g, _h, _a, _b, _c, _d, W_64_79, 28);
405         R(_d, _e, _f, _g, _h, _a, _b, _c, W_64_79, 29);
406         R(_c, _d, _e, _f, _g, _h, _a, _b, W_64_79, 30);
407         R(_b, _c, _d, _e, _f, _g, _h, _a, W_64_79, 31);
408
409         ldr %r0, [%sp, #(ctx)];
410         adds RT2lo, RWlo; /* _h = t2 + Maj(_a,_b,_c) */
411         ldr %r1, [%sp, #(data)];
412         adc RT2hi, RWhi;
413
414         ldm %r0, {RT1lo,RT1hi,RWlo,RWhi,RT3lo,RT3hi,RT4lo,RT4hi}
415         adds RT1lo, RT2lo;
416         ldr RT2lo, [%sp, #(_b + 0)];
417         adc  RT1hi, RT2hi;
418         ldr RT2hi, [%sp, #(_b + 4)];
419         adds RWlo, RT2lo;
420         ldr RT2lo, [%sp, #(_c + 0)];
421         adc  RWhi, RT2hi;
422         ldr RT2hi, [%sp, #(_c + 4)];
423         adds RT3lo, RT2lo;
424         ldr RT2lo, [%sp, #(_d + 0)];
425         adc  RT3hi, RT2hi;
426         ldr RT2hi, [%sp, #(_d + 4)];
427         adds RT4lo, RT2lo;
428         ldr RT2lo, [%sp, #(_e + 0)];
429         adc  RT4hi, RT2hi;
430         stm %r0!, {RT1lo,RT1hi,RWlo,RWhi,RT3lo,RT3hi,RT4lo,RT4hi}
431
432         ldr RT2hi, [%sp, #(_e + 4)];
433         ldm %r0, {RT1lo,RT1hi,RWlo,RWhi,RT3lo,RT3hi,RT4lo,RT4hi}
434         adds RT1lo, RT2lo;
435         ldr RT2lo, [%sp, #(_f + 0)];
436         adc  RT1hi, RT2hi;
437         ldr RT2hi, [%sp, #(_f + 4)];
438         adds RWlo, RT2lo;
439         ldr RT2lo, [%sp, #(_g + 0)];
440         adc  RWhi, RT2hi;
441         ldr RT2hi, [%sp, #(_g + 4)];
442         adds RT3lo, RT2lo;
443         ldr RT2lo, [%sp, #(_h + 0)];
444         adc  RT3hi, RT2hi;
445         ldr RT2hi, [%sp, #(_h + 4)];
446         adds RT4lo, RT2lo;
447         adc  RT4hi, RT2hi;
448         stm %r0, {RT1lo,RT1hi,RWlo,RWhi,RT3lo,RT3hi,RT4lo,RT4hi}
449         sub %r0, %r0, #(4 * 8);
450         ldr RWlo, [%sp, #nblks];
451
452         sub RK, #(80 * 8);
453         subs RWlo, #1;
454         bne .Loop_blocks;
455
456 .Ldone:
457         mov %r0, #STACK_MAX;
458 __out:
459         add %sp, %sp, #STACK_MAX;
460         pop {%r4-%r11, %ip, %pc};
461 .size _gcry_sha512_transform_arm,.-_gcry_sha512_transform_arm;
462
463 #endif
464 #endif