-
Notifications
You must be signed in to change notification settings - Fork 15
Metadata API
In addition to the standard External API, INExports
also exposes several functions that can query all the metadata for each webassembly module compiled into a binary. This is useful for finding memory locations, globals, or functions that might have been exported, or to bypass the exports entirely. The second half of this page describes the data structures used by the Metadata API.
IN_Entrypoint LoadFunction(void* assembly, const char* module_name, const char* function); // if function is null, loads the entrypoint function
-
assembly: A pointer to a webassembly binary loaded by
LoadAssembly()
. - module_name: The name of the module the function is exported from.
- function: The name of the function. If null, loads the entrypoint function.
-
Returns an IN_Entrypoint function pointer that must be cast to the correct function signature, or
NULL
if the lookup fails.
Gets a function from a WebAssembly binary that has been loaded into memory. This function cannot determine the type signature, you must cast it manually to the correct function type. This lookup is case-sensitive, but should work for any valid UTF8 identifier exported by a WebAssembly module because the function name is properly mangled before the lookup occurs/
IN_Entrypoint LoadTable(void* assembly, const char* module_name, const char* table, varuint32 index);
- assembly: A pointer to a WebAssembly binary loaded by LoadAssembly.
- module_name: The name of the module the table is exported from.
- function: The name of the table the function pointer belongs to.
-
index: The index of the function pointer. Returns
NULL
if this is out of bounds. -
Returns an IN_Entrypoint function pointer that must be cast to the correct function signature, or
NULL
if the lookup fails. Can also returnNULL
if the lookup succeeds but the table entry itself isNULL
.
Gets a function pointer from a table, given the specified index.
IRGlobal* LoadGlobal(void* assembly, const char* module_name, const char* export_name);
- assembly: A pointer to a webassembly binary loaded by LoadAssembly.
- module_name: The name of the module the global is exported from.
- export_name: The name of the global that has been exported.
-
Returns an
IRGlobal
union that contains the global, orNULL
if the lookup fails.
Gets a pointer to a global from a webassembly binary loaded by LoadAssembly, which can potentially be modified if it is mutable (but this function cannot determine whether it was intended to be mutable).
INModuleMetadata* GetModuleMetadata(void* assembly, uint32_t module_index);
- assembly: A pointer to a WebAssembly binary loaded by LoadAssembly.
- module_index: A zero-based index. If this is out-of-bounds, the function returns null.
-
Returns a pointer to the module's Metadata structure, or
NULL
if it doesn't exist.
Gets the metadata associated with the module at the given zero-based index.
IN_Entrypoint LoadTableIndex(void* assembly, uint32_t module_index, uint32_t table_index, varuint32 function_index);
- assembly: A pointer to a webassembly binary loaded by LoadAssembly.
- module_index: The index of the module the table is exported from.
- table_index: The index of the table the function pointer belongs to.
- function_index: The index of the function pointer.
-
Returns a generic function pointer that must be cast to the correct function pointer type, or
NULL
if any of the indexes are out of bounds.
Gets a function pointer from a table, given the specified index. This function pointer is not guaranteed to use _cdecl
, so be careful about calling it.
INGlobal* LoadGlobalIndex(void* assembly, uint32_t module_index, uint32_t global_index);
- assembly: A pointer to a WebAssembly binary loaded by LoadAssembly.
- module_index: The index of the module the table is exported from.
- global_index: The index of the global to retrieve.
-
Returns a pointer to a global variable union, or
NULL
if it doesn't exist.
Gets a global value at the specified index, or returns NULL
if the index is out of bounds.
INGlobal* LoadMemoryIndex(void* assembly, uint32_t module_index, uint32_t memory_index);
- assembly A pointer to a WebAssembly binary loaded by LoadAssembly.
- module_index The index of the module the table is exported from.
- global_index The index of the linear memory to retrieve.
- Returns a pointer to a global variable union which contains the memory pointer. This memory pointer can change, so it should be accessed from the global variable, not stored.
Gets a linear memory global at the specified index, or returns NULL
if the index is out of bounds.
int ReplaceTableFuncPtr(void* assembly, uint32_t module_index, uint32_t table_index, const char* function, IN_Entrypoint replace);
- assembly A pointer to a WebAssembly binary loaded by LoadAssembly.
- module_index The index of the module the table is exported from.
- table_index The index of the table to search through.
- function Name of the exported function to search the table for.
- replace function pointer to another function that should replace the function's table entry.
- Returns 0 if it succeeded, or a negative error code otherwise.
This gets the address of the given exported function, then searches the given table for a matching address. If it finds a match, it replaces that table entry's function pointer with replace
. This function is intended to be used to set function pointers inside WebAssembly to external host functions. The function you search for should be a placeholder, it's only purpose is to give us something we can use to find the table entry we need to find. Your WebAssembly should look like this:
__attribute__((visibility("default"))) int replace_me(int a, int b) { return 0; } // exported placeholder
int (*testfn)(int, int) = &replace_me; // function pointer we want to redirect to a host function
int test(int i, int j) { return (*testfn)(i, j); } // Use the function pointer
Then the host provides an implementation and replaces it:
int replacement(int a, int b) { return a + b; }
// ...
void* assembly = (*_exports.LoadAssembly)("target.dll");
(*_exports.ReplaceTableFuncPtr)(assembly, 0, 0, "replace_me", (IN_Entrypoint)&replacement);
// ...
This is a list of the external data structures used by the API, with instructions on how they work.
typedef struct IN__TABLE_ENTRY
{
IN_Entrypoint func;
varuint32 type;
} INTableEntry;
Represents an entry in a webassembly table, which contains a function pointer and a 32-bit tag indicating what type signature it has. This mimics the memory layout of the actual internal buffer used by the module, so you can safely index through it.
typedef union __IN_GLOBAL_TYPE
{
uint32_t i32;
uint64_t i64;
float f32;
double f64;
void* memory;
INTableEntry* table;
} INGlobal;
A pointer to an INGlobal struct is returned when calling any metadata function that returns a global. When dereferencing this pointer, choose the appropriate type that you are trying to access - getting this type wrong may result in an out-of-bounds access. Note that the memory field is itself also a pointer, which is because it is essentially a byte array that must be indexed if you access it. The memory pointer can change if the module's linear memory is resized, so never cache the pointer directly - always access it from the union.
typedef struct IN__MODULE_METADATA
{
const char* name;
varuint32 version;
varuint32 n_tables;
INTableEntry*** tables;
varuint32 n_memories;
void*** memories;
varuint32 n_globals;
INGlobal** globals;
varuint32 n_functions;
IN_Entrypoint* functions;
} INModuleMetadata;
This structure contains metadata about a given module. This includes the name, webassembly version, and pointers to internal collections of tables, globals, memories, and functions. The list of functions here are externalized
, meaning they refer to a __cdecl
wrapper around each function and are safe to call from C. Some of the function pointers in the array could potentially be NULL
if they do not have a safe __cdecl
wrapper. You are encouraged to use the indexing functions instead of directly querying this function when possible, as they do bounds checks for you and know what to do with all the pointer indirections. The exception is the list of functions, which is safe to iterate through like a normal array.