我正在为ARM STM32F4开发一个混合的C/C++程序,但是我在访问C部分中定义的全局变量时遇到了问题.这是一个简单的测试代码来重现问题.
test.h:
#ifndef TEST_H_ #define TEST_H_ #ifdef __cplusplus extern "C" { #endif extern const char* strings[]; #ifdef __cplusplus } #endif #endif /* TEST_H_ */
test.c的:
#includeconst char* strings[] = {"string a", "string b", "string c" };
main.hpp
#ifndef MAIN_HPP_ #define MAIN_HPP_ #define STM32F4 #include#include #include #endif /* MAIN_HPP_ */
main.cpp中:
#includeint 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"); } } } } }
但是,当我在调试器中运行它时,我可以看到字符串[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文件中出现了两次.
那么,链接器脚本中是否有错误?
正如奥拉夫在评论中所说,你并没有将你的字符串表声明为常量.因此编译器/链接器将其视为初始化的读/写数据,而不是只读数据.
也许你的初始化代码(在主入口点之前执行)没有正确地将初始化数据从闪存复制到RAM.
作为快速修复,尝试使您的字符串表保持不变:
char const * const strings[] = {"string a", "string b", "string c" };
如果它工作,你可以调查内存初始化问题...看看-nostartfiles
给链接器的参数,这可能会禁用启动代码(待确认)...