+2002-06-02 Marek Michalkiewicz <marekm@amelek.gda.pl>
+
+ Support for C++ constructors/destructors.
+ * config/avr/avr.c (avr_output_function_epilogue): Jump to exit()
+ instead of looping if main() returns.
+ (asm_file_start): Output global symbols that cause .data and .bss
+ initialization code to be linked in, unconditionally for now.
+ (avr_asm_out_ctor, avr_asm_out_dtor): New functions.
+ * config/avr/avr.h (CTORS_SECTION_ASM_OP, DTORS_SECTION_ASM_OP): New.
+ (TARGET_ASM_CONSTRUCTOR, TARGET_ASM_DESTRUCTOR): New.
+ (LIBSTDCXX): New.
+ * config/avr/libgcc.S (_exit): Split in .fini9 and .fini0 sections.
+ (__tablejump__): New.
+ (__do_copy_data, __do_clear_bss): New.
+ (__do_global_ctors, __do_global_dtors): New.
+ * config/avr/t-avr (LIB1ASMFUNCS): Add _copy_data, _clear_bss,
+ _ctors, _dtors.
+
2002-06-02 Neil Booth <neil@daikokuya.demon.co.uk>
* c4x/c4x.h (TARGET_CPU_CPP_BUILTINS): New.
static void avr_unique_section PARAMS ((tree, int));
static void avr_encode_section_info PARAMS ((tree, int));
+static void avr_asm_out_ctor PARAMS ((rtx, int));
+static void avr_asm_out_dtor PARAMS ((rtx, int));
+
/* Allocate registers from r25 to r8 for parameters for function calls */
#define FIRST_CUM_REG 26
fprintf (file, "/* epilogue: frame size=%d */\n", size);
if (main_p)
{
- fprintf (file, "__stop_progIi__:\n\trjmp __stop_progIi__\n");
- ++epilogue_size;
+ /* Return value from main() is already in the correct registers
+ (r25:r24) as the exit() argument. */
+ if (AVR_MEGA)
+ {
+ fputs ("\t" AS1 (jmp,exit) "\n", file);
+ epilogue_size += 2;
+ }
+ else
+ {
+ fputs ("\t" AS1 (rjmp,exit) "\n", file);
+ ++epilogue_size;
+ }
}
else if (minimize && (frame_pointer_needed || live_seq > 4))
{
fputs ("__tmp_reg__ = 0\n"
"__zero_reg__ = 1\n"
"_PC_ = 2\n", file);
-
+
+ /* FIXME: output these only if there is anything in the .data / .bss
+ sections - some code size could be saved by not linking in the
+ initialization code from libgcc if one or both sections are empty. */
+ fputs ("\t.global __do_copy_data\n", file);
+ fputs ("\t.global __do_clear_bss\n", file);
+
commands_in_file = 0;
commands_in_prologues = 0;
commands_in_epilogues = 0;
return AS1 (rjmp,%3);
return "";
}
+
+static void
+avr_asm_out_ctor (symbol, priority)
+ rtx symbol;
+ int priority;
+{
+ fputs ("\t.global __do_global_ctors\n", asm_out_file);
+ default_ctor_section_asm_out_constructor (symbol, priority);
+}
+
+static void
+avr_asm_out_dtor (symbol, priority)
+ rtx symbol;
+ int priority;
+{
+ fputs ("\t.global __do_global_dtors\n", asm_out_file);
+ default_dtor_section_asm_out_destructor (symbol, priority);
+}
+
`-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
used. */
+/* Define the pseudo-ops used to switch to the .ctors and .dtors sections.
+ There are no shared libraries on this target, and these sections are
+ placed in the read-only program memory, so they are not writable. */
+
+#undef CTORS_SECTION_ASM_OP
+#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"a\",@progbits"
+
+#undef DTORS_SECTION_ASM_OP
+#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"a\",@progbits"
+
+#define TARGET_ASM_CONSTRUCTOR avr_asm_out_ctor
+/* If defined, a function that outputs assembler code to arrange to
+ call the function referenced by SYMBOL at initialization time. */
+
+#define TARGET_ASM_DESTRUCTOR avr_asm_out_dtor
+/* This is like `TARGET_ASM_CONSTRUCTOR' but used for termination
+ functions rather than initialization functions. */
+
#define EXTRA_SECTIONS in_progmem
/* A list of names for sections other than the standard two, which are
`in_text' and `in_data'. You need not define this macro on a
If this macro is not defined, a default is provided that loads the
standard C library from the usual place. See `gcc.c'. */
+#define LIBSTDCXX "-lgcc"
+/* No libstdc++ for now. Empty string doesn't work. */
+
#define LIBGCC_SPEC \
"%{!mmcu=at90s1*:%{!mmcu=attiny1*:%{!mmcu=attiny28: -lgcc }}}"
/* Another C string constant that tells the GNU CC driver program how
#endif /* defined (L_epilogue) */
#ifdef L_exit
- .weak _exit
+ .section .fini9,"ax",@progbits
+ .global _exit
.func _exit
_exit:
- rjmp _exit
-.endfunc
+ .weak exit
+exit:
+
+ /* Code from .fini8 ... .fini1 sections inserted by ld script. */
+
+ .section .fini0,"ax",@progbits
+__stop_program:
+ rjmp __stop_program
+ .endfunc
#endif /* defined (L_exit) */
#ifdef L_cleanup
__tablejump2__:
lsl r30
rol r31
+ .global __tablejump__
+__tablejump__:
#if defined (__AVR_ENHANCED__)
lpm __tmp_reg__, Z+
lpm r31, Z
ijmp
#else
lpm
+ adiw r30, 1
push r0
- inc r30 ; table is word aligned, no carry to high byte
lpm
push r0
ret
#endif
-.endfunc
+ .endfunc
#endif /* defined (L_tablejump) */
+/* __do_copy_data is only necessary if there is anything in .data section.
+ Does not use RAMPZ - crt*.o provides a replacement for >64K devices. */
+
+#ifdef L_copy_data
+ .section .init4,"ax",@progbits
+ .global __do_copy_data
+__do_copy_data:
+ ldi r17, hi8(__data_end)
+ ldi r26, lo8(__data_start)
+ ldi r27, hi8(__data_start)
+ ldi r30, lo8(__data_load_start)
+ ldi r31, hi8(__data_load_start)
+ rjmp .do_copy_data_start
+.do_copy_data_loop:
+#if defined (__AVR_ENHANCED__)
+ lpm r0, Z+
+#else
+ lpm
+ adiw r30, 1
+#endif
+ st X+, r0
+.do_copy_data_start:
+ cpi r26, lo8(__data_end)
+ cpc r27, r17
+ brne .do_copy_data_loop
+#endif /* L_copy_data */
+
+/* __do_clear_bss is only necessary if there is anything in .bss section. */
+
+#ifdef L_clear_bss
+ .section .init4,"ax",@progbits
+ .global __do_clear_bss
+__do_clear_bss:
+ ldi r17, hi8(__bss_end)
+ ldi r26, lo8(__bss_start)
+ ldi r27, hi8(__bss_start)
+ rjmp .do_clear_bss_start
+.do_clear_bss_loop:
+ st X+, __zero_reg__
+.do_clear_bss_start:
+ cpi r26, lo8(__bss_end)
+ cpc r27, r17
+ brne .do_clear_bss_loop
+#endif /* L_clear_bss */
+
+/* __do_global_ctors and __do_global_dtors are only necessary
+ if there are any constructors/destructors. */
+
+#if defined (__AVR_MEGA__)
+#define XCALL call
+#else
+#define XCALL rcall
+#endif
+
+#ifdef L_ctors
+ .section .init6,"ax",@progbits
+ .global __do_global_ctors
+__do_global_ctors:
+ ldi r17, hi8(__ctors_start)
+ ldi r28, lo8(__ctors_end)
+ ldi r29, hi8(__ctors_end)
+ rjmp .do_global_ctors_start
+.do_global_ctors_loop:
+ sbiw r28, 2
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump__
+.do_global_ctors_start:
+ cpi r28, lo8(__ctors_start)
+ cpc r29, r17
+ brne .do_global_ctors_loop
+#endif /* L_ctors */
+
+#ifdef L_dtors
+ .section .fini6,"ax",@progbits
+ .global __do_global_dtors
+__do_global_dtors:
+ ldi r17, hi8(__dtors_end)
+ ldi r28, lo8(__dtors_start)
+ ldi r29, hi8(__dtors_start)
+ rjmp .do_global_dtors_start
+.do_global_dtors_loop:
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump__
+ adiw r28, 2
+.do_global_dtors_start:
+ cpi r28, lo8(__dtors_end)
+ cpc r29, r17
+ brne .do_global_dtors_loop
+#endif /* L_dtors */
+
_epilogue \
_exit \
_cleanup \
- _tablejump
+ _tablejump \
+ _copy_data \
+ _clear_bss \
+ _ctors \
+ _dtors
# We do not have the DF type.
# Most of the C functions in libgcc2 use almost all registers,