xan*_*ndy 3 assembly avr avr-gcc
我目前正在Atmel Studio中为Atmega328P(Arduino UNO)开发一个引导加载程序,从反汇编中我发现了以下代码(我的引导加载程序从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
Run Code Online (Sandbox Code Playgroud)
为什么 GCC 会生成这样的代码?是否有办法避免它们?
它是什么
\n\n正如Javier Silva Ort\xc3\xadz在评论中提到的,它是一个放置在程序存储器最开头的中断表。
\n\n第一条指令是一个RESET向量,我们可以看到它指向的地址。换句话说,复位后,MCU 立即执行第一JMP 0x00003834条指令并准确移动到程序的开头。
顺便说一下,看看其他JMP指令:它们都指向同一个地址,即所谓的__bad_interrupt(),唯一的指令RETI就放置在那里。如果这些中断之一意外命中(并且您的程序不知道如何处理该中断),则单RETI条指令会立即完成该中断,并且程序将返回到正常执行。
避免它
\n\n如果您绝对确定引导加载程序中没有可能的中断命中,则可以避免中断表,将CFLAGS = -nostartfiles标志传递给编译器。
当心!
\n\n其他一些东西会被-nostartfilesflag破坏!
问题是 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会破坏所有静态阵列。
和?..
\n\n您应该非常小心地尝试使用-nostartfiles. 仅当您 200% 确定发生了什么时才执行此操作。