- name: Install clang (Windows)
shell: bash
run: |
- curl -fsSLO https://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe
- 7z x LLVM-9.0.0-win64.exe -y -o"llvm"
+ curl -fsSLO https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe
+ 7z x LLVM-10.0.0-win64.exe -y -o"llvm"
echo "::add-path::$(pwd)/llvm/bin"
echo "::set-env name=WASM_AR::$(pwd)/llvm/bin/llvm-ar.exe"
if: matrix.os == 'windows-latest'
- name: Install clang (MacOS)
shell: bash
run: |
- curl -sSf http://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-darwin-apple.tar.xz | tar xJf -
- export CLANG_DIR=`pwd`/clang+llvm-9.0.0-x86_64-darwin-apple/bin
+ curl -sSfL https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-apple-darwin.tar.xz | tar xJf -
+ export CLANG_DIR=`pwd`/clang+llvm-10.0.0-x86_64-apple-darwin/bin
echo "::add-path::$CLANG_DIR"
echo "::set-env name=WASM_CC::$CLANG_DIR/clang"
if: matrix.os == 'macos-latest'
- name: Install clang (Linux)
shell: bash
run: |
- curl -sSf https://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJf -
- export CLANG_DIR=`pwd`/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/bin
+ curl -sSfL https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | tar xJf -
+ export CLANG_DIR=`pwd`/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin
echo "::add-path::$CLANG_DIR"
echo "::set-env name=WASM_CC::$CLANG_DIR/clang"
if: matrix.os == 'ubuntu-latest'
dlmalloc/ - CC0; see the notice in malloc.c for details
libc-bottom-half/cloudlibc/ - BSD-2-Clause; see the LICENSE file for details
-libc-bottom-half/libpreopen/ - BSD-2-Clause; see the notice in libpreopen.c for details
libc-top-half/musl/ - MIT; see the COPYRIGHT file for details
wasi-libc's changes to these files are multi-licensed under the
-# These variables are specifically meant to be overridable via
-# the make command-line.
+# These variables are specifically meant to be overridable via the make
+# command-line.
WASM_CC ?= clang
WASM_NM ?= $(patsubst %clang,%llvm-nm,$(WASM_CC))
WASM_AR ?= $(patsubst %clang,%llvm-ar,$(WASM_CC))
# A directory to install to for "make install".
INSTALL_DIR ?= /usr/local
# single or posix
-THREAD_MODEL = single
+THREAD_MODEL ?= single
# yes or no
-BUILD_DLMALLOC = yes
-BUILD_LIBC_BOTTOM_HALF = yes
-BUILD_LIBC_TOP_HALF = yes
+BUILD_DLMALLOC ?= yes
+BUILD_LIBC_TOP_HALF ?= yes
# The directory where we're store intermediate artifacts.
-OBJDIR = $(CURDIR)/build
+OBJDIR ?= $(CURDIR)/build
# Check dependencies.
-ifeq ($(BUILD_LIBC_TOP_HALF),yes)
-ifneq ($(BUILD_LIBC_BOTTOM_HALF),yes)
-$(error BUILD_LIBC_TOP_HALF=yes depends on BUILD_LIBC_BOTTOM_HALF=yes)
-endif
-endif
-ifeq ($(BUILD_LIBC_BOTTOM_HALF),yes)
ifneq ($(BUILD_DLMALLOC),yes)
-$(error BUILD_LIBC_BOTTOM_HALF=yes depends on BUILD_DLMALLOC=yes)
-endif
+$(error build currently depends on BUILD_DLMALLOC=yes)
endif
-# These variables describe the locations of various files and
-# directories in the source tree.
-BASICS_DIR = $(CURDIR)/basics
-BASICS_INC = $(BASICS_DIR)/include
-BASICS_CRT_SOURCES = $(wildcard $(BASICS_DIR)/crt/*.c)
-BASICS_SOURCES = \
- $(wildcard $(BASICS_DIR)/sources/*.c) \
- $(wildcard $(BASICS_DIR)/sources/math/*.c)
+# Variables from this point on are not meant to be overridable via the
+# make command-line.
+
+# Set the target variables. Multiarch triples notably omit the vendor field,
+# which happens to be what we do for the main target triple too.
+TARGET_TRIPLE = wasm32-wasi
+MULTIARCH_TRIPLE = wasm32-wasi
+
+# These variables describe the locations of various files and directories in
+# the source tree.
DLMALLOC_DIR = $(CURDIR)/dlmalloc
DLMALLOC_SRC_DIR = $(DLMALLOC_DIR)/src
DLMALLOC_SOURCES = $(DLMALLOC_SRC_DIR)/dlmalloc.c
LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include
LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public
LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private
-LIBC_BOTTOM_HALF_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen
LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources
LIBC_BOTTOM_HALF_ALL_SOURCES = \
$(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \
- $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/libpreopen.c \
$(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c)
LIBWASI_EMULATED_MMAN_SOURCES = \
$(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c)
+LIBWASI_EMULATED_SIGNAL_SOURCES = \
+ $(shell find $(LIBC_BOTTOM_HALF_DIR)/signal -name \*.c)
+LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES = \
+ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/signal/psignal.c \
+ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/strsignal.c
LIBC_BOTTOM_HALF_CRT_SOURCES = $(wildcard $(LIBC_BOTTOM_HALF_DIR)/crt/*.c)
LIBC_TOP_HALF_DIR = $(CURDIR)/libc-top-half
LIBC_TOP_HALF_MUSL_DIR = $(LIBC_TOP_HALF_DIR)/musl
LIBC_TOP_HALF_MUSL_SRC_DIR = $(LIBC_TOP_HALF_MUSL_DIR)/src
LIBC_TOP_HALF_MUSL_INC = $(LIBC_TOP_HALF_MUSL_DIR)/include
LIBC_TOP_HALF_MUSL_SOURCES = \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/a64l.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/basename.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/dirname.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffs.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffsl.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffsll.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/fmtmsg.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getdomainname.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/gethostid.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getopt.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getopt_long.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getsubopt.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/uname.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/nftw.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/errno/strerror.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/htonl.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/htons.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/ntohl.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/ntohs.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_ntop.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_pton.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_aton.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/in6addr_any.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/in6addr_loopback.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fesetround.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/feupdateenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fesetexceptflag.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fegetexceptflag.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/feholdexcept.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/exit.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/atexit.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/assert.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/quick_exit.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/at_quick_exit.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/strftime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/asctime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/asctime_r.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ctime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ctime_r.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/wcsftime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/strptime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/difftime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/timegm.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ftime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/gmtime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/gmtime_r.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/timespec_get.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/getdate.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/localtime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/localtime_r.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/mktime.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__tm_to_secs.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__month_to_secs.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__secs_to_tm.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__year_to_secs.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__tz.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fcntl/creat.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/alphasort.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/versionsort.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/clearenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/getenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/putenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/setenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/unsetenv.c \
- $(LIBC_TOP_HALF_MUSL_SRC_DIR)/unistd/posix_close.c \
+ $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \
+ misc/a64l.c \
+ misc/basename.c \
+ misc/dirname.c \
+ misc/ffs.c \
+ misc/ffsl.c \
+ misc/ffsll.c \
+ misc/fmtmsg.c \
+ misc/getdomainname.c \
+ misc/gethostid.c \
+ misc/getopt.c \
+ misc/getopt_long.c \
+ misc/getsubopt.c \
+ misc/uname.c \
+ misc/nftw.c \
+ errno/strerror.c \
+ network/htonl.c \
+ network/htons.c \
+ network/ntohl.c \
+ network/ntohs.c \
+ network/inet_ntop.c \
+ network/inet_pton.c \
+ network/inet_aton.c \
+ network/in6addr_any.c \
+ network/in6addr_loopback.c \
+ fenv/fenv.c \
+ fenv/fesetround.c \
+ fenv/feupdateenv.c \
+ fenv/fesetexceptflag.c \
+ fenv/fegetexceptflag.c \
+ fenv/feholdexcept.c \
+ exit/exit.c \
+ exit/atexit.c \
+ exit/assert.c \
+ exit/quick_exit.c \
+ exit/at_quick_exit.c \
+ time/strftime.c \
+ time/asctime.c \
+ time/asctime_r.c \
+ time/ctime.c \
+ time/ctime_r.c \
+ time/wcsftime.c \
+ time/strptime.c \
+ time/difftime.c \
+ time/timegm.c \
+ time/ftime.c \
+ time/gmtime.c \
+ time/gmtime_r.c \
+ time/timespec_get.c \
+ time/getdate.c \
+ time/localtime.c \
+ time/localtime_r.c \
+ time/mktime.c \
+ time/__tm_to_secs.c \
+ time/__month_to_secs.c \
+ time/__secs_to_tm.c \
+ time/__year_to_secs.c \
+ time/__tz.c \
+ fcntl/creat.c \
+ dirent/alphasort.c \
+ dirent/versionsort.c \
+ env/clearenv.c \
+ env/getenv.c \
+ env/putenv.c \
+ env/setenv.c \
+ env/unsetenv.c \
+ unistd/posix_close.c \
+ ) \
$(filter-out %/procfdname.c %/syscall.c %/syscall_ret.c %/vdso.c %/version.c, \
$(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/*.c)) \
$(filter-out %/flockfile.c %/funlockfile.c %/__lockfile.c %/ftrylockfile.c \
$(LIBC_TOP_HALF_MUSL_SOURCES) \
$(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.c)
-# Set the target variables. Multiarch triples notably omit the vendor
-# field, which happens to be what we do for the main target triple too.
-TARGET_TRIPLE = wasm32-wasi
-MULTIARCH_TRIPLE = wasm32-wasi
-
-# These variables describe the locations of various files and
-# directories in the generated sysroot tree.
-SYSROOT_LIB = $(SYSROOT)/lib/$(MULTIARCH_TRIPLE)
-SYSROOT_INC = $(SYSROOT)/include
-SYSROOT_SHARE = $(SYSROOT)/share/$(MULTIARCH_TRIPLE)
-
# Set the target.
-override WASM_CFLAGS += --target=$(TARGET_TRIPLE)
+WASM_CFLAGS += --target=$(TARGET_TRIPLE)
# WebAssembly floating-point match doesn't trap.
# TODO: Add -fno-signaling-nans when the compiler supports it.
-override WASM_CFLAGS += -fno-trapping-math
+WASM_CFLAGS += -fno-trapping-math
# Configure support for threads.
ifeq ($(THREAD_MODEL), single)
-override WASM_CFLAGS += -mthread-model single
+WASM_CFLAGS += -mthread-model single
endif
ifeq ($(THREAD_MODEL), posix)
-override WASM_CFLAGS += -mthread-model posix -pthread
+WASM_CFLAGS += -mthread-model posix -pthread
endif
# Set the sysroot.
-override WASM_CFLAGS += --sysroot="$(SYSROOT)"
+WASM_CFLAGS += --sysroot="$(SYSROOT)"
+# These variables describe the locations of various files and directories in
+# the build tree.
objs = $(patsubst $(CURDIR)/%.c,$(OBJDIR)/%.o,$(1))
-override BASICS_OBJS = $(call objs,$(BASICS_SOURCES))
-override DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES))
-override LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES))
-override LIBC_TOP_HALF_ALL_OBJS = $(call objs,$(LIBC_TOP_HALF_ALL_SOURCES))
-override LIBC_OBJS := $(BASICS_OBJS)
+DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES))
+LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES))
+LIBC_TOP_HALF_ALL_OBJS = $(call objs,$(LIBC_TOP_HALF_ALL_SOURCES))
ifeq ($(BUILD_DLMALLOC),yes)
-override LIBC_OBJS += $(DLMALLOC_OBJS)
+LIBC_OBJS += $(DLMALLOC_OBJS)
endif
-ifeq ($(BUILD_LIBC_BOTTOM_HALF),yes)
-# Override basics' string.o with libc-bottom-half's.
-override LIBC_OBJS := $(filter-out %/string.o,$(LIBC_OBJS))
# Add libc-bottom-half's objects.
-override LIBC_OBJS += $(LIBC_BOTTOM_HALF_ALL_OBJS)
-endif
+LIBC_OBJS += $(LIBC_BOTTOM_HALF_ALL_OBJS)
ifeq ($(BUILD_LIBC_TOP_HALF),yes)
-# Override libc-bottom-half's string.o with libc-top-half's.
-override LIBC_OBJS := $(filter-out %/string.o,$(LIBC_OBJS))
-# Override libc-bottom-half's qsort.o with libc-top-half's.
-override LIBC_OBJS := $(filter-out %/qsort.o,$(LIBC_OBJS))
# libc-top-half is musl.
-override LIBC_OBJS += $(LIBC_TOP_HALF_ALL_OBJS)
+LIBC_OBJS += $(LIBC_TOP_HALF_ALL_OBJS)
endif
-override MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES))
-override MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS))
-override MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS))
-override LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES))
+MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES))
+MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS))
+MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS))
+LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES))
+LIBWASI_EMULATED_SIGNAL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_SOURCES))
+LIBWASI_EMULATED_SIGNAL_MUSL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES))
+
+# These variables describe the locations of various files and
+# directories in the generated sysroot tree.
+SYSROOT_LIB := $(SYSROOT)/lib/$(MULTIARCH_TRIPLE)
+SYSROOT_INC = $(SYSROOT)/include
+SYSROOT_SHARE = $(SYSROOT)/share/$(MULTIARCH_TRIPLE)
# Files from musl's include directory that we don't want to install in the
# sysroot's include directory.
-override MUSL_OMIT_HEADERS :=
+MUSL_OMIT_HEADERS :=
# Remove files which aren't headers (we generate alltypes.h below).
-override MUSL_OMIT_HEADERS += \
+MUSL_OMIT_HEADERS += \
"bits/syscall.h.in" \
"bits/alltypes.h.in" \
"alltypes.h.in"
# Use the compiler's version of these headers.
-override MUSL_OMIT_HEADERS += \
+MUSL_OMIT_HEADERS += \
"stdarg.h" \
"stddef.h"
# Use the WASI errno definitions.
-override MUSL_OMIT_HEADERS += \
+MUSL_OMIT_HEADERS += \
"bits/errno.h"
# Remove headers that aren't supported yet or that aren't relevant for WASI.
-override MUSL_OMIT_HEADERS += \
+MUSL_OMIT_HEADERS += \
"sys/procfs.h" \
"sys/user.h" \
"sys/kd.h" "sys/vt.h" "sys/soundcard.h" "sys/sem.h" \
"netinet/ether.h" \
"sys/timerfd.h" \
"libintl.h" \
- "sys/sysmacros.h" \
- "utime.h"
+ "sys/sysmacros.h"
ifeq ($(THREAD_MODEL), single)
# Remove headers not supported in single-threaded mode.
-override MUSL_OMIT_HEADERS += "aio.h" "pthread.h"
+MUSL_OMIT_HEADERS += "aio.h" "pthread.h"
endif
-default: check
+default: finish
$(SYSROOT_LIB)/libc.a: $(LIBC_OBJS)
$(SYSROOT_LIB)/libwasi-emulated-mman.a: $(LIBWASI_EMULATED_MMAN_OBJS)
+$(SYSROOT_LIB)/libwasi-emulated-signal.a: $(LIBWASI_EMULATED_SIGNAL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS)
+
%.a:
@mkdir -p "$(@D)"
# On Windows, the commandline for the ar invocation got too long, so it needs to be split up.
# silently dropping the tail.
$(WASM_AR) crs $@ $(wordlist 800, 100000, $^)
-$(MUSL_PRINTSCAN_OBJS): override WASM_CFLAGS += \
+$(MUSL_PRINTSCAN_OBJS): WASM_CFLAGS += \
-D__wasilibc_printscan_no_long_double \
-D__wasilibc_printscan_full_support_option="\"add -lc-printscan-long-double to the link command\""
-$(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_CFLAGS += \
+$(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): WASM_CFLAGS += \
-D__wasilibc_printscan_no_floating_point \
-D__wasilibc_printscan_floating_point_support_option="\"remove -lc-printscan-no-floating-point from the link command\""
+$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS): WASM_CFLAGS += \
+ -D_WASI_EMULATED_SIGNAL
+
$(OBJDIR)/%.long-double.o: $(CURDIR)/%.c include_dirs
@mkdir -p "$(@D)"
"$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $<
-include $(shell find $(OBJDIR) -name \*.d)
-$(DLMALLOC_OBJS): override WASM_CFLAGS += \
+$(DLMALLOC_OBJS): WASM_CFLAGS += \
-I$(DLMALLOC_INC)
-startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \
+startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): WASM_CFLAGS += \
-I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)
-$(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_CFLAGS += \
+$(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS): WASM_CFLAGS += \
-I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \
-I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal \
-I$(LIBC_TOP_HALF_MUSL_DIR)/arch/wasm32 \
# Install the include files.
#
mkdir -p "$(SYSROOT_INC)"
- cp -r "$(BASICS_INC)" "$(SYSROOT)"
cp -r "$(LIBC_BOTTOM_HALF_HEADERS_PUBLIC)"/* "$(SYSROOT_INC)"
# Generate musl's bits/alltypes.h header.
# Remove selected header files.
$(RM) $(patsubst %,$(SYSROOT_INC)/%,$(MUSL_OMIT_HEADERS))
-ifeq ($(BUILD_LIBC_BOTTOM_HALF),no)
-override CRT_SOURCES = $(BASICS_CRT_SOURCES)
-else
-override CRT_SOURCES = $(LIBC_BOTTOM_HALF_CRT_SOURCES)
-endif
-
startup_files: include_dirs
#
# Build the startup files.
#
@mkdir -p "$(OBJDIR)"
cd "$(OBJDIR)" && \
- "$(WASM_CC)" $(WASM_CFLAGS) -c $(CRT_SOURCES) -MD -MP && \
+ "$(WASM_CC)" $(WASM_CFLAGS) -c $(LIBC_BOTTOM_HALF_CRT_SOURCES) -MD -MP && \
mkdir -p "$(SYSROOT_LIB)" && \
mv *.o "$(SYSROOT_LIB)"
$(SYSROOT_LIB)/libc.a \
$(SYSROOT_LIB)/libc-printscan-long-double.a \
$(SYSROOT_LIB)/libc-printscan-no-floating-point.a \
- $(SYSROOT_LIB)/libwasi-emulated-mman.a
+ $(SYSROOT_LIB)/libwasi-emulated-mman.a \
+ $(SYSROOT_LIB)/libwasi-emulated-signal.a
finish: startup_files libc
#
#
mkdir -p "$(SYSROOT_SHARE)"
+ #
# Collect symbol information.
- # TODO: Use llvm-nm --extern-only instead of grep. This is blocked on
- # LLVM PR40497, which is fixed in 9.0, but not in 8.0.
- # Ignore certain llvm builtin symbols such as those starting with __mul
- # since these dependencies can vary between llvm versions.
+ #
+ @# TODO: Use llvm-nm --extern-only instead of grep. This is blocked on
+ @# LLVM PR40497, which is fixed in 9.0, but not in 8.0.
+ @# Ignore certain llvm builtin symbols such as those starting with __mul
+ @# since these dependencies can vary between llvm versions.
"$(WASM_NM)" --defined-only "$(SYSROOT_LIB)"/libc.a "$(SYSROOT_LIB)"/*.o \
|grep ' [[:upper:]] ' |sed 's/.* [[:upper:]] //' |LC_ALL=C sort > "$(SYSROOT_SHARE)/defined-symbols.txt"
- for undef_sym in $$("$(WASM_NM)" --undefined-only "$(SYSROOT_LIB)"/*.a "$(SYSROOT_LIB)"/*.o \
+ for undef_sym in $$("$(WASM_NM)" --undefined-only "$(SYSROOT_LIB)"/libc.a "$(SYSROOT_LIB)"/libc-*.a "$(SYSROOT_LIB)"/*.o \
|grep ' U ' |sed 's/.* U //' |LC_ALL=C sort |uniq); do \
grep -q '\<'$$undef_sym'\>' "$(SYSROOT_SHARE)/defined-symbols.txt" || echo $$undef_sym; \
done | grep -v "^__mul" > "$(SYSROOT_SHARE)/undefined-symbols.txt"
grep '^_*wasi_' "$(SYSROOT_SHARE)/undefined-symbols.txt" \
> "$(SYSROOT_LIB)/libc.imports"
+ #
# Generate a test file that includes all public header files.
+ #
cd "$(SYSROOT)" && \
- for header in $$(find include -type f -not -name mman.h |grep -v /bits/); do \
- echo '#include <'$$header'>' | sed 's/include\///' ; \
+ for header in $$(find include -type f -not -name mman.h -not -name signal.h |grep -v /bits/); do \
+ echo '#include <'$$header'>' | sed 's/include\///' ; \
done |LC_ALL=C sort >share/$(MULTIARCH_TRIPLE)/include-all.c ; \
cd - >/dev/null
+ #
# Test that it compiles.
+ #
"$(WASM_CC)" $(WASM_CFLAGS) -fsyntax-only "$(SYSROOT_SHARE)/include-all.c" -Wno-\#warnings
- # Collect all the predefined macros, except for compiler version macros
- # which we don't need to track here. For the __*_ATOMIC_*_LOCK_FREE
- # macros, squash individual compiler names to attempt, toward keeping
- # these files compiler-independent.
#
- # We have to add `-isystem $(SYSROOT_INC)` because otherwise clang puts
- # its builtin include path first, which produces compiler-specific
- # output.
+ # Collect all the predefined macros, except for compiler version macros
+ # which we don't need to track here.
#
- # TODO: Undefine __FLOAT128__ for now since it's not in clang 8.0.
- # TODO: Filter out __FLT16_* for now, as not all versions of clang have these.
+ @#
+ @# For the __*_ATOMIC_*_LOCK_FREE macros, squash individual compiler names
+ @# to attempt, toward keeping these files compiler-independent.
+ @#
+ @# We have to add `-isystem $(SYSROOT_INC)` because otherwise clang puts
+ @# its builtin include path first, which produces compiler-specific
+ @# output.
+ @#
+ @# TODO: Undefine __FLOAT128__ for now since it's not in clang 8.0.
+ @# TODO: Filter out __FLT16_* for now, as not all versions of clang have these.
"$(WASM_CC)" $(WASM_CFLAGS) "$(SYSROOT_SHARE)/include-all.c" \
-isystem $(SYSROOT_INC) \
-std=gnu17 \
| grep -v '^#define __FLT16_' \
> "$(SYSROOT_SHARE)/predefined-macros.txt"
- #
- # The build succeeded! The generated sysroot is in $(SYSROOT).
- #
-
-check: finish
# Check that the computed metadata matches the expected metadata.
# This ignores whitespace because on Windows the output has CRLF line endings.
diff -wur "$(CURDIR)/expected/$(MULTIARCH_TRIPLE)" "$(SYSROOT_SHARE)"
+ #
+ # The build succeeded! The generated sysroot is in $(SYSROOT).
+ #
+
install: finish
mkdir -p "$(INSTALL_DIR)"
cp -r "$(SYSROOT)/lib" "$(SYSROOT)/share" "$(SYSROOT)/include" "$(INSTALL_DIR)"
-.PHONY: default startup_files libc finish check install include_dirs
+.PHONY: default startup_files libc finish install include_dirs
+++ /dev/null
-extern void __wasm_call_ctors(void);
-extern int __original_main(void);
-extern void __prepare_for_exit(void);
-void _Exit(int) __attribute__((noreturn));
-
-void _start(void) {
- // The linker synthesizes this to call constructors.
- __wasm_call_ctors();
-
- // Call `__original_main` which will either be the application's zero-argument
- // `__original_main` function or a libc routine which calls `__main_void`.
- // TODO: Call `main` directly once we no longer have to support old compilers.
- int r = __original_main();
-
- // Call atexit functions, destructors, stdio cleanup, etc.
- __prepare_for_exit();
-
- // If main exited successfully, just return, otherwise call _Exit.
- if (r != 0) {
- _Exit(r);
- }
-}
+++ /dev/null
-#ifndef __wasm_basics___errno_h
-#define __wasm_basics___errno_h
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-extern thread_local int errno;
-#else
-extern _Thread_local int errno;
-#endif
-
-#define errno errno
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___functions_malloc_h
-#define __wasm_basics___functions_malloc_h
-
-#define __need_size_t
-#define __need_wchar_t
-#define __need_NULL
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void *malloc(size_t __size) __attribute__((__malloc__, __warn_unused_result__));
-void free(void *__ptr);
-void *calloc(size_t __nmemb, size_t __size) __attribute__((__malloc__, __warn_unused_result__));
-void *realloc(void *__ptr, size_t __size) __attribute__((__warn_unused_result__));
-
-#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-void *reallocarray(void *__ptr, size_t __nmemb, size_t __size) __attribute__((__warn_unused_result__));
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___functions_memcpy_h
-#define __wasm_basics___functions_memcpy_h
-
-#define __need_size_t
-#define __need_NULL
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void *memcpy(void *__restrict__ __dst, const void *__restrict__ __src, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1, 2)));
-void *memmove(void *__dst, const void *__src, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1, 2)));
-void *memset(void *__dst, int __c, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1)));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___include_inttypes_h
-#define __wasm_basics___include_inttypes_h
-
-#include <stdint.h>
-
-#define __need_wchar_t
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct { intmax_t quot, rem; } imaxdiv_t;
-
-intmax_t imaxabs(intmax_t);
-imaxdiv_t imaxdiv(intmax_t, intmax_t);
-intmax_t strtoimax(const char *__restrict, char **__restrict, int);
-uintmax_t strtoumax(const char *__restrict, char **__restrict, int);
-intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int);
-uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
-
-#define PRId16 __INT16_FMTd__
-#define PRIi16 __INT16_FMTi__
-#define PRId32 __INT32_FMTd__
-#define PRIi32 __INT32_FMTi__
-#define PRId64 __INT64_FMTd__
-#define PRIi64 __INT64_FMTi__
-#define PRId8 __INT8_FMTd__
-#define PRIi8 __INT8_FMTi__
-#define PRIdMAX __INTMAX_FMTd__
-#define PRIiMAX __INTMAX_FMTi__
-#define PRIdPTR __INTPTR_FMTd__
-#define PRIiPTR __INTPTR_FMTi__
-#define PRIdFAST16 __INT_FAST16_FMTd__
-#define PRIiFAST16 __INT_FAST16_FMTi__
-#define PRIdFAST32 __INT_FAST32_FMTd__
-#define PRIiFAST32 __INT_FAST32_FMTi__
-#define PRIdFAST64 __INT_FAST64_FMTd__
-#define PRIiFAST64 __INT_FAST64_FMTi__
-#define PRIdFAST8 __INT_FAST8_FMTd__
-#define PRIiFAST8 __INT_FAST8_FMTi__
-#define PRIdLEAST16 __INT_LEAST16_FMTd__
-#define PRIiLEAST16 __INT_LEAST16_FMTi__
-#define PRIdLEAST32 __INT_LEAST32_FMTd__
-#define PRIiLEAST32 __INT_LEAST32_FMTi__
-#define PRIdLEAST64 __INT_LEAST64_FMTd__
-#define PRIiLEAST64 __INT_LEAST64_FMTi__
-#define PRIdLEAST8 __INT_LEAST8_FMTd__
-#define PRIiLEAST8 __INT_LEAST8_FMTi__
-#define PRIX16 __UINT16_FMTX__
-#define PRIo16 __UINT16_FMTo__
-#define PRIu16 __UINT16_FMTu__
-#define PRIx16 __UINT16_FMTx__
-#define PRIX32 __UINT32_FMTX__
-#define PRIo32 __UINT32_FMTo__
-#define PRIu32 __UINT32_FMTu__
-#define PRIx32 __UINT32_FMTx__
-#define PRIX64 __UINT64_FMTX__
-#define PRIo64 __UINT64_FMTo__
-#define PRIu64 __UINT64_FMTu__
-#define PRIx64 __UINT64_FMTx__
-#define PRIX8 __UINT8_FMTX__
-#define PRIo8 __UINT8_FMTo__
-#define PRIu8 __UINT8_FMTu__
-#define PRIx8 __UINT8_FMTx__
-#define PRIXMAX __UINTMAX_FMTX__
-#define PRIoMAX __UINTMAX_FMTo__
-#define PRIuMAX __UINTMAX_FMTu__
-#define PRIxMAX __UINTMAX_FMTx__
-#define PRIXPTR __UINTPTR_FMTX__
-#define PRIoPTR __UINTPTR_FMTo__
-#define PRIuPTR __UINTPTR_FMTu__
-#define PRIxPTR __UINTPTR_FMTx__
-#define PRIXFAST16 __UINT_FAST16_FMTX__
-#define PRIoFAST16 __UINT_FAST16_FMTo__
-#define PRIuFAST16 __UINT_FAST16_FMTu__
-#define PRIxFAST16 __UINT_FAST16_FMTx__
-#define PRIXFAST32 __UINT_FAST32_FMTX__
-#define PRIoFAST32 __UINT_FAST32_FMTo__
-#define PRIuFAST32 __UINT_FAST32_FMTu__
-#define PRIxFAST32 __UINT_FAST32_FMTx__
-#define PRIXFAST64 __UINT_FAST64_FMTX__
-#define PRIoFAST64 __UINT_FAST64_FMTo__
-#define PRIuFAST64 __UINT_FAST64_FMTu__
-#define PRIxFAST64 __UINT_FAST64_FMTx__
-#define PRIXFAST8 __UINT_FAST8_FMTX__
-#define PRIoFAST8 __UINT_FAST8_FMTo__
-#define PRIuFAST8 __UINT_FAST8_FMTu__
-#define PRIxFAST8 __UINT_FAST8_FMTx__
-#define PRIXLEAST16 __UINT_LEAST16_FMTX__
-#define PRIoLEAST16 __UINT_LEAST16_FMTo__
-#define PRIuLEAST16 __UINT_LEAST16_FMTu__
-#define PRIxLEAST16 __UINT_LEAST16_FMTx__
-#define PRIXLEAST32 __UINT_LEAST32_FMTX__
-#define PRIoLEAST32 __UINT_LEAST32_FMTo__
-#define PRIuLEAST32 __UINT_LEAST32_FMTu__
-#define PRIxLEAST32 __UINT_LEAST32_FMTx__
-#define PRIXLEAST64 __UINT_LEAST64_FMTX__
-#define PRIoLEAST64 __UINT_LEAST64_FMTo__
-#define PRIuLEAST64 __UINT_LEAST64_FMTu__
-#define PRIxLEAST64 __UINT_LEAST64_FMTx__
-#define PRIXLEAST8 __UINT_LEAST8_FMTX__
-#define PRIoLEAST8 __UINT_LEAST8_FMTo__
-#define PRIuLEAST8 __UINT_LEAST8_FMTu__
-#define PRIxLEAST8 __UINT_LEAST8_FMTx__
-
-#define SCNd16 __INT16_FMTd__
-#define SCNi16 __INT16_FMTi__
-#define SCNd32 __INT32_FMTd__
-#define SCNi32 __INT32_FMTi__
-#define SCNd64 __INT64_FMTd__
-#define SCNi64 __INT64_FMTi__
-#define SCNd8 __INT8_FMTd__
-#define SCNi8 __INT8_FMTi__
-#define SCNdMAX __INTMAX_FMTd__
-#define SCNiMAX __INTMAX_FMTi__
-#define SCNdPTR __INTPTR_FMTd__
-#define SCNiPTR __INTPTR_FMTi__
-#define SCNdFAST16 __INT_FAST16_FMTd__
-#define SCNiFAST16 __INT_FAST16_FMTi__
-#define SCNdFAST32 __INT_FAST32_FMTd__
-#define SCNiFAST32 __INT_FAST32_FMTi__
-#define SCNdFAST64 __INT_FAST64_FMTd__
-#define SCNiFAST64 __INT_FAST64_FMTi__
-#define SCNdFAST8 __INT_FAST8_FMTd__
-#define SCNiFAST8 __INT_FAST8_FMTi__
-#define SCNdLEAST16 __INT_LEAST16_FMTd__
-#define SCNiLEAST16 __INT_LEAST16_FMTi__
-#define SCNdLEAST32 __INT_LEAST32_FMTd__
-#define SCNiLEAST32 __INT_LEAST32_FMTi__
-#define SCNdLEAST64 __INT_LEAST64_FMTd__
-#define SCNiLEAST64 __INT_LEAST64_FMTi__
-#define SCNdLEAST8 __INT_LEAST8_FMTd__
-#define SCNiLEAST8 __INT_LEAST8_FMTi__
-#define SCNo16 __UINT16_FMTo__
-#define SCNu16 __UINT16_FMTu__
-#define SCNx16 __UINT16_FMTx__
-#define SCNo32 __UINT32_FMTo__
-#define SCNu32 __UINT32_FMTu__
-#define SCNx32 __UINT32_FMTx__
-#define SCNo64 __UINT64_FMTo__
-#define SCNu64 __UINT64_FMTu__
-#define SCNx64 __UINT64_FMTx__
-#define SCNo8 __UINT8_FMTo__
-#define SCNu8 __UINT8_FMTu__
-#define SCNx8 __UINT8_FMTx__
-#define SCNoMAX __UINTMAX_FMTo__
-#define SCNuMAX __UINTMAX_FMTu__
-#define SCNxMAX __UINTMAX_FMTx__
-#define SCNoPTR __UINTPTR_FMTo__
-#define SCNuPTR __UINTPTR_FMTu__
-#define SCNxPTR __UINTPTR_FMTx__
-#define SCNoFAST16 __UINT_FAST16_FMTo__
-#define SCNuFAST16 __UINT_FAST16_FMTu__
-#define SCNxFAST16 __UINT_FAST16_FMTx__
-#define SCNoFAST32 __UINT_FAST32_FMTo__
-#define SCNuFAST32 __UINT_FAST32_FMTu__
-#define SCNxFAST32 __UINT_FAST32_FMTx__
-#define SCNoFAST64 __UINT_FAST64_FMTo__
-#define SCNuFAST64 __UINT_FAST64_FMTu__
-#define SCNxFAST64 __UINT_FAST64_FMTx__
-#define SCNoFAST8 __UINT_FAST8_FMTo__
-#define SCNuFAST8 __UINT_FAST8_FMTu__
-#define SCNxFAST8 __UINT_FAST8_FMTx__
-#define SCNoLEAST16 __UINT_LEAST16_FMTo__
-#define SCNuLEAST16 __UINT_LEAST16_FMTu__
-#define SCNxLEAST16 __UINT_LEAST16_FMTx__
-#define SCNoLEAST32 __UINT_LEAST32_FMTo__
-#define SCNuLEAST32 __UINT_LEAST32_FMTu__
-#define SCNxLEAST32 __UINT_LEAST32_FMTx__
-#define SCNoLEAST64 __UINT_LEAST64_FMTo__
-#define SCNuLEAST64 __UINT_LEAST64_FMTu__
-#define SCNxLEAST64 __UINT_LEAST64_FMTx__
-#define SCNoLEAST8 __UINT_LEAST8_FMTo__
-#define SCNuLEAST8 __UINT_LEAST8_FMTu__
-#define SCNxLEAST8 __UINT_LEAST8_FMTx__
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___macro_PAGESIZE_h
-#define __wasm_basics___macro_PAGESIZE_h
-
-/*
- * The page size in WebAssembly is fixed at 64 KiB. If this ever changes,
- * it's expected that applications will need to opt in, so we can change
- * this.
- */
-#define PAGESIZE (0x10000)
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___struct_stat_h
-#define __wasm_basics___struct_stat_h
-
-#include <__typedef_dev_t.h>
-#include <__typedef_ino_t.h>
-#include <__typedef_nlink_t.h>
-#include <__typedef_mode_t.h>
-#include <__typedef_uid_t.h>
-#include <__typedef_gid_t.h>
-#include <__typedef_off_t.h>
-#include <__typedef_blksize_t.h>
-#include <__typedef_blkcnt_t.h>
-#include <__struct_timespec.h>
-
-struct stat {
- dev_t st_dev;
- ino_t st_ino;
- nlink_t st_nlink;
-
- mode_t st_mode;
- uid_t st_uid;
- gid_t st_gid;
- unsigned int __pad0;
- dev_t st_rdev;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- long long __reserved[3];
-};
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___struct_timespec_h
-#define __wasm_basics___struct_timespec_h
-
-#include <__typedef_time_t.h>
-
-/* As specified in POSIX. */
-struct timespec {
- time_t tv_sec;
- long tv_nsec;
-};
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_blkcnt_t_h
-#define __wasm_basics___typedef_blkcnt_t_h
-
-/* Define these as 64-bit signed integers to support files larger than 2 GiB. */
-typedef long long blkcnt_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_blksize_t_h
-#define __wasm_basics___typedef_blksize_t_h
-
-typedef long blksize_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_clock_t_h
-#define __wasm_basics___typedef_clock_t_h
-
-/* Define this as a 64-bit signed integer to avoid wraparounds. */
-typedef long long clock_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_dev_t_h
-#define __wasm_basics___typedef_dev_t_h
-
-/* Define these as 64-bit integers to support billions of devices. */
-typedef unsigned long long dev_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_gid_t_h
-#define __wasm_basics___typedef_gid_t_h
-
-typedef unsigned gid_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_ino_t_h
-#define __wasm_basics___typedef_ino_t_h
-
-/* Define these as 64-bit integers to support billions of inodes. */
-typedef unsigned long long ino_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_mode_t_h
-#define __wasm_basics___typedef_mode_t_h
-
-typedef unsigned mode_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_nlink_t_h
-#define __wasm_basics___typedef_nlink_t_h
-
-/* Define these as 64-bit unsigned integers to support billions of links. */
-typedef unsigned long long nlink_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_off_t_h
-#define __wasm_basics___typedef_off_t_h
-
-/* Define these as 64-bit signed integers to support files larger than 2 GiB. */
-typedef long long off_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_ssize_t_h
-#define __wasm_basics___typedef_ssize_t_h
-
-/* This is defined to be the same size as size_t. */
-typedef long ssize_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_suseconds_t_h
-#define __wasm_basics___typedef_suseconds_t_h
-
-/* Define this to be 64-bit as its main use is in struct timeval where the
- extra space would otherwise be padding. */
-typedef long long suseconds_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_time_t_h
-#define __wasm_basics___typedef_time_t_h
-
-/* Define this as a 64-bit signed integer to avoid the 2038 bug. */
-typedef long long time_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics___typedef_uid_t_h
-#define __wasm_basics___typedef_uid_t_h
-
-typedef unsigned uid_t;
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_errno_h
-#define __wasm_basics_errno_h
-
-#include <__errno.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_inttypes_h
-#define __wasm_basics_inttypes_h
-
-/*
- * Include the real implementation, which is factored into a separate file so
- * that it can be reused by other libc stdlib implementations.
- */
-#include <__header_inttypes.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_stdlib_h
-#define __wasm_basics_stdlib_h
-
-/*
- * Include the real implementation, which is factored into a separate file so
- * that it can be reused by other libc stdlib implementations.
- */
-#include <__functions_malloc.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_string_h
-#define __wasm_basics_string_h
-
-/*
- * Include the real implementation, which is factored into a separate file so
- * that it can be reused by other libc string implementations.
- */
-#include <__functions_memcpy.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_sys_stat_h
-#define __wasm_basics_sys_stat_h
-
-#include <__struct_stat.h>
-
-#define st_atime st_atim.tv_sec
-#define st_mtime st_mtim.tv_sec
-#define st_ctime st_ctim.tv_sec
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_sys_types_h
-#define __wasm_basics_sys_types_h
-
-#define __need_size_t
-#include <stddef.h>
-
-#include <__typedef_clock_t.h>
-#include <__typedef_time_t.h>
-#include <__typedef_blksize_t.h>
-#include <__typedef_off_t.h>
-#include <__typedef_ssize_t.h>
-#include <__typedef_suseconds_t.h>
-#include <__typedef_nlink_t.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_time_h
-#define __wasm_basics_time_h
-
-#define __need_size_t
-#define __need_NULL
-#include <stddef.h>
-
-#include <__typedef_time_t.h>
-#include <__struct_timespec.h>
-
-#endif
+++ /dev/null
-#ifndef __wasm_basics_wchar_h
-#define __wasm_basics_wchar_h
-
-#define __need_size_t
-#define __need_wchar_t
-#define __need_NULL
-#include <stddef.h>
-
-#endif
+++ /dev/null
-#include <stdlib.h>
-
-void abort(void) {
- // WASI doesn't yet support signals, so just trap to halt the program.
- __builtin_trap();
-}
+++ /dev/null
-// Each of the following complex functions can be implemented with a single
-// wasm instruction, so use that implementation rather than the portable
-// one in libm.
-
-#include <complex.h>
-
-float crealf(float _Complex x) {
- return __real__ x;
-}
-
-double creal(double _Complex x) {
- return __real__ x;
-}
-
-float cimagf(float _Complex x) {
- return __imag__ x;
-}
-
-double cimag(double _Complex x) {
- return __imag__ x;
-}
+++ /dev/null
-// Wasm's `min` and `max` operators implement the IEEE 754-2019
-// `minimum` and `maximum` operations, meaning that given a choice
-// between NaN and a number, they return NaN. This differs from
-// the C standard library's `fmin` and `fmax` functions, which
-// return the number. However, we can still use wasm's builtins
-// by handling the NaN cases explicitly, and it still turns out
-// to be faster than doing the whole operation in
-// target-independent C. And, it's smaller.
-
-#include <math.h>
-
-float fminf(float x, float y) {
- if (isnan(x)) return y;
- if (isnan(y)) return x;
- return __builtin_wasm_min_f32(x, y);
-}
-
-float fmaxf(float x, float y) {
- if (isnan(x)) return y;
- if (isnan(y)) return x;
- return __builtin_wasm_max_f32(x, y);
-}
-
-double fmin(double x, double y) {
- if (isnan(x)) return y;
- if (isnan(y)) return x;
- return __builtin_wasm_min_f64(x, y);
-}
-
-double fmax(double x, double y) {
- if (isnan(x)) return y;
- if (isnan(y)) return x;
- return __builtin_wasm_max_f64(x, y);
-}
+++ /dev/null
-// Each of the following math functions can be implemented with a single
-// wasm instruction, so use that implementation rather than the portable
-// one in libm.
-
-#include <math.h>
-
-float fabsf(float x) {
- return __builtin_fabsf(x);
-}
-
-double fabs(double x) {
- return __builtin_fabs(x);
-}
-
-float sqrtf(float x) {
- return __builtin_sqrtf(x);
-}
-
-double sqrt(double x) {
- return __builtin_sqrt(x);
-}
-
-float copysignf(float x, float y) {
- return __builtin_copysignf(x, y);
-}
-
-double copysign(double x, double y) {
- return __builtin_copysign(x, y);
-}
-
-float ceilf(float x) {
- return __builtin_ceilf(x);
-}
-
-double ceil(double x) {
- return __builtin_ceil(x);
-}
-
-float floorf(float x) {
- return __builtin_floorf(x);
-}
-
-double floor(double x) {
- return __builtin_floor(x);
-}
-
-float truncf(float x) {
- return __builtin_truncf(x);
-}
-
-double trunc(double x) {
- return __builtin_trunc(x);
-}
-
-float nearbyintf(float x) {
- return __builtin_nearbyintf(x);
-}
-
-double nearbyint(double x) {
- return __builtin_nearbyint(x);
-}
-
-float rintf(float x) {
- return __builtin_rintf(x);
-}
-
-double rint(double x) {
- return __builtin_rint(x);
-}
+++ /dev/null
-#include <stdlib.h>
-#include <errno.h>
-
-void *__reallocarray(void *ptr, size_t nmemb, size_t size) {
- size_t bytes;
- if (__builtin_umull_overflow(nmemb, size, &bytes)) {
- errno = ENOMEM;
- return NULL;
- }
- return realloc(ptr, bytes);
-}
-
-void *reallocarray(void *ptr, size_t nmemb, size_t size)
- __attribute__((__weak__, __alias__("__reallocarray")));
+++ /dev/null
-#include <string.h>
-#include <stdint.h>
-
-static void *copy_forward(void *restrict dst, const void *restrict src, size_t n) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
- while (n-- != 0) {
- *d++ = *s++;
- }
- return dst;
-}
-
-static void *copy_backward(void *restrict dst, const void *restrict src, size_t n) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
- d += n;
- s += n;
- while (n-- != 0) {
- *--d = *--s;
- }
- return dst;
-}
-
-void *memcpy(void *restrict dst, const void *restrict src, size_t n) {
- return copy_forward(dst, src, n);
-}
-
-void *memmove(void *dst, const void *src, size_t n) {
- if ((uintptr_t)dst - (uintptr_t)src >= n) {
- return copy_forward(dst, src, n);
- }
- return copy_backward(dst, src, n);
-}
-
-void *memset(void *restrict dst, int c, size_t n) {
- char *d = (char *)dst;
- while (n-- != 0) {
- *d++ = c;
- }
- return dst;
-}
__posix_getopt
__pow_log_data
__powf_log2_data
-__prepare_for_exit
__progname
__progname_full
__putenv
__wasilibc_rmdirat
__wasilibc_tell
__wasilibc_unlinkat
+__wasm_call_dtors
__wcscoll_l
__wcsftime_l
__wcsxfrm_l
__year_to_secs
_environ
_exit
-_fini
_flushlbf
+_initialize
_start
a64l
abort
optopt
optreset
pathconf
-pause
perror
poll
posix_close
unsetenv
uselocale
usleep
+utime
utimensat
vasprintf
vdprintf
#include <__function___isatty.h>
#include <__functions_malloc.h>
#include <__functions_memcpy.h>
-#include <__header_bits_signal.h>
#include <__header_dirent.h>
#include <__header_fcntl.h>
#include <__header_inttypes.h>
#include <sched.h>
#include <search.h>
#include <semaphore.h>
-#include <signal.h>
#include <stdalign.h>
#include <stdbool.h>
#include <stdc-predef.h>
#include <sys/reg.h>
#include <sys/resource.h>
#include <sys/select.h>
-#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/stropts.h>
#include <time.h>
#include <uchar.h>
#include <unistd.h>
+#include <utime.h>
#include <values.h>
#include <wasi/api.h>
#include <wasi/libc-environ.h>
#define BLK_RESTART 0x10
#define BREAK 243
#define BUFSIZ 1024
-#define BUS_ADRALN 1
-#define BUS_ADRERR 2
-#define BUS_MCEERR_AO 5
-#define BUS_MCEERR_AR 4
-#define BUS_OBJERR 3
#define BYTE_ORDER __BYTE_ORDER
#define CANBSIZ 255
#define CBRK CEOL
#define CHRTYPE '3'
#define CINTR CTRL('c')
#define CKILL CTRL('u')
-#define CLD_CONTINUED 6
-#define CLD_DUMPED 3
-#define CLD_EXITED 1
-#define CLD_KILLED 2
-#define CLD_STOPPED 5
-#define CLD_TRAPPED 4
#define CLNEXT CTRL('v')
#define CLOCKS_PER_SEC ((clock_t)1000000000)
#define CLOCK_MONOTONIC (&_CLOCK_MONOTONIC)
#define FORM_C 3
#define FORM_N 1
#define FORM_T 2
-#define FPE_FLTDIV 3
-#define FPE_FLTINV 7
-#define FPE_FLTOVF 4
-#define FPE_FLTRES 6
-#define FPE_FLTSUB 8
-#define FPE_FLTUND 5
-#define FPE_INTDIV 1
-#define FPE_INTOVF 2
#define FP_ILOGB0 FP_ILOGBNAN
#define FP_ILOGBNAN (-1-0x7fffffff)
#define FP_INFINITE 1
#define F_GETFD (1)
#define F_GETFL (3)
#define F_LOCK 1
-#define F_OK 0
+#define F_OK (0)
#define F_SETFD (2)
#define F_SETFL (4)
#define F_TEST 3
#define IGMP_V2_MEMBERSHIP_REPORT 0x16
#define IGMP_v1_ROUTER 1
#define IGMP_v2_ROUTER 2
-#define ILL_BADSTK 8
-#define ILL_COPROC 7
-#define ILL_ILLADR 3
-#define ILL_ILLOPC 1
-#define ILL_ILLOPN 2
-#define ILL_ILLTRP 4
-#define ILL_PRVOPC 5
-#define ILL_PRVREG 6
#define IN6ADDRSZ NS_IN6ADDRSZ
#define IN6ADDR_ANY_INIT { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
#define IN6ADDR_LOOPBACK_INIT { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }
#define RS_HIPRI 0x01
#define RUSAGE_CHILDREN 2
#define RUSAGE_SELF 1
-#define R_OK 1
+#define R_OK (4)
#define SARMAG 8
#define SB 250
#define SCHAR_MAX 127
#define SEEK_END __WASI_WHENCE_END
#define SEEK_SET __WASI_WHENCE_SET
#define SEGSIZE 512
-#define SEGV_ACCERR 2
-#define SEGV_BNDERR 3
-#define SEGV_MAPERR 1
-#define SEGV_PKUERR 4
#define SEM_FAILED ((sem_t *)0)
#define SERVFAIL ns_r_servfail
#define SHORTBITS (sizeof(short) * 8)
#define SHUT_RD __WASI_SDFLAGS_RD
#define SHUT_RDWR (SHUT_RD | SHUT_WR)
#define SHUT_WR __WASI_SDFLAGS_WR
-#define SIGABRT __WASI_SIGNAL_ABRT
-#define SIGALRM __WASI_SIGNAL_ALRM
-#define SIGBUS __WASI_SIGNAL_BUS
-#define SIGCHLD __WASI_SIGNAL_CHLD
-#define SIGCONT __WASI_SIGNAL_CONT
-#define SIGEV_NONE 1
-#define SIGEV_SIGNAL 0
-#define SIGEV_THREAD 2
-#define SIGFPE __WASI_SIGNAL_FPE
-#define SIGHUP __WASI_SIGNAL_HUP
-#define SIGILL __WASI_SIGNAL_ILL
-#define SIGINT __WASI_SIGNAL_INT
-#define SIGIO SIGPOLL
-#define SIGIOT SIGABRT
-#define SIGKILL __WASI_SIGNAL_KILL
-#define SIGPIPE __WASI_SIGNAL_PIPE
-#define SIGPOLL __WASI_SIGNAL_POLL
-#define SIGPROF __WASI_SIGNAL_PROF
-#define SIGPWR __WASI_SIGNAL_PWR
-#define SIGQUIT __WASI_SIGNAL_QUIT
-#define SIGSEGV __WASI_SIGNAL_SEGV
-#define SIGSTOP __WASI_SIGNAL_STOP
-#define SIGSYS __WASI_SIGNAL_SYS
-#define SIGTERM __WASI_SIGNAL_TERM
-#define SIGTRAP __WASI_SIGNAL_TRAP
-#define SIGTSTP __WASI_SIGNAL_TSTP
-#define SIGTTIN __WASI_SIGNAL_TTIN
-#define SIGTTOU __WASI_SIGNAL_TTOU
-#define SIGUNUSED SIGSYS
-#define SIGURG __WASI_SIGNAL_URG
-#define SIGUSR1 __WASI_SIGNAL_USR1
-#define SIGUSR2 __WASI_SIGNAL_USR2
-#define SIGVTALRM __WASI_SIGNAL_VTALRM
-#define SIGWINCH __WASI_SIGNAL_WINCH
-#define SIGXCPU __WASI_SIGNAL_XCPU
-#define SIGXFSZ __WASI_SIGNAL_XFSZ
#define SIG_ATOMIC_MAX INT32_MAX
#define SIG_ATOMIC_MIN INT32_MIN
-#define SIG_BLOCK 0
-#define SIG_HOLD ((void (*)(int)) 2)
-#define SIG_SETMASK 2
-#define SIG_UNBLOCK 1
#define SIZE_MAX UINT32_MAX
-#define SI_ASYNCIO (-4)
-#define SI_ASYNCNL (-60)
-#define SI_KERNEL 128
#define SI_LOAD_SHIFT 16
-#define SI_MESGQ (-3)
-#define SI_QUEUE (-1)
-#define SI_SIGIO (-5)
-#define SI_TIMER (-2)
-#define SI_TKILL (-6)
-#define SI_USER 0
#define SLC_ABORT 7
#define SLC_ACK 0x80
#define SLC_AO 4
#define WONT 252
#define WORD_BIT 32
#define WRQ 02
-#define W_OK 2
-#define X_OK 4
+#define W_OK (2)
+#define X_OK (1)
#define YESEXPR 0x50000
#define YESSTR 0x50002
#define YXDOMAIN ns_r_yxdomain
#define _SC_XOPEN_XPG4 100
#define _SEARCH_H
#define _SEMAPHORE_H
-#define _SIGNAL_H
#define _SIZE_T
#define _STDALIGN_H
#define _STDBOOL_H
#define _TIME_H
#define _UCHAR_H
#define _UNISTD_H
+#define _UTIME_H
#define _VALUES_H
#define _VA_LIST
#define _WCHAR_H
#define __wasi_libc_environ_h
#define __wasi_libc_find_relpath_h
#define __wasi_libc_h
+#define __wasilibc___errno_h
#define __wasilibc___errno_values_h
#define __wasilibc___fd_set_h
#define __wasilibc___function___isatty_h
-#define __wasilibc___header_bits_signal_h
+#define __wasilibc___functions_malloc_h
+#define __wasilibc___functions_memcpy_h
#define __wasilibc___header_dirent_h
#define __wasilibc___header_fcntl_h
#define __wasilibc___header_netinet_in_h
#define __wasilibc___header_sys_stat_h
#define __wasilibc___header_time_h
#define __wasilibc___header_unistd_h
+#define __wasilibc___include_inttypes_h
#define __wasilibc___macro_FD_SETSIZE_h
+#define __wasilibc___macro_PAGESIZE_h
#define __wasilibc___mode_t_h
#define __wasilibc___seek_h
#define __wasilibc___struct_dirent_h
#define __wasilibc___struct_sockaddr_in_h
#define __wasilibc___struct_sockaddr_storage_h
#define __wasilibc___struct_sockaddr_un_h
+#define __wasilibc___struct_stat_h
+#define __wasilibc___struct_timespec_h
#define __wasilibc___struct_timeval_h
#define __wasilibc___struct_tm_h
#define __wasilibc___struct_tms_h
#define __wasilibc___typedef_DIR_h
+#define __wasilibc___typedef_blkcnt_t_h
+#define __wasilibc___typedef_blksize_t_h
+#define __wasilibc___typedef_clock_t_h
#define __wasilibc___typedef_clockid_t_h
+#define __wasilibc___typedef_dev_t_h
#define __wasilibc___typedef_fd_set_h
+#define __wasilibc___typedef_gid_t_h
#define __wasilibc___typedef_in_addr_t_h
#define __wasilibc___typedef_in_port_t_h
+#define __wasilibc___typedef_ino_t_h
+#define __wasilibc___typedef_mode_t_h
#define __wasilibc___typedef_nfds_t_h
+#define __wasilibc___typedef_nlink_t_h
+#define __wasilibc___typedef_off_t_h
#define __wasilibc___typedef_sa_family_t_h
#define __wasilibc___typedef_sigset_t_h
#define __wasilibc___typedef_socklen_t_h
+#define __wasilibc___typedef_ssize_t_h
+#define __wasilibc___typedef_suseconds_t_h
+#define __wasilibc___typedef_time_t_h
+#define __wasilibc___typedef_uid_t_h
#define __wasm 1
#define __wasm32 1
#define __wasm32__ 1
#define __wasm__ 1
-#define __wasm_basics___errno_h
-#define __wasm_basics___functions_malloc_h
-#define __wasm_basics___functions_memcpy_h
-#define __wasm_basics___include_inttypes_h
-#define __wasm_basics___macro_PAGESIZE_h
-#define __wasm_basics___struct_stat_h
-#define __wasm_basics___struct_timespec_h
-#define __wasm_basics___typedef_blkcnt_t_h
-#define __wasm_basics___typedef_blksize_t_h
-#define __wasm_basics___typedef_clock_t_h
-#define __wasm_basics___typedef_dev_t_h
-#define __wasm_basics___typedef_gid_t_h
-#define __wasm_basics___typedef_ino_t_h
-#define __wasm_basics___typedef_mode_t_h
-#define __wasm_basics___typedef_nlink_t_h
-#define __wasm_basics___typedef_off_t_h
-#define __wasm_basics___typedef_ssize_t_h
-#define __wasm_basics___typedef_suseconds_t_h
-#define __wasm_basics___typedef_time_t_h
-#define __wasm_basics___typedef_uid_t_h
#define _tolower(a) ((a)|0x20)
#define _toupper(a) ((a)&0x5f)
#define acos(x) __tg_real_complex(acos, (x))
#define rr_code rr_hdr.icmp6_code
#define rr_seqnum rr_hdr.icmp6_data32[0]
#define rr_type rr_hdr.icmp6_type
-#define sa_handler __sa_handler.sa_handler
-#define sa_sigaction __sa_handler.sa_sigaction
#define scalbln(x,y) __tg_real_2_1(scalbln, (x), (y))
#define scalbn(x,y) __tg_real_2_1(scalbn, (x), (y))
#define scandir64 scandir
#define setbit(x,i) __bitop(x,i,|=)
-#define si_addr __si_fields.__sigfault.si_addr
-#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb
-#define si_arch __si_fields.__sigsys.si_arch
-#define si_band __si_fields.__sigpoll.si_band
-#define si_call_addr __si_fields.__sigsys.si_call_addr
-#define si_fd __si_fields.__sigpoll.si_fd
-#define si_int si_value.sival_int
-#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower
-#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun
-#define si_pid __si_fields.__si_common.__first.__piduid.si_pid
-#define si_pkey __si_fields.__sigfault.__first.si_pkey
-#define si_ptr si_value.sival_ptr
-#define si_status __si_fields.__si_common.__second.__sigchld.si_status
-#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime
-#define si_syscall __si_fields.__sigsys.si_syscall
-#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid
-#define si_uid __si_fields.__si_common.__first.__piduid.si_uid
-#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper
-#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime
-#define si_value __si_fields.__si_common.__second.si_value
#define signbit(x) (__builtin_signbit(x))
#define sin(x) __tg_real_complex(sin, (x))
#define sinh(x) __tg_real_complex(sinh, (x))
-"WASI" the WebAssembly System Interface.
+# WASI libc "bottom half".
-WASI libc is conceptually the lower half of a traditional libc implementation.
-It provides C interfaces to the low-level WASI syscalls.
+The WASI libc "bottom half" is conceptually the lower half of a traditional libc
+implementation, consisting of C interfaces to the low-level WASI syscalls.
-This is largely based on [CloudABI], [cloudlibc], and [libpreopen], however we
-use just the low-level syscall wrappers rather than all of cloudlibc and
-libpreopen, and we have several customizations for use in a WebAssembly sysroot.
+This implementation is partially derived from the "bottom half" of [cloudlibc],
+revision 8835639f27fc42d32096d59d294a0bbb857dc368.
-[CloudABI]: https://github.com/NuxiNL/cloudabi
[cloudlibc]: https://github.com/NuxiNL/cloudlibc
-[libpreopen]: https://github.com/musec/libpreopen
-
-The upstream repositories and versions used here are:
-cloudlibc - https://github.com/NuxiNL/cloudlibc 8835639f27fc42d32096d59d294a0bbb857dc368
-libpreopen - https://github.com/musec/libpreopen b29e9287cc75a7db7291ce3eb468a3d2bad8ceb1
+This implementation includes preopen functionality, which emulates POSIX APIs
+accepting absolute paths by translating them into pre-opened directory handles
+and relative paths that can be opened with `openat`. This technique is inspired
+by [libpreopen], however the implementation here is designed to be built into
+libc rather than to be a layer on top of libc.
-Whole files which are unused are omitted. Changes to upstream code are wrapped
-in preprocessor directives controlled by the macro `__wasilibc_unmodified_upstream`,
-except that CloudABI names have also been renamed to WASI names without annotations.
+[libpreopen]: https://github.com/musec/libpreopen
-WASI libc currently depends on the basics and dlmalloc components of reference-sysroot.
+The WASI libc lower half currently depends on the dlmalloc component.
// Construct events for poll().
size_t maxevents = 2 * nfds + 1;
__wasi_subscription_t subscriptions[maxevents];
- size_t nevents = 0;
+ size_t nsubscriptions = 0;
for (size_t i = 0; i < nfds; ++i) {
struct pollfd *pollfd = &fds[i];
if (pollfd->fd < 0)
continue;
bool created_events = false;
if ((pollfd->events & POLLRDNORM) != 0) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.userdata = (uintptr_t)pollfd,
.u.tag = __WASI_EVENTTYPE_FD_READ,
created_events = true;
}
if ((pollfd->events & POLLWRNORM) != 0) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.userdata = (uintptr_t)pollfd,
.u.tag = __WASI_EVENTTYPE_FD_WRITE,
// Create extra event for the timeout.
if (timeout >= 0) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.u.tag = __WASI_EVENTTYPE_CLOCK,
.u.u.clock.id = __WASI_CLOCKID_REALTIME,
}
// Execute poll().
- __wasi_event_t events[nevents];
+ size_t nevents;
+ __wasi_event_t events[nsubscriptions];
__wasi_errno_t error =
-#ifdef __wasilibc_unmodified_upstream
- __wasi_poll(subscriptions, events, nevents, &nevents);
-#else
- __wasi_poll_oneoff(subscriptions, events, nevents, &nevents);
-#endif
+ __wasi_poll_oneoff(subscriptions, events, nsubscriptions, &nevents);
if (error != 0) {
- errno = error;
+ // WASI's poll requires at least one subscription, or else it returns
+ // `EINVAL`. Since a `poll` with nothing to wait for is valid in POSIX,
+ // return `ENOTSUP` to indicate that we don't support that case.
+ //
+ // Wasm has no signal handling, so if none of the user-provided `pollfd`
+ // elements, nor the timeout, led us to producing even one subscription
+ // to wait for, there would be no way for the poll to wake up. WASI
+ // returns `EINVAL` in this case, but for users of `poll`, `ENOTSUP` is
+ // more likely to be understood.
+ if (nsubscriptions == 0)
+ errno = ENOTSUP;
+ else
+ errno = error;
return -1;
}
if (event->type == __WASI_EVENTTYPE_FD_READ ||
event->type == __WASI_EVENTTYPE_FD_WRITE) {
struct pollfd *pollfd = (struct pollfd *)(uintptr_t)event->userdata;
-#ifdef __wasilibc_unmodified_upstream // generated constant names
- if (event->error == __WASI_EBADF) {
-#else
if (event->error == __WASI_ERRNO_BADF) {
-#endif
// Invalid file descriptor.
pollfd->revents |= POLLNVAL;
-#ifdef __wasilibc_unmodified_upstream // generated constant names
- } else if (event->error == __WASI_EPIPE) {
-#else
} else if (event->error == __WASI_ERRNO_PIPE) {
-#endif
// Hangup on write side of pipe.
pollfd->revents |= POLLHUP;
} else if (event->error != 0) {
+++ /dev/null
-// Copyright (c) 2015 Nuxi, https://nuxi.nl/
-//
-// SPDX-License-Identifier: BSD-2-Clause
-
-#include <stdlib.h>
-
-#ifndef qsort
-#error "qsort is supposed to be a macro as well"
-#endif
-
-// clang-format off
-void (qsort)(void *base, size_t nel, size_t width,
- int (*compar)(const void *, const void *)) {
- return qsort(base, nel, width, compar);
-}
int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
fd_set *restrict errorfds, const struct timespec *restrict timeout,
-#ifdef __wasilibc_unmodified_upstream
- ...) {
-#else
const sigset_t *sigmask) {
-#endif
// Negative file descriptor upperbound.
if (nfds < 0) {
errno = EINVAL;
// Determine the maximum number of events.
size_t maxevents = readfds->__nfds + writefds->__nfds + 1;
__wasi_subscription_t subscriptions[maxevents];
- size_t nevents = 0;
+ size_t nsubscriptions = 0;
// Convert the readfds set.
for (size_t i = 0; i < readfds->__nfds; ++i) {
int fd = readfds->__fds[i];
if (fd < nfds) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.userdata = fd,
.u.tag = __WASI_EVENTTYPE_FD_READ,
for (size_t i = 0; i < writefds->__nfds; ++i) {
int fd = writefds->__fds[i];
if (fd < nfds) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.userdata = fd,
.u.tag = __WASI_EVENTTYPE_FD_WRITE,
// Create extra event for the timeout.
if (timeout != NULL) {
- __wasi_subscription_t *subscription = &subscriptions[nevents++];
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
*subscription = (__wasi_subscription_t){
.u.tag = __WASI_EVENTTYPE_CLOCK,
.u.u.clock.id = __WASI_CLOCKID_REALTIME,
}
// Execute poll().
- __wasi_event_t events[nevents];
+ size_t nevents;
+ __wasi_event_t events[nsubscriptions];
__wasi_errno_t error =
-#ifdef __wasilibc_unmodified_upstream
- __wasi_poll(subscriptions, events, nevents, &nevents);
-#else
- __wasi_poll_oneoff(subscriptions, events, nevents, &nevents);
-#endif
+ __wasi_poll_oneoff(subscriptions, events, nsubscriptions, &nevents);
if (error != 0) {
- errno = error;
+ // WASI's poll requires at least one subscription, or else it returns
+ // `EINVAL`. Since a `pselect` with nothing to wait for is valid in POSIX,
+ // return `ENOTSUP` to indicate that we don't support that case.
+ //
+ // Wasm has no signal handling, so if none of the user-provided `pollfd`
+ // elements, nor the timeout, led us to producing even one subscription
+ // to wait for, there would be no way for the poll to wake up. WASI
+ // returns `EINVAL` in this case, but for users of `poll`, `ENOTSUP` is
+ // more likely to be understood.
+ if (nsubscriptions == 0)
+ errno = ENOTSUP;
+ else
+ errno = error;
return -1;
}
const __wasi_event_t *event = &events[i];
if ((event->type == __WASI_EVENTTYPE_FD_READ ||
event->type == __WASI_EVENTTYPE_FD_WRITE) &&
-#ifdef __wasilibc_unmodified_upstream // generated constant names
- event->error == __WASI_EBADF) {
-#else
event->error == __WASI_ERRNO_BADF) {
-#endif
errno = EBADF;
return -1;
}
--- /dev/null
+extern void __wasm_call_ctors(void);
+
+__attribute__((export_name("_initialize")))
+void _initialize(void) {
+ // The linker synthesizes this to call constructors.
+ __wasm_call_ctors();
+}
#include <wasi/api.h>
extern void __wasm_call_ctors(void);
extern int __original_main(void);
-extern void __prepare_for_exit(void);
+extern void __wasm_call_dtors(void);
+__attribute__((export_name("_start")))
void _start(void) {
// The linker synthesizes this to call constructors.
__wasm_call_ctors();
int r = __original_main();
// Call atexit functions, destructors, stdio cleanup, etc.
- __prepare_for_exit();
+ __wasm_call_dtors();
// If main exited successfully, just return, otherwise call
// `__wasi_proc_exit`.
--- /dev/null
+#ifndef __wasilibc___errno_h
+#define __wasilibc___errno_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+extern thread_local int errno;
+#else
+extern _Thread_local int errno;
+#endif
+
+#define errno errno
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef __wasilibc___functions_malloc_h
+#define __wasilibc___functions_malloc_h
+
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *malloc(size_t __size) __attribute__((__malloc__, __warn_unused_result__));
+void free(void *__ptr);
+void *calloc(size_t __nmemb, size_t __size) __attribute__((__malloc__, __warn_unused_result__));
+void *realloc(void *__ptr, size_t __size) __attribute__((__warn_unused_result__));
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+void *reallocarray(void *__ptr, size_t __nmemb, size_t __size) __attribute__((__warn_unused_result__));
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef __wasilibc___functions_memcpy_h
+#define __wasilibc___functions_memcpy_h
+
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *memcpy(void *__restrict__ __dst, const void *__restrict__ __src, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1, 2)));
+void *memmove(void *__dst, const void *__src, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1, 2)));
+void *memset(void *__dst, int __c, size_t __n) __attribute__((__nothrow__, __leaf__, __nonnull__(1)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+++ /dev/null
-#ifndef __wasilibc___header_bits_signal_h
-#define __wasilibc___header_bits_signal_h
-
-#include <wasi/api.h>
-
-#define SIGHUP __WASI_SIGNAL_HUP
-#define SIGINT __WASI_SIGNAL_INT
-#define SIGQUIT __WASI_SIGNAL_QUIT
-#define SIGILL __WASI_SIGNAL_ILL
-#define SIGTRAP __WASI_SIGNAL_TRAP
-#define SIGABRT __WASI_SIGNAL_ABRT
-#define SIGBUS __WASI_SIGNAL_BUS
-#define SIGFPE __WASI_SIGNAL_FPE
-#define SIGKILL __WASI_SIGNAL_KILL
-#define SIGUSR1 __WASI_SIGNAL_USR1
-#define SIGSEGV __WASI_SIGNAL_SEGV
-#define SIGUSR2 __WASI_SIGNAL_USR2
-#define SIGPIPE __WASI_SIGNAL_PIPE
-#define SIGALRM __WASI_SIGNAL_ALRM
-#define SIGTERM __WASI_SIGNAL_TERM
-#define SIGCHLD __WASI_SIGNAL_CHLD
-#define SIGCONT __WASI_SIGNAL_CONT
-#define SIGSTOP __WASI_SIGNAL_STOP
-#define SIGTSTP __WASI_SIGNAL_TSTP
-#define SIGTTIN __WASI_SIGNAL_TTIN
-#define SIGTTOU __WASI_SIGNAL_TTOU
-#define SIGURG __WASI_SIGNAL_URG
-#define SIGXCPU __WASI_SIGNAL_XCPU
-#define SIGXFSZ __WASI_SIGNAL_XFSZ
-#define SIGVTALRM __WASI_SIGNAL_VTALRM
-#define SIGPROF __WASI_SIGNAL_PROF
-#define SIGWINCH __WASI_SIGNAL_WINCH
-#define SIGPOLL __WASI_SIGNAL_POLL
-#define SIGPWR __WASI_SIGNAL_PWR
-#define SIGSYS __WASI_SIGNAL_SYS
-
-#define SIGIOT SIGABRT
-#define SIGIO SIGPOLL
-#define SIGUNUSED SIGSYS
-
-#endif
--- /dev/null
+#ifndef __wasilibc___include_inttypes_h
+#define __wasilibc___include_inttypes_h
+
+#include <stdint.h>
+
+#define __need_wchar_t
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct { intmax_t quot, rem; } imaxdiv_t;
+
+intmax_t imaxabs(intmax_t);
+imaxdiv_t imaxdiv(intmax_t, intmax_t);
+intmax_t strtoimax(const char *__restrict, char **__restrict, int);
+uintmax_t strtoumax(const char *__restrict, char **__restrict, int);
+intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int);
+uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
+
+#define PRId16 __INT16_FMTd__
+#define PRIi16 __INT16_FMTi__
+#define PRId32 __INT32_FMTd__
+#define PRIi32 __INT32_FMTi__
+#define PRId64 __INT64_FMTd__
+#define PRIi64 __INT64_FMTi__
+#define PRId8 __INT8_FMTd__
+#define PRIi8 __INT8_FMTi__
+#define PRIdMAX __INTMAX_FMTd__
+#define PRIiMAX __INTMAX_FMTi__
+#define PRIdPTR __INTPTR_FMTd__
+#define PRIiPTR __INTPTR_FMTi__
+#define PRIdFAST16 __INT_FAST16_FMTd__
+#define PRIiFAST16 __INT_FAST16_FMTi__
+#define PRIdFAST32 __INT_FAST32_FMTd__
+#define PRIiFAST32 __INT_FAST32_FMTi__
+#define PRIdFAST64 __INT_FAST64_FMTd__
+#define PRIiFAST64 __INT_FAST64_FMTi__
+#define PRIdFAST8 __INT_FAST8_FMTd__
+#define PRIiFAST8 __INT_FAST8_FMTi__
+#define PRIdLEAST16 __INT_LEAST16_FMTd__
+#define PRIiLEAST16 __INT_LEAST16_FMTi__
+#define PRIdLEAST32 __INT_LEAST32_FMTd__
+#define PRIiLEAST32 __INT_LEAST32_FMTi__
+#define PRIdLEAST64 __INT_LEAST64_FMTd__
+#define PRIiLEAST64 __INT_LEAST64_FMTi__
+#define PRIdLEAST8 __INT_LEAST8_FMTd__
+#define PRIiLEAST8 __INT_LEAST8_FMTi__
+#define PRIX16 __UINT16_FMTX__
+#define PRIo16 __UINT16_FMTo__
+#define PRIu16 __UINT16_FMTu__
+#define PRIx16 __UINT16_FMTx__
+#define PRIX32 __UINT32_FMTX__
+#define PRIo32 __UINT32_FMTo__
+#define PRIu32 __UINT32_FMTu__
+#define PRIx32 __UINT32_FMTx__
+#define PRIX64 __UINT64_FMTX__
+#define PRIo64 __UINT64_FMTo__
+#define PRIu64 __UINT64_FMTu__
+#define PRIx64 __UINT64_FMTx__
+#define PRIX8 __UINT8_FMTX__
+#define PRIo8 __UINT8_FMTo__
+#define PRIu8 __UINT8_FMTu__
+#define PRIx8 __UINT8_FMTx__
+#define PRIXMAX __UINTMAX_FMTX__
+#define PRIoMAX __UINTMAX_FMTo__
+#define PRIuMAX __UINTMAX_FMTu__
+#define PRIxMAX __UINTMAX_FMTx__
+#define PRIXPTR __UINTPTR_FMTX__
+#define PRIoPTR __UINTPTR_FMTo__
+#define PRIuPTR __UINTPTR_FMTu__
+#define PRIxPTR __UINTPTR_FMTx__
+#define PRIXFAST16 __UINT_FAST16_FMTX__
+#define PRIoFAST16 __UINT_FAST16_FMTo__
+#define PRIuFAST16 __UINT_FAST16_FMTu__
+#define PRIxFAST16 __UINT_FAST16_FMTx__
+#define PRIXFAST32 __UINT_FAST32_FMTX__
+#define PRIoFAST32 __UINT_FAST32_FMTo__
+#define PRIuFAST32 __UINT_FAST32_FMTu__
+#define PRIxFAST32 __UINT_FAST32_FMTx__
+#define PRIXFAST64 __UINT_FAST64_FMTX__
+#define PRIoFAST64 __UINT_FAST64_FMTo__
+#define PRIuFAST64 __UINT_FAST64_FMTu__
+#define PRIxFAST64 __UINT_FAST64_FMTx__
+#define PRIXFAST8 __UINT_FAST8_FMTX__
+#define PRIoFAST8 __UINT_FAST8_FMTo__
+#define PRIuFAST8 __UINT_FAST8_FMTu__
+#define PRIxFAST8 __UINT_FAST8_FMTx__
+#define PRIXLEAST16 __UINT_LEAST16_FMTX__
+#define PRIoLEAST16 __UINT_LEAST16_FMTo__
+#define PRIuLEAST16 __UINT_LEAST16_FMTu__
+#define PRIxLEAST16 __UINT_LEAST16_FMTx__
+#define PRIXLEAST32 __UINT_LEAST32_FMTX__
+#define PRIoLEAST32 __UINT_LEAST32_FMTo__
+#define PRIuLEAST32 __UINT_LEAST32_FMTu__
+#define PRIxLEAST32 __UINT_LEAST32_FMTx__
+#define PRIXLEAST64 __UINT_LEAST64_FMTX__
+#define PRIoLEAST64 __UINT_LEAST64_FMTo__
+#define PRIuLEAST64 __UINT_LEAST64_FMTu__
+#define PRIxLEAST64 __UINT_LEAST64_FMTx__
+#define PRIXLEAST8 __UINT_LEAST8_FMTX__
+#define PRIoLEAST8 __UINT_LEAST8_FMTo__
+#define PRIuLEAST8 __UINT_LEAST8_FMTu__
+#define PRIxLEAST8 __UINT_LEAST8_FMTx__
+
+#define SCNd16 __INT16_FMTd__
+#define SCNi16 __INT16_FMTi__
+#define SCNd32 __INT32_FMTd__
+#define SCNi32 __INT32_FMTi__
+#define SCNd64 __INT64_FMTd__
+#define SCNi64 __INT64_FMTi__
+#define SCNd8 __INT8_FMTd__
+#define SCNi8 __INT8_FMTi__
+#define SCNdMAX __INTMAX_FMTd__
+#define SCNiMAX __INTMAX_FMTi__
+#define SCNdPTR __INTPTR_FMTd__
+#define SCNiPTR __INTPTR_FMTi__
+#define SCNdFAST16 __INT_FAST16_FMTd__
+#define SCNiFAST16 __INT_FAST16_FMTi__
+#define SCNdFAST32 __INT_FAST32_FMTd__
+#define SCNiFAST32 __INT_FAST32_FMTi__
+#define SCNdFAST64 __INT_FAST64_FMTd__
+#define SCNiFAST64 __INT_FAST64_FMTi__
+#define SCNdFAST8 __INT_FAST8_FMTd__
+#define SCNiFAST8 __INT_FAST8_FMTi__
+#define SCNdLEAST16 __INT_LEAST16_FMTd__
+#define SCNiLEAST16 __INT_LEAST16_FMTi__
+#define SCNdLEAST32 __INT_LEAST32_FMTd__
+#define SCNiLEAST32 __INT_LEAST32_FMTi__
+#define SCNdLEAST64 __INT_LEAST64_FMTd__
+#define SCNiLEAST64 __INT_LEAST64_FMTi__
+#define SCNdLEAST8 __INT_LEAST8_FMTd__
+#define SCNiLEAST8 __INT_LEAST8_FMTi__
+#define SCNo16 __UINT16_FMTo__
+#define SCNu16 __UINT16_FMTu__
+#define SCNx16 __UINT16_FMTx__
+#define SCNo32 __UINT32_FMTo__
+#define SCNu32 __UINT32_FMTu__
+#define SCNx32 __UINT32_FMTx__
+#define SCNo64 __UINT64_FMTo__
+#define SCNu64 __UINT64_FMTu__
+#define SCNx64 __UINT64_FMTx__
+#define SCNo8 __UINT8_FMTo__
+#define SCNu8 __UINT8_FMTu__
+#define SCNx8 __UINT8_FMTx__
+#define SCNoMAX __UINTMAX_FMTo__
+#define SCNuMAX __UINTMAX_FMTu__
+#define SCNxMAX __UINTMAX_FMTx__
+#define SCNoPTR __UINTPTR_FMTo__
+#define SCNuPTR __UINTPTR_FMTu__
+#define SCNxPTR __UINTPTR_FMTx__
+#define SCNoFAST16 __UINT_FAST16_FMTo__
+#define SCNuFAST16 __UINT_FAST16_FMTu__
+#define SCNxFAST16 __UINT_FAST16_FMTx__
+#define SCNoFAST32 __UINT_FAST32_FMTo__
+#define SCNuFAST32 __UINT_FAST32_FMTu__
+#define SCNxFAST32 __UINT_FAST32_FMTx__
+#define SCNoFAST64 __UINT_FAST64_FMTo__
+#define SCNuFAST64 __UINT_FAST64_FMTu__
+#define SCNxFAST64 __UINT_FAST64_FMTx__
+#define SCNoFAST8 __UINT_FAST8_FMTo__
+#define SCNuFAST8 __UINT_FAST8_FMTu__
+#define SCNxFAST8 __UINT_FAST8_FMTx__
+#define SCNoLEAST16 __UINT_LEAST16_FMTo__
+#define SCNuLEAST16 __UINT_LEAST16_FMTu__
+#define SCNxLEAST16 __UINT_LEAST16_FMTx__
+#define SCNoLEAST32 __UINT_LEAST32_FMTo__
+#define SCNuLEAST32 __UINT_LEAST32_FMTu__
+#define SCNxLEAST32 __UINT_LEAST32_FMTx__
+#define SCNoLEAST64 __UINT_LEAST64_FMTo__
+#define SCNuLEAST64 __UINT_LEAST64_FMTu__
+#define SCNxLEAST64 __UINT_LEAST64_FMTx__
+#define SCNoLEAST8 __UINT_LEAST8_FMTo__
+#define SCNuLEAST8 __UINT_LEAST8_FMTu__
+#define SCNxLEAST8 __UINT_LEAST8_FMTx__
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
#include <__seek.h>
-#define F_OK 0
-#define R_OK 1
-#define W_OK 2
-#define X_OK 4
+#define F_OK (0)
+#define X_OK (1)
+#define W_OK (2)
+#define R_OK (4)
#ifdef __cplusplus
extern "C" {
--- /dev/null
+#ifndef __wasilibc___macro_PAGESIZE_h
+#define __wasilibc___macro_PAGESIZE_h
+
+/*
+ * The page size in WebAssembly is fixed at 64 KiB. If this ever changes,
+ * it's expected that applications will need to opt in, so we can change
+ * this.
+ */
+#define PAGESIZE (0x10000)
+
+#endif
--- /dev/null
+#ifndef __wasilibc___struct_stat_h
+#define __wasilibc___struct_stat_h
+
+#include <__typedef_dev_t.h>
+#include <__typedef_ino_t.h>
+#include <__typedef_nlink_t.h>
+#include <__typedef_mode_t.h>
+#include <__typedef_uid_t.h>
+#include <__typedef_gid_t.h>
+#include <__typedef_off_t.h>
+#include <__typedef_blksize_t.h>
+#include <__typedef_blkcnt_t.h>
+#include <__struct_timespec.h>
+
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ nlink_t st_nlink;
+
+ mode_t st_mode;
+ uid_t st_uid;
+ gid_t st_gid;
+ unsigned int __pad0;
+ dev_t st_rdev;
+ off_t st_size;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ long long __reserved[3];
+};
+
+#endif
--- /dev/null
+#ifndef __wasilibc___struct_timespec_h
+#define __wasilibc___struct_timespec_h
+
+#include <__typedef_time_t.h>
+
+/* As specified in POSIX. */
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_blkcnt_t_h
+#define __wasilibc___typedef_blkcnt_t_h
+
+/* Define these as 64-bit signed integers to support files larger than 2 GiB. */
+typedef long long blkcnt_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_blksize_t_h
+#define __wasilibc___typedef_blksize_t_h
+
+typedef long blksize_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_clock_t_h
+#define __wasilibc___typedef_clock_t_h
+
+/* Define this as a 64-bit signed integer to avoid wraparounds. */
+typedef long long clock_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_dev_t_h
+#define __wasilibc___typedef_dev_t_h
+
+/* Define these as 64-bit integers to support billions of devices. */
+typedef unsigned long long dev_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_gid_t_h
+#define __wasilibc___typedef_gid_t_h
+
+typedef unsigned gid_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_ino_t_h
+#define __wasilibc___typedef_ino_t_h
+
+/* Define these as 64-bit integers to support billions of inodes. */
+typedef unsigned long long ino_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_mode_t_h
+#define __wasilibc___typedef_mode_t_h
+
+typedef unsigned mode_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_nlink_t_h
+#define __wasilibc___typedef_nlink_t_h
+
+/* Define these as 64-bit unsigned integers to support billions of links. */
+typedef unsigned long long nlink_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_off_t_h
+#define __wasilibc___typedef_off_t_h
+
+/* Define these as 64-bit signed integers to support files larger than 2 GiB. */
+typedef long long off_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_ssize_t_h
+#define __wasilibc___typedef_ssize_t_h
+
+/* This is defined to be the same size as size_t. */
+typedef long ssize_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_suseconds_t_h
+#define __wasilibc___typedef_suseconds_t_h
+
+/* Define this to be 64-bit as its main use is in struct timeval where the
+ extra space would otherwise be padding. */
+typedef long long suseconds_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_time_t_h
+#define __wasilibc___typedef_time_t_h
+
+/* Define this as a 64-bit signed integer to avoid the 2038 bug. */
+typedef long long time_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc___typedef_uid_t_h
+#define __wasilibc___typedef_uid_t_h
+
+typedef unsigned uid_t;
+
+#endif
--- /dev/null
+#ifndef __wasilibc_inttypes_h
+#define __wasilibc_inttypes_h
+
+/*
+ * Include the real implementation, which is factored into a separate file so
+ * that it can be reused by other libc stdlib implementations.
+ */
+#include <__header_inttypes.h>
+
+#endif
* Include the real implementation, which is factored into a separate file so
* that it can be reused by other libc stdlib implementations.
*/
-#include <__header_stdlib.h>
+#include <__functions_malloc.h>
#endif
_Static_assert(_Alignof(__wasi_rights_t) == 8, "witx calculated align");
/**
- * A file descriptor index.
+ * A file descriptor handle.
*/
-typedef uint32_t __wasi_fd_t;
+typedef int __wasi_fd_t;
_Static_assert(sizeof(__wasi_fd_t) == 4, "witx calculated size");
_Static_assert(_Alignof(__wasi_fd_t) == 4, "witx calculated align");
_Static_assert(_Alignof(__wasi_subclockflags_t) == 2, "witx calculated align");
/**
- * The contents of a $subscription when type is `eventtype::clock`.
+ * The contents of a `subscription` when type is `eventtype::clock`.
*/
typedef struct __wasi_subscription_clock_t {
/**
_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset");
/**
- * The contents of a $subscription when type is type is
+ * The contents of a `subscription` when type is type is
* `eventtype::fd_read` or `eventtype::fd_write`.
*/
typedef struct __wasi_subscription_fd_readwrite_t {
_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, file_descriptor) == 0, "witx calculated offset");
/**
- * The contents of a $subscription.
+ * The contents of a `subscription`.
*/
typedef union __wasi_subscription_u_u_t {
__wasi_subscription_clock_t clock;
));
/**
- * Return command-line argument data sizes.
+ * Return environment variable data sizes.
*/
__wasi_errno_t __wasi_environ_sizes_get(
/**
- * The number of arguments.
+ * The number of environment variable arguments.
*/
- __wasi_size_t *argc,
+ __wasi_size_t *environc,
/**
- * The size of the argument string data.
+ * The size of the environment variable data.
*/
- __wasi_size_t *argv_buf_size
+ __wasi_size_t *environ_buf_size
) __attribute__((
__import_module__("wasi_snapshot_preview1"),
__import_name__("environ_sizes_get"),
*
* Returns -1 if no directories were suitable.
*/
-int __wasilibc_find_relpath(const char *path, const char **relative_path);
+int __wasilibc_find_relpath(const char *path,
+ const char **__restrict__ relative_path);
#ifdef __cplusplus
}
extern "C" {
#endif
-int __wasilibc_register_preopened_fd(int fd, const char *path);
+/// Register the given pre-opened file descriptor under the given path.
+///
+/// This function does not take ownership of `prefix` (it makes its own copy).
+int __wasilibc_register_preopened_fd(int fd, const char *prefix);
+
+/// Renumber `fd` to `newfd`; similar to `dup2` but does a move rather than a
+/// copy.
int __wasilibc_fd_renumber(int fd, int newfd);
+
+/// Like `unlinkat`, but without depending on `__wasi_path_remove_directory`.
int __wasilibc_unlinkat(int fd, const char *path);
+
+/// An `*at` version of rmdir.
int __wasilibc_rmdirat(int fd, const char *path);
+
+/// Like `open`, but without the varargs in the signature.
int __wasilibc_open_nomode(const char *path, int oflag);
+
+/// Like `openat`, but without the varargs in the signature.
int __wasilibc_openat_nomode(int fd, const char *path, int oflag);
+
+/// Return the current file offset. Like `lseek(fd, 0, SEEK_CUR)`, but without
+/// depending on `lseek`.
off_t __wasilibc_tell(int fd);
#ifdef __cplusplus
--- /dev/null
+#ifndef __wasilibc_wchar_h
+#define __wasilibc_wchar_h
+
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+#include <stddef.h>
+
+#endif
+++ /dev/null
-//! Preopen functionality for WASI libc, for emulating support for absolute
-//! path names on top of WASI's OCap-style API.
-//!
-//! This file is derived from code in libpreopen, the upstream for which is:
-//!
-//! https://github.com/musec/libpreopen
-//!
-//! and which bears the following copyrights and license:
-
-/*-
- * Copyright (c) 2016-2017 Stanley Uche Godfrey
- * Copyright (c) 2016-2018 Jonathan Anderson
- * All rights reserved.
- *
- * This software was developed at Memorial University under the
- * NSERC Discovery program (RGPIN-2015-06048).
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifdef _REENTRANT
-#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads"
-#endif
-
-#define _ALL_SOURCE
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <assert.h>
-#include <sysexits.h>
-#include <wasi/libc.h>
-#include <wasi/libc-find-relpath.h>
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// POSIX API compatibility wrappers
-//
-////////////////////////////////////////////////////////////////////////////////
-
-int
-open(const char *path, int flags, ...)
-{
- // WASI libc's openat ignores the mode argument, so call a special
- // entrypoint which avoids the varargs calling convention.
- return __wasilibc_open_nomode(path, flags);
-}
-
-int
-__wasilibc_open_nomode(const char *path, int flags)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(path, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return __wasilibc_openat_nomode(dirfd, relative_path, flags);
-}
-
-int
-access(const char *path, int mode)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(path, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return faccessat(dirfd, relative_path, mode, 0);
-}
-
-int
-lstat(const char *path, struct stat *st)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(path, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW);
-}
-
-int
-rename(const char *from, const char *to)
-{
- const char *from_relative_path;
- int from_dirfd = __wasilibc_find_relpath(from, &from_relative_path);
-
- const char *to_relative_path;
- int to_dirfd = __wasilibc_find_relpath(to, &to_relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (from_dirfd == -1 || to_dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return renameat(from_dirfd, from_relative_path, to_dirfd, to_relative_path);
-}
-
-int
-stat(const char *path, struct stat *st)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(path, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW);
-}
-
-int
-unlink(const char *path)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(path, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- // `unlinkat` ends up importing `__wasi_path_remove_directory` even
- // though we're not passing `AT_REMOVEDIR` here. So instead, use a
- // specialized function which just imports `__wasi_path_unlink_file`.
- return __wasilibc_unlinkat(dirfd, relative_path);
-}
-
-int
-rmdir(const char *pathname)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(pathname, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return __wasilibc_rmdirat(dirfd, relative_path);
-}
-
-int
-remove(const char *pathname)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(pathname, &relative_path);
-
- // If searching for both file and directory rights failed, try searching
- // for either individually.
- if (dirfd == -1) {
- dirfd = __wasilibc_find_relpath(pathname, &relative_path);
- if (dirfd == -1) {
- dirfd = __wasilibc_find_relpath(pathname, &relative_path);
- }
- }
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- int r = __wasilibc_unlinkat(dirfd, relative_path);
- if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE))
- r = __wasilibc_rmdirat(dirfd, relative_path);
- return r;
-}
-
-int
-link(const char *oldpath, const char *newpath)
-{
- const char *old_relative_path;
- int old_dirfd = __wasilibc_find_relpath(oldpath, &old_relative_path);
-
- const char *new_relative_path;
- int new_dirfd = __wasilibc_find_relpath(newpath, &new_relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (old_dirfd == -1 || new_dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return linkat(old_dirfd, old_relative_path, new_dirfd, new_relative_path, 0);
-}
-
-int
-mkdir(const char *pathname, mode_t mode)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(pathname, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return mkdirat(dirfd, relative_path, mode);
-}
-
-DIR *
-opendir(const char *name)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(name, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return NULL;
- }
-
- return opendirat(dirfd, relative_path);
-}
-
-ssize_t
-readlink(const char *pathname, char *buf, size_t bufsiz)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(pathname, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return readlinkat(dirfd, relative_path, buf, bufsiz);
-}
-
-int
-scandir(
- const char *dirp,
- struct dirent ***namelist,
- int (*filter)(const struct dirent *),
- int (*compar)(const struct dirent **, const struct dirent **))
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(dirp, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return scandirat(dirfd, relative_path, namelist, filter, compar);
-}
-
-int
-symlink(const char *target, const char *linkpath)
-{
- const char *relative_path;
- int dirfd = __wasilibc_find_relpath(linkpath, &relative_path);
-
- // If we can't find a preopened directory handle to open this file with,
- // indicate that the program lacks the capabilities.
- if (dirfd == -1) {
- errno = ENOTCAPABLE;
- return -1;
- }
-
- return symlinkat(target, dirfd, relative_path);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// Support library
-//
-////////////////////////////////////////////////////////////////////////////////
-
-/// An entry in a po_map.
-struct po_map_entry {
- /// The name this file or directory is mapped to.
- ///
- /// This name should look like a path, but it does not necessarily need
- /// match to match the path it was originally obtained from.
- const char *name;
-
- /// File descriptor (which may be a directory)
- int fd;
-};
-
-/// A vector of po_map_entry.
-struct po_map {
- struct po_map_entry *entries;
- size_t capacity;
- size_t length;
-};
-
-static struct po_map global_map;
-
-/// Is a directory a prefix of a given path?
-///
-/// @param dir a directory path, e.g., `/foo/bar`
-/// @param dirlen the length of @b dir
-/// @param path a path that may have @b dir as a prefix,
-/// e.g., `/foo/bar/baz`
-static bool
-po_isprefix(const char *dir, size_t dirlen, const char *path)
-{
- assert(dir != NULL);
- assert(path != NULL);
-
- // Allow an empty string as a prefix of any relative path.
- if (path[0] != '/' && dirlen == 0)
- return true;
-
- size_t i;
- for (i = 0; i < dirlen; i++)
- {
- if (path[i] != dir[i])
- return false;
- }
-
- // Ignore trailing slashes in directory names.
- while (i > 0 && dir[i - 1] == '/') {
- --i;
- }
-
- return path[i] == '/' || path[i] == '\0';
-}
-
-/// Enlarge a @ref po_map's capacity.
-///
-/// This results in new memory being allocated and existing entries being copied.
-/// If the allocation fails, the function will return -1.
-static int
-po_map_enlarge(void)
-{
- size_t start_capacity = 4;
- size_t new_capacity = global_map.capacity == 0 ?
- start_capacity :
- global_map.capacity * 2;
-
- struct po_map_entry *enlarged =
- calloc(sizeof(struct po_map_entry), new_capacity);
- if (enlarged == NULL) {
- return -1;
- }
- memcpy(enlarged, global_map.entries, global_map.length * sizeof(*enlarged));
- free(global_map.entries);
- global_map.entries = enlarged;
- global_map.capacity = new_capacity;
- return 0;
-}
-
-/// Assert that the global_map is valid.
-#ifdef NDEBUG
-#define po_map_assertvalid()
-#else
-static void
-po_map_assertvalid(void)
-{
- const struct po_map_entry *entry;
- size_t i;
-
- assert(global_map.length <= global_map.capacity);
- assert(global_map.entries != NULL || global_map.capacity == 0);
-
- for (i = 0; i < global_map.length; i++) {
- entry = &global_map.entries[i];
-
- assert(entry->name != NULL);
- assert(entry->fd >= 0);
- }
-}
-#endif
-
-/// Register the given pre-opened file descriptor under the given path.
-///
-/// This function takes ownership of `name`.
-static int
-internal_register_preopened_fd(int fd, const char *name)
-{
- po_map_assertvalid();
-
- assert(fd >= 0);
- assert(name != NULL);
-
- if (global_map.length == global_map.capacity) {
- int n = po_map_enlarge();
-
- po_map_assertvalid();
-
- if (n != 0) {
- return n;
- }
- }
-
- struct po_map_entry *entry = &global_map.entries[global_map.length++];
-
- entry->name = name;
- entry->fd = fd;
-
- po_map_assertvalid();
-
- return 0;
-}
-
-/// Register the given pre-opened file descriptor under the given path.
-///
-/// This function does not take ownership of `path`.
-int
-__wasilibc_register_preopened_fd(int fd, const char *path)
-{
- const char *name = strdup(path);
- return name == NULL ? -1 : internal_register_preopened_fd(fd, name);
-}
-
-int
-__wasilibc_find_relpath(
- const char *path,
- const char **relative_path)
-{
- size_t bestlen = 0;
- int best = -1;
-
- po_map_assertvalid();
-
- assert(path != NULL);
- assert(relative_path != NULL);
-
- bool any_matches = false;
- for (size_t i = 0; i < global_map.length; i++) {
- const struct po_map_entry *entry = &global_map.entries[i];
- const char *name = entry->name;
- size_t len = strlen(name);
-
- if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) {
- // We're matching a relative path that doesn't start with "./" and isn't ".".
- if (len >= 2 && name[0] == '.' && name[1] == '/') {
- // The entry starts with "./", so skip that prefix.
- name += 2;
- len -= 2;
- } else if (len == 1 && name[0] == '.') {
- // The entry is ".", so match it as an empty string.
- name += 1;
- len -= 1;
- }
- }
-
- if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) {
- continue;
- }
-
- best = entry->fd;
- bestlen = len;
- any_matches = true;
- }
-
- const char *relpath = path + bestlen;
-
- while (*relpath == '/') {
- relpath++;
- }
-
- if (*relpath == '\0') {
- relpath = ".";
- }
-
- *relative_path = relpath;
- return best;
-}
-
-/// This is referenced by weak reference from crt1.c and lives in the same source
-/// file as `__wasilibc_find_relpath` so that it's linked in when it's needed.
-// Concerning the 51 -- see the comment by the constructor priority in
-// libc-bottom-half/sources/__wasilibc_environ.c.
-__attribute__((constructor(51)))
-static void
-__wasilibc_populate_libpreopen(void)
-{
- // Skip stdin, stdout, and stderr, and count up until we reach an invalid
- // file descriptor.
- for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
- __wasi_prestat_t prestat;
- __wasi_errno_t ret = __wasi_fd_prestat_get(fd, &prestat);
- if (ret == __WASI_ERRNO_BADF)
- break;
- if (ret != __WASI_ERRNO_SUCCESS)
- goto oserr;
- switch (prestat.tag) {
- case __WASI_PREOPENTYPE_DIR: {
- char *path = malloc(prestat.u.dir.pr_name_len + 1);
- if (path == NULL)
- goto software;
-
- // TODO: Remove the cast on `path` once the witx is updated with char8 support.
- ret = __wasi_fd_prestat_dir_name(fd, (uint8_t *)path, prestat.u.dir.pr_name_len);
- if (ret != __WASI_ERRNO_SUCCESS) {
- goto oserr;
- }
- path[prestat.u.dir.pr_name_len] = '\0';
-
- if (internal_register_preopened_fd(fd, path) != 0) {
- goto software;
- }
-
- break;
- }
- default:
- break;
- }
- }
-
- return;
-oserr:
- _Exit(EX_OSERR);
-software:
- _Exit(EX_SOFTWARE);
-}
int flags;
off_t offset;
size_t length;
- char body[];
};
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset) {
// Check for unsupported flags.
- if ((flags & MAP_FIXED) != 0 ||
+ if ((flags & (MAP_PRIVATE | MAP_SHARED)) == 0 ||
+ (flags & MAP_FIXED) != 0 ||
#ifdef MAP_SHARED_VALIDATE
- (flags & MAP_SHARED_VALIDATE) != 0 ||
+ (flags & MAP_SHARED_VALIDATE) == MAP_SHARED_VALIDATE ||
#endif
#ifdef MAP_NORESERVE
(flags & MAP_NORESERVE) != 0 ||
// Initialize the main memory buffer, either with the contents of a file,
// or with zeros.
+ addr = map + 1;
if ((flags & MAP_ANON) == 0) {
- char *body = map->body;
+ char *body = (char *)addr;
while (length > 0) {
const ssize_t nread = pread(fd, body, length, offset);
if (nread < 0) {
body += (size_t)nread;
}
} else {
- memset(map->body, 0, length);
+ memset(addr, 0, length);
}
- return map->body;
+ return addr;
}
int munmap(void *addr, size_t length) {
--- /dev/null
+// Userspace emulation of `raise` and `signal`.
+//
+// WebAssembly doesn't support asynchronous signal delivery, so we can't
+// support it in WASI libc. But we can make things like `raise` work.
+
+#define _WASI_EMULATED_SIGNAL
+#define _ALL_SOURCE
+#define _GNU_SOURCE
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+void __SIG_IGN(int sig) {
+ // do nothing
+}
+
+_Noreturn
+void __SIG_ERR(int sig) {
+ __builtin_trap();
+}
+
+_Noreturn
+static void core_handler(int sig) {
+ fprintf(stderr, "Program recieved fatal signal: %s\n", strsignal(sig));
+ abort();
+}
+
+_Noreturn
+static void terminate_handler(int sig) {
+ fprintf(stderr, "Program recieved termination signal: %s\n", strsignal(sig));
+ abort();
+}
+
+_Noreturn
+static void stop_handler(int sig) {
+ fprintf(stderr, "Program recieved stop signal: %s\n", strsignal(sig));
+ abort();
+}
+
+static void continue_handler(int sig) {
+ // do nothing
+}
+
+static const sighandler_t default_handlers[_NSIG] = {
+ // Default behavior: "core".
+ [SIGABRT] = core_handler,
+ [SIGBUS] = core_handler,
+ [SIGFPE] = core_handler,
+ [SIGILL] = core_handler,
+#if SIGIOT != SIGABRT
+ [SIGIOT] = core_handler,
+#endif
+ [SIGQUIT] = core_handler,
+ [SIGSEGV] = core_handler,
+ [SIGSYS] = core_handler,
+ [SIGTRAP] = core_handler,
+ [SIGXCPU] = core_handler,
+ [SIGXFSZ] = core_handler,
+#if defined(SIGUNUSED) && SIGUNUSED != SIGSYS
+ [SIGUNUSED] = core_handler,
+#endif
+
+ // Default behavior: ignore.
+ [SIGCHLD] = SIG_IGN,
+#if defined(SIGCLD) && SIGCLD != SIGCHLD
+ [SIGCLD] = SIG_IGN,
+#endif
+ [SIGURG] = SIG_IGN,
+ [SIGWINCH] = SIG_IGN,
+
+ // Default behavior: "continue".
+ [SIGCONT] = continue_handler,
+
+ // Default behavior: "stop".
+ [SIGSTOP] = stop_handler,
+ [SIGTSTP] = stop_handler,
+ [SIGTTIN] = stop_handler,
+ [SIGTTOU] = stop_handler,
+
+ // Default behavior: "terminate".
+ [SIGHUP] = terminate_handler,
+ [SIGINT] = terminate_handler,
+ [SIGKILL] = terminate_handler,
+ [SIGUSR1] = terminate_handler,
+ [SIGUSR2] = terminate_handler,
+ [SIGPIPE] = terminate_handler,
+ [SIGALRM] = terminate_handler,
+ [SIGTERM] = terminate_handler,
+ [SIGSTKFLT] = terminate_handler,
+ [SIGVTALRM] = terminate_handler,
+ [SIGPROF] = terminate_handler,
+ [SIGIO] = terminate_handler,
+#if SIGPOLL != SIGIO
+ [SIGPOLL] = terminate_handler,
+#endif
+ [SIGPWR] = terminate_handler,
+};
+
+static sighandler_t handlers[_NSIG];
+
+int raise(int sig) {
+ if (sig < 0 || sig >= _NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ sighandler_t func = handlers[sig];
+
+ if (func == NULL) {
+ default_handlers[sig](sig);
+ } else {
+ func(sig);
+ }
+
+ return 0;
+}
+
+void (*signal(int sig, void (*func)(int)))(int) {
+ assert(SIG_DFL == NULL);
+
+ if (sig < 0 || sig >= _NSIG) {
+ errno = EINVAL;
+ return SIG_ERR;
+ }
+
+ if (sig == SIGKILL || sig == SIGSTOP) {
+ errno = EINVAL;
+ return SIG_ERR;
+ }
+
+ sighandler_t old = handlers[sig];
+
+ handlers[sig] = func;
+
+ return old;
+}
+
+extern __typeof(signal) bsd_signal __attribute__((weak, alias("signal")));
+extern __typeof(signal) __sysv_signal __attribute__((weak, alias("signal")));
--- /dev/null
+#include <stdlib.h>
+
+void abort(void) {
+ // wasm doesn't support signals, so just trap to halt the program.
+ __builtin_trap();
+}
--- /dev/null
+// Each of the following complex functions can be implemented with a single
+// wasm instruction, so use that implementation rather than the portable
+// one in libm.
+
+#include <complex.h>
+
+float crealf(float _Complex x) {
+ return __real__ x;
+}
+
+double creal(double _Complex x) {
+ return __real__ x;
+}
+
+float cimagf(float _Complex x) {
+ return __imag__ x;
+}
+
+double cimag(double _Complex x) {
+ return __imag__ x;
+}
#include <errno.h>
-#include <threads.h>
// These values are used by reference-sysroot's dlmalloc.
const int __EINVAL = EINVAL;
--- /dev/null
+// Wasm's `min` and `max` operators implement the IEEE 754-2019
+// `minimum` and `maximum` operations, meaning that given a choice
+// between NaN and a number, they return NaN. This differs from
+// the C standard library's `fmin` and `fmax` functions, which
+// return the number. However, we can still use wasm's builtins
+// by handling the NaN cases explicitly, and it still turns out
+// to be faster than doing the whole operation in
+// target-independent C. And, it's smaller.
+
+#include <math.h>
+
+float fminf(float x, float y) {
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ return __builtin_wasm_min_f32(x, y);
+}
+
+float fmaxf(float x, float y) {
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ return __builtin_wasm_max_f32(x, y);
+}
+
+double fmin(double x, double y) {
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ return __builtin_wasm_min_f64(x, y);
+}
+
+double fmax(double x, double y) {
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ return __builtin_wasm_max_f64(x, y);
+}
--- /dev/null
+// Each of the following math functions can be implemented with a single
+// wasm instruction, so use that implementation rather than the portable
+// one in libm.
+
+#include <math.h>
+
+float fabsf(float x) {
+ return __builtin_fabsf(x);
+}
+
+double fabs(double x) {
+ return __builtin_fabs(x);
+}
+
+float sqrtf(float x) {
+ return __builtin_sqrtf(x);
+}
+
+double sqrt(double x) {
+ return __builtin_sqrt(x);
+}
+
+float copysignf(float x, float y) {
+ return __builtin_copysignf(x, y);
+}
+
+double copysign(double x, double y) {
+ return __builtin_copysign(x, y);
+}
+
+float ceilf(float x) {
+ return __builtin_ceilf(x);
+}
+
+double ceil(double x) {
+ return __builtin_ceil(x);
+}
+
+float floorf(float x) {
+ return __builtin_floorf(x);
+}
+
+double floor(double x) {
+ return __builtin_floor(x);
+}
+
+float truncf(float x) {
+ return __builtin_truncf(x);
+}
+
+double trunc(double x) {
+ return __builtin_trunc(x);
+}
+
+float nearbyintf(float x) {
+ return __builtin_nearbyintf(x);
+}
+
+double nearbyint(double x) {
+ return __builtin_nearbyint(x);
+}
+
+float rintf(float x) {
+ return __builtin_rintf(x);
+}
+
+double rint(double x) {
+ return __builtin_rint(x);
+}
+++ /dev/null
-#include <stddef.h>
-#include <errno.h>
-#include <wasi/api.h>
-#include <unistd.h>
-
-int pause(void) {
- size_t n;
- __wasi_errno_t error = __wasi_poll_oneoff(0, 0, 0, &n);
- if (error != 0) {
- errno = error;
- return -1;
- }
- __builtin_trap();
-}
--- /dev/null
+//! POSIX-like functions supporting absolute path arguments, implemented in
+//! terms of `__wasilibc_find_relpath` and `*at`-style functions.
+
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <wasi/libc.h>
+#include <wasi/libc-find-relpath.h>
+
+int open(const char *path, int oflag, ...) {
+ // WASI libc's `openat` ignores the mode argument, so call a special
+ // entrypoint which avoids the varargs calling convention.
+ return __wasilibc_open_nomode(path, oflag);
+}
+
+// See the documentation in libc.h
+int __wasilibc_open_nomode(const char *path, int oflag) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return __wasilibc_openat_nomode(dirfd, relative_path, oflag);
+}
+
+int access(const char *path, int amode) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return faccessat(dirfd, relative_path, amode, 0);
+}
+
+ssize_t readlink(
+ const char *restrict path,
+ char *restrict buf,
+ size_t bufsize)
+{
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return readlinkat(dirfd, relative_path, buf, bufsize);
+}
+
+int stat(const char *restrict path, struct stat *restrict buf) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return fstatat(dirfd, relative_path, buf, 0);
+}
+
+int lstat(const char *restrict path, struct stat *restrict buf) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return fstatat(dirfd, relative_path, buf, AT_SYMLINK_NOFOLLOW);
+}
+
+int utime(const char *path, const struct utimbuf *times) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return utimensat(dirfd, relative_path,
+ times ? ((struct timespec [2]) {
+ { .tv_sec = times->actime },
+ { .tv_sec = times->modtime }
+ })
+ : NULL,
+ 0);
+}
+
+int unlink(const char *path) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ // `unlinkat` imports `__wasi_path_remove_directory` even when
+ // `AT_REMOVEDIR` isn't passed. Instead, use a specialized function which
+ // just imports `__wasi_path_unlink_file`.
+ return __wasilibc_unlinkat(dirfd, relative_path);
+}
+
+int rmdir(const char *path) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return __wasilibc_rmdirat(dirfd, relative_path);
+}
+
+int remove(const char *path) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ // First try to remove it as a file.
+ int r = __wasilibc_unlinkat(dirfd, relative_path);
+ if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE)) {
+ // That failed, but it might be a directory.
+ r = __wasilibc_rmdirat(dirfd, relative_path);
+
+ // If it isn't a directory, we lack capabilities to remove it as a file.
+ if (errno == ENOTDIR)
+ errno = ENOTCAPABLE;
+ }
+ return r;
+}
+
+int mkdir(const char *path, mode_t mode) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(path, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return mkdirat(dirfd, relative_path, mode);
+}
+
+DIR *opendir(const char *dirname) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(dirname, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return NULL;
+ }
+
+ return opendirat(dirfd, relative_path);
+}
+
+int scandir(
+ const char *restrict dir,
+ struct dirent ***restrict namelist,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **)
+) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(dir, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return scandirat(dirfd, relative_path, namelist, filter, compar);
+}
+
+int symlink(const char *target, const char *linkpath) {
+ const char *relative_path;
+ int dirfd = __wasilibc_find_relpath(linkpath, &relative_path);
+
+ // If we can't find a preopen for it, indicate that we lack capabilities.
+ if (dirfd == -1) {
+ errno = ENOTCAPABLE;
+ return -1;
+ }
+
+ return symlinkat(target, dirfd, relative_path);
+}
+
+int link(const char *old, const char *new) {
+ const char *old_relative_path;
+ int old_dirfd = __wasilibc_find_relpath(old, &old_relative_path);
+
+ if (old_dirfd != -1) {
+ const char *new_relative_path;
+ int new_dirfd = __wasilibc_find_relpath(new, &new_relative_path);
+
+ if (new_dirfd != -1)
+ return linkat(old_dirfd, old_relative_path,
+ new_dirfd, new_relative_path, 0);
+ }
+
+ // We couldn't find a preopen for it; indicate that we lack capabilities.
+ errno = ENOTCAPABLE;
+ return -1;
+}
+
+int rename(const char *old, const char *new) {
+ const char *old_relative_path;
+ int old_dirfd = __wasilibc_find_relpath(old, &old_relative_path);
+
+ if (old_dirfd != -1) {
+ const char *new_relative_path;
+ int new_dirfd = __wasilibc_find_relpath(new, &new_relative_path);
+
+ if (new_dirfd != -1)
+ return renameat(old_dirfd, old_relative_path,
+ new_dirfd, new_relative_path);
+ }
+
+ // We couldn't find a preopen for it; indicate that we lack capabilities.
+ errno = ENOTCAPABLE;
+ return -1;
+}
--- /dev/null
+//! Support for "preopens", file descriptors passed into the program from the
+//! environment, with associated path prefixes, which can be used to map
+//! absolute paths to capabilities with relative paths.
+
+#ifdef _REENTRANT
+#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads"
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <wasi/api.h>
+#include <wasi/libc.h>
+#include <wasi/libc-find-relpath.h>
+
+/// A name and file descriptor pair.
+typedef struct preopen {
+ /// The path prefix associated with the file descriptor.
+ const char *prefix;
+
+ /// The file descriptor.
+ __wasi_fd_t fd;
+} preopen;
+
+/// A simple growable array of `preopen`.
+static preopen *preopens;
+static size_t num_preopens;
+static size_t preopen_capacity;
+
+#ifdef NDEBUG
+#define assert_invariants() // assertions disabled
+#else
+static void assert_invariants(void) {
+ assert(num_preopens <= preopen_capacity);
+ assert(preopen_capacity == 0 || preopens != NULL);
+ assert(preopen_capacity == 0 ||
+ preopen_capacity * sizeof(preopen) > preopen_capacity);
+
+ for (size_t i = 0; i < num_preopens; ++i) {
+ const preopen *pre = &preopens[i];
+ assert(pre->prefix != NULL);
+ assert(pre->fd != (__wasi_fd_t)-1);
+#ifdef __wasm__
+ assert((uintptr_t)pre->prefix <
+ (__uint128_t)__builtin_wasm_memory_size(0) * PAGESIZE);
+#endif
+ }
+}
+#endif
+
+/// Allocate space for more preopens. Returns 0 on success and -1 on failure.
+static int resize(void) {
+ size_t start_capacity = 4;
+ size_t old_capacity = preopen_capacity;
+ size_t new_capacity = old_capacity == 0 ? start_capacity : old_capacity * 2;
+
+ preopen *old_preopens = preopens;
+ preopen *new_preopens = calloc(sizeof(preopen), new_capacity);
+ if (new_preopens == NULL)
+ return -1;
+
+ memcpy(new_preopens, old_preopens, num_preopens * sizeof(preopen));
+ preopens = new_preopens;
+ preopen_capacity = new_capacity;
+ free(old_preopens);
+
+ assert_invariants();
+ return 0;
+}
+
+/// Register the given preopened file descriptor under the given path.
+///
+/// This function takes ownership of `prefix`.
+static int internal_register_preopened_fd(__wasi_fd_t fd, const char *prefix) {
+ assert_invariants();
+
+ if (num_preopens == preopen_capacity && resize() != 0)
+ return -1;
+
+ preopens[num_preopens++] = (preopen) { prefix, fd, };
+
+ assert_invariants();
+ return 0;
+}
+
+/// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`?
+static bool prefix_matches(const char *prefix, size_t prefix_len, const char *path) {
+ // Allow an empty string as a prefix of any relative path.
+ if (path[0] != '/' && prefix_len == 0)
+ return true;
+
+ // Check whether any bytes of the prefix differ.
+ if (memcmp(path, prefix, prefix_len) != 0)
+ return false;
+
+ // Ignore trailing slashes in directory names.
+ size_t i = prefix_len;
+ while (i > 0 && prefix[i - 1] == '/') {
+ --i;
+ }
+
+ // Match only complete path components.
+ char last = path[i];
+ return last == '/' || last == '\0';
+}
+
+// See the documentation in libc.h
+int __wasilibc_register_preopened_fd(int fd, const char *prefix) {
+ prefix = strdup(prefix);
+ return prefix == NULL ? -1 :
+ internal_register_preopened_fd((__wasi_fd_t)fd, prefix);
+}
+
+// See the documentation in libc-find-relpath.h.
+int __wasilibc_find_relpath(const char *path,
+ const char **restrict relative_path) {
+ assert_invariants();
+
+ // Search through the preopens table. Iterate in reverse so that more
+ // recently added preopens take precedence over less recently addded ones.
+ size_t match_len = 0;
+ int fd = -1;
+ for (size_t i = num_preopens; i > 0; --i) {
+ const preopen *pre = &preopens[i - 1];
+ const char *prefix = pre->prefix;
+ size_t len = strlen(prefix);
+
+ if (path[0] != '/' &&
+ (path[0] != '.' || (path[1] != '/' && path[1] != '\0')))
+ {
+ // We're matching a relative path that doesn't start with "./" and
+ // isn't ".".
+ if (len >= 2 && prefix[0] == '.' && prefix[1] == '/') {
+ // The preopen starts with "./", so skip that prefix.
+ prefix += 2;
+ len -= 2;
+ } else if (len == 1 && prefix[0] == '.') {
+ // The preopen is ".", so match it as an empty string.
+ prefix += 1;
+ len -= 1;
+ }
+ }
+
+ // If we haven't had a match yet, or the candidate path is longer than
+ // our current best match's path, and the candidate path is a prefix of
+ // the requested path, take that as the new best path.
+ if ((fd == -1 || len > match_len) &&
+ prefix_matches(prefix, len, path))
+ {
+ fd = pre->fd;
+ match_len = len;
+ }
+ }
+
+ // The relative path is the substring after the portion that was matched.
+ const char *computed = path + match_len;
+
+ // Omit leading slashes in the relative path.
+ while (*computed == '/')
+ ++computed;
+
+ // *at syscalls don't accept empty relative paths, so use "." instead.
+ if (*computed == '\0')
+ computed = ".";
+
+ *relative_path = computed;
+ return fd;
+}
+
+/// This is referenced by weak reference from crt1.c and lives in the same
+/// source file as `__wasilibc_find_relpath` so that it's linked in when it's
+/// needed.
+// Concerning the 51 -- see the comment by the constructor priority in
+// libc-bottom-half/sources/environ.c.
+__attribute__((constructor(51)))
+static void __wasilibc_populate_preopens(void) {
+ // Skip stdin, stdout, and stderr, and count up until we reach an invalid
+ // file descriptor.
+ for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
+ __wasi_prestat_t prestat;
+ __wasi_errno_t ret = __wasi_fd_prestat_get(fd, &prestat);
+ if (ret == __WASI_ERRNO_BADF)
+ break;
+ if (ret != __WASI_ERRNO_SUCCESS)
+ goto oserr;
+ switch (prestat.tag) {
+ case __WASI_PREOPENTYPE_DIR: {
+ char *prefix = malloc(prestat.u.dir.pr_name_len + 1);
+ if (prefix == NULL)
+ goto software;
+
+ // TODO: Remove the cast on `path` once the witx is updated with
+ // char8 support.
+ ret = __wasi_fd_prestat_dir_name(fd, (uint8_t *)prefix,
+ prestat.u.dir.pr_name_len);
+ if (ret != __WASI_ERRNO_SUCCESS)
+ goto oserr;
+ prefix[prestat.u.dir.pr_name_len] = '\0';
+
+ if (internal_register_preopened_fd(fd, prefix) != 0)
+ goto software;
+
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return;
+oserr:
+ _Exit(EX_OSERR);
+software:
+ _Exit(EX_SOFTWARE);
+}
--- /dev/null
+#include <stdlib.h>
+#include <errno.h>
+
+void *__reallocarray(void *ptr, size_t nmemb, size_t size) {
+ size_t bytes;
+ if (__builtin_umull_overflow(nmemb, size, &bytes)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(ptr, bytes);
+}
+
+void *reallocarray(void *ptr, size_t nmemb, size_t size)
+ __attribute__((__weak__, __alias__("__reallocarray")));
+++ /dev/null
-#include <string.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-size_t strlen(const char *str) {
- const char *s = str;
- while (*s) {
- ++s;
- }
- return s - str;
-}
-
-char *strdup(const char *str) {
- size_t buf_len = strlen(str) + 1;
- void *ptr = malloc(buf_len);
- if (ptr == NULL) {
- return NULL;
- }
- return memcpy(ptr, str, buf_len);
-}
-
-int strcmp(const char *a, const char *b) {
- while (*a != '\0' && (*a == *b)) {
- ++a;
- ++b;
- }
- return *(const unsigned char*)a - *(const unsigned char*)b;
-}
-
-void *memchr(const void *ptr, int c, size_t len) {
- const unsigned char *p = ptr;
- while (len != 0 && *p != (unsigned char)c) {
- ++p;
- --len;
- }
- if (len == 0) {
- return NULL;
- }
- return (void *)p;
-}
+# WASI libc "top half".
+
+The WASI libc "top half" is conceptually the upper half of a traditional libc
+implementation, consisting of C standard library and other relatively
+higher-level functionality.
+
Code in the musl directory is based on musl revision
-b07d45eb01e900f0176894fdedab62285f5cb8be, which is v1.1.23, from
+040c1d16b468c50c04fc94edff521f1637708328, which is v1.2.0, from
git://git.musl-libc.org/musl.
Whole files which are unused are omitted. Changes to upstream code are wrapped
bootstrapping, and Linux distributions built on musl can be found on
the project website:
- http://www.musl-libc.org/
+ https://musl.libc.org/
-#include <__header_bits_signal.h>
+#ifdef _WASI_EMULATED_SIGNAL
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT SIGABRT
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL 29
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED SIGSYS
+
+#define _NSIG 65
+
+#endif
+#ifndef _WASI_EMULATED_SIGNAL
+#error "wasm lacks signal support; to enable minimal signal emulation, \
+compile with -D_WASI_EMULATED_SIGNAL and link with -lwasi-emulated-signal"
+#else
#ifndef _SIGNAL_H
#define _SIGNAL_H
#ifdef _GNU_SOURCE
#define __ucontext ucontext
#endif
-#endif
#define __NEED_size_t
#define __NEED_pid_t
#define SI_KERNEL 128
typedef struct sigaltstack stack_t;
+#endif
#endif
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
+#ifdef __wasilibc_unmodified_upstream /* WASI has no sigaction */
#define SIG_HOLD ((void (*)(int)) 2)
#define FPE_INTDIV 1
#define SIGEV_SIGNAL 0
#define SIGEV_NONE 1
#define SIGEV_THREAD 2
+#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no realtime signals */
int __libc_current_sigrtmin(void);
int sigqueue(pid_t, int, union sigval);
#endif
+#ifdef __wasilibc_unmodified_upstream /* WASI has no threads yet */
int pthread_sigmask(int, const sigset_t *__restrict, sigset_t *__restrict);
int pthread_kill(pthread_t, int);
+#endif
-#ifdef __wasilibc_unmodified_upstream /* WASI has no signals */
+#ifdef __wasilibc_unmodified_upstream /* WASI has no siginfo */
void psiginfo(const siginfo_t *, const char *);
-void psignal(int, const char *);
#endif
+void psignal(int, const char *);
#endif
#endif
#endif
-#ifdef __wasilibc_unmodified_upstream /* WASI has no signals */
#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
#define NSIG _NSIG
typedef void (*sig_t)(int);
#ifdef _GNU_SOURCE
typedef void (*sighandler_t)(int);
void (*bsd_signal(int, void (*)(int)))(int);
+#ifdef __wasilibc_unmodified_upstream /* WASI has no signal sets */
int sigisemptyset(const sigset_t *);
int sigorset (sigset_t *, const sigset_t *, const sigset_t *);
int sigandset(sigset_t *, const sigset_t *, const sigset_t *);
#define SA_NOMASK SA_NODEFER
#define SA_ONESHOT SA_RESETHAND
#endif
+#endif
+#ifdef __wasilibc_unmodified_upstream /* 1 is a valid function pointer on wasm */
#define SIG_ERR ((void (*)(int))-1)
#define SIG_DFL ((void (*)(int)) 0)
#define SIG_IGN ((void (*)(int)) 1)
+#else
+void __SIG_ERR(int);
+void __SIG_IGN(int);
+#define SIG_ERR (__SIG_ERR)
+#define SIG_DFL ((void (*)(int)) 0)
+#define SIG_IGN (__SIG_IGN)
#endif
+#ifdef __wasilibc_unmodified_upstream /* Make sig_atomic_t 64-bit on wasm64 */
typedef int sig_atomic_t;
+#else
+typedef long sig_atomic_t;
+#endif
-#ifdef __wasilibc_unmodified_upstream /* WASI has no signals */
void (*signal(int, void (*)(int)))(int);
-#endif
int raise(int);
+#ifdef __wasilibc_unmodified_upstream /* WASI has no sigtimedwait */
#if _REDIR_TIME64
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
__REDIR(sigtimedwait, __sigtimedwait_time64);
#endif
#endif
+#endif
#ifdef __cplusplus
}
#endif
#endif
+#endif
unsigned alarm(unsigned);
#endif
unsigned sleep(unsigned);
+#ifdef __wasilibc_unmodified_upstream /* WASI has no pause */
int pause(void);
+#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no fork/exec */
pid_t fork(void);
#include <limits.h>
#include <errno.h>
#include <sys/resource.h>
+#ifdef __wasilibc_unmodified_upstream // WASI has no realtime signals
#include <signal.h>
+#endif
#include <sys/sysinfo.h>
#include "syscall.h"
#include "libc.h"
* as a consequence of linking either __toread.c or __towrite.c. */
weak_alias(dummy, __funcs_on_exit);
weak_alias(dummy, __stdio_exit);
+#ifdef __wasilibc_unmodified_upstream // fini
weak_alias(dummy, _fini);
-#ifdef __wasilibc_unmodified_upstream // fini
extern weak hidden void (*const __fini_array_start)(void), (*const __fini_array_end)(void);
static void libc_exit_fini(void)
// Split out the cleanup functions so that we can call them without calling
// _Exit if we don't need to. This allows _start to just return if main
// returns 0.
-void __prepare_for_exit(void)
+void __wasm_call_dtors(void)
{
__funcs_on_exit();
__stdio_exit();
_Noreturn void exit(int code)
{
- __prepare_for_exit();
+ __wasm_call_dtors();
_Exit(code);
}
#endif
#include "../../include/signal.h"
+#ifdef __wasilibc_unmodified_upstream // WASI has no sigaction
hidden int __sigaction(int, const struct sigaction *, struct sigaction *);
hidden void __block_all_sigs(void *);
hidden void __restore_sigs(void *);
hidden void __get_handler_set(sigset_t *);
+#endif
#endif
hidden void __stdio_exit(void);
hidden void __stdio_exit_needed(void);
+#ifdef __wasilibc_unmodified_upstream // wasm has no "protected" visibility
#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
__attribute__((visibility("protected")))
#endif
+#endif
int __overflow(FILE *, int), __uflow(FILE *);
hidden int __fseeko(FILE *, off_t, int);
}
fn print_handle(ret: &mut String, name: &Id, h: &HandleDatatype) {
- ret.push_str(&format!("typedef int __wasi_{}_t;", ident_name(name)));
+ ret.push_str(&format!("typedef int __wasi_{}_t;\n\n", ident_name(name)));
ret.push_str(&format!(
"_Static_assert(sizeof(__wasi_{}_t) == {}, \"witx calculated size\");\n",