bug with relaxation on mega2560

hi,
i discovered a bug with mega2560 and ide 1.0.3 (ubuntu 12.10)
compiling a program with a size of ~33kb and adding Serial.x stuff makes the linker throw the following error:

/home/--/arduino-1.0/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/lib/avr6/crtm2560.o: In function __bad_interrupt': ../../../../crt1/gcrt1.S:193: relocation truncated to fit: R_AVR_13_PCREL against symbol __vector_46' defined in .text section in /home/--/arduino-1.0/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/lib/avr6/crtm2560.o

removing the --relax linker option fixes that (beginning at line 193 in Compiler.java).

furthermore i dont know why exactly relaxation is enabled on mega2560?
from the avr-gcc description:

Enables linker relaxations. By default, the linker links functions will a full CALL statement,
which is wasteful if two functions are near each other.
Relaxations will do more in the future, but currently (AFAIK) just replace CALL
statements with RCALL where possible to save a few bytes.

but afaik rcall can only jump to regions +-4kib away! the mega2560 has 256kib flash,
im in doubt about the compiler can optimize every call to rcall to within +-4kib limit.
am i overlooking something?

side hint: hard coding such exception seems not the right solution to me (i searched and grepped a long bit).

Is this the same issue?

seems so.
i attached a patched version (current git version) of the ide without the --relax parameter at linker stage.
(just copy to /lib path inside the arduino directory)

pde.jar (781 KB)

Here's a link to the issue for which we included the relax compiler argument: Google Code Archive - Long-term storage for Google Code Project Hosting.

If the interrupt functions can only be a certain distance from 0, then a way to solve the problem and still use the linker relax, is to create a new section that the linker puts into memory before the normal text section and put the interrupt code into that section, so the linker has a better chance of using the appropriate jump. Looking at the binutils source (probably a few months old), the avr port has several special sections:

  • .progmem.gcc* and .progmem for code that must be in the lower 64k of progmem
  • .lowtext* for code that must be in the lower 128k of progmem

A quick glance in the 4.7 sources doesn't seem to have a function attribute to put a function into the .progmem or .lowtext sections, but you could use the section attribute to hardwire the function.

I have just hit this problem in my project - taken up my last two nights. I've tried compiling with 1.0.2, 1.0.4, 1.0.5, 1.5.3 - all give the same R_AVR_13_PCREL error.

Additionally, if I change the Avr target to anything other than 2560 then it compiles successfully - which is very interesting (I'm guessing that's because the 2560 interrupt table is larger). My Sketch code is only around 28KB in size with just over 4K PROGMEM.

In addition to the work around of adding more PROGMEM, I found another simple workaround. If you explicitly define a dummy interrupt handler for the one that the linker chokes on, then the linker won't try to put an rjmp in the interrupt table.

So for instance the OP's error you would add the following to one of your cpp files.

extern "C" {

void __vector_46() {    
  // emulate __bad_interrupt (jump to 0)
  void(* resetFunc) (void) = 0; //declare reset function @ address 0
  resetFunc(); 
}

}

and it links. [If you just add extern "C" { void __vector_46() { } } this also works.]

Using objdump to look at the <__vectors> table I see that the vector which fails is exactly 0x1004 below the address of __bad_interrupt (where 0x1000 is the limit of an rjmp instruction). All the interrupt vectors below (in address value) the one which fails use jmp and all the ones above use rjmp (but are within 0x1000 of the __bad_interrupt function.

This bug has been known about for ages - I have no idea why they can't patch it.

There's another good article here: arduino - AVR linker error, "relocation truncated to fit" - Stack Overflow

Also a trap for young players: if you are adding more PROGMEM to workaround it the other way, then you need to actually read the PROGMEM pad variable otherwise the linker doesn't include it (i.e., will have no effect).

May I suggest:

The way I get around the whole issue is to just use make.
Yes that isn't for everybody, but, things always compile for everybody who use my code. XD

removing the --relax linker option fixes that (beginning at line 193 in Compiler.java).

This solved also my problem.
But why also the current nightly build of the Arduino IDE have this bug?

buildrob solution is working for me too....

I tried removing the relax option and while it did allow my large program to compile, this problem has arisen:

int foo = 300;
String s = String(foo, DEC);

That used to compile, but now it fails with,

error: call of overloaded 'String(uint16_t&, int)' is ambiguous

DEC is defined in Print.h in the Arduino 1.0.5 source code here,

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2

if we change the (new) problem code to this, casting the DEC to an unsigned char, all is well, but that's a pain. Is there another simple way to fix this without defining typed consts to replace the defines? I wonder what else won't work with --relax removed...

int foo = 300;
String s = String(foo, (unsigned char)DEC);

Update, I have a larger complex program and it may not cover all the things that might also not work but changing the defines of DEC, HEX... to typed constants seems to let things compile normally:

This is in Print.h in the Arduino IDE 1.0.5 source code. On OS X this is located here in the root (of the source code),

/hardware/arduino/cores/arduino/Print.h on line 29...32

// #define DEC 10
// #define HEX 16
// #define OCT 8
// #define BIN 2
const uint8_t DEC = 10;
const uint8_t HEX = 16;
const uint8_t OCT = 8;
const uint8_t BIN = 2;