LoongsonNBL  0.8
 All Data Structures Files Functions Variables Enumerations Enumerator Macros
Data Structures | Macros | Enumerations | Functions
nbl.h File Reference

LoongsonNBL – heterogeneous library loader. More...

#include <dlfcn.h>
#include <elf.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
Include dependency graph for nbl.h:

Go to the source code of this file.

Data Structures

struct  Nbl
 Dispatch table of NBL runtime functions. More...
 

Macros

#define NBL_MAXPATHLEN   2048
 

Enumerations

enum  NblVaargsPolicy { NBL_VAARGS_NONE = 0, NBL_VAARGS_NULL_TERMINATED = 1 }
 Variadic-argument handling policy for host function registration. More...
 

Functions

Nbl * nbl_load (int tr_mode, const char *nbl_lib_base, bool host_dispatch_signal)
 Create and initialise an Nbl instance. More...
 
void nbl_unload (Nbl *nbl)
 Destroy an Nbl instance previously created by nbl_load() and release all associated resources.
 
void set_host_sighandle (int(*host_sig_handler)(int signo, void *siginfo, void *ucontext, int abort_if_unrecognized))
 Register a host (LoongArch) signal handler with the current NBL instance so that the translator can delegate signal dispatch to it. More...
 

Detailed Description

LoongsonNBL – heterogeneous library loader.

NBL is a userspace runtime that lets a LoongArch (la64 / la32) process load x86_64 ELF shared objects and invoke functions inside them, by routing cross-architecture calls through a binary translator.

The public C API mirrors a subset of libdl.so (dlopen / dlclose / dlsym / ...) so that callers familiar with POSIX dynamic loading can use it with minimal friction, while extending it with the extra entry points required for cross-architecture bridging – signature-aware symbol lookup, host function registration, wrapper-stub generation, and so on.

NBL signature grammar

Several entry points of Nbl – dlsym_with_signature(), method_stub() and the register_hostfunc*() family – take a nbl_signature string. It is the only description of a function's parameter list and return type that NBL receives, so it must match the real prototype exactly.

<signature> ::= <ret_type> "F" <arg_type>*

Primitive type letters:
  v : void
  B : uint8_t   (unsigned byte)
  b : int8_t    (signed   byte)
  S : uint16_t  (unsigned half-word)
  s : int16_t   (signed   half-word)
  I : uint32_t  (unsigned word)
  i : int32_t   (signed   word)
  L : uint64_t  (unsigned double-word) -- 64-bit on LA64, 32-bit on LA32
  l : int64_t   (signed   double-word) -- 64-bit on LA64, 32-bit on LA32
  p : pointer   (sizeof(void*) on the host arch: 8 on LA64, 4 on LA32)
  f : float     (IEEE-754 single precision, 32-bit)
  d : double    (IEEE-754 double precision, 64-bit)
  D : long double
  H : struct    -- followed by a brace-delimited layout, e.g. "H{ii}"
      Structures may nest, e.g. "H{iH{i}}" for
        struct { int a; struct { int b; } inner; }
      and repeated members may use an array count, e.g. "H{i2}".
      The members of a nested structure are laid out with their real
      alignment and tail padding, exactly like the C compiler does.
  U : union
  V : variadic arguments (vaargs)
  A : va_list
  C : complex number. "C1" for float _Complex, "C2" for double
      _Complex, "C3" for long double _Complex.  (TODO)

Platform-dependent sizing (applies to L, l and p):
  - LA64 (64-bit LoongArch): 64-bit wide.
  - LA32 (32-bit LoongArch): 32-bit wide.

Conceptual call path:

 .............................................
 | wrapper_stub (la64 args  -> x86_64 args)  |
 .............................................
               |       x86_64 function       |
 .............................................
 | wrapper_stub (x86_64 ret  -> la64 ret)    |
 .............................................

The helper convert_to_nbl_signature(raw_sig, nbl_sig) is available to translate JNI-style ("(ILjava/lang/String;[I)J") or other raw signatures into nbl_signature form.

Examples:

signature = "vFv" for void test(void)
signature = "iFii" for int add(int, int)
signature = "iFH{ii}" for int add(struct { int a; int b; })
signature = "iFH{i2}" for int add(struct { int a; int b[2]; })
signature = "iFH{iH{i}}" for int add(struct { int a;
struct { int b; } inner; })

JNI example:

raw_signature : "(ILjava/lang/String;[I)J"
nbl_signature : "lFipp"

Macro Definition Documentation

#define NBL_MAXPATHLEN   2048

Maximum length (including the trailing NUL) of an NBL path string.

Enumeration Type Documentation

Variadic-argument handling policy for host function registration.

Note
Unstable API. Currently used to model CPython's variadic call conventions on top of the generic register_hostfunc machinery.
Enumerator
NBL_VAARGS_NONE 

The host function is not variadic (e.g. a JNI entry point).

NBL_VAARGS_NULL_TERMINATED 

The host function is variadic; the caller terminates the argument list with a sentinel value (typically NULL) – printf-style.

Function Documentation

Nbl* nbl_load ( int  tr_mode,
const char *  nbl_lib_base,
bool  host_dispatch_signal 
)

Create and initialise an Nbl instance.

The returned dispatch table must be released with nbl_unload() when no longer needed.

Parameters
tr_modeSelects the underlying translator backend: 1 for the default backend, 2 is under development.
nbl_lib_baseDirectory from which to load libnbl.so and its translator dependencies.
host_dispatch_signal
  • false: the translator installs the signal handler first; suitable for most applications.
  • true: the host application (e.g. JDK, CPython, Node.js) installs the signal handler first and forwards to the translator as needed. Required for runtimes that manage signals on their own.
Returns
Newly allocated Nbl dispatch table on success, or NULL on failure.
Note
Not thread-safe. Call from a single thread before any other thread starts using NBL.
void set_host_sighandle ( int(*)(int signo, void *siginfo, void *ucontext, int abort_if_unrecognized)  host_sig_handler)

Register a host (LoongArch) signal handler with the current NBL instance so that the translator can delegate signal dispatch to it.

Only one host handler is active at a time; passing NULL restores the translator's default behaviour.

Parameters
host_sig_handlerPointer to the host signal handler. Receives signo, siginfo, ucontext and an abort_if_unrecognized flag, and returns 0 when the signal has been fully handled, non-zero to fall back to the translator's own handling. Pass NULL to restore the translator's default behaviour.