I think you highlight the problem for gcc.
We are have to treat program memory as byte addressable to support LPM.
Direct, function calls only want word address to form the correct
opcode. But we use byte address labels and assembler removes the
redundant bit to form the correct opcode.
Indirect (icall) functions show up the anomaly as these are formed
outside of the assembler.
Gcc is assuming that the item that a function pointer points to is
size 1. When in fact it is size 2.
This is similar as having pointer to some other object such as long:
long *ptr;
x = ptr+1; /* x will be assinged byte address potr+4 */
So if we can correct that mistake, I believe the problem is resolved.
Now, I am not sure how gcc determines that size! So I will look.
Andy
Wouter van Gulik wrote:
Compiling the following program ends up in "main.c:(.text+0x2):
warning: internal error: out of range error"
================= main.c ================
//Dummy func
void foo(void) {}
//Table with address manipulation
void (* const pFuncTable[]) (void) = {
foo + 0,
foo + 1, //need odd offset
}; int main(int argc, char* argv[]) {
//Call table
pFuncTable[1]();
return 1;
}
Looking into the generated assembler gives:
pFuncTable:
.word gs(foo)
.word foo+1
Which is wrong. It should have been gs(foo + 1) or perhaps gs(foo)+1
But the true wrong thing is that gcc out smarts the table (since it's
const)
and directly does: "call foo+1". This gives the internal error.
Even worse is that the compiler does not stop!! IMHO it should stop
here,
instead it generates this final assembly: 000000a6 <main>:
a6: 0e 94 00 00 call 0 ; 0x0 <__vectors>
aa: 81 e0 ldi r24, 0x01 ; 1
ac: 90 e0 ldi r25, 0x00 ; 0
ae: 08 95 ret
Before I post a note to the existing bug report (it's probably
related with
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27192 ) I want to know
what foo
+ 1 is supposed to do. GCC seems to mix up byte address (for lpm) and
word
addresses (for ijmp/jmp//icall/call).
Is it supposed to increment the byte address or the word address?
I guess byte addresses are what it's supposed to be, since calling
foo + 2
ends up in calling foo + 2 bytes. Leaving foo + 1 as illegal address.
And I just found another nasty error:
//Dummy func
void foo(void) {}
//Table with address manipulation
void (* const pFuncTable[]) (void) = {
foo + 4, //need odd offset
}; int main(int argc, char* argv[]) {
//Call table
pFuncTable[0]();
return 1;
}
This will generate a correct call (4 bytes after foo) but the value
in the
table is not left shifted! Meaning that a call via the table will
generate a
call to the wrong address, while the original call is ok.
Wouter
_______________________________________________
AVR-GCC-list mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
_______________________________________________
AVR-GCC-list mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list