/* libgcc routines for M68HC11 & M68HC12.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
. */
#ifdef __HAVE_SHORT_INT__
.mode mshort
#else
.mode mlong
#endif
.macro declare_near name
.globl \name
.type \name,@function
.size \name,.Lend-\name
\name:
.endm
#if defined(__USE_RTC__)
# define ARG(N) N+1
.macro ret
#if defined(mc68hc12)
rtc
#else
jmp __return_32
#endif
.endm
.macro declare name
.globl \name
.type \name,@function
.size \name,.Lend-\name
.far \name
\name:
.endm
.macro farsym name
.far NAME
.endm
#else
# define ARG(N) N
.macro ret
rts
.endm
.macro farsym name
.endm
.macro declare name
.globl \name
.type \name,@function
.size \name,.Lend-\name
\name:
.endm
#endif
.sect .text
#define REG(NAME) \
NAME: .dc.w 1; \
.type NAME,@object ; \
.size NAME,2
#ifdef L_regs_min
/* Pseudo hard registers used by gcc.
They should be located in page0. */
.sect .softregs
.globl _.tmp
.globl _.z,_.xy
REG(_.tmp)
REG(_.z)
REG(_.xy)
#endif
#ifdef L_regs_frame
.sect .softregs
.globl _.frame
REG(_.frame)
#endif
#ifdef L_regs_d1_2
.sect .softregs
.globl _.d1,_.d2
REG(_.d1)
REG(_.d2)
#endif
#ifdef L_regs_d3_4
.sect .softregs
.globl _.d3,_.d4
REG(_.d3)
REG(_.d4)
#endif
#ifdef L_regs_d5_6
.sect .softregs
.globl _.d5,_.d6
REG(_.d5)
REG(_.d6)
#endif
#ifdef L_regs_d7_8
.sect .softregs
.globl _.d7,_.d8
REG(_.d7)
REG(_.d8)
#endif
#ifdef L_regs_d9_16
/* Pseudo hard registers used by gcc.
They should be located in page0. */
.sect .softregs
.globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14
.globl _.d15,_.d16
REG(_.d9)
REG(_.d10)
REG(_.d11)
REG(_.d12)
REG(_.d13)
REG(_.d14)
REG(_.d15)
REG(_.d16)
#endif
#ifdef L_regs_d17_32
/* Pseudo hard registers used by gcc.
They should be located in page0. */
.sect .softregs
.globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22
.globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28
.globl _.d29,_.d30,_.d31,_.d32
REG(_.d17)
REG(_.d18)
REG(_.d19)
REG(_.d20)
REG(_.d21)
REG(_.d22)
REG(_.d23)
REG(_.d24)
REG(_.d25)
REG(_.d26)
REG(_.d27)
REG(_.d28)
REG(_.d29)
REG(_.d30)
REG(_.d31)
REG(_.d32)
#endif
#ifdef L_premain
;;
;; Specific initialization for 68hc11 before the main.
;; Nothing special for a generic routine; Just enable interrupts.
;;
declare_near __premain
clra
tap ; Clear both I and X.
rts
#endif
#ifdef L__exit
;;
;; Exit operation. Just loop forever and wait for interrupts.
;; (no other place to go)
;; This operation is split in several pieces collected together by
;; the linker script. This allows to support destructors at the
;; exit stage while not impacting program sizes when there is no
;; destructors.
;;
;; _exit:
;; *(.fini0) /* Beginning of finish code (_exit symbol). */
;; *(.fini1) /* Place holder for applications. */
;; *(.fini2) /* C++ destructors. */
;; *(.fini3) /* Place holder for applications. */
;; *(.fini4) /* Runtime exit. */
;;
.sect .fini0,"ax",@progbits
.globl _exit
.globl exit
.weak exit
farsym exit
farsym _exit
exit:
_exit:
.sect .fini4,"ax",@progbits
fatal:
cli
wai
bra fatal
#endif
#ifdef L_abort
;;
;; Abort operation. This is defined for the GCC testsuite.
;;
declare abort
ldd #255 ;
#ifdef mc68hc12
trap #0x30
#else
.byte 0xCD ; Generate an illegal instruction trap
.byte 0x03 ; The simulator catches this and stops.
#endif
jmp _exit
#endif
#ifdef L_cleanup
;;
;; Cleanup operation used by exit().
;;
declare _cleanup
ret
#endif
;-----------------------------------------
; required gcclib code
;-----------------------------------------
#ifdef L_memcpy
declare memcpy
declare __memcpy
.weak memcpy
;;;
;;; void* memcpy(void*, const void*, size_t)
;;;
;;; D = dst Pmode
;;; 2,sp = src Pmode
;;; 4,sp = size HImode (size_t)
;;;
#ifdef mc68hc12
ldx ARG(2),sp
ldy ARG(4),sp
pshd
xgdy
lsrd
bcc Start
movb 1,x+,1,y+
Start:
beq Done
Loop:
movw 2,x+,2,y+
dbne d,Loop
Done:
puld
ret
#else
xgdy
tsx
ldd ARG(4),x
ldx ARG(2),x ; SRC = X, DST = Y
cpd #0
beq End
pshy
inca ; Correction for the deca below
L0:
psha ; Save high-counter part
L1:
ldaa 0,x ; Copy up to 256 bytes
staa 0,y
inx
iny
decb
bne L1
pula
deca
bne L0
puly ; Restore Y to return the DST
End:
xgdy
ret
#endif
#endif
#ifdef L_memset
declare memset
declare __memset
;;;
;;; void* memset(void*, int value, size_t)
;;;
#ifndef __HAVE_SHORT_INT__
;;; D = dst Pmode
;;; 2,sp = src SImode
;;; 6,sp = size HImode (size_t)
val = ARG(5)
size = ARG(6)
#else
;;; D = dst Pmode
;;; 2,sp = src SImode
;;; 6,sp = size HImode (size_t)
val = ARG(3)
size = ARG(4)
#endif
#ifdef mc68hc12
xgdx
ldab val,sp
ldy size,sp
pshx
beq End
Loop:
stab 1,x+
dbne y,Loop
End:
puld
ret
#else
xgdx
tsy
ldab val,y
ldy size,y ; DST = X, CNT = Y
beq End
pshx
L0:
stab 0,x ; Fill up to 256 bytes
inx
dey
bne L0
pulx ; Restore X to return the DST
End:
xgdx
ret
#endif
#endif
#ifdef L_adddi3
declare ___adddi3
tsx
xgdy
ldd ARG(8),x ; Add LSB
addd ARG(16),x
std 6,y ; Save (carry preserved)
ldd ARG(6),x
adcb ARG(15),x
adca ARG(14),x
std 4,y
ldd ARG(4),x
adcb ARG(13),x
adca ARG(12),x
std 2,y
ldd ARG(2),x
adcb ARG(11),x ; Add MSB
adca ARG(10),x
std 0,y
xgdy
ret
#endif
#ifdef L_subdi3
declare ___subdi3
tsx
xgdy
ldd ARG(8),x ; Subtract LSB
subd ARG(16),x
std 6,y ; Save, borrow preserved
ldd ARG(6),x
sbcb ARG(15),x
sbca ARG(14),x
std 4,y
ldd ARG(4),x
sbcb ARG(13),x
sbca ARG(12),x
std 2,y
ldd ARG(2),x ; Subtract MSB
sbcb ARG(11),x
sbca ARG(10),x
std 0,y
xgdy ;
ret
#endif
#ifdef L_notdi2
declare ___notdi2
tsy
xgdx
ldd ARG(8),y
coma
comb
std 6,x
ldd ARG(6),y
coma
comb
std 4,x
ldd ARG(4),y
coma
comb
std 2,x
ldd ARG(2),y
coma
comb
std 0,x
xgdx
ret
#endif
#ifdef L_negsi2
declare_near ___negsi2
comb
coma
xgdx
comb
coma
inx
xgdx
bne done
inx
done:
rts
#endif
#ifdef L_one_cmplsi2
declare_near ___one_cmplsi2
comb
coma
xgdx
comb
coma
xgdx
rts
#endif
#ifdef L_ashlsi3
declare_near ___ashlsi3
xgdy
clra
andb #0x1f
xgdy
beq Return
Loop:
lsld
xgdx
rolb
rola
xgdx
dey
bne Loop
Return:
rts
#endif
#ifdef L_ashrsi3
declare_near ___ashrsi3
xgdy
clra
andb #0x1f
xgdy
beq Return
Loop:
xgdx
asra
rorb
xgdx
rora
rorb
dey
bne Loop
Return:
rts
#endif
#ifdef L_lshrsi3
declare_near ___lshrsi3
xgdy
clra
andb #0x1f
xgdy
beq Return
Loop:
xgdx
lsrd
xgdx
rora
rorb
dey
bne Loop
Return:
rts
#endif
#ifdef L_lshrhi3
declare_near ___lshrhi3
cpx #16
bge Return_zero
cpx #0
beq Return
Loop:
lsrd
dex
bne Loop
Return:
rts
Return_zero:
clra
clrb
rts
#endif
#ifdef L_lshlhi3
declare_near ___lshlhi3
cpx #16
bge Return_zero
cpx #0
beq Return
Loop:
lsld
dex
bne Loop
Return:
rts
Return_zero:
clra
clrb
rts
#endif
#ifdef L_rotrhi3
declare_near ___rotrhi3
___rotrhi3:
xgdx
clra
andb #0x0f
xgdx
beq Return
Loop:
tap
rorb
rora
dex
bne Loop
Return:
rts
#endif
#ifdef L_rotlhi3
declare_near ___rotlhi3
___rotlhi3:
xgdx
clra
andb #0x0f
xgdx
beq Return
Loop:
asrb
rolb
rola
rolb
dex
bne Loop
Return:
rts
#endif
#ifdef L_ashrhi3
declare_near ___ashrhi3
cpx #16
bge Return_minus_1_or_zero
cpx #0
beq Return
Loop:
asra
rorb
dex
bne Loop
Return:
rts
Return_minus_1_or_zero:
clrb
tsta
bpl Return_zero
comb
Return_zero:
tba
rts
#endif
#ifdef L_ashrqi3
declare_near ___ashrqi3
cmpa #8
bge Return_minus_1_or_zero
tsta
beq Return
Loop:
asrb
deca
bne Loop
Return:
rts
Return_minus_1_or_zero:
clrb
tstb
bpl Return_zero
coma
Return_zero:
tab
rts
#endif
#ifdef L_lshlqi3
declare_near ___lshlqi3
cmpa #8
bge Return_zero
tsta
beq Return
Loop:
lslb
deca
bne Loop
Return:
rts
Return_zero:
clrb
rts
#endif
#ifdef L_divmodhi4
#ifndef mc68hc12
/* 68HC12 signed divisions are generated inline (idivs). */
declare_near __divmodhi4
;
;; D = numerator
;; X = denominator
;;
;; Result: D = D / X
;; X = D % X
;;
tsta
bpl Numerator_pos
comb ; D = -D <=> D = (~D) + 1
coma
xgdx
inx
tsta
bpl Numerator_neg_denominator_pos
Numerator_neg_denominator_neg:
comb ; X = -X
coma
addd #1
xgdx
idiv
coma
comb
xgdx ; Remainder <= 0 and result >= 0
inx
rts
Numerator_pos_denominator_pos:
xgdx
idiv
xgdx ; Both values are >= 0
rts
Numerator_pos:
xgdx
tsta
bpl Numerator_pos_denominator_pos
Numerator_pos_denominator_neg:
coma ; X = -X
comb
xgdx
inx
idiv
xgdx ; Remainder >= 0 but result <= 0
coma
comb
addd #1
rts
Numerator_neg_denominator_pos:
xgdx
idiv
coma ; One value is > 0 and the other < 0
comb ; Change the sign of result and remainder
xgdx
inx
coma
comb
addd #1
rts
#endif /* !mc68hc12 */
#endif
#ifdef L_mulqi3
declare_near ___mulqi3
;
; short __mulqi3(signed char a, signed char b);
;
; signed char a -> register A
; signed char b -> register B
;
; returns the signed result of A * B in register D.
;
tsta
bmi A_neg
tstb
bmi B_neg
mul
rts
B_neg:
negb
bra A_or_B_neg
A_neg:
nega
tstb
bmi AB_neg
A_or_B_neg:
mul
coma
comb
addd #1
rts
AB_neg:
negb
mul
rts
#endif
#ifdef L_mulhi3
declare_near ___mulhi3
;
;
; unsigned short ___mulhi3(unsigned short a, unsigned short b)
;
; a = register D
; b = register X
;
#ifdef mc68hc12
pshx ; Preserve X
exg x,y
emul
exg x,y
pulx
rts
#else
#ifdef NO_TMP
;
; 16-bit multiplication without temp memory location.
; (smaller but slower)
;
pshx ; (4)
ins ; (3)
pshb ; (3)
psha ; (3)
pshx ; (4)
pula ; (4)
pulx ; (5)
mul ; (10) B.high * A.low
xgdx ; (3)
mul ; (10) B.low * A.high
abx ; (3)
pula ; (4)
pulb ; (4)
mul ; (10) B.low * A.low
pshx ; (4)
tsx ; (3)
adda 1,x ; (4)
pulx ; (5)
rts ; (5) 20 bytes
; ---
; 91 cycles
#else
stx *_.tmp ; (4)
pshb ; (3)
ldab *_.tmp+1 ; (3)
mul ; (10) A.high * B.low
ldaa *_.tmp ; (3)
stab *_.tmp ; (3)
pulb ; (4)
pshb ; (4)
mul ; (10) A.low * B.high
addb *_.tmp ; (4)
stab *_.tmp ; (3)
ldaa *_.tmp+1 ; (3)
pulb ; (4)
mul ; (10) A.low * B.low
adda *_.tmp ; (4)
rts ; (5) 24/32 bytes
; 77/85 cycles
#endif
#endif
#endif
#ifdef L_mulhi32
;
;
; unsigned long __mulhi32(unsigned short a, unsigned short b)
;
; a = register D
; b = value on stack
;
; +---------------+
; | B low | <- 7,x
; +---------------+
; | B high | <- 6,x
; +---------------+
; | PC low |
; +---------------+
; | PC high |
; +---------------+
; | Tmp low |
; +---------------+
; | Tmp high |
; +---------------+
; | A low |
; +---------------+
; | A high |
; +---------------+ <- 0,x
;
;
; 5,x
; 4,x
; 2,x
; 1,x
; 0,x
;
declare_near __mulhi32
#ifdef mc68hc12
ldy 2,sp
emul
exg x,y
rts
#else
pshx ; Room for temp value
pshb
psha
tsx
ldab 6,x
mul
xgdy ; A.high * B.high
ldab 7,x
pula
mul ; A.high * B.low
std 2,x
ldaa 1,x
ldab 6,x
mul ; A.low * B.high
addd 2,x
stab 2,x
tab
aby
bcc N
ldab #0xff
aby
iny
N:
ldab 7,x
pula
mul ; A.low * B.low
adda 2,x
pulx ; Drop temp location
pshy ; Put high part in X
pulx
bcc Ret
inx
Ret:
rts
#endif
#endif
#ifdef L_mulsi3
;
; 8,y
; 6,y
; 4,y
; 2,y
; 0,y
;
; D,X -> A
; Stack -> B
;
; The result is:
;
; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
;
;
;
declare __mulsi3
#ifdef mc68hc12
pshd ; Save A.low
ldy ARG(4),sp
emul ; A.low * B.high
ldy ARG(6),sp
exg x,d
emul ; A.high * B.low
leax d,x
ldy ARG(6),sp
puld
emul ; A.low * B.low
exg d,y
leax d,x
exg d,y
ret
#else
B_low = ARG(8)
B_high = ARG(6)
A_low = 0
A_high = 2
pshx
pshb
psha
tsy
;
; If B.low is 0, optimize into: (A.low * B.high) << 16
;
ldd B_low,y
beq B_low_zero
;
; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
;
cpx #0
beq A_high_zero
bsr ___mulhi3 ; A.high * B.low
;
; If A.low is 0, optimize into: (A.high * B.low) << 16
;
ldx A_low,y
beq A_low_zero ; X = 0, D = A.high * B.low
std 2,y
;
; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
;
ldd B_high,y
beq B_high_zero
bsr ___mulhi3 ; A.low * B.high
addd 2,y
std 2,y
;
; Here, we know that A.low and B.low are not 0.
;
B_high_zero:
ldd B_low,y ; A.low is on the stack
bsr __mulhi32 ; A.low * B.low
xgdx
tsy ; Y was clobbered, get it back
addd 2,y
A_low_zero: ; See A_low_zero_non_optimized below
xgdx
Return:
ins
ins
ins
ins
ret
;
;
; A_low_zero_non_optimized:
;
; At this step, X = 0 and D = (A.high * B.low)
; Optimize into: (A.high * B.low) << 16
;
; xgdx
; clra ; Since X was 0, clearing D is superfuous.
; clrb
; bra Return
; ----------------
; B.low == 0, the result is: (A.low * B.high) << 16
;
; At this step:
; D = B.low = 0
; X = A.high ?
; A.low is at A_low,y ?
; B.low is at B_low,y ?
;
B_low_zero:
ldd A_low,y
beq Zero1
ldx B_high,y
beq Zero2
bsr ___mulhi3
Zero1:
xgdx
Zero2:
clra
clrb
bra Return
; ----------------
; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
;
; At this step:
; D = B.low != 0
; X = A.high = 0
; A.low is at A_low,y ?
; B.low is at B_low,y ?
;
A_high_zero:
ldd A_low,y ; A.low
beq Zero1
ldx B_high,y ; B.high
beq A_low_B_low
bsr ___mulhi3
std 2,y
bra B_high_zero ; Do the (A.low * B.low) and the add.
; ----------------
; A.high and B.high are 0 optimize into: (A.low * B.low)
;
; At this step:
; D = B.high = 0
; X = A.low != 0
; A.low is at A_low,y != 0
; B.high is at B_high,y = 0
;
A_low_B_low:
ldd B_low,y ; A.low is on the stack
bsr __mulhi32
bra Return
#endif
#endif
#ifdef L_map_data
.sect .install2,"ax",@progbits
.globl __map_data_section
.globl __data_image
#ifdef mc68hc12
.globl __data_section_size
#endif
__map_data_section:
#ifdef mc68hc12
ldx #__data_image
ldy #__data_section_start
ldd #__data_section_size
beq Done
Loop:
movb 1,x+,1,y+
dbne d,Loop
#else
ldx #__data_image
ldy #__data_section_start
bra Start_map
Loop:
ldaa 0,x
staa 0,y
inx
iny
Start_map:
cpx #__data_image_end
blo Loop
#endif
Done:
#endif
#ifdef L_init_bss
.sect .install2,"ax",@progbits
.globl __init_bss_section
__init_bss_section:
ldd #__bss_size
beq Done
ldx #__bss_start
Loop:
#ifdef mc68hc12
clr 1,x+
dbne d,Loop
#else
clr 0,x
inx
subd #1
bne Loop
#endif
Done:
#endif
#ifdef L_ctor
; End of constructor table
.sect .install3,"ax",@progbits
.globl __do_global_ctors
__do_global_ctors:
; Start from the end - sizeof(void*)
ldx #__CTOR_END__-2
ctors_loop:
cpx #__CTOR_LIST__
blo ctors_done
pshx
ldx 0,x
jsr 0,x
pulx
dex
dex
bra ctors_loop
ctors_done:
#endif
#ifdef L_dtor
.sect .fini3,"ax",@progbits
.globl __do_global_dtors
;;
;; This piece of code is inserted in the _exit() code by the linker.
;;
__do_global_dtors:
pshb ; Save exit code
psha
ldx #__DTOR_LIST__
dtors_loop:
cpx #__DTOR_END__
bhs dtors_done
pshx
ldx 0,x
jsr 0,x
pulx
inx
inx
bra dtors_loop
dtors_done:
pula ; Restore exit code
pulb
#endif
#ifdef L_far_tramp
#ifdef mc68hc12
.sect .tramp,"ax",@progbits
.globl __far_trampoline
;; This is a trampoline used by the linker to invoke a function
;; using rtc to return and being called with jsr/bsr.
;; The trampoline generated is:
;;
;; foo_tramp:
;; ldy #foo
;; call __far_trampoline,page(foo)
;;
;; The linker transforms:
;;
;; jsr foo
;;
;; into
;; jsr foo_tramp
;;
;; The linker generated trampoline and _far_trampoline must be in
;; non-banked memory.
;;
__far_trampoline:
movb 0,sp, 2,sp ; Copy page register below the caller's return
leas 2,sp ; address.
jmp 0,y ; We have a 'call/rtc' stack layout now
; and can jump to the far handler
; (whose memory bank is mapped due to the
; call to the trampoline).
#endif
#ifdef mc68hc11
.sect .tramp,"ax",@progbits
.globl __far_trampoline
;; Trampoline generated by gcc for 68HC11:
;;
;; pshb
;; ldab #%page(func)
;; ldy #%addr(func)
;; jmp __far_trampoline
;;
__far_trampoline:
psha ; (2) Save function parameter (high)
;;
psha ; (2)
;;
pshx ; (4)
tsx ; (3)
ldab 4,x ; (4) Restore function parameter (low)
ldaa 2,x ; (4) Get saved page number
staa 4,x ; (4) Save it below return PC
pulx ; (5)
pula ; (3)
pula ; (3) Restore function parameter (high)
jmp 0,y ; (4)
#endif
#endif
#ifdef L_call_far
#ifdef mc68hc11
.sect .tramp,"ax",@progbits
.globl __call_a16
.globl __call_a32
;;
;; The call methods are used for 68HC11 to support memory bank switching.
;; Every far call is redirected to these call methods. Its purpose is to:
;;
;; 1/ Save the current page on the stack (1 byte to follow 68HC12 call frame)
;; 2/ Install the new page
;; 3/ Jump to the real function
;;
;; The page switching (get/save) is board dependent. The default provided
;; here does nothing (just create the appropriate call frame).
;;
;; Call sequence (10 bytes, 13 cycles):
;;
;; ldx #page ; (3)
;; ldy #func ; (4)
;; jsr __call_a16 ; (6)
;;
;; Call trampoline (11 bytes, 19 cycles):
;;
__call_a16:
;; xgdx ; (3)
;; ; (3) ldaa _current_page
psha ; (2)
;; ; (4) staa _current_page
;; xgdx ; (3)
jmp 0,y ; (4)
;;
;; Call sequence (10 bytes, 14 cycles):
;;
;; pshb ; (2)
;; ldab #page ; (2)
;; ldy #func ; (4)
;; jsr __call_a32 ; (6)
;;
;; Call trampoline (87 bytes, 57 cycles):
;;
__call_a32:
pshx ; (4)
psha ; (2)
;; ; (3) ldaa _current_page
psha ; (2)
;; ; (4) staa _current_page
tsx ; (3)
ldab 6,x ; (4) Restore function parameter
ldaa 5,x ; (4) Move PC return at good place
staa 6,x ; (4)
ldaa 4,x ; (4)
staa 5,x ; (4)
pula ; (3)
staa 4,x ; (4)
pula ; (3)
pulx ; (5)
jmp 0,y ; (4)
#endif
#endif
#ifdef L_return_far
#ifdef mc68hc11
.sect .tramp,"ax",@progbits
.globl __return_void
.globl __return_16
.globl __return_32
__return_void:
;; pulb
;; (Board specific)
;; rts
__return_16:
;; xgdx
;; pulb
;; (Board specific)
;; xgdx
;; rts
__return_32:
;; xgdy
;; pulb
;; (Board specific)
;; xgdy
;; rts
ins
rts
#endif
#endif
.Lend:
;-----------------------------------------
; end required gcclib code
;-----------------------------------------