Merge -r 127928:132243 from trunk
[official-gcc.git] / gcc / config / avr / libgcc.S
blob397778b82d9409497d016dcced84b292593713ea
1 /*  -*- Mode: Asm -*-  */
2 /* Copyright (C) 1998, 1999, 2000, 2007, 2008 
3    Free Software Foundation, Inc.
4    Contributed by Denis Chertykov <denisc@overta.ru>
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file.  (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
20 This file is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING.  If not, write to
27 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301, USA.  */
30 #define __zero_reg__ r1
31 #define __tmp_reg__ r0
32 #define __SREG__ 0x3f
33 #define __SP_H__ 0x3e
34 #define __SP_L__ 0x3d
36 /* Most of the functions here are called directly from avr.md
37    patterns, instead of using the standard libcall mechanisms.
38    This can make better code because GCC knows exactly which
39    of the call-used registers (not all of them) are clobbered.  */
41         .section .text.libgcc, "ax", @progbits
43         .macro  mov_l  r_dest, r_src
44 #if defined (__AVR_HAVE_MOVW__)
45         movw    \r_dest, \r_src
46 #else
47         mov     \r_dest, \r_src
48 #endif
49         .endm
51         .macro  mov_h  r_dest, r_src
52 #if defined (__AVR_HAVE_MOVW__)
53         ; empty
54 #else
55         mov     \r_dest, \r_src
56 #endif
57         .endm
59 /* Note: mulqi3, mulhi3 are open-coded on the enhanced core.  */
60 #if !defined (__AVR_HAVE_MUL__)
61 /*******************************************************
62                Multiplication  8 x 8
63 *******************************************************/
64 #if defined (L_mulqi3)
66 #define r_arg2  r22             /* multiplicand */
67 #define r_arg1  r24             /* multiplier */
68 #define r_res   __tmp_reg__     /* result */
70         .global __mulqi3
71         .func   __mulqi3
72 __mulqi3:
73         clr     r_res           ; clear result
74 __mulqi3_loop:
75         sbrc    r_arg1,0
76         add     r_res,r_arg2
77         add     r_arg2,r_arg2   ; shift multiplicand
78         breq    __mulqi3_exit   ; while multiplicand != 0
79         lsr     r_arg1          ; 
80         brne    __mulqi3_loop   ; exit if multiplier = 0
81 __mulqi3_exit:  
82         mov     r_arg1,r_res    ; result to return register
83         ret
85 #undef r_arg2  
86 #undef r_arg1  
87 #undef r_res   
88         
89 .endfunc
90 #endif  /* defined (L_mulqi3) */
92 #if defined (L_mulqihi3)
93         .global __mulqihi3
94         .func   __mulqihi3
95 __mulqihi3:
96         clr     r25
97         sbrc    r24, 7
98         dec     r25
99         clr     r23
100         sbrc    r22, 7
101         dec     r22
102         rjmp    __mulhi3
103         .endfunc
104 #endif /* defined (L_mulqihi3) */
106 #if defined (L_umulqihi3)
107         .global __umulqihi3
108         .func   __umulqihi3
109 __umulqihi3:
110         clr     r25
111         clr     r23
112         rjmp    __mulhi3
113         .endfunc
114 #endif /* defined (L_umulqihi3) */
116 /*******************************************************
117                Multiplication  16 x 16
118 *******************************************************/
119 #if defined (L_mulhi3)
120 #define r_arg1L r24             /* multiplier Low */
121 #define r_arg1H r25             /* multiplier High */
122 #define r_arg2L r22             /* multiplicand Low */
123 #define r_arg2H r23             /* multiplicand High */
124 #define r_resL  __tmp_reg__     /* result Low */
125 #define r_resH  r21             /* result High */
127         .global __mulhi3
128         .func   __mulhi3
129 __mulhi3:
130         clr     r_resH          ; clear result
131         clr     r_resL          ; clear result
132 __mulhi3_loop:
133         sbrs    r_arg1L,0
134         rjmp    __mulhi3_skip1
135         add     r_resL,r_arg2L  ; result + multiplicand
136         adc     r_resH,r_arg2H
137 __mulhi3_skip1: 
138         add     r_arg2L,r_arg2L ; shift multiplicand
139         adc     r_arg2H,r_arg2H
141         cp      r_arg2L,__zero_reg__
142         cpc     r_arg2H,__zero_reg__
143         breq    __mulhi3_exit   ; while multiplicand != 0
145         lsr     r_arg1H         ; gets LSB of multiplier
146         ror     r_arg1L
147         sbiw    r_arg1L,0
148         brne    __mulhi3_loop   ; exit if multiplier = 0
149 __mulhi3_exit:
150         mov     r_arg1H,r_resH  ; result to return register
151         mov     r_arg1L,r_resL
152         ret
154 #undef r_arg1L
155 #undef r_arg1H
156 #undef r_arg2L
157 #undef r_arg2H
158 #undef r_resL   
159 #undef r_resH 
161 .endfunc
162 #endif /* defined (L_mulhi3) */
163 #endif /* !defined (__AVR_HAVE_MUL__) */
165 #if defined (L_mulhisi3)
166         .global __mulhisi3
167         .func   __mulhisi3
168 __mulhisi3:
169         mov_l   r18, r24
170         mov_h   r19, r25
171         clr     r24
172         sbrc    r23, 7
173         dec     r24
174         mov     r25, r24
175         clr     r20
176         sbrc    r19, 7
177         dec     r20
178         mov     r21, r20
179         rjmp    __mulsi3
180         .endfunc
181 #endif /* defined (L_mulhisi3) */
183 #if defined (L_umulhisi3)
184         .global __umulhisi3
185         .func   __umulhisi3
186 __umulhisi3:
187         mov_l   r18, r24
188         mov_h   r19, r25
189         clr     r24
190         clr     r25
191         clr     r20
192         clr     r21
193         rjmp    __mulsi3
194         .endfunc
195 #endif /* defined (L_umulhisi3) */
197 #if defined (L_mulsi3)
198 /*******************************************************
199                Multiplication  32 x 32
200 *******************************************************/
201 #define r_arg1L  r22            /* multiplier Low */
202 #define r_arg1H  r23
203 #define r_arg1HL r24
204 #define r_arg1HH r25            /* multiplier High */
207 #define r_arg2L  r18            /* multiplicand Low */
208 #define r_arg2H  r19    
209 #define r_arg2HL r20
210 #define r_arg2HH r21            /* multiplicand High */
211         
212 #define r_resL   r26            /* result Low */
213 #define r_resH   r27
214 #define r_resHL  r30
215 #define r_resHH  r31            /* result High */
217         
218         .global __mulsi3
219         .func   __mulsi3
220 __mulsi3:
221 #if defined (__AVR_HAVE_MUL__)
222         mul     r_arg1L, r_arg2L
223         movw    r_resL, r0
224         mul     r_arg1H, r_arg2H
225         movw    r_resHL, r0
226         mul     r_arg1HL, r_arg2L
227         add     r_resHL, r0
228         adc     r_resHH, r1
229         mul     r_arg1L, r_arg2HL
230         add     r_resHL, r0
231         adc     r_resHH, r1
232         mul     r_arg1HH, r_arg2L
233         add     r_resHH, r0
234         mul     r_arg1HL, r_arg2H
235         add     r_resHH, r0
236         mul     r_arg1H, r_arg2HL
237         add     r_resHH, r0
238         mul     r_arg1L, r_arg2HH
239         add     r_resHH, r0
240         clr     r_arg1HH        ; use instead of __zero_reg__ to add carry
241         mul     r_arg1H, r_arg2L
242         add     r_resH, r0
243         adc     r_resHL, r1
244         adc     r_resHH, r_arg1HH ; add carry
245         mul     r_arg1L, r_arg2H
246         add     r_resH, r0
247         adc     r_resHL, r1
248         adc     r_resHH, r_arg1HH ; add carry
249         movw    r_arg1L, r_resL
250         movw    r_arg1HL, r_resHL
251         clr     r1              ; __zero_reg__ clobbered by "mul"
252         ret
253 #else
254         clr     r_resHH         ; clear result
255         clr     r_resHL         ; clear result
256         clr     r_resH          ; clear result
257         clr     r_resL          ; clear result
258 __mulsi3_loop:
259         sbrs    r_arg1L,0
260         rjmp    __mulsi3_skip1
261         add     r_resL,r_arg2L          ; result + multiplicand
262         adc     r_resH,r_arg2H
263         adc     r_resHL,r_arg2HL
264         adc     r_resHH,r_arg2HH
265 __mulsi3_skip1:
266         add     r_arg2L,r_arg2L         ; shift multiplicand
267         adc     r_arg2H,r_arg2H
268         adc     r_arg2HL,r_arg2HL
269         adc     r_arg2HH,r_arg2HH
270         
271         lsr     r_arg1HH        ; gets LSB of multiplier
272         ror     r_arg1HL
273         ror     r_arg1H
274         ror     r_arg1L
275         brne    __mulsi3_loop
276         sbiw    r_arg1HL,0
277         cpc     r_arg1H,r_arg1L
278         brne    __mulsi3_loop           ; exit if multiplier = 0
279 __mulsi3_exit:
280         mov_h   r_arg1HH,r_resHH        ; result to return register
281         mov_l   r_arg1HL,r_resHL
282         mov_h   r_arg1H,r_resH
283         mov_l   r_arg1L,r_resL
284         ret
285 #endif /* defined (__AVR_HAVE_MUL__) */
286 #undef r_arg1L 
287 #undef r_arg1H 
288 #undef r_arg1HL
289 #undef r_arg1HH
290              
291              
292 #undef r_arg2L 
293 #undef r_arg2H 
294 #undef r_arg2HL
295 #undef r_arg2HH
296              
297 #undef r_resL  
298 #undef r_resH  
299 #undef r_resHL 
300 #undef r_resHH 
302 .endfunc
303 #endif /* defined (L_mulsi3) */
304         
305 /*******************************************************
306        Division 8 / 8 => (result + remainder)
307 *******************************************************/
308 #define r_rem   r25     /* remainder */
309 #define r_arg1  r24     /* dividend, quotient */
310 #define r_arg2  r22     /* divisor */
311 #define r_cnt   r23     /* loop count */
313 #if defined (L_udivmodqi4)
314         .global __udivmodqi4
315         .func   __udivmodqi4
316 __udivmodqi4:
317         sub     r_rem,r_rem     ; clear remainder and carry
318         ldi     r_cnt,9         ; init loop counter
319         rjmp    __udivmodqi4_ep ; jump to entry point
320 __udivmodqi4_loop:
321         rol     r_rem           ; shift dividend into remainder
322         cp      r_rem,r_arg2    ; compare remainder & divisor
323         brcs    __udivmodqi4_ep ; remainder <= divisor
324         sub     r_rem,r_arg2    ; restore remainder
325 __udivmodqi4_ep:
326         rol     r_arg1          ; shift dividend (with CARRY)
327         dec     r_cnt           ; decrement loop counter
328         brne    __udivmodqi4_loop
329         com     r_arg1          ; complement result 
330                                 ; because C flag was complemented in loop
331         ret
332         .endfunc
333 #endif /* defined (L_udivmodqi4) */
335 #if defined (L_divmodqi4)
336         .global __divmodqi4
337         .func   __divmodqi4
338 __divmodqi4:
339         bst     r_arg1,7        ; store sign of dividend
340         mov     __tmp_reg__,r_arg1
341         eor     __tmp_reg__,r_arg2; r0.7 is sign of result
342         sbrc    r_arg1,7
343         neg     r_arg1          ; dividend negative : negate
344         sbrc    r_arg2,7
345         neg     r_arg2          ; divisor negative : negate
346         rcall   __udivmodqi4    ; do the unsigned div/mod
347         brtc    __divmodqi4_1
348         neg     r_rem           ; correct remainder sign
349 __divmodqi4_1:
350         sbrc    __tmp_reg__,7
351         neg     r_arg1          ; correct result sign
352 __divmodqi4_exit:
353         ret
354         .endfunc
355 #endif /* defined (L_divmodqi4) */
357 #undef r_rem
358 #undef r_arg1
359 #undef r_arg2
360 #undef r_cnt
361         
362                 
363 /*******************************************************
364        Division 16 / 16 => (result + remainder)
365 *******************************************************/
366 #define r_remL  r26     /* remainder Low */
367 #define r_remH  r27     /* remainder High */
369 /* return: remainder */
370 #define r_arg1L r24     /* dividend Low */
371 #define r_arg1H r25     /* dividend High */
373 /* return: quotient */
374 #define r_arg2L r22     /* divisor Low */
375 #define r_arg2H r23     /* divisor High */
376         
377 #define r_cnt   r21     /* loop count */
379 #if defined (L_udivmodhi4)
380         .global __udivmodhi4
381         .func   __udivmodhi4
382 __udivmodhi4:
383         sub     r_remL,r_remL
384         sub     r_remH,r_remH   ; clear remainder and carry
385         ldi     r_cnt,17        ; init loop counter
386         rjmp    __udivmodhi4_ep ; jump to entry point
387 __udivmodhi4_loop:
388         rol     r_remL          ; shift dividend into remainder
389         rol     r_remH
390         cp      r_remL,r_arg2L  ; compare remainder & divisor
391         cpc     r_remH,r_arg2H
392         brcs    __udivmodhi4_ep ; remainder < divisor
393         sub     r_remL,r_arg2L  ; restore remainder
394         sbc     r_remH,r_arg2H
395 __udivmodhi4_ep:
396         rol     r_arg1L         ; shift dividend (with CARRY)
397         rol     r_arg1H
398         dec     r_cnt           ; decrement loop counter
399         brne    __udivmodhi4_loop
400         com     r_arg1L
401         com     r_arg1H
402 ; div/mod results to return registers, as for the div() function
403         mov_l   r_arg2L, r_arg1L        ; quotient
404         mov_h   r_arg2H, r_arg1H
405         mov_l   r_arg1L, r_remL         ; remainder
406         mov_h   r_arg1H, r_remH
407         ret
408         .endfunc
409 #endif /* defined (L_udivmodhi4) */
411 #if defined (L_divmodhi4)
412         .global __divmodhi4
413         .func   __divmodhi4
414 __divmodhi4:
415         .global _div
416 _div:
417         bst     r_arg1H,7       ; store sign of dividend
418         mov     __tmp_reg__,r_arg1H
419         eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
420         rcall   __divmodhi4_neg1 ; dividend negative : negate
421         sbrc    r_arg2H,7
422         rcall   __divmodhi4_neg2 ; divisor negative : negate
423         rcall   __udivmodhi4    ; do the unsigned div/mod
424         rcall   __divmodhi4_neg1 ; correct remainder sign
425         tst     __tmp_reg__
426         brpl    __divmodhi4_exit
427 __divmodhi4_neg2:
428         com     r_arg2H
429         neg     r_arg2L         ; correct divisor/result sign
430         sbci    r_arg2H,0xff
431 __divmodhi4_exit:
432         ret
433 __divmodhi4_neg1:
434         brtc    __divmodhi4_exit
435         com     r_arg1H
436         neg     r_arg1L         ; correct dividend/remainder sign
437         sbci    r_arg1H,0xff
438         ret
439         .endfunc
440 #endif /* defined (L_divmodhi4) */
442 #undef r_remH  
443 #undef r_remL  
444              
445 #undef r_arg1H 
446 #undef r_arg1L 
447              
448 #undef r_arg2H 
449 #undef r_arg2L 
450                 
451 #undef r_cnt    
452         
453 /*******************************************************
454        Division 32 / 32 => (result + remainder)
455 *******************************************************/
456 #define r_remHH r31     /* remainder High */
457 #define r_remHL r30
458 #define r_remH  r27
459 #define r_remL  r26     /* remainder Low */
461 /* return: remainder */
462 #define r_arg1HH r25    /* dividend High */
463 #define r_arg1HL r24
464 #define r_arg1H  r23
465 #define r_arg1L  r22    /* dividend Low */
467 /* return: quotient */
468 #define r_arg2HH r21    /* divisor High */
469 #define r_arg2HL r20
470 #define r_arg2H  r19
471 #define r_arg2L  r18    /* divisor Low */
472         
473 #define r_cnt __zero_reg__  /* loop count (0 after the loop!) */
475 #if defined (L_udivmodsi4)
476         .global __udivmodsi4
477         .func   __udivmodsi4
478 __udivmodsi4:
479         ldi     r_remL, 33      ; init loop counter
480         mov     r_cnt, r_remL
481         sub     r_remL,r_remL
482         sub     r_remH,r_remH   ; clear remainder and carry
483         mov_l   r_remHL, r_remL
484         mov_h   r_remHH, r_remH
485         rjmp    __udivmodsi4_ep ; jump to entry point
486 __udivmodsi4_loop:
487         rol     r_remL          ; shift dividend into remainder
488         rol     r_remH
489         rol     r_remHL
490         rol     r_remHH
491         cp      r_remL,r_arg2L  ; compare remainder & divisor
492         cpc     r_remH,r_arg2H
493         cpc     r_remHL,r_arg2HL
494         cpc     r_remHH,r_arg2HH
495         brcs    __udivmodsi4_ep ; remainder <= divisor
496         sub     r_remL,r_arg2L  ; restore remainder
497         sbc     r_remH,r_arg2H
498         sbc     r_remHL,r_arg2HL
499         sbc     r_remHH,r_arg2HH
500 __udivmodsi4_ep:
501         rol     r_arg1L         ; shift dividend (with CARRY)
502         rol     r_arg1H
503         rol     r_arg1HL
504         rol     r_arg1HH
505         dec     r_cnt           ; decrement loop counter
506         brne    __udivmodsi4_loop
507                                 ; __zero_reg__ now restored (r_cnt == 0)
508         com     r_arg1L
509         com     r_arg1H
510         com     r_arg1HL
511         com     r_arg1HH
512 ; div/mod results to return registers, as for the ldiv() function
513         mov_l   r_arg2L,  r_arg1L       ; quotient
514         mov_h   r_arg2H,  r_arg1H
515         mov_l   r_arg2HL, r_arg1HL
516         mov_h   r_arg2HH, r_arg1HH
517         mov_l   r_arg1L,  r_remL        ; remainder
518         mov_h   r_arg1H,  r_remH
519         mov_l   r_arg1HL, r_remHL
520         mov_h   r_arg1HH, r_remHH
521         ret
522         .endfunc
523 #endif /* defined (L_udivmodsi4) */
525 #if defined (L_divmodsi4)
526         .global __divmodsi4
527         .func   __divmodsi4
528 __divmodsi4:
529         bst     r_arg1HH,7      ; store sign of dividend
530         mov     __tmp_reg__,r_arg1HH
531         eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
532         rcall   __divmodsi4_neg1 ; dividend negative : negate
533         sbrc    r_arg2HH,7
534         rcall   __divmodsi4_neg2 ; divisor negative : negate
535         rcall   __udivmodsi4    ; do the unsigned div/mod
536         rcall   __divmodsi4_neg1 ; correct remainder sign
537         rol     __tmp_reg__
538         brcc    __divmodsi4_exit
539 __divmodsi4_neg2:
540         com     r_arg2HH
541         com     r_arg2HL
542         com     r_arg2H
543         neg     r_arg2L         ; correct divisor/quotient sign
544         sbci    r_arg2H,0xff
545         sbci    r_arg2HL,0xff
546         sbci    r_arg2HH,0xff
547 __divmodsi4_exit:
548         ret
549 __divmodsi4_neg1:
550         brtc    __divmodsi4_exit
551         com     r_arg1HH
552         com     r_arg1HL
553         com     r_arg1H
554         neg     r_arg1L         ; correct dividend/remainder sign
555         sbci    r_arg1H, 0xff
556         sbci    r_arg1HL,0xff
557         sbci    r_arg1HH,0xff
558         ret
559         .endfunc
560 #endif /* defined (L_divmodsi4) */
562 /**********************************
563  * This is a prologue subroutine
564  **********************************/
565 #if defined (L_prologue)
567         .global __prologue_saves__
568         .func   __prologue_saves__
569 __prologue_saves__:
570         push r2
571         push r3
572         push r4
573         push r5
574         push r6
575         push r7
576         push r8
577         push r9
578         push r10
579         push r11
580         push r12
581         push r13
582         push r14
583         push r15
584         push r16
585         push r17
586         push r28
587         push r29
588         in      r28,__SP_L__
589         in      r29,__SP_H__
590         sub     r28,r26
591         sbc     r29,r27
592         in      __tmp_reg__,__SREG__
593         cli
594         out     __SP_H__,r29
595         out     __SREG__,__tmp_reg__
596         out     __SP_L__,r28
597         ijmp
598 .endfunc
599 #endif /* defined (L_prologue) */
602  * This is an epilogue subroutine
603  */
604 #if defined (L_epilogue)
606         .global __epilogue_restores__
607         .func   __epilogue_restores__
608 __epilogue_restores__:
609         ldd     r2,Y+18
610         ldd     r3,Y+17
611         ldd     r4,Y+16
612         ldd     r5,Y+15
613         ldd     r6,Y+14
614         ldd     r7,Y+13
615         ldd     r8,Y+12
616         ldd     r9,Y+11
617         ldd     r10,Y+10
618         ldd     r11,Y+9
619         ldd     r12,Y+8
620         ldd     r13,Y+7
621         ldd     r14,Y+6
622         ldd     r15,Y+5
623         ldd     r16,Y+4
624         ldd     r17,Y+3
625         ldd     r26,Y+2
626         ldd     r27,Y+1
627         add     r28,r30
628         adc     r29,__zero_reg__
629         in      __tmp_reg__,__SREG__
630         cli
631         out     __SP_H__,r29
632         out     __SREG__,__tmp_reg__
633         out     __SP_L__,r28
634         mov_l   r28, r26
635         mov_h   r29, r27
636         ret
637 .endfunc
638 #endif /* defined (L_epilogue) */
640 #ifdef L_exit
641         .section .fini9,"ax",@progbits
642         .global _exit
643         .func   _exit
644 _exit:
645         .weak   exit
646 exit:
648         /* Code from .fini8 ... .fini1 sections inserted by ld script.  */
650         .section .fini0,"ax",@progbits
651         cli
652 __stop_program:
653         rjmp    __stop_program
654         .endfunc
655 #endif /* defined (L_exit) */
657 #ifdef L_cleanup
658         .weak   _cleanup
659         .func   _cleanup
660 _cleanup:
661         ret
662 .endfunc
663 #endif /* defined (L_cleanup) */
665 #ifdef L_tablejump
666         .global __tablejump2__
667         .func   __tablejump2__
668 __tablejump2__:
669         lsl     r30
670         rol     r31
671         .global __tablejump__
672 __tablejump__:
673 #if defined (__AVR_HAVE_LPMX__)
674         lpm     __tmp_reg__, Z+
675         lpm     r31, Z
676         mov     r30, __tmp_reg__
677         ijmp
678 #else
679         lpm
680         adiw    r30, 1
681         push    r0
682         lpm
683         push    r0
684         ret
685 #endif
686         .endfunc
687 #endif /* defined (L_tablejump) */
689 /* __do_copy_data is only necessary if there is anything in .data section.
690    Does not use RAMPZ - crt*.o provides a replacement for >64K devices.  */
692 #ifdef L_copy_data
693         .section .init4,"ax",@progbits
694         .global __do_copy_data
695 __do_copy_data:
696         ldi     r17, hi8(__data_end)
697         ldi     r26, lo8(__data_start)
698         ldi     r27, hi8(__data_start)
699         ldi     r30, lo8(__data_load_start)
700         ldi     r31, hi8(__data_load_start)
701         rjmp    .do_copy_data_start
702 .do_copy_data_loop:
703 #if defined (__AVR_HAVE_LPMX__)
704         lpm     r0, Z+
705 #else
706         lpm
707         adiw    r30, 1
708 #endif
709         st      X+, r0
710 .do_copy_data_start:
711         cpi     r26, lo8(__data_end)
712         cpc     r27, r17
713         brne    .do_copy_data_loop
714 #endif /* L_copy_data */
716 /* __do_clear_bss is only necessary if there is anything in .bss section.  */
718 #ifdef L_clear_bss
719         .section .init4,"ax",@progbits
720         .global __do_clear_bss
721 __do_clear_bss:
722         ldi     r17, hi8(__bss_end)
723         ldi     r26, lo8(__bss_start)
724         ldi     r27, hi8(__bss_start)
725         rjmp    .do_clear_bss_start
726 .do_clear_bss_loop:
727         st      X+, __zero_reg__
728 .do_clear_bss_start:
729         cpi     r26, lo8(__bss_end)
730         cpc     r27, r17
731         brne    .do_clear_bss_loop
732 #endif /* L_clear_bss */
734 /* __do_global_ctors and __do_global_dtors are only necessary
735    if there are any constructors/destructors.  */
737 #if defined (__AVR_MEGA__)
738 #define XCALL call
739 #else
740 #define XCALL rcall
741 #endif
743 #ifdef L_ctors
744         .section .init6,"ax",@progbits
745         .global __do_global_ctors
746 __do_global_ctors:
747         ldi     r17, hi8(__ctors_start)
748         ldi     r28, lo8(__ctors_end)
749         ldi     r29, hi8(__ctors_end)
750         rjmp    .do_global_ctors_start
751 .do_global_ctors_loop:
752         sbiw    r28, 2
753         mov_h   r31, r29
754         mov_l   r30, r28
755         XCALL   __tablejump__
756 .do_global_ctors_start:
757         cpi     r28, lo8(__ctors_start)
758         cpc     r29, r17
759         brne    .do_global_ctors_loop
760 #endif /* L_ctors */
762 #ifdef L_dtors
763         .section .fini6,"ax",@progbits
764         .global __do_global_dtors
765 __do_global_dtors:
766         ldi     r17, hi8(__dtors_end)
767         ldi     r28, lo8(__dtors_start)
768         ldi     r29, hi8(__dtors_start)
769         rjmp    .do_global_dtors_start
770 .do_global_dtors_loop:
771         mov_h   r31, r29
772         mov_l   r30, r28
773         XCALL   __tablejump__
774         adiw    r28, 2
775 .do_global_dtors_start:
776         cpi     r28, lo8(__dtors_end)
777         cpc     r29, r17
778         brne    .do_global_dtors_loop
779 #endif /* L_dtors */