Skip to content

Commit

Permalink
wip ffi
Browse files Browse the repository at this point in the history
* stub out ___chkstk_ms to avoid linking errors when zig.exe is not the linker
* expose globals
* expose import errors
  • Loading branch information
rdunnington committed Aug 1, 2023
1 parent 7885001 commit 40cc4d5
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
5 changes: 3 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
const Builder = std.build.Builder;
const LibExeObjStep = std.build.LibExeObjStep;
const InstallFileStep = std.build.InstallFileStep;

const ExeOpts = struct {
exe_name: []const u8,
Expand Down Expand Up @@ -47,9 +48,9 @@ pub fn build(b: *Builder) void {
},
});

var c_header = b.addInstallFileWithDir(std.build.FileSource{ .path = "src/bytebox.h" }, .header, "bytebox.h");
var c_header: *InstallFileStep = b.addInstallFileWithDir(std.build.FileSource{ .path = "src/bytebox.h" }, .header, "bytebox.h");

const lib_bytebox = b.addStaticLibrary("bytebox", "src/cffi.zig");
const lib_bytebox: *LibExeObjStep = b.addStaticLibrary("bytebox", "src/cffi.zig");
lib_bytebox.setTarget(target);
lib_bytebox.setBuildMode(b.standardReleaseOptions());
lib_bytebox.step.dependOn(&c_header.step);
Expand Down
18 changes: 18 additions & 0 deletions src/bytebox.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ enum bb_error
BB_ERROR_OUTOFMEMORY,
BB_ERROR_INVALIDPARAM,
BB_ERROR_UNKNOWNEXPORT,
BB_ERROR_UNKNOWNIMPORT,
BB_ERROR_INCOMPATIBLEIMPORT,
};
typedef enum bb_error bb_error;

Expand Down Expand Up @@ -90,6 +92,21 @@ typedef enum bb_debug_trap_mode bb_debug_trap_mode;

typedef void bb_host_function(void* userdata, bb_module_instance* module, const bb_val* params, bb_val* returns);

enum bb_global_mut
{
BB_GLOBAL_MUT_IMMUTABLE,
BB_GLOBAL_MUT_MUTABLE,
};
typedef enum bb_global_mut bb_global_mut;

struct bb_global
{
bb_val* value;
bb_valtype type;
bb_global_mut mut;
};
typedef struct bb_global bb_global;

// typedef void* bb_malloc_func(size_t size, void* userdata);
// typedef void* bb_realloc_func(void* mem, size_t size, void* userdata);
// typedef void bb_free_func(void* mem, void* userdata);
Expand Down Expand Up @@ -118,5 +135,6 @@ bb_error bb_module_instance_step(bb_module_instance* instance, bb_val* returns,
bb_error bb_module_instance_debug_set_trap(bb_module_instance* instance, uint32_t address, bb_debug_trap_mode trap_mode);
void* bb_module_instance_mem(bb_module_instance* instance, size_t offset, size_t length);
bb_slice bb_module_instance_mem_all(bb_module_instance* instance);
bb_global bb_module_instance_find_global(bb_module_instance* instance, const char* global_name);

bool bb_func_handle_isvalid(bb_func_handle handle);
52 changes: 51 additions & 1 deletion src/cffi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const CError = enum(c_int) {
OutOfMemory,
InvalidParameter,
UnknownExport,
UnknownImport,
IncompatibleImport,
};

const CModuleDefinitionInitOpts = extern struct {
Expand Down Expand Up @@ -130,13 +132,15 @@ var cffi_gpa = std.heap.GeneralPurposeAllocator(.{}){};
// cffi_allocator.userdata = userdata;
// }

export fn bb_error_str(c_error: CError) [*]const c_char {
export fn bb_error_str(c_error: CError) [*:0]const c_char {
return switch (c_error) {
.Ok => "BB_ERROR_OK",
.Failed => "BB_ERROR_FAILED",
.OutOfMemory => "BB_ERROR_OUTOFMEMORY",
.InvalidParameter => "BB_ERROR_INVALIDPARAMETER",
.UnknownExport => "BB_ERROR_UNKNOWNEXPORT",
.UnknownImport => "BB_ERROR_UNKNOWNIMPORT",
.IncompatibleImport => "BB_ERROR_INCOMPATIBLEIMPORT",
};
}

Expand Down Expand Up @@ -411,16 +415,62 @@ export fn bb_module_instance_mem_all(module: ?*ModuleInstance) CSlice {
};
}

const CGlobalMut = enum(c_int) {
Immutable = 0,
Mutable = 1,
};

const CGlobalExport = extern struct {
value: ?*Val,
type: ValType,
mut: CGlobalMut,
};

export fn bb_module_instance_find_global(module: ?*ModuleInstance, c_global_name: ?[*:0]const c_char) CGlobalExport {
comptime {
std.debug.assert(@enumToInt(CGlobalMut.Immutable) == @enumToInt(core.GlobalMut.Immutable));
std.debug.assert(@enumToInt(CGlobalMut.Mutable) == @enumToInt(core.GlobalMut.Mutable));
}

if (module != null and c_global_name != null) {
const global_name = std.mem.sliceTo(c_global_name.?, 0);
if (module.?.getGlobalExport(global_name)) |global| {
return CGlobalExport{
.value = global.val,
.type = global.valtype,
.mut = @intToEnum(CGlobalMut, @enumToInt(global.mut)),
};
} else |_| {}
}

return CGlobalExport{
.value = null,
.type = .I32,
.mut = .Immutable,
};
}

export fn bb_func_handle_isvalid(c_handle: CFuncHandle) bool {
return c_handle.index != INVALID_FUNC_INDEX;
}

// NOTE: Zig expects this function to be present during linking, which would be fine if zig linked
// this code, but when linking with the MSVC compiler, the compiler runtime doesn't provide this
// function. Manually defining it here ensures the linker error gets resolved.
fn ___chkstk_ms() callconv(.Naked) void {}

comptime {
@export(___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = .Weak });
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Local helpers

fn translateError(err: anyerror) CError {
switch (err) {
error.OutOfMemory => return CError.OutOfMemory,
error.UnlinkableUnknownImport => return CError.UnknownImport,
error.UnlinkableIncompatibleImportType => return CError.IncompatibleImport,
else => return CError.Failed,
}
}

0 comments on commit 40cc4d5

Please sign in to comment.