我目前在Atmel Studio中为Atmega328P(Arduino UNO)制作Bootloader,从反汇编中找到了以下代码(我的Bootloader从0x3800开始):
--- ../../../../crt1/gcrt1.S ---------------------------------------------------
00003800 JMP 0x00003834 Jump
00003802 JMP 0x00003979 Jump
00003804 JMP 0x00003979 Jump
00003806 JMP 0x00003979 Jump
00003808 JMP 0x00003979 Jump
0000380A JMP 0x00003979 Jump
0000380C JMP 0x00003979 Jump
0000380E JMP 0x00003979 Jump
--- ../../../../crt1/gcrt1.S ---------------------------------------------------
00003810 JMP 0x00003979 Jump
00003812 JMP 0x00003979 Jump
00003814 JMP 0x00003979 Jump
00003816 JMP 0x00003979 Jump
00003818 JMP 0x00003979 Jump
0000381A JMP 0x00003979 Jump
0000381C JMP 0x00003979 Jump
0000381E JMP 0x00003979 Jump
00003820 JMP 0x00003979 Jump
00003822 JMP 0x00003979 Jump
00003824 JMP 0x00003979 Jump
00003826 JMP 0x00003979 Jump
00003828 JMP 0x00003979 Jump
0000382A JMP 0x00003979 Jump
0000382C JMP 0x00003979 Jump
0000382E JMP 0x00003979 Jump
00003830 JMP 0x00003979 Jump
00003832 JMP 0x00003979 Jump
--- C:\Users\andy\Documents\Atmel Studio\7.0\CannyFlashy\CannyFlashy\CannyFlashy\Debug/.././Sketch.cpp
int main(){
00003834 IN R28,0x3D In from I/O location
为什么GCC会生成这样的代码,总之有避免它们的方法?
这是什么
如注释中提到的Javier Silva Ortíz,它是放在程序存储器最开始的中断表。
第一条指令是RESET向量,我们可以看到它指向的地址。换句话说,复位后,MCU会先执行第一条JMP 0x00003834
指令,然后精确地移至程序的开头。
顺便说一下,看看其他JMP
指令:它们全部都指向相同的地址,即所谓的__bad_interrupt()
,唯一的指令RETI
放置在该地址中。如果这些中断之一意外命中(并且您的程序不知道如何处理此中断),则单条RETI
指令会立即完成此中断的处理,程序将返回到正常执行状态。
避免它
如果您绝对确定Bootloader中没有可能的中断命中,则可以避免中断表,将CFLAGS = -nostartfiles
标志传递给编译器。
请小心!
其他一些东西将被-nostartfiles
标志破坏!
问题是avr-gcc在编译程序的开始就产生了一些魔力。编译器在中断表之后放置一些常用操作。这些操作由__ctors_end
,__do_copy_data
,__do_clear_bss
等部分划分。他们需要什么?
首先,在r1
部分中,__ctors_end
寄存器被设置为零。为什么这么重要?每次编译器将其他寄存器与零进行比较时,默认情况下都使用r1
。是的,avr-gcc知道此“魔术” r1
并且不会写入,但在某些情况下,当它更改时(例如,乘法结果放在r0:r1寄存器对中),并且每次更改时,avr-gcc都会将其无效。如果在启动过程中未将r1
设置为零,则一切都会出错...
在程序开始时做的另一件事是将零变量设置为零。它是在__do_clear_bss
部分完成的。试想一下,您期望某物为零,但事实并非如此。有什么后果?
另一个重要操作是将数据从程序存储器复制到SRAM。它在__do_copy_data
部分完成。关闭__do_copy_data
会破坏所有静态数组。
AND?..
[使用-nostartfiles
优化中断表时应格外小心。仅在您200%确定发生了什么情况时,才执行此操作。