我尝试在STM32设备上使用c++,用gcc编译。设备加载代码并开始执行,但在任何成员变量写入时出现硬错误。
我可以看到GDB的成员变量存储在内存的开始(具体来说是0x7),当然STM32在第一次写入该位置时会出现硬错误。
我可以看到BSS部分不会生成,除非我在main中声明一个变量(在最终的elf文件中使用readelf)。
成员变量不应该放在bss中吗?
我正在编译和链接-nostdlib -mcpu=cortex-m0plus -fno-exceptions -O0 -g
。
链接器脚本为:
ENTRY(start_of_memory);
MEMORY {
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
}
SECTIONS {
.text : {
*(.text)
} > rom
.data : {
*(.data)
*(.data.*)
} > ram
.bss : {
*(.bss)
*(.bss.*)
*(COMMON)
} > ram
}
readelf的输出(没有变量声明,只有对象用法):
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x8000000
Start of program headers: 52 (bytes into file)
Start of section headers: 76536 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 14
Section header string table index: 13
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08000000 010000 0005a8 00 AX 0 0 4
[ 2] .rodata PROGBITS 080005a8 0105a8 00005c 00 A 0 0 4
[ 3] .ARM.attributes ARM_ATTRIBUTES 00000000 010604 00002d 00 0 0 1
[ 4] .comment PROGBITS 00000000 010631 000049 01 MS 0 0 1
[ 5] .debug_info PROGBITS 00000000 01067a 000a93 00 0 0 1
[ 6] .debug_abbrev PROGBITS 00000000 01110d 0003b8 00 0 0 1
[ 7] .debug_aranges PROGBITS 00000000 0114c5 000060 00 0 0 1
[ 8] .debug_line PROGBITS 00000000 011525 000580 00 0 0 1
[ 9] .debug_str PROGBITS 00000000 011aa5 000416 01 MS 0 0 1
[10] .debug_frame PROGBITS 00000000 011ebc 000228 00 0 0 4
[11] .symtab SYMTAB 00000000 0120e4 000640 10 12 86 4
[12] .strtab STRTAB 00000000 012724 000344 00 0 0 1
[13] .shstrtab STRTAB 00000000 012a68 00008f 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x08000000 0x08000000 0x00604 0x00604 R E 0x10000
Section to Segment mapping:
Segment Sections...
00 .text .rodata
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 100 entries:
main(init平台可能不使用任何变量):
int main(void) {
init_platform(SPEED_4_MHz);
gpio testpin(GPIO_A, 5);
testpin.dir(MODE_OUTPUT);
while (1) {
testpin.high();
wait();
testpin.low();
wait();
}
return 0;
}
- 更新#1:**
向量表位于内存开头,sp和msp初始化成功。
(gdb) p/x *0x00000000
$2 = 0x20000700
(gdb) p/x *0x00000004
$3 = 0x80000f1
(gdb) info registers
sp 0x20000700 0x20000700
lr 0xffffffff -1
pc 0x80000f6 0x80000f6 <main()+6>
xPSR 0xf1000000 -251658240
msp 0x20000700 0x20000700
psp 0xfffffffc 0xfffffffc
在GPIO类的构造函数上放置断点,我可以看到变量位于0x00000XXX
Breakpoint 2, gpio::gpio (this=0x7, port=0 '\000', pin=5 '\005') at gpio.cpp:25
25 mypin = pin;
(gdb) p/x &mypin
$6 = 0xb
我试图使mypin成为一个公共成员变量(是私有的),没有做任何改变。
开始认为C++* 需要 * 动态分配。
3条答案
按热度按时间whitzsjs1#
地址
0x7
位于ROM的初始向量表中,不可写入。不幸的是,你没有一个部分来填充向量表,所以这段代码永远不会工作,你也没有一个堆栈,这是
gpio
的成员将被放置的地方(因为它是在一个没有static关键字的函数中定义的)。首先获取作为STM32Cube包的一部分提供的链接器脚本,然后(如果必须的话)一次修改一点,直到您破坏它。然后您将知道您破坏了什么。编写这样一个幼稚的链接器脚本并期望它在微控制器上工作是不合理的。
vs3odd8k2#
当然,STM32在该位置的第一次写入时发生硬故障。
如果您尝试写入闪存,STM32不会"出错"。它将不会产生任何影响。
你需要在闪存的开始有一个向量表。它必须包含最小的有效的堆栈指针地址和固件入口点。
您的链接器脚本和代码(我知道您没有使用任何STM提供的启动代码)远远不够。
我的建议:
1.使用STM32Cube创建项目。
1.那就看看应该怎么做
1.有了这些知识,你就可以开始重新发明轮子了
uujelgoq3#
真正的问题不在链接器脚本、启动代码或gcc中,而是我用GDB启动程序的方式。
我是用批处理文件启动的
问题出在最后一条指令
j main
上。将脚本更改为:成功了。
我尝试了这种新的启动程序的方法,因为我把所有的东西都重写成了C,并且在局部变量上也遇到了同样的问题。我还注意到在启动时看到的第一个地址之间有一点偏移(was main+OFF)和向量表中的主地址,所以我尝试从gdb命令行中删除跳转指令。GDB在main开始之前启动了一些可能是缺少了我在其中定义的局部变量的POP。这样做也使这个问题在C++中消失了,这个类现在工作得很好。