Relative jump to an address within PC - 2K +1 and PC + 2K (words). In the assembler, labels are used instead of relative operands. For AVR microcontrollers with program memory not exceeding 4K words (8K bytes) this instruction can address the entire memory from every address location.
This is expected. For the convenience of assembly language programmers, the rjmp operation takes an absolute address instead of a relative one. The absolute address will be converted to a relative one when it actually compiles the binary machine code, and you'll get an error if the address is too far away to jump to.
There seems to be a chronic problem where making some minor change to their code (like just changing the length of a string) then their code won't compile/upload. This is not an arduino bug but a problem with the linker.
For a quick fix, put this in your code in the global variable area before your setup() routine. You may have to try a few different array sizes, and for people running on Tiny machines, feel free to try small numbers like 50. In some cases, just 2 bytes will be enough to fix the problem.
Here's what's going on. The first 224 bytes of flash memory on a Mega2560 are the interrupt vector table. When an interrupt occurs (like a timer expires or there's a byte waiting in some receive buffer), this table tells the processor what code to execute. This example doesn't use many interrupts, so unused vectors get sent
to the routine bad_interrupt(). Here's a few lines from the vector table.
The use of both jmp and rjmp is an artifact of the -mrelax compiler flag. Amongst other things, it tells the compiler to use rjmp instructions when the destination is close enough (which is +/- 4k). Otherwise, the compiler should use jmp. This isn't a bad thing, rjmp instructions run 1 clock faster and use 2 bytes less data.
Without -mrelax, the compiler uses only jmp instructions in the vector table and the problem goes away. BTW, for our purposes, --relax is the same as -mrelax and is turned on by default on the larger processors.
The problem is that the linker is getting jammed up somehow. In the above example, when the bad_interrupt routine is located at address 0x1028, the vector should at address 0x24 should turn into a jmp but the linker can't do it for some reason. Instead, it leaves the instruction as a rjmp with a relative offset of +4098. As the allowed range is 4096, the offset would get truncated to +2, which is a serious error.
The reason why "pad[500] PROGMEM = 0 ;" should work is it will allocate a chunk of flash memory between the vector table and moves bad_interrupt() far enough away from the vector table that the linker isn't even tempted to use a rjmp instruction.
In searching the web, this appears to be a chronic problem with all sorts of solutions that sometimes work. Popular are using more/less PSTR("Hello World") constructs and various -lm -lc options. I suspect these things are just jiggling around subroutine addresses and by blind luck they fall in places that work.
The problem is that the linker is getting jammed up somehow. In the above example, when the bad_interrupt routine is located at address 0x1028, the vector at address 0x24 should turn into a jmp but the linker can't do it for some reason. Instead, it leaves the instruction as a rjmp with a relative offset of +4098. As the allowed range is 4096, the offset would get truncated to +2, which is a serious error.
With my Mega2560, when I finally tracked down what was going on, I removed 4 characters from a PSTR ("string") and the problem went away. I've been using the char pad[500] PROGMEM construct because I don't need the 500 bytes and with smaller values around 50, I still occasionally bump into the bug. When I do my final compile, I'll optimize a better value.
Agreed, a working linker is way better than a workaround. I've poked around for a few minutes, couldn't find a Linux version of the patch, I'd really like to try it on the little test program posted in this thread. Can someone out there do a quick test for me and share the results?
c80f0f1006