Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global variables between C and C++

I'm developing a mixed C/C++ program for an ARM STM32F4, but I have problems in accessing global variables defined in the C part. Here is a simple test code to reproduce the problem.

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

However, when I run it in the debugger I can see that the memory where strings[0] (for example) is pointing is completely zeroed.

Note: the part in the while loop is not relevant, I've just added it to have some feedback and to avoid that the compiler strips the unused values of strings.

So what am I doing wrong here?

EDIT

I'm working with Eclipse under Linux, gnu-arm-none-eabi.

complier and linker command lines and output:

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

Linker scripts (not the cleanest one, I did some testing with it).

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

EDIT

I'm looking into the problem but I'm a bit puzzled.

The startup code includes the following:

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

So it seems ok to me.

The .map file gives the following infos:

.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

Now, when I run the debugger I see that right from the start &_data==&_edata==0x2000000c , and I notice also that _data is present two times in the .map file.

So, is there an error in the linker script?

like image 336
apalazzi Avatar asked Jan 24 '17 12:01

apalazzi


1 Answers

As Olaf said in a comment, you did not declare your string table as constant. So it is considered by the compiler/linker as initialized read/write data, instead of read only data.

Maybe your initialization code (executed before the main entry point) does not properly copy the initialized data from flash to RAM.

As a quick fix, try to make your string table as constant:

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

If it works, you could then investigate memory initialization issues... Have a look to the -nostartfiles argument given to the linker, which may probably disable the startup code (to be confirmed)...

like image 116
greydet Avatar answered Sep 28 '22 04:09

greydet