Pregunta Variables globales entre C y C ++


Estoy desarrollando un programa mixto C / C ++ para un ARM STM32F4, pero tengo problemas para acceder a las variables globales definidas en la parte C. Aquí hay un código de prueba simple para reproducir el problema.

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

Sin embargo, cuando lo ejecuto en el depurador, puedo ver que la memoria a la que apuntan las cadenas [0] (por ejemplo) está completamente puesta a cero.

Nota: la parte del ciclo while no es relevante, solo la agregué para obtener algunos comentarios y para evitar que el compilador elimine los valores de las cadenas que no se usan.

Entonces, ¿qué estoy haciendo mal aquí?

EDITAR

Estoy trabajando con Eclipse en Linux, gnu-arm-none-eabi.

líneas de comando y salida de compilador y enlazador:

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

Scripts Linker (no el más limpio, hice algunas pruebas con él).

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

EDITAR

Estoy investigando el problema, pero estoy un poco desconcertado.

El código de inicio incluye lo siguiente:

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

Entonces me parece bien.

El archivo .map proporciona las siguientes informaciones:

.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

Ahora, cuando ejecuto el depurador lo veo desde el principio y _data == & _ edata == 0x2000000c, y también noto que _data está presente dos veces en el archivo .map.

Entonces, ¿hay un error en el script del enlazador?


7
2018-01-24 12:11


origen


Respuestas:


Como dijo Olaf en un comentario, no declaraste tu tabla de cadenas como constante. Por lo tanto, el compilador / vinculador lo considera datos de lectura / escritura inicializados, en lugar de datos de solo lectura.

Tal vez su código de inicialización (ejecutado antes del punto de entrada principal) no copie correctamente los datos inicializados de flash a RAM.

Como solución rápida, intente hacer que su tabla de cadenas sea constante:

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

Si funciona, podría investigar los problemas de inicialización de la memoria ... Eche un vistazo al -nostartfiles argumento dado al enlazador, que probablemente deshabilite el código de inicio (por confirmar) ...


5
2018-01-24 13:15



El problema finalmente fue con la configuración del proyecto en Eclipse: especifiqué ambos archivos .ld como scripts para ser incluidos, pero el primero ya tenía una directiva de inclusión para el segundo archivo; esto provocó la doble especificación _data y el comportamiento incorrecto del código de inicio.


0
2018-01-25 17:28