AVR-GCC 用 Main 覆盖中断向量 Table
AVR-GCC Overwrites Interrupt Vector Table with Main
我有一个为 ATmega168 编写的简单 C 程序:
#include "avr/io.h"
#include "avr/interrupt.h"
volatile uint8_t intrs;
int main(void){
TCCR1B |= _BV(CS12) | _BV(CS10); \ set clock source
TIMSDK1 |= _BV(TOIE1); \ Enable overflow interrupts
... // initialize timer and intrs
sei(); \ enable global interrupts
while(1){}
}
ISR(TIMER1_OVF_vect){
//do stuff
reti();
}
我的 CMakeLists:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib -Wall -Wextra")
set(TARGET_CPU ATmega168)
project(clion_avr_c_demo C)
include(CMakeVerifyCompiler.txt)
add_compile_definitions("__AVR_${TARGET_CPU}__")
add_link_options(-Wl,--print-memory-usage)
add_executable(${PROJECT_NAME} src/main.c)
当我编译它时(直接从命令行使用 avr-gcc 和在 CLion 中通过我的 CMakeLists 文件),编译器(link呃?)似乎正在覆盖中断向量 table 与我的主要功能。当我在 .elf 文件上使用 objdump 生成代码的反汇编时,我得到:
clion_avr_c_demo: file format elf32-avr
Disassembly of section .text:
00000000 <main>:
0: cf 93 push r28
2: df 93 push r29
4: cd b7 in r28, 0x3d ; 61
6: de b7 in r29, 0x3e ; 62
... ; clearly the disassembled main function
00000054 <__vector_13>:
54: 1f 92 push r1
56: 0f 92 push r0
... ; clearly the disassembled ISR
根据 ATmega168 的数据表,在没有中断的情况下这是完全可以的:
"If the program never enables an interrupt source, the Interrupt Vectors are not used, and regular program code can be placed at these locations."
但由于我有中断,我希望反汇编看起来像这样:
...
0x0000 jmp main ; RESET
...
0x001A jmp __vector_13 ; TIM1_OVF_vect
...
我的代码或编译中是否缺少某些东西导致编译器错误地认为我没有使用中断,或者我是否完全误解了我的反汇编输出?
编辑:使用 CMAKE_VERBOSE_MAKEFILE 进行构建,我得到以下构建和 link:
...\avr-gcc.exe -D__AVR_ATmega168__ -nostdlib -Wall -Wextra -g -o ...\main.c.obj -c ...\main.c
...\avr-gcc.exe -nostdlib -Wall -Wextra -g -Wl,--print-memory-usage .../main.c.obj -o clion_avr_c_demo
这正是 CMakeLists.txt 中定义的内容(即,没有额外的内容)。
我做了一些实验,得出了这个结论:
您没有获得矢量 table 因为您没有提供矢量。显然,选项 -nostdlib
排除了实现 table.
的那部分(库的?)
所以第一个错误是上述选项的使用。
但这还不够,因为链接器不知道 MCU,所以 table 使用哪个。 (或者要包括库的哪一部分。)
所以第二个错误是没有提供合适的选项-mmcu=atmega168
.
使用此链接器调用现在构建向量 table:
avr-gcc -mmcu=atmega168 -Wall -Wextra -g main.c.obj -o clion_avr_c_demo
备注:
- 我没有尝试如何提供自己的向量table。这绝对有效。
- 通过使用上述选项,您还排除了启动代码。此启动代码是标准做出的承诺,例如清除包含显式或隐式初始化为零的静态变量的 BSS。也请注意数据部分。
- 我没有尝试如何提供自己的启动代码。这绝对有效。
- 如果您想避免使用标准库的函数,请不要使用它们。如果你想确定 none 是否被链接,让链接器生成一个交叉引用并检查它。
我有一个为 ATmega168 编写的简单 C 程序:
#include "avr/io.h"
#include "avr/interrupt.h"
volatile uint8_t intrs;
int main(void){
TCCR1B |= _BV(CS12) | _BV(CS10); \ set clock source
TIMSDK1 |= _BV(TOIE1); \ Enable overflow interrupts
... // initialize timer and intrs
sei(); \ enable global interrupts
while(1){}
}
ISR(TIMER1_OVF_vect){
//do stuff
reti();
}
我的 CMakeLists:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib -Wall -Wextra")
set(TARGET_CPU ATmega168)
project(clion_avr_c_demo C)
include(CMakeVerifyCompiler.txt)
add_compile_definitions("__AVR_${TARGET_CPU}__")
add_link_options(-Wl,--print-memory-usage)
add_executable(${PROJECT_NAME} src/main.c)
当我编译它时(直接从命令行使用 avr-gcc 和在 CLion 中通过我的 CMakeLists 文件),编译器(link呃?)似乎正在覆盖中断向量 table 与我的主要功能。当我在 .elf 文件上使用 objdump 生成代码的反汇编时,我得到:
clion_avr_c_demo: file format elf32-avr
Disassembly of section .text:
00000000 <main>:
0: cf 93 push r28
2: df 93 push r29
4: cd b7 in r28, 0x3d ; 61
6: de b7 in r29, 0x3e ; 62
... ; clearly the disassembled main function
00000054 <__vector_13>:
54: 1f 92 push r1
56: 0f 92 push r0
... ; clearly the disassembled ISR
根据 ATmega168 的数据表,在没有中断的情况下这是完全可以的:
"If the program never enables an interrupt source, the Interrupt Vectors are not used, and regular program code can be placed at these locations."
但由于我有中断,我希望反汇编看起来像这样:
...
0x0000 jmp main ; RESET
...
0x001A jmp __vector_13 ; TIM1_OVF_vect
...
我的代码或编译中是否缺少某些东西导致编译器错误地认为我没有使用中断,或者我是否完全误解了我的反汇编输出?
编辑:使用 CMAKE_VERBOSE_MAKEFILE 进行构建,我得到以下构建和 link:
...\avr-gcc.exe -D__AVR_ATmega168__ -nostdlib -Wall -Wextra -g -o ...\main.c.obj -c ...\main.c
...\avr-gcc.exe -nostdlib -Wall -Wextra -g -Wl,--print-memory-usage .../main.c.obj -o clion_avr_c_demo
这正是 CMakeLists.txt 中定义的内容(即,没有额外的内容)。
我做了一些实验,得出了这个结论:
您没有获得矢量 table 因为您没有提供矢量。显然,选项 -nostdlib
排除了实现 table.
所以第一个错误是上述选项的使用。
但这还不够,因为链接器不知道 MCU,所以 table 使用哪个。 (或者要包括库的哪一部分。)
所以第二个错误是没有提供合适的选项-mmcu=atmega168
.
使用此链接器调用现在构建向量 table:
avr-gcc -mmcu=atmega168 -Wall -Wextra -g main.c.obj -o clion_avr_c_demo
备注:
- 我没有尝试如何提供自己的向量table。这绝对有效。
- 通过使用上述选项,您还排除了启动代码。此启动代码是标准做出的承诺,例如清除包含显式或隐式初始化为零的静态变量的 BSS。也请注意数据部分。
- 我没有尝试如何提供自己的启动代码。这绝对有效。
- 如果您想避免使用标准库的函数,请不要使用它们。如果你想确定 none 是否被链接,让链接器生成一个交叉引用并检查它。