13. Manipulating ELF binaries

The libjit library contains routines that permit pre-compiling
JIT'ed functions into an on-disk representation. This representation
can be loaded at some future time, to avoid the overhead of compiling
the functions at runtime.

We use the ELF format for this purpose, which is a common binary format
used by modern operating systems and compilers.

It isn't necessary for your operating system to be based on ELF natively.
We use our own routines to read and write ELF binaries. We chose ELF
because it has all of the features that we require, and reusing an
existing format was better than inventing a completely new one.

Look up the symbol called name in the ELF binary represented
by readelf. Returns NULL if the symbol is not present.

External references from this ELF binary to others are not resolved
until the ELF binary is loaded into a JIT context using
jit_readelf_add_to_context and jit_readelf_resolve_all.
You should not call functions within this ELF binary until after you
have fully resolved it.

Get the address and size of a particular section from an ELF binary.
Returns NULL if the section is not present in the ELF binary.

The virtual machine may have stored auxillary information
in the section when the binary was first generated. This function
allows the virtual machine to retrieve its auxillary information.

Examples of such information may be version numbers, timestamps,
checksums, and other identifying information for the bytecode that
was previously compiled by the virtual machine. The virtual machine
can use this to determine if the ELF binary is up to date and
relevant to its needs.

It is recommended that virtual machines prefix their special sections
with a unique string (e.g. .foovm) to prevent clashes with
system-defined section names. The prefix .libjit is reserved
for use by libjit itself.

Get a particular section using its raw ELF section type (i.e. one of
the SHT_* constants in jit-elf-defs.h). This is mostly
for internal use, but some virtual machines may find it useful for
debugging purposes.

Map a virtual address to an actual address in a loaded ELF binary.
Returns NULL if vaddr could not be mapped.

Function: unsigned int jit_readelf_num_needed (jit_readelf_t readelf)

Get the number of dependent libraries that are needed by this
ELF binary. The virtual machine will normally need to arrange
to load these libraries with jit_readelf_open as well,
so that all of the necessary symbols can be resolved.

Add this ELF binary to a JIT context, so that its contents can be used
when executing JIT-managed code. The binary will be closed automatically
if the context is destroyed and jit_readelf_close has not been
called explicitly yet.

The functions in the ELF binary cannot be used until you also call
jit_readelf_resolve_all to resolve cross-library symbol references.
The reason why adding and resolution are separate steps is to allow for
resolving circular dependencies between ELF binaries.

Resolve all of the cross-library symbol references in ELF binaries
that have been added to context but which were not resolved
in the previous call to this function. If print_failures
is non-zero, then diagnostic messages will be written to stdout
for any symbol resolutions that fail.

Returns zero on failure, or non-zero if all symbols were successfully
resolved. If there are no ELF binaries awaiting resolution, then
this function will return a non-zero result.

Register value with name on the specified context.
Whenever symbols are resolved with jit_readelf_resolve_all,
and the symbol name is encountered, value will be
substituted. Returns zero if out of memory or there is something
wrong with the parameters.

If after is non-zero, then name will be resolved after all
other ELF libraries; otherwise it will be resolved before the ELF
libraries.

This function is used to register intrinsic symbols that are specific to
the front end virtual machine. References to intrinsics within
libjit itself are resolved automatically.