Add Cosmopolitan Libc Platform (#2598)

This PR adds the Cosmopolitan Libc platform enabling compatibility with multiple
x86_64 operating systems with the same binary. The platform is similar to the
Linux platform, but for now only x86_64 with interpreter modes are supported.

The only major change to the core is `posix.c/convert_errno()` was rewritten to use
a switch statement. With Cosmopolitan errno values depend on the currently
running operating system, and so they are non-constant and cannot be used in array
designators. However, the `cosmocc` compiler allows non-constant case labels in
switch statements, enabling the new version.

And updated wamr-test-suites script to add `-j <platform>` option. The spec tests
can be ran via `CC=cosmocc ./test_wamr.sh -j cosmopolitan -t classic-interp`
or `CC=cosmocc ./test_wamr.sh -j cosmopolitan -t fast-interp`.
This commit is contained in:
Gavin Hayes 2023-10-04 09:55:37 -04:00 committed by GitHub
parent 8987432f36
commit d8ee771e28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 512 additions and 94 deletions

View File

@ -60,98 +60,99 @@ static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t),
static __wasi_errno_t
convert_errno(int error)
{
static const __wasi_errno_t errors[] = {
#define X(v) [v] = __WASI_##v
X(E2BIG),
X(EACCES),
X(EADDRINUSE),
X(EADDRNOTAVAIL),
X(EAFNOSUPPORT),
X(EAGAIN),
X(EALREADY),
X(EBADF),
X(EBADMSG),
X(EBUSY),
X(ECANCELED),
X(ECHILD),
X(ECONNABORTED),
X(ECONNREFUSED),
X(ECONNRESET),
X(EDEADLK),
X(EDESTADDRREQ),
X(EDOM),
X(EDQUOT),
X(EEXIST),
X(EFAULT),
X(EFBIG),
X(EHOSTUNREACH),
X(EIDRM),
X(EILSEQ),
X(EINPROGRESS),
X(EINTR),
X(EINVAL),
X(EIO),
X(EISCONN),
X(EISDIR),
X(ELOOP),
X(EMFILE),
X(EMLINK),
X(EMSGSIZE),
X(EMULTIHOP),
X(ENAMETOOLONG),
X(ENETDOWN),
X(ENETRESET),
X(ENETUNREACH),
X(ENFILE),
X(ENOBUFS),
X(ENODEV),
X(ENOENT),
X(ENOEXEC),
X(ENOLCK),
X(ENOLINK),
X(ENOMEM),
X(ENOMSG),
X(ENOPROTOOPT),
X(ENOSPC),
X(ENOSYS),
__wasi_errno_t code = __WASI_ENOSYS;
#define X(v) \
case v: \
code = __WASI_##v; \
break;
switch (error) {
X(E2BIG)
X(EACCES)
X(EADDRINUSE)
X(EADDRNOTAVAIL)
X(EAFNOSUPPORT)
X(EAGAIN)
X(EALREADY)
X(EBADF)
X(EBADMSG)
X(EBUSY)
X(ECANCELED)
X(ECHILD)
X(ECONNABORTED)
X(ECONNREFUSED)
X(ECONNRESET)
X(EDEADLK)
X(EDESTADDRREQ)
X(EDOM)
X(EDQUOT)
X(EEXIST)
X(EFAULT)
X(EFBIG)
X(EHOSTUNREACH)
X(EIDRM)
X(EILSEQ)
X(EINPROGRESS)
X(EINTR)
X(EINVAL)
X(EIO)
X(EISCONN)
X(EISDIR)
X(ELOOP)
X(EMFILE)
X(EMLINK)
X(EMSGSIZE)
X(EMULTIHOP)
X(ENAMETOOLONG)
X(ENETDOWN)
X(ENETRESET)
X(ENETUNREACH)
X(ENFILE)
X(ENOBUFS)
X(ENODEV)
X(ENOENT)
X(ENOEXEC)
X(ENOLCK)
X(ENOLINK)
X(ENOMEM)
X(ENOMSG)
X(ENOPROTOOPT)
X(ENOSPC)
X(ENOSYS)
#ifdef ENOTCAPABLE
X(ENOTCAPABLE),
X(ENOTCAPABLE)
#endif
X(ENOTCONN),
X(ENOTDIR),
X(ENOTEMPTY),
X(ENOTRECOVERABLE),
X(ENOTSOCK),
X(ENOTSUP),
X(ENOTTY),
X(ENXIO),
X(EOVERFLOW),
X(EOWNERDEAD),
X(EPERM),
X(EPIPE),
X(EPROTO),
X(EPROTONOSUPPORT),
X(EPROTOTYPE),
X(ERANGE),
X(EROFS),
X(ESPIPE),
X(ESRCH),
X(ESTALE),
X(ETIMEDOUT),
X(ETXTBSY),
X(EXDEV),
X(ENOTCONN)
X(ENOTDIR)
X(ENOTEMPTY)
X(ENOTRECOVERABLE)
X(ENOTSOCK)
X(ENOTSUP)
X(ENOTTY)
X(ENXIO)
X(EOVERFLOW)
X(EOWNERDEAD)
X(EPERM)
X(EPIPE)
X(EPROTO)
X(EPROTONOSUPPORT)
X(EPROTOTYPE)
X(ERANGE)
X(EROFS)
X(ESPIPE)
X(ESRCH)
X(ESTALE)
X(ETIMEDOUT)
X(ETXTBSY)
X(EXDEV)
default:
if (error == EOPNOTSUPP)
code = __WASI_ENOTSUP;
else if (code == EWOULDBLOCK)
code = __WASI_EAGAIN;
break;
}
#undef X
#if EOPNOTSUPP != ENOTSUP
[EOPNOTSUPP] = __WASI_ENOTSUP,
#endif
#if EWOULDBLOCK != EAGAIN
[EWOULDBLOCK] = __WASI_EAGAIN,
#endif
};
if (error < 0 || (size_t)error >= sizeof(errors) / sizeof(errors[0])
|| errors[error] == 0)
return __WASI_ENOSYS;
return errors[error];
return code;
}
static bool

View File

@ -65,7 +65,7 @@
#endif
#endif
#if !defined(__APPLE__) && !defined(ESP_PLATFORM)
#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__)
#define CONFIG_HAS_POSIX_FALLOCATE 1
#else
#define CONFIG_HAS_POSIX_FALLOCATE 0
@ -83,7 +83,8 @@
#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0
#endif
#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX)
#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) \
&& !defined(__COSMOPOLITAN__)
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
#else
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0

View File

@ -799,7 +799,7 @@ os_socket_set_ip_add_membership(bh_socket_t socket,
{
assert(imr_multiaddr);
if (is_ipv6) {
#ifdef IPPROTO_IPV6
#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN)
struct ipv6_mreq mreq;
for (int i = 0; i < 8; i++) {
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =
@ -837,7 +837,7 @@ os_socket_set_ip_drop_membership(bh_socket_t socket,
{
assert(imr_multiaddr);
if (is_ipv6) {
#ifdef IPPROTO_IPV6
#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN)
struct ipv6_mreq mreq;
for (int i = 0; i < 8; i++) {
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_vmcore.h"
int
bh_platform_init()
{
return 0;
}
void
bh_platform_destroy()
{}
int
os_printf(const char *format, ...)
{
int ret = 0;
va_list ap;
va_start(ap, format);
#ifndef BH_VPRINTF
ret += vprintf(format, ap);
#else
ret += BH_VPRINTF(format, ap);
#endif
va_end(ap);
return ret;
}
int
os_vprintf(const char *format, va_list ap)
{
#ifndef BH_VPRINTF
return vprintf(format, ap);
#else
return BH_VPRINTF(format, ap);
#endif
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* Copyright (C) 2023 Dylibso. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _PLATFORM_INTERNAL_H
#define _PLATFORM_INTERNAL_H
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sched.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BH_PLATFORM_COSMOPOLITAN
#define BH_PLATFORM_COSMOPOLITAN
#endif
/* Stack size of applet threads's native part. */
#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
typedef pthread_t korp_tid;
typedef pthread_mutex_t korp_mutex;
typedef pthread_cond_t korp_cond;
typedef pthread_t korp_thread;
typedef sem_t korp_sem;
#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define os_thread_local_attribute __thread
#define bh_socket_t int
#if WASM_DISABLE_WRITE_GS_BASE == 0
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#define os_writegsbase(base_addr) \
do { \
uint64 __gs_value = (uint64)(uintptr_t)base_addr; \
asm volatile("wrgsbase %0" ::"r"(__gs_value) : "memory"); \
} while (0)
#if 0
/* _writegsbase_u64 also works, but need to add -mfsgsbase flag for gcc */
#include <immintrin.h>
#define os_writegsbase(base_addr) \
_writegsbase_u64(((uint64)(uintptr_t)base_addr))
#endif
#endif
#endif
#if WASM_DISABLE_HW_BOUND_CHECK == 0
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \
|| defined(BUILD_TARGET_RISCV64_LP64)
#include <setjmp.h>
#define OS_ENABLE_HW_BOUND_CHECK
typedef jmp_buf korp_jmpbuf;
#define os_setjmp setjmp
#define os_longjmp longjmp
#define os_alloca alloca
#define os_getpagesize getpagesize
typedef void (*os_signal_handler)(void *sig_addr);
int
os_thread_signal_init(os_signal_handler handler);
void
os_thread_signal_destroy();
bool
os_thread_signal_inited();
void
os_signal_unmask();
void
os_sigreturn();
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64/RISCV64 */
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
#ifdef __cplusplus
}
#endif
#endif /* end of _PLATFORM_INTERNAL_H */

View File

@ -0,0 +1,19 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# Copyright (C) 2023 Dylibso. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions(-DBH_PLATFORM_COSMOPOLITAN)
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
include (${CMAKE_CURRENT_LIST_DIR}/../common/posix/platform_api_posix.cmake)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_POSIX_SOURCE})
file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h)
LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header})

View File

@ -443,3 +443,23 @@ make
aos make
```
download the binary to developerkit board, check the output from serial port
## Cosmopolitan Libc
Currently, only x86_64 architecture with interpreter modes is supported.
Clone the Cosmopolitan Libc. Setup `cosmocc` as described in [Getting Started](https://github.com/jart/cosmopolitan/#getting-started) being sure to get it into `PATH`.
Build iwasm
``` Bash
export CC=cosmocc
export CXX=cosmoc++
rm -rf build
mkdir build
cmake -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=1 -B build
cmake --build build -j
```
Run like
``` Bash
./build/iwasm.com <wasm file>
```

View File

@ -0,0 +1,175 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# Copyright (C) 2023 Dylibso. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
include(CheckPIESupported)
project (iwasm)
set (CMAKE_VERBOSE_MAKEFILE OFF)
set (WAMR_BUILD_PLATFORM "cosmopolitan")
set(CMAKE_EXECUTABLE_SUFFIX ".com")
# Reset default linker flags
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
set (CMAKE_C_STANDARD 99)
set (CMAKE_CXX_STANDARD 17)
# Set WAMR_BUILD_TARGET, currently values supported:
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
if (NOT DEFINED WAMR_BUILD_TARGET)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
set (WAMR_BUILD_TARGET "AARCH64")
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
set (WAMR_BUILD_TARGET "RISCV64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
# Build as X86_64 by default in 64-bit platform
set (WAMR_BUILD_TARGET "X86_64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
# Build as X86_32 by default in 32-bit platform
set (WAMR_BUILD_TARGET "X86_32")
else ()
message(SEND_ERROR "Unsupported build target platform!")
endif ()
endif ()
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
if (NOT DEFINED WAMR_BUILD_INTERP)
# Enable Interpreter by default
set (WAMR_BUILD_INTERP 1)
endif ()
if (NOT DEFINED WAMR_BUILD_AOT)
# Enable AOT by default.
set (WAMR_BUILD_AOT 1)
endif ()
if (NOT DEFINED WAMR_BUILD_JIT)
# Disable JIT by default.
set (WAMR_BUILD_JIT 0)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_JIT)
# Disable Fast JIT by default
set (WAMR_BUILD_FAST_JIT 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
# Enable libc builtin support by default
set (WAMR_BUILD_LIBC_BUILTIN 1)
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
# Enable libc wasi support by default
set (WAMR_BUILD_LIBC_WASI 1)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
# Enable fast interpreter
set (WAMR_BUILD_FAST_INTERP 1)
endif ()
if (NOT DEFINED WAMR_BUILD_MULTI_MODULE)
# Disable multiple modules by default
set (WAMR_BUILD_MULTI_MODULE 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD)
# Disable pthread library by default
set (WAMR_BUILD_LIB_PTHREAD 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
# Disable wasi threads library by default
set (WAMR_BUILD_LIB_WASI_THREADS 0)
endif()
if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
# Disable wasm mini loader by default
set (WAMR_BUILD_MINI_LOADER 0)
endif ()
if (NOT DEFINED WAMR_BUILD_SIMD)
# Enable SIMD by default
set (WAMR_BUILD_SIMD 1)
endif ()
if (NOT DEFINED WAMR_BUILD_REF_TYPES)
# Disable reference types by default
set (WAMR_BUILD_REF_TYPES 0)
endif ()
if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP)
# Disable Debug feature by default
set (WAMR_BUILD_DEBUG_INTERP 0)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_FAST_INTERP 0)
set (WAMR_BUILD_MINI_LOADER 0)
set (WAMR_BUILD_SIMD 0)
endif ()
set (WAMR_DISABLE_STACK_HW_BOUND_CHECK 1)
set (WAMR_BUILD_AOT 0)
set (WAMR_DISABLE_WRITE_GS_BASE 1)
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
check_pie_supported()
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
set_target_properties (vmlib PROPERTIES POSITION_INDEPENDENT_CODE ON)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow")
# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused")
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mindirect-branch-register")
# UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub
endif ()
endif ()
# The following flags are to enhance security, but it may impact performance,
# we disable them by default.
#if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftrapv -D_FORTIFY_SOURCE=2")
#endif ()
#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4")
#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now")
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE})
set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON)
install (TARGETS iwasm DESTINATION bin)
target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} ${WASI_NN_LIBS} -lm -ldl -lpthread)
add_library (libiwasm STATIC ${WAMR_RUNTIME_LIB_SOURCE})
install (TARGETS libiwasm DESTINATION lib)
set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm)
target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} ${WASI_NN_LIBS} -lm -ldl -lpthread)

View File

@ -0,0 +1,10 @@
#!/bin/sh
# Copyright (C) 2023 Dylibso. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
export CC=cosmocc
export CXX=cosmoc++
rm -rf build
mkdir build
cmake -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=1 -B build
cmake --build build -j

View File

@ -0,0 +1,6 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "../posix/main.c"

View File

@ -31,6 +31,7 @@ function help()
echo "-Q enable qemu"
echo "-F set the firmware path used by qemu"
echo "-C enable code coverage collect"
echo "-j set the platform to test"
}
OPT_PARSED=""
@ -58,7 +59,7 @@ QEMU_FIRMWARE=""
# prod/testsuite-all branch
WASI_TESTSUITE_COMMIT="cf64229727f71043d5849e73934e249e12cb9e06"
while getopts ":s:cabgvt:m:MCpSXxwPGQF:" opt
while getopts ":s:cabgvt:m:MCpSXxwPGQF:j:" opt
do
OPT_PARSED="TRUE"
case $opt in
@ -160,6 +161,10 @@ do
echo "QEMU firmware" ${OPTARG}
QEMU_FIRMWARE=${OPTARG}
;;
j)
echo "test platform " ${OPTARG}
PLATFORM=${OPTARG}
;;
?)
help
exit 1;;
@ -383,6 +388,8 @@ function spec_test()
local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm
if [ ! -f ${WAT2WASM} ]; then
case ${PLATFORM} in
cosmopolitan)
;&
linux)
WABT_PLATFORM=ubuntu
;;
@ -656,6 +663,20 @@ function build_iwasm_with_cfg()
echo -e "build iwasm failed"
exit 1
fi
if [[ ${PLATFORM} == "cosmopolitan" ]]; then
# convert from APE to ELF so it can be ran easier
# HACK: link to linux so tests work when platform is detected by uname
cp iwasm.com iwasm \
&& ./iwasm --assimilate \
&& rm -rf ../../linux/build \
&& mkdir ../../linux/build \
&& ln -s ../../cosmopolitan/build/iwasm ../../linux/build/iwasm
if [ "$?" != 0 ];then
echo -e "build iwasm failed (cosmopolitan)"
exit 1
fi
fi
}
function build_wamrc()