title: Global variables between C and C++
body: <p>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.</p>
  
  <p>test.h:</p>
  
  <pre><code>#ifndef TEST_H_
  #define TEST_H_
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  extern const char* strings[];
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* TEST_H_ */
  </code></pre>
  
  <p>test.c:</p>
  
  <pre><code>#include &lt;test.h&gt;
  const char* strings[] = {"string a", "string b", "string c" };
  </code></pre>
  
  <p>main.hpp</p>
  
  <pre><code>#ifndef MAIN_HPP_
  #define MAIN_HPP_
  
  #define STM32F4
  
  #include &lt;test.h&gt;
  #include &lt;libopencm3/stm32/rcc.h&gt;
  #include &lt;libopencm3/stm32/gpio.h&gt;
  
  #endif /* MAIN_HPP_ */
  </code></pre>
  
  <p>main.cpp:</p>
  
  <pre><code>#include &lt;main.hpp&gt;
  
  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 &lt; 3; i++) {
              for (int j = 0; j &lt; 9; j++) {
                  s2[i][j] = strings[i][j];
                  if (s2[i][j] == 'i') {
                      gpio_toggle(GPIOD, GPIO12);
                  }
  
                  for (int k = 0; k &lt; 1000000; k++) {
                      __asm__("nop");
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>However, when I run it in the debugger I can see that the memory where strings[0] (for example) is pointing is completely zeroed.</p>
  
  <p>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.</p>
  
  <p>So what am I doing wrong here?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>I'm working with Eclipse under Linux, gnu-arm-none-eabi.</p>
  
  <p>complier and linker command lines and output:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Linker scripts (not the cleanest one, I did some testing with it).</p>
  
  <pre><code>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
  </code></pre>
  
  <p>libopencm3_stm32f4.ld:</p>
  
  <pre><code>/* 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);
      } &gt;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 = .;
      } &gt;rom
      .init_array : {
          . = ALIGN(4);
          __init_array_start = .;
          KEEP (*(SORT(.init_array.*)))
          KEEP (*(.init_array))
          __init_array_end = .;
      } &gt;rom
      .fini_array : {
          . = ALIGN(4);
          __fini_array_start = .;
          KEEP (*(.fini_array))
          KEEP (*(SORT(.fini_array.*)))
          __fini_array_end = .;
      } &gt;rom
  
      /*
       * Another section used by C++ stuff, appears when using newlib with
       * 64bit (long long) printf support
       */
      .ARM.extab : {
          *(.ARM.extab*)
      } &gt;rom
      .ARM.exidx : {
          __exidx_start = .;
          *(.ARM.exidx*)
          __exidx_end = .;
      } &gt;rom
  
      . = ALIGN(4);
      _etext = .;
  
      .data : {
          _data = .;
          *(.data*)   /* Read-write initialized data */
          . = ALIGN(4);
          _edata = .;
      } &gt;ram AT &gt;rom
      _data_loadaddr = LOADADDR(.data);
  
      .bss : {
          *(.bss*)    /* Read-write zero initialized data */
          *(COMMON)
          . = ALIGN(4);
          _ebss = .;
      } &gt;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));
  </code></pre>
  
  <p><strong>EDIT</strong></p>
  
  <p>I'm looking into the problem but I'm a bit puzzled.</p>
  
  <p>The startup code includes the following:</p>
  
  <pre><code>for (src = &amp;_data_loadaddr, dest = &amp;_data;
      dest &lt; &amp;_edata;
      src++, dest++) {
      *dest = *src;
  }
  </code></pre>
  
  <p>So it seems ok to me.</p>
  
  <p>The .map file gives the following infos:</p>
  
  <pre><code>.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
  </code></pre>
  
  <p>Now, when I run the debugger I see that right from the start &amp;_data==&amp;_edata==0x2000000c , and I notice also that _data is present two times in the .map file.</p>
  
  <p>So, is there an error in the linker script?</p>