arm-none-eabi-g++ does not initialize class static members in code generated on debian

Bug #1556430 reported by Miroslav Scaldov
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
Confirmed
Undecided
Unassigned

Bug Description

code falls in hard fault if I compile it on debian with gcc-arm-none-eabi-5_2-2015q4
and runs as expected if compiled on ubuntu.

I investigated the case and found that when led_list.push_back(this) called in class led constructor, the led_list is UNINITIALIZED and
str r0, [r3, #0]
causes Hard Fault.

There differences of contexts of code compiled on ubuntu and debian:
function _ZNSt8__detail15_List_node_base7_M_hookEPS0_
ldr r3, [r1, #4]
stmia.w r0, {r1, r3}
ldr r3, [r1, #4]
str r0, [r3, #0]
str r0, [r1, #4]
bx lr

debian compiled regs and memory:
r0 0x200014e0
r1 0x20000a3c
r2 0x20000128
r3 0x1
r4 0x20000a3c
r5 0x20000a1c
0x20000a3c <_ZN2lk3led8led_listB5cxx11E>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x20000a44 <_ZN2lk3led8led_listB5cxx11E+8>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

ubuntu compiled regs and memory:
r0 0x200014e0
r1 0x20000a0c
r2 0x20000128
r3 0x1
r4 0x20000a0c
r5 0x20000a28
0x20000a0c <_ZN2lk3led8led_listB5cxx11E>: 0x0c 0x0a 0x00 0x20 0x0c 0x0a 0x00 0x20
0x20000a14 <_ZN2lk3led8led_listB5cxx11E+8>: 0x00 0x00 0x00 0x00 0x80 0x14 0x00 0x20

It is obvious that static std::list<led*> led_list is UNINITIALIZED on debian compiled code.

cpu is STM32F103C8T6

..............main.cc..................

lk::led led0(lk::gpio_c, 13);

..............led.hh..................

namespace lk {

class led : public pin{
 int index, cnt, state;
 static std::list<led*> led_list;
public:
 enum PATTERN {
  PTRN_HEARTBEAT = 0x23050505,
  PTRN_BLINK = 0x1919,
  PTRN_ALARM = 0x0703
 };
 uint32_t pattern;
 int scale;
 led(gpio *port, int pin_num)
 :pin::pin(port, pin_num, 1)
 {
  reset();
  printf("led\n");
  this->pattern = PTRN_HEARTBEAT;
  scale = 1;
  led_list.push_back(this);
 }

..............led.cc..................

namespace lk {
std::list<led*> led::led_list;
}

Changed in gcc-arm-embedded:
status: New → Confirmed
Revision history for this message
Miroslav Scaldov (scaldov-s) wrote :

Here is full project.

folders
build.debian
build.ubuntu
contains .elf .bin .o files
compiled in OS mentioned.

Revision history for this message
Tejas Belagod (belagod-tejas) wrote :

This could be related to #1560533.

Revision history for this message
Miroslav Scaldov (scaldov-s) wrote :

There is difference: in my case my static constructors works well. Only std::list static member is affected.

Revision history for this message
Marc Singer (eleventen) wrote :

Understanding that this issue has sat here for a while, I'd like to make an observation.

I wonder if we're not talking about the same sort of initialization. The initialization of statics is performed by the run-time and not the compiler. So, assuming that the problem here *is* initialization, it is hard for me to imagine that the difference is between ubuntu and debian per-se. Instead, I'd expect that there is a difference with the installation and paths of the compilers on the two systems.

There are three ways that statics are initialized, barring changes from the default linker script. For BSS, the RAM region is zeroed. For static-ly initialized scalars and POD aggregates, data may be copied from the text segment into RAM. For objects that invoke constructors, there is a list of calls that the runtime invokes before starting main.

The lk:led::led_list symbol is BSS on ubuntu:

  $ nm -C testservo.elf | grep led_list
  080003bc t _GLOBAL__sub_I__ZN2lk3led8led_listB5cxx11E
  20000a0c B lk::led::led_list[abi:cxx11]

as well as debian:

  $ nm -C testservo.elf | grep led_list
  08000910 t _GLOBAL__sub_I__ZN2lk3led8led_listB5cxx11E
  20000a3c B lk::led::led_list[abi:cxx11]

Though at different addresses.

There appears to be a constructor for this object in led.hh that would be invoked by the declaration of an object in main:

  lk::led led0(lk::gpio_c, 13);

You can also verify that there are constructors by checking the symbols in the elf files.

  $ nm ../*/testservo.elf | grep __init_array
  080084a4 t __init_array_end
  08008490 t __init_array_start
  080084a4 t __init_array_end
  08008490 t __init_array_start

The arrays are the same size in both builds, which is good.

Before we decide this is a failure of initialization, it is worthwhile breaking the program on _main and looking at the memory where this symbol lives. My hunch is that initialization is being performed and we're seeing corruption instead.

Without reviewing the build, I could only guess that, perhaps, the order of linking differs on the two systems which results in a different location for the symbol. This different is probably worth investigating. There may also be an ambient difference in the build such as a pathname or other datum pulled from the build that is changing the location of the symbols.

Cheers

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

This example code is broken. The language does not guarantee the order in which globals are initialized. You could evade that problem by using function local statics, for things like the led_list.

Or simply pick a better design.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.