我正在为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的:
#include <test.h>
const char* strings[] = {"string a", "string b", "string c" };
main.hpp
#ifndef MAIN_HPP_
#define MAIN_HPP_
#define STM32F4
#include <test.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#endif /* MAIN_HPP_ */
main.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");
}
}
}
}
}
但是,当我在调试器中运行它时,我可以看到字符串[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
现在,当我运行调试器时,我从一开始就看到了&amp; _data ==&amp; _edata == 0x2000000c,我还注意到_data在.map文件中出现了两次。
那么,链接描述文件中是否有错误?
答案 0 :(得分:5)
正如奥拉夫在评论中所说,你并没有将你的字符串表声明为常量。因此编译器/链接器将其视为初始化的读/写数据,而不是只读数据。
也许你的初始化代码(在主入口点之前执行)没有正确地将初始化数据从闪存复制到RAM。
作为快速解决方法,请尝试将字符串表设为常量:
char const * const strings[] = {"string a", "string b", "string c" };
如果它有效,你可以调查内存初始化问题...查看给链接器的-nostartfiles
参数,这可能会禁用启动代码(待确认)......
答案 1 :(得分:0)
问题最终在于Eclipse中的项目配置:我将.ld文件指定为要包含的脚本,但第一个已经有第二个文件的include指令;这导致了双_data规范和启动代码的错误行为。