Щаз я Вам все объясню

Дело в том что у WinAVR есть такая бага/фича (бага с точки зрения стандарта)
что переход по ((void(*)(void))0x0)(); может осуществляться НЕ на нулевой адрес.
Это зависит от того сколько флеша есть у контроллера.
Если на проце >8Kb(4Кслов) , то такой вызов будет правильным call 0x0000 ,
если же на проце меньше или равно 8Kb то у проца просто нет инструкций
call/jmp а есть только rcall/rjmp те абсолютные адреса понимать он не может(на этапе компиляции),
поэтому для таких процов джамп будет не на 0 адрес.
Вот примеры одного и того же кода для mega16:
Код
int main(void)
{
8e: cf e5 ldi r28, 0x5F; 95
90: d4 e0 ldi r29, 0x04; 4
92: de bf out 0x3e, r29; 62
94: cd bf out 0x3d, r28; 61
((void(*)(void))0x0)();
96: 0e 94 00 00 call 0x0 <__vectors>
Прыгнули куда надо!
и для mega8:
Код
int main(void)
{
5c: cf e5 ldi r28, 0x5F; 95
5e: d4 e0 ldi r29, 0x04; 4
60: de bf out 0x3e, r29; 62
62: cd bf out 0x3d, r28; 61
((void(*)(void))0x0)();
64: fb df rcall .-10 ; 0x5c <main>
Не знали куда надо прыгать, поэтому прыгнули на main!
А теперь добавляем функцию на мега8:
Код
void softreset()
{
((void(*)(void))0x0)();
5c: ff df rcall .-2 ; 0x5c <softreset>
5e: 08 95 ret
00000060 <main>:
}
int main(void)
{
60: cf e5 ldi r28, 0x5F; 95
62: d4 e0 ldi r29, 0x04; 4
64: de bf out 0x3e, r29; 62
66: cd bf out 0x3d, r28; 61
softreset();
68: f9 df rcall .-14 ; 0x5c <softreset>
ОБА-НА, прыжок то на адрес начала функции(интересно что будет
когда стек налезет на на регистры

)
Почему разработчики WinAVR не сделали вполне валидный в этом случае icall для меня
загадка, наверное регистры r31:r30 решили сэкономить

итого для чипов с <=8Kb лучше так:
Код
__asm__ __volatile__("ldi r30,0\n\t"\
"ldi r31,0\n\t"\
"ijmp");