FLiT
FLiT copied to clipboard
Symbol bisect cannot handle out-of-line inline functions
When an inline function is not inlined, but instead generated out-of-line as a symbol, those symbols are collapsed at link time. This means that the linker is free to choose any one of the symbols and throw the rest of them away. This can be problematic if there were assumptions made by the compiler that the same inline function would be compiled in an identical way across all translation units. It also limits what symbol bisect can search.
There are a few approaches to maybe fix this issue:
- Turn these object files into shared libraries, making the inline symbols hidden (so as to use the local
definition using
-fvisibility-inlines-hidden
). This has the unfortunate side effect that it nullifies the entire symbol weak symbol approach. - Turn the inline symbols into strong symbols along with the
-fno-inline
option to disable inlining - making all instances out-of-line symbols. This has the unfortunate side effect of potentially disabling the optimization we are trying to identify by disabling inlining. I also have not found a way to make a local symbol or a weak symbol into a strong symbol yet. Also, you would run into the problem that we would have the symbol be local or weak in other object files as well. - Another approach is to make all inline functions be used locally. Maybe this can be done by telling the
compiler to always inline, however that is not always possible such as with recursive inline functions.
This could work if we could somehow mark all uses of inline functions as local, in the same way static
functions are local only to the translation unit, and duplicate symbols with the same name do not
collide. I have not yet found a compiler option or an
objcopy
option that can accomplish this task. - Another option is to somehow strip out the definition of certain symbols from one object file in order to
force the compiler to use a particular version. I have had little luck in stripping out symbols from an
object file using
strip
orobjcopy
and still be able to successfully link it into the executable. It may be that the only way to do this is to create my own tool to safely remove a function from an object file and turn that symbol into an undefined symbol.
These are at least some approaches that I have thought of at the moment. There may be more possibilities, so keep an open mind :).
Turns out I can do what I want with
objcopy --redefine-symbol <inlinefunc>=<newfuncname> ...
This will cause the symbol to have a new name within this object file, so it will use that one instead of the collapsed one from the other files.
However, this did not solve the problem of the inconsistent failures (e.g. segmentation fault, double free). So I'm back to not knowing what was causing the issue. It must be some other kind of optimization made with the assumption that the translation unit is the smallest indivisible unit of compilation. I am obviously violating that assumption by trying to mix and match two compilations of the same translation unit together.
There seem to be options in objcopy
that I missed before. They may be useful in this regard, specifically
-
--localize-symbol
: convert a global or weak symbol into a local symbol -
--globalize-symbol
: convert symbol into a global symbol (does this make it strong?) -
--weaken-symbol
: convert symbol into a weak symbol -
--add-symbol
: create a new symbol and tell it where to point -
--redefine-sym
: rename symbol both in the symbol table and at the call site
For this particular issue, I think --localize-symbol
or --globalize-symbol
may be useful.