Undefined symbol vtable: what the F*** does that mean?

| Comments (2) | Software
Note to self, when you see the following error:

Undefined symbols for architecture x86_64:
  "vtable for Foo", referenced from:
      Foo::Foo()   in ccqNJSZ0.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

It means you have declared virtual functions but you haven't defined any of them non-inline. Here's the code that caused this:

class Foo {
    virtual void f();
};

int main(int argc, char **argv)
{
  Foo foo;

  return(0);
}

Now, it's true that you would expect a linkage error here, but not this linkage error. Rather, you'd appear to get a complaint about function f() being missing, which is what happens when you change the class definition a bit to have f() defined but b() undefined.

class Foo {
    virtual void f();
    virtual void b();
};
void Foo::f() {}

This gives the expected error:

Undefined symbols for architecture x86_64:
  "Foo::b()", referenced from:
      vtable for Fooin ccxuo26H.o
ld: symbol(s) not found for architecture x86_64

What's going on here is described in a GCC FAQ entry:

The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8. Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.

Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.

Pretty sweet, huh?

2 Comments

The symbol it's complaining about isn't unrelated, it is the vtable for Foo, after all (__ZTV3Foo on Mac OS X, probably _ZTV3Foo on Linux since Linux doesn't typically decorate symbols with leading underscores).

A little experimentation shows that the translation unit that contains the definition of the first, noninline virtual function gets the vtable and the type info.

Consider the following:

// a.h
class Foo { virtual void f(); virtual void b(); };

// a.cc
#include "a.h"
void Foo::f() {}

// b.cc
#include "a.h"
void Foo::b() {}

// c.cc
#include "a.h"
Foo foo;

If you compile a.cc, b.cc, and c.cc and take a look at the symbols of each, you see that a.o defines symbols __ZN3Foo1fEv (which, unfortunately, I can read without c++filt *sigh*), __ZTI3Foo, __ZTS3Foo, and __ZTV3Foo--Foo::f(void), typeinfo for Foo, typeinfo name for Foo, and vtable for Foo respectively. It has __ZN3Foo1bEv--Foo::b(void)--undefined since the vtable depends on it (also some c++ abi symbol due to how g++ handles inheritance and typeinfo stuff).

b.o, on the other hand, only defines __ZN3Foo1bEv. Finally, c.o defines the ctor __ZN3FooC1Ev--Foo::Foo(void)--and has the vtable for Foo undefined since the ctor is responsible for setting the first word of a Foo instance to be a pointer to the vtable. (Actually, it sets it to the address of the third word in the vtable which is where the function pointers start, at least for single inheritance. I've never had the misfortune of disassembling multiple-inheritance.)

So from the linker's perspective, it really is the symbol for the vtable that's gone missing. My guess is that by the point it gets to the linker, the information about which member function was the first, virtual, noninline and thus should be defined along with the vtable has vanished.

Isn't C++ fun?

Clang is a bit more helpful:

Undefined symbols for architecture x86_64:
"vtable for Foo", referenced from:
Foo::Foo() in cc-MGx2PI.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Leave a comment