[docs][ORC] Reword "How to Add Process and Library Symbols to the JITDylibs".

Now opens with advice on what to do, rather than what *not* to do.
This commit is contained in:
Lang Hames 2022-03-26 13:02:01 -07:00
parent bcf1978a87
commit 824a73bbfa
1 changed files with 33 additions and 27 deletions

View File

@ -775,22 +775,17 @@ all modules on the same context:
.. _ProcessAndLibrarySymbols:
How to Add Process and Library Symbols to the JITDylibs
=======================================================
How to Add Process and Library Symbols to JITDylibs
===================================================
JIT'd code typically needs access to symbols in the host program or in
supporting libraries. References to process symbols can be "baked in" to code
as it is compiled by turning external references into pre-resolved integer
constants, however this ties the JIT'd code to the current process's virtual
memory layout (meaning that it can not be cached between runs) and makes
debugging lower level program representations difficult (as all external
references are opaque integer values). A bettor solution is to maintain symbolic
external references and let the jit-linker bind them for you at runtime. To
allow the JIT linker to find these external definitions their addresses must
be added to a JITDylib that the JIT'd definitions link against.
JIT'd code may need to access symbols in the host program or in supporting
libraries. The best way to enable this is to reflect these symbols into your
JITDylibs so that they appear the same as any other symbol defined within the
execution session (i.e. they are findable via `ExecutionSession::lookup`, and
so visible to the JIT linker during linking).
Adding definitions for external symbols could be done using the absoluteSymbols
function:
One way to reflect external symbols is to add them manually using the
absoluteSymbols function:
.. code-block:: c++
@ -805,25 +800,26 @@ function:
{ Mangle("gets"), pointerToJITTargetAddress(&getS)}
}));
Manually adding absolute symbols for a large or changing interface is cumbersome
however, so ORC provides an alternative to generate new definitions on demand:
*definition generators*. If a definition generator is attached to a JITDylib,
then any unsuccessful lookup on that JITDylib will fall back to calling the
definition generator, and the definition generator may choose to generate a new
definition for the missing symbols. Of particular use here is the
``DynamicLibrarySearchGenerator`` utility. This can be used to reflect the whole
exported symbol set of the process or a specific dynamic library, or a subset
of either of these determined by a predicate.
Using absoluteSymbols is reasonable if the set of symbols to be reflected is
small and fixed. On the other hand, if the set of symbols is large or variable
it may make more sense to have the definitions added for you on demand by a
*definition generator*.A definition generator is an object that can be attached
to a JITDylib, receiving a callback whenever a lookup within that JITDylib fails
to find one or more symbols. The definition generator is given a chance to
produce a definition of the missing symbol(s) before the lookup proceeds.
For example, to load the whole interface of a runtime library:
ORC provides the ``DynamicLibrarySearchGenerator`` utility for reflecting symbols
from the process (or a specific dynamic library) for you. For example, to reflect
the whole interface of a runtime library:
.. code-block:: c++
const DataLayout &DL = getDataLayout();
auto &JD = ES.createJITDylib("main");
if (auto DLSGOrErr = DynamicLibrarySearchGenerator::Load("/path/to/lib"
DL.getGlobalPrefix()))
if (auto DLSGOrErr =
DynamicLibrarySearchGenerator::Load("/path/to/lib"
DL.getGlobalPrefix()))
JD.addGenerator(std::move(*DLSGOrErr);
else
return DLSGOrErr.takeError();
@ -832,7 +828,9 @@ For example, to load the whole interface of a runtime library:
// at '/path/to/lib'.
CompileLayer.add(JD, loadModule(...));
Or, to expose an allowed set of symbols from the main process:
The ``DynamicLibrarySearchGenerator`` utility can also be constructed with a
filter function to restrict the set of symbols that may be reflected. For
example, to expose an allowed set of symbols from the main process:
.. code-block:: c++
@ -856,6 +854,14 @@ Or, to expose an allowed set of symbols from the main process:
// and contained in the list.
CompileLayer.add(JD, loadModule(...));
As an aside, it's worth pointing out that references to process or library
symbols could simply be hardcoded into your IR or object files using the
symbols' raw addresses. Symbolic resolution using the JIT symbol tables should
usually be preferred though: Both methods require you to resolve the process
symbol addresses, but symbolic resolution via the JIT symbol tables keeps the
IR and objects readable and reusable in subsequent JIT sessions. Hardcoded
addresses are difficult to read, and usually only good for one session.
Roadmap
=======