我正在使用avr-gcc 4.8.2编程Atmel ATtiny13a微控制器.
这是我的c代码:
#include#include int main(void) { DDRB = 1; // PB0 is output for (uint8_t i = 0; i < 10; i++) { PORTB = 1; _delay_ms(500); PORTB = 0; _delay_ms(500); } while(1); } void test(void) { DDRB = 1; // PB0 is output for (uint8_t i = 0; i < 10; i++) { PORTB = 1; _delay_ms(100); PORTB = 0; _delay_ms(100); } }
从不通过主功能调用测试功能(LED快速闪烁),因此控制器只应进入主功能(慢速闪烁).
当我编译代码时-O1
,一切正常:
avr-gcc -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -mmcu=attiny13 -DF_CPU=1200000 -Wall -Wstrict-prototypes -Os -c test.c -o test.o avr-gcc test.o -o test.elf avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature test.elf test.hex
但是如果我使用-Os
(优化尺寸)或者-O2
,微控制器运行test
功能而不是main
功能:LED快速闪烁并且永不停止.
-Os
标志是否太危险而无法使用,是否应该避免?或者我的代码中是否可以更改某些内容以避免此类错误?ATtiny13a只有1K的闪光灯,因此尺寸减小很重要.
编辑:正如评论中所建议的,这里是汇编器差异-O1
和-O2
:http://www.diffchecker.com/3l9cdln6
在那里,您可以看到-O2
将第一部分更改.text
为.text.startup
.
--- test.o1.txt 2013-12-03 19:10:43.874598682 +0100 +++ test.o2.txt 2013-12-03 19:10:50.574674155 +0100 @@ -3,7 +3,7 @@ __SREG__ = 0x3f __tmp_reg__ = 0 __zero_reg__ = 1 - .text + .section .text.startup,"ax",@progbits .global main .type main, @function main:
这可能是这里的主要问题.经过一些进一步的测试后,我发现罪魁祸首就是-freorder-functions
优化.有没有办法防止这种行为?
我做了一些进一步的调试,发现"罪魁祸首"是-freorder-functions
优化.它在联机帮助页中记录如下:
-freorder-functions Reorder functions in the object file in order to improve code locality. This is implemented by using special subsections ".text.hot" for most frequently executed functions and ".text.unlikely" for unlikely executed functions. Reordering is done by the linker so object file format must support named sections and linker must place them in a reasonable way.
文档中的最后一行解释了我遇到的问题.如果我们再次查看原始问题的编译命令:
$ avr-gcc -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct \ -fshort-enums -mmcu=attiny13 -DF_CPU=1200000 -Wall -Wstrict-prototypes \ -Os -c test.c -o test.o $ avr-gcc test.o -o test.elf
...我们看到我将优化标志传递给编译器,但没有传递给链接器.我假设CFLAGS
唯一影响编译而不是链接,所以我没有将它们传递给链接器,但在那种情况下我错了.
结果:汇编代码由编译器重新排序(包括适当的标签),但链接器不考虑这些标签.并且因为函数由编译器test
放在函数之前main
而不是由链接器重新排列,这就是在微控制器上实际执行的代码.
所以解决方案结果是:编译器标志也应该传递给链接器!