Skip to content

Commit

Permalink
Add windows implementation of wasm2c runtime
Browse files Browse the repository at this point in the history
Split out from #1833
  • Loading branch information
sbc100 committed Mar 2, 2022
1 parent 1dea1ee commit 9059009
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 37 deletions.
18 changes: 13 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,19 @@ set(WABT_LIBRARY_SRC

add_library(wabt STATIC ${WABT_LIBRARY_SRC})

IF (NOT WIN32)
add_library(wasm-rt-impl STATIC wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-impl.h)
install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES wasm2c/wasm-rt.h wasm2c/wasm-rt-impl.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif ()
add_library(wasm-rt-impl SHARED STATIC
wasm2c/wasm-rt-impl.c
wasm2c/wasm-rt-os-unix.c
wasm2c/wasm-rt-os-win.c)
set_property(TARGET wasm-rt-impl PROPERTY POSITION_INDEPENDENT_CODE ON)
install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES wasm2c/wasm-rt.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

add_custom_target(wasm-rt-impl-copy-to-bin ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:wasm-rt-impl> ${WABT_SOURCE_DIR}/bin
DEPENDS wasm-rt-impl
)

if (BUILD_FUZZ_TOOLS)
set(FUZZ_FLAGS "-fsanitize=fuzzer,address")
Expand Down
20 changes: 13 additions & 7 deletions test/run-spec-wasm2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
WASM2C_DIR = os.path.join(find_exe.REPO_ROOT_DIR, 'wasm2c')
IS_WINDOWS = sys.platform == 'win32'


def ReinterpretF32(f32_bits):
Expand Down Expand Up @@ -335,7 +336,10 @@ def _Action(self, command):

def Compile(cc, c_filename, out_dir, *args):
o_filename = utils.ChangeDir(utils.ChangeExt(c_filename, '.o'), out_dir)
cc.RunWithArgs('-c', c_filename, '-o', o_filename, *args)
if IS_WINDOWS:
cc.RunWithArgs('/c', c_filename, '/Fo"%s"' % o_filename, *args)
else:
cc.RunWithArgs('-c', c_filename, '-o', o_filename, *args)
return o_filename


Expand All @@ -345,6 +349,9 @@ def Link(cc, o_filenames, main_exe, *args):


def main(args):
default_compiler = 'cc'
if IS_WINDOWS:
default_compiler = 'cl.exe'
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--out-dir', metavar='PATH',
help='output directory for files.')
Expand All @@ -356,7 +363,8 @@ def main(args):
parser.add_argument('--wasmrt-dir', metavar='PATH',
help='directory with wasm-rt files', default=WASM2C_DIR)
parser.add_argument('--cc', metavar='PATH',
help='the path to the C compiler', default='cc')
help='the path to the C compiler',
default=default_compiler)
parser.add_argument('--cflags', metavar='FLAGS',
help='additional flags for C compiler.',
action='append', default=[])
Expand Down Expand Up @@ -423,10 +431,6 @@ def main(args):
o_filenames = []
includes = '-I%s' % options.wasmrt_dir

# Compile wasm-rt-impl.
wasm_rt_impl_c = os.path.join(options.wasmrt_dir, 'wasm-rt-impl.c')
o_filenames.append(Compile(cc, wasm_rt_impl_c, out_dir, includes))

for i, wasm_filename in enumerate(cwriter.GetModuleFilenames()):
wasm_filename = os.path.join(out_dir, wasm_filename)
c_filename = utils.ChangeExt(wasm_filename, '.c')
Expand All @@ -438,7 +442,9 @@ def main(args):
if options.compile:
o_filenames.append(Compile(cc, main_filename, out_dir, includes, defines))
main_exe = utils.ChangeExt(json_file_path, '')
Link(cc, o_filenames, main_exe, '-lm')
find_exe.GetDefaultPath()
Link(cc, o_filenames, main_exe,
'-L' + find_exe.GetDefaultPath(), '-lwasm-rt-impl', '-lm')

if options.compile and options.run:
utils.Executable(main_exe, forward_stdout=True).RunWithArgs()
Expand Down
4 changes: 0 additions & 4 deletions test/run-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,6 @@
]
}

# TODO(binji): Add Windows support for compiling using run-spec-wasm2c.py
if IS_WINDOWS:
TOOLS['run-spec-wasm2c'].append(('SKIP', ''))

ROUNDTRIP_TOOLS = ('wat2wasm',)


Expand Down
4 changes: 2 additions & 2 deletions test/spec-wasm2c-prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#include "wasm-rt.h"
#include "wasm-rt-impl.h"

int g_tests_run;
int g_tests_passed;
static int g_tests_run;
static int g_tests_passed;

static void run_spec_tests(void);

Expand Down
7 changes: 4 additions & 3 deletions wasm2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ int main(int argc, char** argv) {
```
To compile the executable, we need to use `main.c` and the generated `fac.c`.
We'll also include `wasm-rt-impl.c` which has implementations of the various
`wasm_rt_*` functions used by `fac.c` and `fac.h`.
We'll also include `wasm-rt-impl.c`, `wasm-rt-os-unix.c` and `wasm-rt-os-win.c`
which include some OS specific initialization which has implementations of the
various `wasm_rt_*` functions used by `fac.c` and `fac.h`.
```sh
$ cc -o fac main.c fac.c wasm-rt-impl.c
$ cc -o fac main.c fac.c wasm-rt-impl.c wasm-rt-os-unix.c wasm-rt-os-win.c
```

Now let's test it out!
Expand Down
24 changes: 19 additions & 5 deletions wasm2c/wasm-rt-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "wasm-rt-impl.h"
#include "wasm-rt-os.h"

#include <assert.h>
#include <stdarg.h>
Expand Down Expand Up @@ -108,7 +109,10 @@ static void signal_handler(int sig, siginfo_t* si, void* unused) {
}
#endif

void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
// Heap aligned to 4GB
#define WASM_HEAP_ALIGNMENT 0x100000000ull

bool wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
uint32_t initial_pages,
uint32_t max_pages) {
uint32_t byte_length = initial_pages * PAGE_SIZE;
Expand All @@ -130,19 +134,25 @@ void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,

/* Reserve 8GiB. */
void* addr =
mmap(NULL, 0x200000000ul, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
os_mmap_aligned(NULL, 0x200000000ul, MMAP_PROT_NONE, MMAP_MAP_NONE,
WASM_HEAP_ALIGNMENT, /*alignment_offset=*/0);

if (addr == (void*)-1) {
perror("mmap failed");
os_print_last_error("os_mmap failed.");
abort();
}
mprotect(addr, byte_length, PROT_READ | PROT_WRITE);
int ret = os_mmap_commit(addr, byte_length, MMAP_PROT_READ | MMAP_PROT_WRITE);
if (ret != 0) {
return false;
}
memory->data = addr;
#else
memory->data = calloc(byte_length, 1);
#endif
memory->size = byte_length;
memory->pages = initial_pages;
memory->max_pages = max_pages;
return true;
}

uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
Expand All @@ -159,7 +169,11 @@ uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
uint32_t delta_size = delta * PAGE_SIZE;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
uint8_t* new_data = memory->data;
mprotect(new_data + old_size, delta_size, PROT_READ | PROT_WRITE);
int ret = os_mmap_commit(new_data + old_size, delta_size,
MMAP_PROT_READ | MMAP_PROT_WRITE);
if (ret != 0) {
return (uint32_t)-1;
}
#else
uint8_t* new_data = realloc(memory->data, new_size);
if (new_data == NULL) {
Expand Down
190 changes: 190 additions & 0 deletions wasm2c/wasm-rt-os-unix.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Based on
// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD
// Check for any posix or unix OS
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \
(defined(__APPLE__) && defined(__MACH__)))

#include "wasm-rt-os.h"
#include "wasm-rt.h"

#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__APPLE__) && defined(__MACH__)
// Macs priors to OSX 10.12 don't have the clock functions. So we will use mac
// specific options
#include <mach/mach_time.h>
#include <sys/time.h>
#endif
#include <sys/mman.h>
#include <unistd.h>

#ifdef VERBOSE_LOGGING
#define VERBOSE_LOG(...) \
{ printf(__VA_ARGS__); }
#else
#define VERBOSE_LOG(...)
#endif

size_t os_getpagesize() {
return getpagesize();
}

void* os_mmap(void* hint, size_t size, int prot, int flags) {
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint64_t request_size, page_size;
uint8_t* addr;

page_size = (uint64_t)os_getpagesize();
request_size = (size + page_size - 1) & ~(page_size - 1);

if ((size_t)request_size < size)
/* integer overflow */
return NULL;

if (request_size > 16 * (uint64_t)UINT32_MAX)
/* At most 16 G is allowed */
return NULL;

if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;

if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;

if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;

#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#ifndef __APPLE__
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
#endif
#endif

if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;

addr = mmap(hint, request_size, map_prot, map_flags, -1, 0);

if (addr == MAP_FAILED)
return NULL;

return addr;
}

void os_munmap(void* addr, size_t size) {
uint64_t page_size = (uint64_t)os_getpagesize();
uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);

if (addr) {
if (munmap(addr, request_size)) {
printf("os_munmap error addr:%p, size:0x%" PRIx64 ", errno:%d\n", addr,
request_size, errno);
}
}
}

int os_mprotect(void* addr, size_t size, int prot) {
int map_prot = PROT_NONE;
uint64_t page_size = (uint64_t)os_getpagesize();
uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);

if (!addr)
return 0;

if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;

if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;

if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;

return mprotect(addr, request_size, map_prot);
}

void* os_mmap_aligned(void* addr,
size_t requested_length,
int prot,
int flags,
size_t alignment,
size_t alignment_offset) {
size_t padded_length = requested_length + alignment + alignment_offset;
uintptr_t unaligned = (uintptr_t)os_mmap(addr, padded_length, prot, flags);

VERBOSE_LOG(
"os_mmap_aligned: alignment:%llu, alignment_offset:%llu, "
"requested_length:%llu, padded_length: %llu, initial mapping: %p\n",
(unsigned long long)alignment, (unsigned long long)alignment_offset,
(unsigned long long)requested_length, (unsigned long long)padded_length,
(void*)unaligned);

if (!unaligned) {
return (void*)unaligned;
}

// Round up the next address that has addr % alignment = 0
const size_t alignment_corrected = alignment == 0 ? 1 : alignment;
uintptr_t aligned_nonoffset =
(unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1);

// Currently offset 0 is aligned according to alignment
// Alignment needs to be enforced at the given offset
uintptr_t aligned = 0;
if ((aligned_nonoffset - alignment_offset) >= unaligned) {
aligned = aligned_nonoffset - alignment_offset;
} else {
aligned = aligned_nonoffset - alignment_offset + alignment;
}

// Sanity check
if (aligned < unaligned ||
(aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) ||
(aligned + alignment_offset) % alignment_corrected != 0) {
VERBOSE_LOG("os_mmap_aligned: sanity check fail. aligned: %p\n",
(void*)aligned);
os_munmap((void*)unaligned, padded_length);
return NULL;
}

{
size_t unused_front = aligned - unaligned;
if (unused_front != 0) {
os_munmap((void*)unaligned, unused_front);
}
}

{
size_t unused_back =
(unaligned + (padded_length - 1)) - (aligned + (requested_length - 1));
if (unused_back != 0) {
os_munmap((void*)(aligned + requested_length), unused_back);
}
}

VERBOSE_LOG("os_mmap_aligned: final mapping: %p\n", (void*)aligned);
return (void*)aligned;
}

int os_mmap_commit(void* curr_heap_end_pointer,
size_t expanded_size,
int prot) {
return os_mprotect(curr_heap_end_pointer, expanded_size, prot);
}

void os_print_last_error(const char* msg) {
perror(msg);
}

#undef VERBOSE_LOG

#else
// https://stackoverflow.com/questions/26541150/warning-iso-c-forbids-an-empty-translation-unit
typedef int make_iso_compilers_happy;
#endif
Loading

0 comments on commit 9059009

Please sign in to comment.