[SOLVED] Problems with virtual functions

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • [SOLVED] Problems with virtual functions

    Hello,

    I'm working with nRF SDK 14.2 and the NRF52832 Dev kit, developing in C++. I have a base class with a few virtual functions and a derived class that I'm using. The code compiled, linked and flashed fine, but in debugging found that the virtual functions were not working (virtual calls in the base class calling the base implementation rather than the derived implementation).

    I tried turning on rtti in the compile, in case this was required to enable virtual functions, but that is producing the following linker error:

    undefined reference to `vtable for __cxxabiv1::__si_class_type_info'

    Searching I've done suggests the linker needs to be directed to link to C++ runtime ( -lstdc++ ) but this option does not appear to be supported by the SEGGER linker. Linker version info is below.
    C:\Program Files\SEGGER\SEGGER Embedded Studio for ARM 4.12\gcc\arm-none-eabi\bin>ld --version
    GNU ld (GNU Binutils) 2.30.0.20180329

    The post was edited 1 time, last by smithron99 ().

  • Hello,

    Thank you for your inquiry.

    smithron99 wrote:

    Searching I've done suggests the linker needs to be directed to link to C++ runtime ( -lstdc++ ) but this option does not appear to be supported by the SEGGER linker. Linker version info is below.
    Correct, see here: Segger Linker 2.25
    However Embedded Studio also comes with the gcc Linker which should support this.

    Best regards,
    Nino
    Please read the forum rules before posting.

    Keep in mind, this is *not* a support forum.
    Our engineers will try to answer your questions between their projects if possible but this can be delayed by longer periods of time.
    Should you be entitled to support you can contact us via our support system: segger.com/ticket/

    Or you can contact us via e-mail.
  • Hmmm. A few odd things:
    1. When I went into settings I found I already had the linker set to "GNU"
    2. When I re-enabled rtti, the undefined reference was gone.
    3. Virtual functions still aren't working properly. When the derived class is constructed, I see this call sequence:
      • Derived()->PowerCurve()->init()->floor()->delayFromPower()->maxCycles()

      • the only method in this chain overridden by the derived class is maxCycles(), but in this call chain, the base class implementation is called
    Here's the base class definition:

    Source Code

    1. class PowerCurve
    2. {
    3. protected:
    4. static const long CYCLE_MICROS = 8333;
    5. static long _highBuffer;
    6. static long _lowBuffer;
    7. long _floor;
    8. long _maxSpeed;
    9. public:
    10. PowerCurve(long highBuffer, long floor, long maxSpeed)
    11. {
    12. init(highBuffer, floor);
    13. _maxSpeed = maxSpeed;
    14. }
    15. virtual ~PowerCurve() {}
    16. void init(long highBuffer, long floor);
    17. virtual void highBuffer(long buffer);
    18. static long highBuffer(void)
    19. {
    20. return _highBuffer;
    21. }
    22. long delayFromPower(long power);
    23. virtual long delayFromSpeed(long speed)
    24. {
    25. return _lowBuffer;
    26. }
    27. void floor(long aFloor);
    28. long floor(void)
    29. { return _floor; }
    30. static long lowBuffer(void)
    31. { return _lowBuffer; }
    32. virtual long maxCycles(void);
    33. int power(long delay);
    34. long maxSpeed(void)
    35. { return _maxSpeed; }
    36. virtual std::string toString(void);
    37. };
    Display All
    So there are five virtual functions. I'm not sure how to examine the generated vtable from the linker, but looking at the locals in the debugger, it looks (?) like only the destructor is present in the vtable. See the attached image. I've also attached full source for the base and derived classes. The derived instance is allocated on the stack. Declared in main() like so:

    LEDCurve powerCurve( 1000, 500 );

    Images
    • vptr.jpg

      54.21 kB, 450×370, viewed 523 times
    Files
  • If the debugger is telling the truth, then it looks like the vtable is fully populated, but not correct (see attached image). Not sure why the destructor is showing at both offsets [0] and [1]. Could the problem be that this is happening in the base class constructor, and the derived class is not deemed constructed yet? Maybe the correct vtable is not in play yet? This code is borrowed from an existing working project, but built with a different compiler. Hmmm..
    Images
    • vtable.jpg

      156.53 kB, 1,504×380, viewed 645 times
  • Looks like that was it. I reduced the base class ctor to straight member initializations and then called derived.init() explicitly after the class is constructed. All good.

    Maybe this is something common I used to know? Some twinge of familiarity...