[LLVMdev] Modify a module at runtime in MCJIT

Lang Hames lhames at gmail.com
Wed Apr 8 11:33:07 PDT 2015


Hi Manoel,

CCing the Dev List.

Symbol resolution in Orc is handled by supplying a
RuntimeDyld::SymbolResolver instance when you add modules to the JIT. When
the module you've added to the JIT is linked, the SymbolResolver will be
invoked to find any symbols not contained in the module itself.

The Kaleidoscope code that builds the SymbolResolver instance in
Kaleidoscope/initial/toy.cpp file looks like this:

    auto Resolver = createLambdaResolver(
                      [&](const std::string &Name) {
                        if (auto Sym = findSymbol(Name))
                          return RuntimeDyld::SymbolInfo(Sym.getAddress(),
                                                         Sym.getFlags());
                        return RuntimeDyld::SymbolInfo(nullptr);
                      },
                      [](const std::string &S) { return nullptr; }
                    );
    return CompileLayer.addModuleSet(singletonSet(std::move(M)),
                                     make_unique<SectionMemoryManager>(),
                                     std::move(Resolver));


For the purposes of this discussion we can ignore the second lambda (it's
for "logical dylib lookup", which is a feature you probably don't need).
The first lambda is the important one here, and it only tries to do one
thing: resolve the requested symbol by looking elsewhere in the JIT (that's
the call to 'findSymbol').

To enable resolution of other symbols there are two straightforward
approaches.

(1) Construct a map of the external symbols you want to make visible to the
JIT. I prefer this approach where it's practical. It minimizes the surface
area between the JIT'd code and the host, which is good for security.

To use this approach, you just add a StringMap<TargetAddress> member to
your JIT class (call it "ExternalSymbols", or something like that). In your
constructor you populate the map:

ExternalSymbols[Mangle("printd")] = (uint64_t)&printd;

Then in your addModules method you fall back to searching the map if you
can't find the symbol in the JIT:

    auto Resolver = createLambdaResolver(
                      [&](const std::string &Name) {

                        /// Try the JIT first....
                        if (auto Sym = findSymbol(Name))
                          return RuntimeDyld::SymbolInfo(Sym.getAddress(),
                                                         Sym.getFlags());

                        // Try the external symbols map...
                        if (auto Addr = ExternalSymbols.lookup(Name))
                          return RuntimeDyld::SymbolInfo(Addr,

 JITSymbolFlags::Exported);

                        // Symbol not found.
                        return RuntimeDyld::SymbolInfo(nullptr);
                      },
                      [](const std::string &S) { return nullptr; }
                    );




Option (2) is to expose all the symbols from the host process. You can see
an example of this in tools/lli/OrcLazyJIT.{h,cpp}. Before you construct
your JIT you run:

sys::DynamicLibrary::LoadLibraryPermanently(nullptr);

This will make the host process symbols visible to the DynamicLibrary
class. Then you can use the RTDyldMemoryManager::getSymbolAddressInProcess
method (which uses DynamicLibrary for lookup) to search the host process in
your resolver:

    auto Resolver = createLambdaResolver(
      [&](const std::string &Name) {

        if (auto Sym = findSymbol(Name))
          return RuntimeDyld::SymbolInfo(Sym.getAddress(),
                                         Sym.getFlags());

        if (auto Addr =
RTDyldMemoryManager::getSymbolAddressInProcess(Name))
          return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);

        return RuntimeDyld::SymbolInfo(nullptr);
      },
      [](const std::string &S) { return nullptr; }
    };

Hope this helps!

Cheers,
Lang.


On Thu, Apr 2, 2015 at 4:46 AM, Manoel Teixeira <mbsteixeira at gmail.com>
wrote:

>
> Hi, Lang.
>
> I'm beginning the OrcJit. Now I need to import some extern 'C' code. Using
> the old jit it was done with /getEngine()->addGlobalMapping( exfn,
> functionsToLoad[i]->funcPtr );
> and with the new MCJIT it runs fine with  sys::DynamicLibrary::AddSymbol(functionsToLoad[i]->funcName,
> functionsToLoad[i]->funcPtr);
>
> Your examples in Kaleidoscope/Orc/ do not call the extern printd.
> ready> extern printd(c)
> printd(4);
> ready> Expression function:
>
> define double @__anon_expr() {
> entry:
>   %calltmp = call double @printd(double 4.000000e+00)
>   ret double %calltmp
> }
> When the Orc tries to load the anon_expr, it fails.
> Is there some extra step to do that?
>
> Cheers,
> Manoel
>
>
> On Fri, Mar 27, 2015 at 12:15 AM, Lang Hames <lhames at gmail.com> wrote:
>
>> Hi Manoel,
>>
>> CC'ing the dev list, since the answer may be relevant to others...
>>
>> > Do you have news about  Modify a module at runtime in MCJIT?
>> > We need this feature. Who develops dynamic language like lua,
>> javascript has the same problem.
>>
>> MCJIT does not support modification of modules that have already been
>> added to the JIT. There is nothing preventing you from modifying the IR,
>> but if the module has already been compiled then your modifications will
>> have no effect.
>>
>> To modify code in MCJIT you would usually delete the JIT state containing
>> the module (often this just means deleting the whole MCJIT instance), then
>> adding the new version of the Module to the JIT (or building a new MCJIT
>> instance), then update any callers. How this is done is left up to the
>> client - MCJIT provides no built-in support.
>>
>> You can build on MCJIT to do this, and several clients have, but you
>> won't get much help from the infrastructure. I would suggest the new Orc
>> JIT APIs instead, as they offer two advantages over MCJIT:
>>
>> (1) The Orc layers don't take ownership of the IR by default. This means
>> you can retain ownership of the Module and modify it place.
>>
>> (2) The Orc layers provide a "removeModuleSet" method that enables you to
>> delete the JIT state associated with a particular module (or set of
>> modules) that you have added. This saves you from manually managing
>> multiple MCJIT interfaces.
>>
>> Some of the functions in
>> "include/llvm/ExecutionEngine/Orc/IndirectionUtils.h" may also be of use to
>> you if you want to partition multi-function modules or use stubs to handle
>> redirecting function calls.
>>
>> The basic Orc-JIT setup shown in
>> examples/Kaleidoscope/Orc/initial/toy.cpp may help you get up and running
>> with the new APIs if you would like to try them.
>>
>> I hope this helps!
>>
>> Cheers,
>> Lang.
>>
>> On Thu, Mar 26, 2015 at 10:58 PM, Manoel Teixeira <mbsteixeira at gmail.com>
>> wrote:
>>
>>>
>>>  Hello, Lang.
>>>
>>>  Do you have news about  Modify a module at runtime in MCJIT?
>>>  We need this feature. Who develops dynamic language like lua,
>>> javascript has the same problem.
>>>
>>>  Cheers,
>>>  Manoel
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150408/93134bb4/attachment.html>


More information about the llvm-dev mailing list