Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[workspace]
resolver = "2"
members = ["crates/herkos-runtime", "crates/herkos", "crates/herkos-tests"]
members = ["crates/herkos-runtime", "crates/herkos-core", "crates/herkos", "crates/herkos-tests"]

exclude = ["examples/c-to-wasm-to-rust", "examples/inter-module-lending"]
exclude = [
"examples/c-to-wasm-to-rust",
"examples/inter-module-lending",
"examples/herkos-bootstrap",
]

[workspace.dependencies]
anyhow = "1"
Expand Down
23 changes: 23 additions & 0 deletions crates/herkos-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "herkos-core"
version = "0.1.1"
edition = "2021"
description = "Compile-Time Memory Isolation via WebAssembly and Rust Transpilation — core library"
license = "Apache-2.0"
repository = "https://github.com/arnoox/herkos"
homepage = "https://github.com/arnoox/herkos"
authors = ["Arnaud Riess"]
keywords = ["webassembly", "wasm", "transpiler", "rust", "isolation"]
categories = ["wasm", "development-tools::build-utils"]
readme = "../../README.md"

[lib]
crate-type = ["rlib", "cdylib"]
Comment thread
arnoox marked this conversation as resolved.

[dependencies]
wasmparser = { workspace = true }
anyhow = { workspace = true }
heck = { workspace = true }

[dev-dependencies]
wat = { workspace = true }
125 changes: 125 additions & 0 deletions crates/herkos-core/example_c_usage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* example_c_usage.c - Example C program using the herkos transpiler
*
* Compile with:
* gcc example_c_usage.c -L./target/debug -lherkos_core -o example_c_usage
*
* Usage:
* ./example_c_usage input.wasm output.rs
*/

#include "herkos.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

/**
* Read a file into memory
* Returns allocated buffer or NULL on error
*/
static uint8_t *read_file(const char *filename, size_t *out_len) {
FILE *f = fopen(filename, "rb");
if (!f) {
perror("fopen");
return NULL;
}

if (fseek(f, 0, SEEK_END) != 0) {
perror("fseek");
fclose(f);
return NULL;
}

long file_size = ftell(f);
if (file_size < 0) {
perror("ftell");
fclose(f);
return NULL;
}

if (fseek(f, 0, SEEK_SET) != 0) {
perror("fseek");
fclose(f);
return NULL;
}

uint8_t *buffer = malloc((size_t)file_size);
if (!buffer) {
fprintf(stderr, "malloc failed\n");
fclose(f);
return NULL;
}

size_t bytes_read = fread(buffer, 1, (size_t)file_size, f);
if (bytes_read != (size_t)file_size) {
fprintf(stderr, "fread failed: expected %ld bytes, got %zu\n", file_size, bytes_read);
free(buffer);
fclose(f);
return NULL;
}

fclose(f);
*out_len = (size_t)file_size;
return buffer;
}

/**
* Write buffer to file
*/
static int write_file(const char *filename, const char *data, size_t len) {
FILE *f = fopen(filename, "wb");
if (!f) {
perror("fopen");
return 1;
}

size_t bytes_written = fwrite(data, 1, len, f);
if (bytes_written != len) {
fprintf(stderr, "fwrite failed: expected %zu bytes, wrote %zu\n", len, bytes_written);
fclose(f);
return 1;
}

fclose(f);
return 0;
}

int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <input.wasm> <output.rs>\n", argv[0]);
return 1;
}

const char *input_file = argv[1];
const char *output_file = argv[2];

printf("Reading WASM from: %s\n", input_file);
size_t wasm_len = 0;
uint8_t *wasm_bytes = read_file(input_file, &wasm_len);
if (!wasm_bytes) {
fprintf(stderr, "Failed to read input file\n");
return 1;
}

printf("Read %zu bytes, transpiling...\n", wasm_len);
HerkosResult result = herkos_transpile(wasm_bytes, wasm_len);
free(wasm_bytes);

if (result.error_code != HERKOS_OK) {
fprintf(stderr, "Transpilation failed (error code %d):\n%s\n",
result.error_code, result.error_msg);
herkos_free(result.error_msg);
return 1;
}

printf("Transpilation successful, writing output to: %s\n", output_file);
if (write_file(output_file, result.output, result.output_len) != 0) {
fprintf(stderr, "Failed to write output file\n");
herkos_free(result.output);
return 1;
}

printf("Success! Generated %zu bytes of Rust code\n", result.output_len);
herkos_free(result.output);
return 0;
}
89 changes: 89 additions & 0 deletions crates/herkos-core/herkos.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* herkos.h - C FFI interface for the herkos WebAssembly to Rust transpiler
*
* This header provides C-compatible bindings for transpiling WebAssembly
* modules into memory-safe Rust source code.
*/

#ifndef HERKOS_H
#define HERKOS_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Error codes */
#define HERKOS_OK 0
#define HERKOS_ERROR_TRANSPILE 1
#define HERKOS_ERROR_INVALID_INPUT 2

/**
* Result structure returned by transpilation functions.
*
* On success (error_code == HERKOS_OK):
* - output: allocated string containing the Rust source code
* - output_len: length of the output string in bytes (not including null terminator)
* - error_msg: NULL
*
* On failure (error_code != HERKOS_OK):
* - output: NULL
* - output_len: 0
* - error_msg: allocated string describing the error
*
* Both output and error_msg (if non-null) must be freed using herkos_free().
*/
typedef struct {
char *output;
size_t output_len;
int32_t error_code;
char *error_msg;
} HerkosResult;

/**
* Transpile WebAssembly bytes to Rust source code using default options.
*
* This is the main entry point for transpiling WASM binaries. It uses default
* transpilation options (safe backend, 256 max pages, no optimizations).
*
* @param wasm_bytes Pointer to the WebAssembly binary data
* @param wasm_len Length of the WebAssembly binary in bytes
* @return HerkosResult containing output or error
*
* Example:
* uint8_t *wasm_bytes = ...; // Load WASM binary
* size_t wasm_len = ...;
*
* HerkosResult result = herkos_transpile(wasm_bytes, wasm_len);
* if (result.error_code == HERKOS_OK) {
* // Use result.output (a null-terminated C string)
* printf("%s\n", result.output);
* herkos_free(result.output);
* } else {
* fprintf(stderr, "Transpilation failed: %s\n", result.error_msg);
* herkos_free(result.error_msg);
* }
*/
HerkosResult herkos_transpile(const uint8_t *wasm_bytes, size_t wasm_len);

/**
* Free memory allocated by herkos functions.
*
* This function must be called to free:
* - HerkosResult.output (on success)
* - HerkosResult.error_msg (on failure)
*
* @param ptr Pointer to memory allocated by herkos
*
* Passing NULL is safe and does nothing.
* Do not free the same pointer twice.
*/
void herkos_free(char *ptr);

#ifdef __cplusplus
}
#endif

#endif /* HERKOS_H */
File renamed without changes.
Loading
Loading