Search code examples
c++object-files

When will used function not appear in object file symbol table


Sometimes some clearly called funtion in a translation unit (TU) is not in the compiled object file's symbol table (with nm -aC file.o). What could be the reason?

The reason could be:

(1) The call is optimized: not for the bellow example, it is the debug version, compiled with -g.

(2) The call is preprocessed and removed: not for the bellow example, there is no #if around the call

(3) It is aliased or preprocessed to have another name: not for the bellow example, have searched in AOSP source code under the skia branch, there is no related #define/typedef

(4) Since it is inlined, to boost compilation speed it may not be compiled in each TU that call it.

(4-1) But even it is not compiled, it will at least appear in the object file as an undefined symbol to be found by the linker later, but there is not that symbol at all in the example bellow.

(4-2) If so, considering all the TUs that call the function are compiled independently, how the compiler decide when to compile the inlined function or not?

What are the other possible reasons?

One example is SkOTTable_name.cpp in AOSP10:

namespace {
bool BCP47FromLanguageIdLess(const BCP47FromLanguageId& a, const BCP47FromLanguageId& b) {
    return a.languageID < b.languageID;
}
}

bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
...

    // Handle format 0 languages, translating them into BCP 47.
    const BCP47FromLanguageId target = { languageID, "" };
    int languageIndex = SkTSearch<BCP47FromLanguageId, BCP47FromLanguageIdLess>(
        BCP47FromLanguageID, SK_ARRAY_COUNT(BCP47FromLanguageID), target, sizeof(target));
...
}

The called instantiated templated inlined function "SkTSearch" is not in the result of "nm -aC .../SkOTTable_name.o". BTW that function "SkOTTableName::Iterator::next" (which calls "SkTSearch") is in the symbol table.

Reference:

The called function "SkTSearch" is in SkTSearch.h:

template <typename T, bool (LESS)(const T&, const T&)> struct SkTLessFunctionToFunctorAdaptor {
    bool operator()(const T& a, const T& b) { return LESS(a, b); }
};

// Specialization for case when T==K and the caller wants to use a function rather than functor.
template <typename T, bool (LESS)(const T&, const T&)>
int SkTSearch(const T base[], int count, const T& target, size_t elemSize) {
    static SkTLessFunctionToFunctorAdaptor<T, LESS> functor;
    return SkTSearch(base, count, target, elemSize, functor);
}

Solution

  • (Non-explicitly-specialized) templated entities must have a definition in each translation unit that uses the entity in such a way that a definition would be required. The only exception for this is if the entity is explicitly instantiated in some translation unit.

    Therefore the compiler doesn't need to emit a definition of a member function of a template class or a function template if it can inline all calls in the translation unit (or if there are none), since the compiler knows that the other translation units also have the definition available if they need it. If all calls are inlined, there is no need to emit an undefined symbol either, because there are no calls left that need to be resolved by the linker.

    The above rule is why, if explicit instantiation/specialization is not used, generally templates and members of class templates must be defined in the header file, not a source file.