rizinorg / rz-libdemangle

Rizin Library to demangle symbols
7 stars 6 forks source link

Compile time mangling/demangling #22

Closed KOLANICH closed 1 year ago

KOLANICH commented 2 years ago

... should be a nice feature to have.

For example, it can be used to link dlls exporting functions in runtime no matter which compiler has created them without discarding their signatures and while keeping code readable.

wargio commented 2 years ago

can you make a proper example? because i'm not exactly following you

KOLANICH commented 2 years ago

Currently

namespace HydrArgs::Backend{
    extern "C" {
    HYDRARGS_BACKEND_API IArgsParser * argsParserFactory(const std::string &name, const std::string &descr, const std::string &usage [[maybe_unused]], std::vector<Arg*> dashedSpec, std::vector<Arg*> positionalSpec, Streams streams = DEFAULT_STREAMS);  ///< A factory to create a backend.  Can be overridden. Must be exported by a backend shared lib.

    using ArgsParserFactoryT = decltype(argsParserFactory);

};

....

const char ctorFuncName[] = "argsParserFactory";

void loadBackend(DiscoveredBackend &backend){
        loadedLib = new DynLibT(backend.backendPath);
        chosenFactory = loadedLib->get_function<ArgsParserFactoryT>(ctorFuncName);
}

extern C discards the info about types. It is not good: we can accidentially load a library where this function has different signature and get UB. Of course we can try to check a symbol for API version updated explicitly first, but it is a more weak solution. Loading by a mangled name solves this problem, but mangled names are unfortunately not standardized and not portable over compilers.

The solution for functions would be to have templates to generate mangled names for the most of major conventions used.

HYDRARGS_BACKEND_API IArgsParser * argsParserFactory(const std::string &name, const std::string &descr, const std::string &usage [[maybe_unused]], std::vector<Arg*> dashedSpec, std::vector<Arg*> positionalSpec, Streams streams = DEFAULT_STREAMS);  ///< A factory to create a backend.  Can be overridden. Must be exported by a backend shared lib.

void loadBackend(DiscoveredBackend &backend){
        loadedLib = new DynLibT(backend.backendPath);
        chosenFactory = loadedLib->get_function<ArgsParserFactoryT>(ctmn::gen_mangled<ctmn::current_compiler /* a enum */, ArgsParserFactoryT, "argsParserFactory">::name);
}

Then also some template to gen something that can be iterated with all the variants of mangled names (but using the name generated by the current compiler first) for all the compilers, so we can try each variant.

But this example is more about mangling, not demangling.

XVilka commented 1 year ago

I think it's not the goal of this library. @wargio probably we should close it