3

I am compiling an embedded application for ARM Cortex M4 with arm-none-eabi-g++ version 4.9.3. To make the target image as small as possible, I link the application with -specs=nano.specs.

Now I encountered a strange problem: When I anywhere in the code define a pure virtual function (an then I define its body in a child class), I get this linking error:

abort.c:-1: Error: undefined reference to `_exit'
sbrkr.c:-1: Error: undefined reference to `_sbrk'
signalr.c:-1: Error: undefined reference to `_kill'
...

This is correct because I really don't have these functions defined in my project because I don't use them at all. But why the compiler need these functions when I want to make a pure virtual function? When I define an empty body to the virtual function, the linker errors are gone. Can somebody explain me the magic behind the pure virtual functions?

EDIT: To make things more clear, here is a very simple example of my code:

class Parent {
public:
    virtual int foo() { return -1; } // This compiles normally.
    virtual int foo() = 0; // This gives me the linker error above.
}

class Child {
public:
    virtual int foo { return 42; }
}

Child test;
Honza Vojtěch
  • 685
  • 1
  • 7
  • 27
  • Can we see the code that is causing the problem? Is it specific to this environment with the flag that you mention -- it compiles OK without it? – Basya Aug 22 '17 at 13:52
  • Sorry, the code is a part of quite big project, it would be difficult to share it. The error is specific to microcontrollers because they don't use standard libc which defines the functions mentioned in the linker error above. There are several versions of microcontroller libc which differ in the amount of included features and occupied space. I am using the smallest version which does not define the functions mentioned in the linker error. But I cannot understand why I need these functions to define a pure virtual function. – Honza Vojtěch Aug 22 '17 at 14:01
  • 2
    My guess is the following: the compiler references an error handler from the virtual table of the abstract class (`__cxa_pure_virtual`?) and this one possibly indirectly references the missing functions not provided by your library. – PaulR Aug 22 '17 at 15:44
  • You may want to have a look at https://stackoverflow.com/a/9355553 – PaulR Aug 22 '17 at 15:50
  • My suspect is `__cxa_pure_virtual` as well; if your library defines it as a weak symbol you may just define your own custom implementation that does not require the symbols above. OTOH, you may as well define some stubs for those missing symbols - make `kill` and `sbrk` always fail (errno=ENOSYS), and `exit` hang in a tight loop (possibly in low power mode). – Matteo Italia Aug 22 '17 at 16:53

1 Answers1

2

Pure virtual methods need exception support, because it is sometimes possible to call them. The missing library functions are needed to implement exception handling. See a related question here.

  • Thank you for a suggestion, but you misunderstood my question :( Please look at my edit, I attached a simple example. – Honza Vojtěch Aug 22 '17 at 15:05
  • Yes, I thought I was stating the obvious, thank you for clarification. Changed the entire answer. You forgot to declare Child as a subclass of Parent in your example code, BTW. – Oskari Teirilä Aug 22 '17 at 15:32
  • Calling a pure virtual function does not result in exceptions being thrown; exception handling has nothing to do with this (although it is possibly related to the default implementation of the pure virtual function call error handler). – Matteo Italia Aug 22 '17 at 15:34
  • You are correct. Most pure virtual function error handlers simply terminate the program without generating exceptions. It would appear obvious, though, that the handler in the runtime used by klasyc doesn't, because if it did, it really wouldn't need all those additional functions. But it is also possible that the handler is implemented in a module that references all those library functions for unrelated functionality. – Oskari Teirilä Aug 22 '17 at 15:57
  • Actually I'd say that `_exit` and `_kill` are spot-on for a handler that straight terminates the program; `sbrk` is generally needed for low-level dynamic memory allocation, which is a bit strange but not completely far fetched for its support functions. – Matteo Italia Aug 22 '17 at 16:47
  • _exit, certainly, but why _kill? – Oskari Teirilä Aug 22 '17 at 17:04
  • Thank you guys, I added my own definition of `__cxa_pure_virtual` function and the problem is gone. I couldn't understand when the compiler would allow to call a pure virtual function, but this is explained in the [related question](https://stackoverflow.com/questions/99552/where-do-pure-virtual-function-call-crashes-come-from). This edge case also explains why those additional functions `_exit`, `_kill` and others are necessary. – Honza Vojtěch Aug 24 '17 at 08:18