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.

Reading ELF binaries
====================

 -- Function: int jit_readelf_open (jit_readelf_t *READELF, const char *FILENAME, int FORCE)
     Open the specified FILENAME and load the ELF binary that is contained within it.  Returns one of the following result codes:

     JIT_READELF_OK
          The ELF binary was opened successfully.

     JIT_READELF_CANNOT_OPEN
          Could not open the file at the filesystem level (reason in errno).

     JIT_READELF_NOT_ELF
          The file was opened, but it is not an ELF binary.

     JIT_READELF_WRONG_ARCH
          The file is an ELF binary, but it does not pertain to the architecture of this machine.

     JIT_READELF_BAD_FORMAT
          The file is an ELF binary, but the format is corrupted in some fashion.

     JIT_READELF_MEMORY
          There is insufficient memory to open the ELF binary.

     The following flags may be supplied to alter the manner in which the ELF binary is loaded:

     JIT_READELF_FLAG_FORCE
          Force jit_readelf_open to open the ELF binary, even if the architecture does not match this machine.  Useful for debugging.

     JIT_READELF_FLAG_DEBUG
          Print additional debug information to stdout.

 -- Function: void jit_readelf_close (jit_readelf_t READELF)
     Close an ELF reader, reclaiming all of the memory that was used.

 -- Function: const char * jit_readelf_get_name (jit_readelf_t READELF)
     Get the library name that is embedded inside an ELF binary. ELF binaries can refer to each other using this name.

 -- Function: void *jit_readelf_get_symbol (jit_readelf_t READELF, const char *NAME)
     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.

 -- Function: void * jit_readelf_get_section (jit_readelf_t READELF, const char *NAME, jit_nuint *SIZE)
     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.

 -- Function: void * jit_readelf_get_section_by_type (jit_readelf_t READELF, jit_int TYPE, jit_nuint *SIZE)
     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.

 -- Function: void * jit_readelf_map_vaddr (jit_readelf_t READELF, jit_nuint VADDR)
     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.

 -- Function: const char * jit_readelf_get_needed (jit_readelf_t READELF, unsigned int INDEX)
     Get the name of the dependent library at position INDEX within the needed libraries list of this ELF binary.  Returns NULL if the INDEX is invalid.

 -- Function: void jit_readelf_add_to_context (jit_readelf_t READELF, jit_context_t CONTEXT)
     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.

 -- Function: int jit_readelf_resolve_all (jit_context_t CONTEXT, int PRINT_FAILURES)
     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.

 -- Function: int jit_readelf_register_symbol (jit_context_t CONTEXT, const char *NAME, void *VALUE, int AFTER)
     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.