简体   繁体   English

memory开头分配的成员变量

[英]Member variable allocated at start of memory

I'm trying to use c++ on an STM32 device compiling with gcc. The device loads the code and start executing it but hard faults on any member variable write.我正在尝试在使用 gcc 编译的 STM32 设备上使用 c++。该设备加载代码并开始执行它,但在写入任何成员变量时出现硬故障。

I can see with GDB that member variables are stored at beginnning of memory (0x7 to be specific), of course the STM32 hard faults at the first write of that location.我可以看到 GDB 成员变量存储在 memory 的开头(具体为 0x7),当然 STM32 硬故障在第一次写入该位置时出现。

I can see that BSS section is not generated unless i declare a variable in main (used readelf on the final elf file).我可以看到,除非我在 main 中声明一个变量(在最终的 elf 文件中使用 readelf),否则不会生成 BSS 部分。

Shouldnt be member variables be placed in bss?成员变量不应该放在bss里吗?

I'm compiling and linking with -nostdlib -mcpu=cortex-m0plus -fno-exceptions -O0 -g .我正在使用-nostdlib -mcpu=cortex-m0plus -fno-exceptions -O0 -g编译和链接。

The linker script is: linker 脚本是:


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

}

The output of readelf (no variables declaration, only object usage): readelf的output(没有声明变量,只有object的用法):

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 platform probably does not use any variables): Main(初始化平台可能不使用任何变量):

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;
    
}

Update #1:更新#1:

The vector table is at beginning of memory, sp and msp are initialized successfully.向量表在memory开头,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

Putting a breakpoint on a constructor for the GPIO class, i can see variables are at 0x00000XXX在 GPIO class 的构造函数上放置断点,我可以看到变量位于 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

I tried to make mypin a public member variable (was private), did not make any change.我试图让 mypin 成为一个公共成员变量(是私有的),没有做任何改变。

Starting to think that dynamic allocation is needed with C++.开始认为C++需要动态分配。

Address 0x7 is in the initial vector table in ROM, it is not writeable.地址0x7在 ROM 的初始向量表中,不可写。

Unfortunately you don't have a section to populate the vector table, so this code is never going to work.不幸的是,您没有用于填充向量表的部分,因此此代码永远不会起作用。 You also don't appear to have a stack, which is where the members of gpio would be placed (because it is defined inside a function without the static keyword).您似乎也没有堆栈,这是放置gpio成员的地方(因为它是在 function 中定义的,没有 static 关键字)。

Start by taking the linker script provided as part of the STM32Cube package and then (if you must) modify it a little bit at a time until you break it.首先采用作为 STM32Cube package 的一部分提供的 linker 脚本,然后(如果必须的话)一次稍微修改它,直到你破坏它。 Then you will know what you have broken.然后你就会知道你弄坏了什么。 It is not reasonable to write such a naïve linker script as this and expect it to work on a microcontroller.编写这样一个天真的 linker 脚本并期望它在微控制器上运行是不合理的。

of course the STM32 hard faults at the first write of that location.当然,STM32 在第一次写入该位置时会出现硬故障。

STM32 does not "fault" if you try to write FLASH. It will simple have no effect.如果您尝试写入 FLASH,STM32 不会“出错”。它不会产生任何影响。

You need to have a vector table in at the beginning of the FLASH memory. It has to contain as a minimum valid stack pointer address and the firmware entry point.您需要在 FLASH memory 的开头有一个向量表。它必须包含最小有效堆栈指针地址和固件入口点。

Your linker script and the code (I understand you do not use any STM supplied startup code) is far from being sufficient.您的 linker 脚本和代码(我知道您不使用任何 STM 提供的启动代码)远远不够。

My advice:我的建议:

  1. Create the project using STM32Cube.使用 STM32Cube 创建项目。
  2. Then see how it should be done然后看看应该怎么做
  3. Having this knowledge you can start to reinvent the wheel有了这些知识,你就可以开始重新发明轮子了

The actual issue was not in the linker script, in the startup code or in gcc, was in the way i was launching the program with GDB.实际问题不在 linker 脚本中,在启动代码中或在 gcc 中,而是在我使用 GDB 启动程序的方式中。

I was launching GDB by a batch file我正在通过批处理文件启动 GDB

toolchain\bin\arm-none-eabi-gdb.exe ^
    -ex "target remote 127.0.0.1:3333"  ^
    -ex "load"  ^
    -ex "b main" ^
    -ex "b unmanaged_isr_call"  ^
    -ex "b hard_fault_isr"  ^
    -ex "j main" binaries\main.elf

The issue was the last instruction, j main .问题是最后一条指令j main Changing the script to:将脚本更改为:

toolchain\bin\arm-none-eabi-gdb.exe ^
    -ex "target remote 127.0.0.1:3333"  ^
    -ex "load"  ^
    -ex "b unmanaged_isr_call"  ^
    -ex "b hard_fault_isr"  ^
    -ex "set $pc = &main" binaries\main.elf

Made it work.成功了。

I tried this new method of launching the program because i rewrote everything to C, and got the same issue on local variables.我尝试了这种启动程序的新方法,因为我将所有内容重写为 C,并且在局部变量上遇到了同样的问题。 I've also noticed a bit of offset between the first address i saw on launch (was main+OFF) and the main address in the vector table so i tries to remove the jump instruction from the gdb command line.我还注意到我在启动时看到的第一个地址(是 main+OFF)和向量表中的主地址之间有一点偏移,所以我试图从 gdb 命令行中删除跳转指令。 GDB was launching somewere ahead of the start of main, probably missing the POP for the local variables i defined in it. GDB 在 main 开始之前启动了一些,可能缺少我在其中定义的局部变量的 POP。 Doing the same made the issue dissapear in C++ too, the class is now working fine.这样做也使问题在 C++ 中消失,class 现在工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM