In gcc/config/avr/libgcc.S, revision 143306, a change to __do_global_ctors & __do_global_dtors was made which makes use of register r20. This register can be used to pass parameters to the constructors, but it is not pushed/popped from the stack, so it will get clobbered if a constructor uses that register. I have currently worked around it by pushing/popping r20 around the call to __tablejump__, but I am not convinced that this is the correct fix (the constructors should probably push & pop r20 themselves).
Created attachment 21460 [details] Test case showing that register r20 is clobbered when calling a constructor
Created attachment 21461 [details] Patch to gcc/config/avr/libgcc.S saving r20 onto the stack before calling constructors
*** Bug 44617 has been marked as a duplicate of this bug. ***
HelloWorld arduino sketch works now with atmega1280 & gcc-4.5.1. Thanks.
works for me with ATmega2560 (arduino mega) on Gentoo gcc-4.5.1
*** Bug 46706 has been marked as a duplicate of this bug. ***
Created attachment 22579 [details] alternative patch using register r15 instead of r20 avoids pushing/poping In reaction to bug 29141, which is still pending and not fixed, I offer a patch that corrects the handling of global constructors. The fix proposed in bug 29141 leads to wrong handling of global constructors since gcc version 4.4.0. And this is independent of the 64kB boundary because the handling is always wrong. With the first provided patch the register r20 was always pushed and popped but this is not necessary. The global-constructors patch avoids this and uses r15 instead of r20. Due to the compiler abi the register r15 is left unchanged by called routines, and it has to be saved/restored by routines that use it. I applied the global-constructor patch and then the compiler generates correct code for the execution of global constructors regardless of whether the constructor is located below or above 64kB. I tested the patch by my own but I think it needs further tests. Please try it out. I think without such a patch independent of using my one or the r20 patch, this bug is a show stopper since gcc version 4.4.0.
Comment on attachment 22579 [details] alternative patch using register r15 instead of r20 avoids pushing/poping >diff -Naur gcc-4.5.1-orig/gcc/config/avr/libgcc.S gcc-4.5.1/gcc/config/avr/libgcc.S >--- gcc-4.5.1-orig/gcc/config/avr/libgcc.S 2009-05-23 09:16:07.000000000 +0200 >+++ gcc-4.5.1/gcc/config/avr/libgcc.S 2010-11-30 14:35:53.000000000 +0100 >@@ -792,21 +792,22 @@ > __do_global_ctors: > ldi r17, hi8(__ctors_start) > ldi r16, hh8(__ctors_start) >- ldi r28, lo8(__ctors_end) >+ ldi r28, hh8(__ctors_end) >+ mov r15, r28 >+ ldi r28, lo8(__ctors_end) > ldi r29, hi8(__ctors_end) >- ldi r20, hh8(__ctors_end) > rjmp .L__do_global_ctors_start > .L__do_global_ctors_loop: > sbiw r28, 2 >- sbc r20, __zero_reg__ >+ sbc r15, __zero_reg__ > mov_h r31, r29 > mov_l r30, r28 >- out __RAMPZ__, r20 >+ out __RAMPZ__, r15 > XCALL __tablejump_elpm__ > .L__do_global_ctors_start: > cpi r28, lo8(__ctors_start) > cpc r29, r17 >- cpc r20, r16 >+ cpc r15, r16 > brne .L__do_global_ctors_loop > #else > __do_global_ctors: >@@ -833,21 +834,22 @@ > __do_global_dtors: > ldi r17, hi8(__dtors_end) > ldi r16, hh8(__dtors_end) >+ ldi r28, hh8(__dtors_start) >+ mov r15, r28 > ldi r28, lo8(__dtors_start) > ldi r29, hi8(__dtors_start) >- ldi r20, hh8(__dtors_start) > rjmp .L__do_global_dtors_start > .L__do_global_dtors_loop: > sbiw r28, 2 >- sbc r20, __zero_reg__ >+ sbc r15, __zero_reg__ > mov_h r31, r29 > mov_l r30, r28 >- out __RAMPZ__, r20 >+ out __RAMPZ__, r15 > XCALL __tablejump_elpm__ > .L__do_global_dtors_start: > cpi r28, lo8(__dtors_end) > cpc r29, r17 >- cpc r20, r16 >+ cpc r15, r16 > brne .L__do_global_dtors_loop > #else > __do_global_dtors:
This is essentially identical to the patch I provided for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44617 so it looks good to me. I had two worries: Is R15 used anywhere else in startup code that might not obey the register save conventions (ie does do_global_ctors need to preserve R15) The AVR has a lot of opcodes that are not valid on registers less than 16. It doesn't look like any of these are used here, but I wasn't 100% positive that using R15 wouldn't cause problems...
(In reply to comment #9) > Is R15 used anywhere else in startup code that might not obey the register save > conventions (ie does do_global_ctors need to preserve R15) I strongly suggest not using R15. The ATtiny10 Family of devices (ATtiny10/4/5/9/20/40) only has R16-R31. So using R15 won't work for this class of devices. It would be best if we can find a register that will for all AVR devices.
(In reply to comment #9) > This is essentially identical to the patch I provided for > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44617 > so it looks good to me. I hadn't see that patch but you are right it's almost identical. > I had two worries: > Is R15 used anywhere else in startup code that might not obey the register > save conventions (ie does do_global_ctors need to preserve R15) > The AVR has a lot of opcodes that are not valid on registers less than 16. It > doesn't look like any of these are used here, but I wasn't 100% positive that > using R15 wouldn't cause problems... As far as I know r15 isn't used elsewhere in the start-up code and also your second worry seems not to be a problem, because such instructions are not used by that time. (In reply to comment #10) > I strongly suggest not using R15. The ATtiny10 Family of devices > (ATtiny10/4/5/9/20/40) only has R16-R31. So using R15 won't work for this > class of devices. I disagree because the additional register is only in the start up code of devices that have rampz and is omitted in all other cases. The ATtiny don't have a rampz (correct me if I'm wrong) thus they are not faced with the discussed problem in general. IMO, it is absolutely possible and correct to use r15 here. > It would be best if we can find a register that will for all AVR > devices. Due to the compiler's C calling conventions, there are no other free registers to use without the need of pushing and popping this registers. Only registers below r16 are free to use. All other free r16,r17,r28,r29 are already in use.
Author: gjl Date: Wed Apr 13 16:36:50 2011 New Revision: 172384 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172384 Log: PR target/45263 * config/avr/libgcc.S (__do_global_ctors, __do_global_dtors): Save R20 around calls of __tablejump_elpm__ Modified: trunk/gcc/ChangeLog trunk/gcc/config/avr/libgcc.S
Author: gjl Date: Wed Apr 13 16:46:29 2011 New Revision: 172385 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172385 Log: Fix ChangeLog entry for PR target/45263 Modified: trunk/gcc/ChangeLog
Closed as resolved+fixed in 4.7.0
Author: gjl Date: Mon May 30 08:53:12 2011 New Revision: 174427 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=174427 Log: PR target/45263 * config/avr/libgcc.S (__do_global_ctors, __do_global_dtors): Don't use r20 around calls of __tablejump_elpm__ Modified: branches/gcc-4_6-branch/gcc/ChangeLog branches/gcc-4_6-branch/gcc/config/avr/libgcc.S
Author: gjl Date: Wed May 2 17:23:06 2012 New Revision: 187058 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=187058 Log: Backport from 2011-05-30 4.6-branch r174427. PR target/45263 * config/avr/libgcc.S (__do_global_ctors, __do_global_dtors): Don't use r20 around calls of __tablejump_elpm__ Modified: branches/gcc-4_5-branch/gcc/ChangeLog branches/gcc-4_5-branch/gcc/config/avr/libgcc.S
Backport to 4.5.4
*** Bug 60247 has been marked as a duplicate of this bug. ***