7

我正在为 ARM STM32F4 开发混合 C/C++ 程序,但在访问 C 部分中定义的全局变量时遇到问题。这是一个重现问题的简单测试代码。

测试.h:

#ifndef TEST_H_
#define TEST_H_

#ifdef __cplusplus
extern "C" {
#endif

extern const char* strings[];

#ifdef __cplusplus
}
#endif

#endif /* TEST_H_ */

测试.c:

#include <test.h>
const char* strings[] = {"string a", "string b", "string c" };

主文件

#ifndef MAIN_HPP_
#define MAIN_HPP_

#define STM32F4

#include <test.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>

#endif /* MAIN_HPP_ */

主.cpp:

#include <main.hpp>

int main(void)
{
    char s2[3][9];

    rcc_periph_clock_enable(RCC_GPIOD);
    gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
    GPIO12);

    while (1) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 9; j++) {
                s2[i][j] = strings[i][j];
                if (s2[i][j] == 'i') {
                    gpio_toggle(GPIOD, GPIO12);
                }

                for (int k = 0; k < 1000000; k++) {
                    __asm__("nop");
                }
            }
        }
    }
}

但是,当我在调试器中运行它时,我可以看到 strings[0](例如)指向的内存完全归零。

注意:while 循环中的部分不相关,我只是添加它以获得一些反馈并避免编译器剥离未使用的字符串值。

那么我在这里做错了什么?

编辑

我在 Linux 下使用 Eclipse,gnu-arm-none-eabi。

编译器和链接器命令行和输出:

arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal  -g3 -I"/home/andrea/ownCloud/src/arm/libopencm3/include" -I"/home/andrea/ownCloud/src/arm/testt/src" -std=gnu++11 -fabi-version=0 -fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics -Wabi -Wctor-dtor-privacy -Wnoexcept -Wnon-virtual-dtor -Wstrict-null-sentinel -Wsign-promo -MMD -MP -MF"src/main.d" -MT"src/main.o" -c -o "src/main.o" "../src/main.cpp"
In file included from /home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/rcc.h:32:0,
                 from /home/andrea/ownCloud/src/arm/testt/src/main.hpp:14,
                 from ../src/main.cpp:20:
/home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/f4/rcc.h:640:11: warning: padding struct to align 'rcc_clock_scale::plln' [-Wpadded]
  uint16_t plln;
           ^
/home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/f4/rcc.h:644:11: warning: padding struct to align 'rcc_clock_scale::flash_config' [-Wpadded]
  uint32_t flash_config;
           ^
Finished building: ../src/main.cpp

Building file: ../src/test.c
Invoking: Cross ARM C Compiler
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal  -g3 -I"/home/andrea/ownCloud/src/arm/libopencm3/include" -I"/home/andrea/ownCloud/src/arm/testt/src" -std=gnu11 -Wmissing-prototypes -Wstrict-prototypes -Wbad-function-cast -MMD -MP -MF"src/test.d" -MT"src/test.o" -c -o "src/test.o" "../src/test.c"
Finished building: ../src/test.c

Building target: testt.elf
Invoking: Cross ARM C++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal  -g3 -T "/home/andrea/ownCloud/src/arm/testt/src/stm32f407g-discovery.ld" -T "/home/andrea/ownCloud/src/arm/testt/src/libopencm3_stm32f4.ld" -nostartfiles -Xlinker --gc-sections -L"/home/andrea/ownCloud/src/arm/libopencm3/lib" -Wl,-Map,"testt.map" --specs=nano.specs -o "testt.elf"  ./src/main.o ./src/test.o   -lopencm3_stm32f4
Finished building target: testt.elf

链接器脚本(不是最干净的,我用它做了一些测试)。

MEMORY
{
    rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}

_stack_size = 0x400;
/* Include the common ld script. */
INCLUDE libopencm3_stm32f4.ld

libopencm3_stm32f4.ld:

/* Enforce emmition of the vector table. */
EXTERN (vector_table)

/* Define the entry point of the output file. */
ENTRY(reset_handler)

/* Define sections. */
SECTIONS
{
    .text : {
        *(.vectors) /* Vector table */
        *(.text*)   /* Program code */
        . = ALIGN(4);
        *(.rodata*) /* Read-only data */
        . = ALIGN(4);
    } >rom

    /* C++ Static constructors/destructors, also used for __attribute__
     * ((constructor)) and the likes */
    .preinit_array : {
        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;
    } >rom
    .init_array : {
        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        __init_array_end = .;
    } >rom
    .fini_array : {
        . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;
    } >rom

    /*
     * Another section used by C++ stuff, appears when using newlib with
     * 64bit (long long) printf support
     */
    .ARM.extab : {
        *(.ARM.extab*)
    } >rom
    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
    } >rom

    . = ALIGN(4);
    _etext = .;

    .data : {
        _data = .;
        *(.data*)   /* Read-write initialized data */
        . = ALIGN(4);
        _edata = .;
    } >ram AT >rom
    _data_loadaddr = LOADADDR(.data);

    .bss : {
        *(.bss*)    /* Read-write zero initialized data */
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } >ram
    . = ALIGN(4);

    _end_bss = .;
    end = .;
    _end = .;
    _heap_bottom = .;
    _heap_top = ORIGIN(ram)+LENGTH(ram)-_stack_size;

    _stack_bottom =_heap_top;
    _stack_top = ORIGIN(ram) + LENGTH(ram);
    /*
     * The .eh_frame section appears to be used for C++ exception handling.
     * You may need to fix this if you're using C++.
     */
    /DISCARD/ : { *(.eh_frame) }
}

PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

编辑

我正在研究这个问题,但我有点困惑。

启动代码包括以下内容:

for (src = &_data_loadaddr, dest = &_data;
    dest < &_edata;
    src++, dest++) {
    *dest = *src;
}

所以对我来说似乎没问题。

.map 文件提供以下信息:

.data           0x0000000020000000        0xc load address 0x000000000800038c
                0x0000000020000000                _data = .
 *(.data*)
 .data.strings  0x0000000020000000        0xc ./src/test.o
                0x0000000020000000                strings
                0x000000002000000c                . = ALIGN (0x4)
                0x000000002000000c                _edata = .
                0x000000002000000c                _data = .
 *(.data*)
                0x000000002000000c                . = ALIGN (0x4)
                0x000000002000000c                _edata = .
                0x000000000800038c                _data_loadaddr = LOADADDR (.data)

.igot.plt       0x000000002000000c        0x0 load address 0x0000000008000398

现在,当我运行调试器时,我从一开始就看到了 &_data==&_edata==0x2000000c ,而且我还注意到 _data 在 .map 文件中出现了两次。

那么,链接描述文件中是否有错误?

4

2 回答 2

5

正如奥拉夫在评论中所说,您没有将字符串表声明为常量。因此编译器/链接器将其视为初始化的读/写数据,而不是只读数据。

也许您的初始化代码(在主入口点之前执行)没有正确地将初始化数据从闪存复制到 RAM。

作为快速修复,请尝试使您的字符串表保持不变:

char const * const strings[] = {"string a", "string b", "string c" };

如果它有效,那么您可以调查内存初始化问题...查看-nostartfiles提供给链接器的参数,这可能会禁用启动代码(待确认)...

于 2017-01-24T13:15:54.163 回答
0

问题最终出在 Eclipse 中的项目配置上:我将两个 .ld 文件都指定为要包含的脚本,但第一个文件已经有第二个文件的包含指令;这导致了双 _data 规范和启动代码的错误行为。

于 2017-01-25T17:28:54.277 回答