├── Audio ├── Makefile ├── loader.html ├── loader.js ├── main.cpp └── output.wasm ├── Basic ├── Makefile ├── loader.html ├── loader.js ├── main.c └── output.wasm ├── Cpp ├── Makefile ├── loader.html ├── loader.js ├── main.cpp └── output.wasm ├── Embed ├── Makefile ├── loader.html ├── loader.js ├── loader.minified.js ├── main.cpp └── output.html ├── GenJS ├── Makefile ├── loader.html ├── loader.js ├── main.c └── output.wasm ├── LibC ├── Makefile ├── loader.html ├── loader.js ├── main.c └── output.wasm ├── LoadUrl ├── Makefile ├── loader.html ├── loader.js ├── main.cpp └── output.wasm ├── README.md ├── UNLICENSE ├── WebGL ├── Makefile ├── loader.html ├── loader.js ├── main.cpp └── output.wasm └── showsource.js /Audio/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | EXPORTS = WAFNAudio 33 | SOURCES = main.cpp 34 | BUILD = RELEASE 35 | 36 | #------------------------------------------------------------------------------------------------------ 37 | 38 | ifeq ($(BUILD),RELEASE) 39 | OUTDIR := Release-wasm 40 | DBGCFLAGS := -DNDEBUG 41 | LDFLAGS := -strip-all -gc-sections 42 | WOPTFLAGS := -O3 43 | else 44 | OUTDIR := Debug-wasm 45 | DBGCFLAGS := -DDEBUG -D_DEBUG 46 | LDFLAGS := 47 | WOPTFLAGS := -g -O0 48 | endif 49 | 50 | # Global compiler flags 51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 53 | 54 | # Global compiler flags for Wasm targeting 55 | CLANGFLAGS := -target wasm32 -nostdinc 56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 63 | 64 | # Flags for wasm-ld 65 | LDFLAGS += -no-entry -allow-undefined -import-memory 66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 68 | 69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 71 | 72 | # Check if there are any source files 73 | ifeq ($(SOURCES),) 74 | $(error No source files found for build) 75 | endif 76 | 77 | # Compute tool paths 78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 82 | endif 83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 85 | endif 86 | 87 | # Surround used commands with double quotes 88 | CC := "$(LLVM_ROOT)/clang" 89 | CXX := "$(LLVM_ROOT)/clang" -x c++ 90 | LD := "$(LLVM_ROOT)/wasm-ld" 91 | 92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 93 | .PHONY: clean cleanall run analyze 94 | 95 | clean: 96 | $(info Removing all build files ...) 97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 98 | 99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 101 | -include $(OBJS:%.o=%.d) 102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 105 | 106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 107 | $(info Linking $@ ...) 108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 110 | 111 | $(OUTDIR)/loader.js : loader.js 112 | $(info Copying $^ to $@ ...) 113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 115 | 116 | $(OUTDIR)/loader.html : loader.html 117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 119 | 120 | define COMPILE 121 | $(info $2) 122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 124 | endef 125 | 126 | #------------------------------------------------------------------------------------------------------ 127 | #if System.bc exists, don't even bother checking sources, build once and forget for now 128 | ifeq ($(if $(wildcard System.bc),1,0),0) 129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 131 | 132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 137 | 138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 140 | 141 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 143 | endif 144 | 145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 146 | ifeq ($(if $(SYS_MISSING),1,0),1) 147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 148 | endif 149 | 150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 152 | 153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 155 | 156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 161 | 162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 166 | 167 | define SYS_COMPILE 168 | $(info $2) 169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 171 | endef 172 | 173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 174 | $(info Creating archive $@ ...) 175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 177 | endif #need System.bc 178 | #------------------------------------------------------------------------------------------------------ 179 | -------------------------------------------------------------------------------- /Audio/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: Audio 7 | 8 | 9 |

WebAssembly Sample: Audio

10 |
11 |
Loading...
12 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Audio/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Some global state variables and max heap definition 32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32; 33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB 34 | 35 | // Define print and error functions if not yet defined by the outer html file 36 | WA.print = WA.print || function (msg) { console.log(msg); }; 37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 38 | 39 | // A generic abort function that if called stops the execution of the program and shows an error 40 | function abort(code, msg) 41 | { 42 | WA.error(code, msg); 43 | throw 'abort'; 44 | } 45 | 46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional) 47 | function WriteHeapString(str, ptr, max_length) 48 | { 49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;} 54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 58 | } 59 | return r[f]=0,f-a; 60 | } 61 | 62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8) 63 | function ReadHeapString(ptr, length) 64 | { 65 | if (length === 0 || !ptr) return ''; 66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++) 67 | { 68 | t = HEAPU8[((ptr)+(i))>>0]; 69 | if (t == 0 && !length) break; 70 | hasUtf |= t; 71 | } 72 | if (!length) length = i; 73 | if (hasUtf & 128) 74 | { 75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;) 76 | { 77 | if(o==p||(e=r[o++],!e)) return g; 78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e); 79 | } 80 | } 81 | // split up into chunks, because .apply on a huge string can overflow the stack 82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024) 83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024))); 84 | return ret; 85 | } 86 | 87 | // Defines our custom functions in the env object that get passed to the wasm module 88 | function WAJS_WASM_IMPORTS(env) 89 | { 90 | // Function that starts the audio output 91 | env.WAJS_StartAudio = function() 92 | { 93 | // Try to initialize WebAudio context with stereo channels and 44100 hz frequency 94 | var audioCtx; 95 | function findAlias(el, a, b, c) { return el[a+c] || el['moz'+b+c] || el['webkit'+b+c] || el['ms'+b+c]; } 96 | try { audioCtx = new (findAlias(window,'','','AudioContext'))(); } catch (e) { } 97 | if (!audioCtx) { WA.print('Warning: WebAudio not supported\n'); return; } 98 | var encTime = 0, audioSamples = 882, audioSecs = audioSamples/44100; 99 | var ptrTempBuf = 0, f32TempBuf = 0, audioBufs = [{'length':0}], audioBufIdx = 0; 100 | 101 | // Call a function every few milliseconds to fill the audio buffer if required 102 | setInterval(function() 103 | { 104 | // Try to start the audio playback if suspended/blocked by the browser 105 | if (audioCtx.state == 'suspended') { audioCtx.resume(); if (audioCtx.state == 'suspended') return; } 106 | 107 | // Check if enough time has passed for the next audio block to be generated (or return if not) 108 | var ctxTime = audioCtx.currentTime; 109 | if (ctxTime == 0) encTime = 0; 110 | if (encTime - ctxTime > audioSecs) return; 111 | 112 | // Check if the audio buffer size was increased (due to starvation) or if this is the first call 113 | if (audioBufs[0].length != audioSamples) 114 | { 115 | // Allocate memory on the wasm heap where it will place the float encoded stereo audio data 116 | WA.asm.free(ptrTempBuf); 117 | f32TempBuf = ((ptrTempBuf = WA.asm.malloc(audioSamples<<3))>>2); //2 channels, 4 byte per float sized sample 118 | 119 | // Prepare 4 matching audio buffers that get cycled through 120 | for (var i = 0; i != 4; i++) audioBufs[i] = audioCtx.createBuffer(2, audioSamples, 44100); 121 | } 122 | 123 | // Call the wasm module function WAFNAudio to generate audio data 124 | if (WA.asm.WAFNAudio(ptrTempBuf, audioSamples)) 125 | { 126 | // Copy the generated data for both channels into the next cycled audio buffer 127 | var soundBuffer = audioBufs[audioBufIdx = ((audioBufIdx + 1) % 4)]; 128 | soundBuffer.getChannelData(0).set(HEAPF32.subarray(f32TempBuf, f32TempBuf + audioSamples)); 129 | soundBuffer.getChannelData(1).set(HEAPF32.subarray(f32TempBuf + audioSamples, f32TempBuf + (audioSamples<<1))); 130 | 131 | // Send the buffer off to be played back 132 | var source = audioCtx.createBufferSource(); 133 | source.connect(audioCtx.destination); 134 | source.buffer = soundBuffer; 135 | source[source.start ? 'start' : 'noteOn'](0.005+encTime); 136 | } 137 | 138 | // Check if this call is too late (and audio data generation is behind audio playback) 139 | if (ctxTime > encTime && ctxTime > .5) 140 | { 141 | // Depending on if the site/tab is focused extend the audio buffer length (up to a maximum of .25 second duration) 142 | if (ctxTime - encTime < audioSecs * 10 && audioSamples < 11025 && document.hasFocus()) 143 | { 144 | //only increase buffer when at least some time has passed (not directly after loading) and it's not a giant hickup 145 | audioSecs = (audioSamples += 441)/44100; 146 | WA.print('Warning: Audio callback had starved sending audio by ' + (ctxTime - encTime) + ' seconds. (extending samples to: ' + audioSamples + ')\n'); 147 | } 148 | // Reset the encode time cursor (if the site/tab is not focused intentionally delay the playback to be more relaxed) 149 | encTime = ctxTime + (document.hasFocus() ? 0 : 1.5); 150 | } 151 | 152 | // Advance the encode time cursor by the amount played back 153 | encTime += audioSecs; 154 | }, 10); 155 | }; 156 | } 157 | 158 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript 159 | function MemorySetBufferViews() 160 | { 161 | var buf = WASM_MEMORY.buffer; 162 | HEAP32 = new Int32Array(buf); 163 | HEAPU8 = new Uint8Array(buf); 164 | HEAPU16 = new Uint16Array(buf); 165 | HEAPU32 = new Uint32Array(buf); 166 | HEAPF32 = new Float32Array(buf); 167 | } 168 | 169 | // Set up the env and wasi objects that contains the functions passed to the wasm module 170 | var env = 171 | { 172 | // sbrk gets called to increase the size of the memory heap by an increment 173 | sbrk: function(increment) 174 | { 175 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength; 176 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : '')); 177 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory'); 178 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); } 179 | WASM_HEAP = heapNew; 180 | return heapOld|0; 181 | }, 182 | 183 | // Functions querying the system time 184 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; }, 185 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; }, 186 | 187 | // Various functions thet can be called from wasm that abort the program 188 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); }, 189 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); }, 190 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); }, 191 | abort: function() { abort('CRASH', 'Abort called'); }, 192 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); }, 193 | }; 194 | 195 | // Functions that do nothing in this wasm context 196 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {}; 197 | 198 | // Math functions 199 | env.ceil = env.ceilf = Math.ceil; 200 | env.exp = env.expf = Math.exp; 201 | env.floor = env.floorf = Math.floor; 202 | env.log = env.logf = Math.log; 203 | env.pow = env.powf = Math.pow; 204 | env.cos = env.cosf = Math.cos; 205 | env.sin = env.sinf = Math.sin; 206 | env.tan = env.tanf = Math.tan; 207 | env.acos = env.acosf = Math.acos; 208 | env.asin = env.asinf = Math.asin; 209 | env.sqrt = env.sqrtf = Math.sqrt; 210 | env.atan = env.atanf = Math.atan; 211 | env.atan2 = env.atan2f = Math.atan2; 212 | env.fabs = env.fabsf = env.abs = Math.abs; 213 | env.round = env.roundf = env.rint = env.rintf = Math.round; 214 | 215 | // Extend the env object with our custom functions 216 | WAJS_WASM_IMPORTS(env); 217 | 218 | // Find the start point of the stack and the heap to calculate the initial memory requirements 219 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536; 220 | // This code goes through the wasm file sections according the binary encoding description 221 | // https://webassembly.org/docs/binary-encoding/ 222 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 223 | { 224 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 225 | function Get() { return wasmBytes[i++]; } 226 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 227 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 228 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 229 | if (type == 6) 230 | { 231 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 232 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 233 | wasmHeapBase = offset; 234 | } 235 | if (type == 11) 236 | { 237 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area 238 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++) 239 | { 240 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB(); 241 | wasmDataEnd = (doffset + dsize); 242 | wasmStackTop = (wasmDataEnd+15)>>4<<4; 243 | i += dsize; 244 | } 245 | } 246 | } 247 | 248 | // Validate the queried pointers 249 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')'); 250 | 251 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk) 252 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 253 | WASM_HEAP = wasmHeapBase; 254 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 }); 255 | MemorySetBufferViews(); 256 | 257 | // Instantiate the wasm module by passing the prepared env object containing import functions for the wasm module 258 | WebAssembly.instantiate(wasmBytes, {env:env}).then(function (output) 259 | { 260 | // Store the list of the functions exported by the wasm module in WA.asm 261 | WA.asm = output.instance.exports; 262 | 263 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 264 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 265 | 266 | // If function 'main' exists, call it 267 | if (WA.asm.main) 268 | { 269 | // Store the argument list with 1 entry at the far end of the stack to pass to main 270 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe'; 271 | 272 | // Store the program name string after the argv list 273 | WriteHeapString(exe, (argv + 8)); 274 | 275 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer 276 | HEAPU32[(argv>>2) + 0] = (argv + 8) 277 | HEAPU32[(argv>>2) + 1] = 0; 278 | 279 | WA.asm.main(argc, argv); 280 | } 281 | 282 | // If the outer HTML file supplied a 'started' callback, call it 283 | if (WA.started) WA.started(); 284 | }) 285 | .catch(function (err) 286 | { 287 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 288 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 289 | }); 290 | 291 | }); 292 | -------------------------------------------------------------------------------- /Audio/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | 30 | // Function defined in loader.js 31 | extern "C" void WAJS_StartAudio(); 32 | 33 | // This function is called at startup 34 | int main(int argc, char *argv[]) 35 | { 36 | WAJS_StartAudio(); 37 | 38 | return 0; 39 | } 40 | 41 | // This function is called by loader.js to feed audio 42 | extern "C" bool WAFNAudio(float* sample_buffer, unsigned int samples) 43 | { 44 | float *pLeft = sample_buffer, *pRight = sample_buffer + samples; 45 | for(unsigned int i = 0; i < samples; i++) 46 | { 47 | // Render 220 HZ sine wave at 25% volume into both channels 48 | static size_t waveCount; 49 | float wave = (((waveCount++) % 44100) / 44100.0f); 50 | pLeft[i] = pRight[i] = sinf(2.0f * 3.14159f * 220.0f * wave) * 0.25f; 51 | } 52 | return true; 53 | } 54 | -------------------------------------------------------------------------------- /Audio/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/Audio/output.wasm -------------------------------------------------------------------------------- /Basic/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | WASMOPT = D:/dev/wasm/wasm-opt.exe 30 | 31 | EXPORTS = square 32 | SOURCES = main.c 33 | BUILD = RELEASE 34 | 35 | #------------------------------------------------------------------------------------------------------ 36 | 37 | ifeq ($(BUILD),RELEASE) 38 | OUTDIR := Release-wasm 39 | DBGCFLAGS := -DNDEBUG 40 | LDFLAGS := -strip-all -gc-sections 41 | WOPTFLAGS := -O3 42 | else 43 | OUTDIR := Debug-wasm 44 | DBGCFLAGS := -DDEBUG -D_DEBUG 45 | LDFLAGS := 46 | WOPTFLAGS := -g -O0 47 | endif 48 | 49 | # Global compiler flags 50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 52 | 53 | # Global compiler flags for Wasm targeting 54 | CLANGFLAGS := -target wasm32 -nostdinc 55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 57 | 58 | # Flags for wasm-ld 59 | LDFLAGS += -no-entry -allow-undefined -import-memory 60 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 61 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 62 | 63 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 64 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 65 | 66 | # Check if there are any source files 67 | ifeq ($(SOURCES),) 68 | $(error No source files found for build) 69 | endif 70 | 71 | # Compute tool paths 72 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 73 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 74 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 75 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 76 | endif 77 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 78 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 79 | endif 80 | 81 | # Surround used commands with double quotes 82 | CC := "$(LLVM_ROOT)/clang" 83 | CXX := "$(LLVM_ROOT)/clang" -x c++ 84 | LD := "$(LLVM_ROOT)/wasm-ld" 85 | 86 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 87 | .PHONY: clean cleanall run analyze 88 | 89 | clean: 90 | $(info Removing all build files ...) 91 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 92 | 93 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 94 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 95 | -include $(OBJS:%.o=%.d) 96 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 97 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 98 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 99 | 100 | $(OUTDIR)/output.wasm : Makefile $(OBJS) 101 | $(info Linking $@ ...) 102 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) 103 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 104 | 105 | $(OUTDIR)/loader.js : loader.js 106 | $(info Copying $^ to $@ ...) 107 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 108 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 109 | 110 | $(OUTDIR)/loader.html : loader.html 111 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 112 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 113 | 114 | define COMPILE 115 | $(info $2) 116 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 117 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 118 | endef 119 | -------------------------------------------------------------------------------- /Basic/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: Pure C 7 | 8 | 9 |

WebAssembly Sample: Pure C

10 |
11 |
Loading...
12 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Basic/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Define print and error functions if not yet defined by the outer html file 32 | WA.print = WA.print || function (msg) { console.log(msg); }; 33 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 34 | 35 | // A generic abort function that if called stops the execution of the program and shows an error 36 | function abort(code, msg) 37 | { 38 | WA.error(code, msg); 39 | throw 'abort'; 40 | } 41 | 42 | // Find the start point of the heap to calculate the initial memory requirements 43 | var wasmHeapBase = 65536; 44 | // This code goes through the wasm file sections according the binary encoding description 45 | // https://webassembly.org/docs/binary-encoding/ 46 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 47 | { 48 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 49 | function Get() { return wasmBytes[i++]; } 50 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 51 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 52 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 53 | if (type == 6) 54 | { 55 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 56 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 57 | wasmHeapBase = offset; 58 | break; 59 | } 60 | } 61 | 62 | // Set the wasm memory size to [DATA] + [STACK] + [256KB HEAP] 63 | // (This loader does not support memory growing so it stays at this size) 64 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 65 | var env = { memory: new WebAssembly.Memory({initial: wasmMemInitial>>16 }) }; 66 | 67 | // Instantiate the wasm module by passing the prepared environment 68 | WebAssembly.instantiate(wasmBytes, {env:env}).then(function (output) 69 | { 70 | // Store the list of the functions exported by the wasm module in WA.asm 71 | WA.asm = output.instance.exports; 72 | 73 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 74 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 75 | 76 | // If function 'main' exists, call it with dummy arguments 77 | if (WA.asm.main) WA.asm.main(0, 0); 78 | 79 | // If the outer HTML file supplied a 'started' callback, call it 80 | if (WA.started) WA.started(); 81 | }) 82 | .catch(function (err) 83 | { 84 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 85 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 86 | }); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /Basic/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | int square(int num) 29 | { 30 | return num * num; 31 | } 32 | -------------------------------------------------------------------------------- /Basic/output.wasm: -------------------------------------------------------------------------------- 1 | asm ``__wasm_call_ctorssquare 2 |   l -------------------------------------------------------------------------------- /Cpp/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | SOURCES = main.cpp 33 | BUILD = RELEASE 34 | 35 | #------------------------------------------------------------------------------------------------------ 36 | 37 | ifeq ($(BUILD),RELEASE) 38 | OUTDIR := Release-wasm 39 | DBGCFLAGS := -DNDEBUG 40 | LDFLAGS := -strip-all -gc-sections 41 | WOPTFLAGS := -O3 42 | else 43 | OUTDIR := Debug-wasm 44 | DBGCFLAGS := -DDEBUG -D_DEBUG 45 | LDFLAGS := 46 | WOPTFLAGS := -g -O0 47 | endif 48 | 49 | # Global compiler flags 50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 52 | 53 | # Global compiler flags for Wasm targeting 54 | CLANGFLAGS := -target wasm32 -nostdinc 55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 62 | 63 | # Flags for wasm-ld 64 | LDFLAGS += -no-entry -allow-undefined -import-memory 65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 67 | 68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 70 | 71 | # Check if there are any source files 72 | ifeq ($(SOURCES),) 73 | $(error No source files found for build) 74 | endif 75 | 76 | # Compute tool paths 77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 81 | endif 82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 84 | endif 85 | 86 | # Surround used commands with double quotes 87 | CC := "$(LLVM_ROOT)/clang" 88 | CXX := "$(LLVM_ROOT)/clang" -x c++ 89 | LD := "$(LLVM_ROOT)/wasm-ld" 90 | 91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 92 | .PHONY: clean cleanall run analyze 93 | 94 | clean: 95 | $(info Removing all build files ...) 96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 97 | 98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 100 | -include $(OBJS:%.o=%.d) 101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 104 | 105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 106 | $(info Linking $@ ...) 107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 109 | 110 | $(OUTDIR)/loader.js : loader.js 111 | $(info Copying $^ to $@ ...) 112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 114 | 115 | $(OUTDIR)/loader.html : loader.html 116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 118 | 119 | define COMPILE 120 | $(info $2) 121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 123 | endef 124 | 125 | #------------------------------------------------------------------------------------------------------ 126 | #if System.bc exists, don't even bother checking sources, build once and forget for now 127 | ifeq ($(if $(wildcard System.bc),1,0),0) 128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 130 | 131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 136 | 137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 139 | 140 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 142 | endif 143 | 144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 145 | ifeq ($(if $(SYS_MISSING),1,0),1) 146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 147 | endif 148 | 149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 151 | 152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 154 | 155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 160 | 161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 165 | 166 | define SYS_COMPILE 167 | $(info $2) 168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 170 | endef 171 | 172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 173 | $(info Creating archive $@ ...) 174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 176 | endif #need System.bc 177 | #------------------------------------------------------------------------------------------------------ 178 | -------------------------------------------------------------------------------- /Cpp/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: C++ 7 | 8 | 9 |

WebAssembly Sample: C++

10 |
11 |
Loading...

12 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Cpp/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Some global state variables and max heap definition 32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32; 33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB 34 | 35 | // Define print and error functions if not yet defined by the outer html file 36 | WA.print = WA.print || function (msg) { console.log(msg); }; 37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 38 | 39 | // A generic abort function that if called stops the execution of the program and shows an error 40 | function abort(code, msg) 41 | { 42 | WA.error(code, msg); 43 | throw 'abort'; 44 | } 45 | 46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional) 47 | function WriteHeapString(str, ptr, max_length) 48 | { 49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;} 54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 58 | } 59 | return r[f]=0,f-a; 60 | } 61 | 62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8) 63 | function ReadHeapString(ptr, length) 64 | { 65 | if (length === 0 || !ptr) return ''; 66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++) 67 | { 68 | t = HEAPU8[((ptr)+(i))>>0]; 69 | if (t == 0 && !length) break; 70 | hasUtf |= t; 71 | } 72 | if (!length) length = i; 73 | if (hasUtf & 128) 74 | { 75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;) 76 | { 77 | if(o==p||(e=r[o++],!e)) return g; 78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e); 79 | } 80 | } 81 | // split up into chunks, because .apply on a huge string can overflow the stack 82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024) 83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024))); 84 | return ret; 85 | } 86 | 87 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module 88 | function SYSCALLS_WASM_IMPORTS(env, wasi) 89 | { 90 | // Function to decode Base64 encoded string to a byte array 91 | function Base64Decode(B) 92 | { 93 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];}; 94 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63; 95 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0; 96 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; } 97 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; } 98 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255; 99 | return a; 100 | } 101 | 102 | // For the file open/file reading emulation, keep a seek cursor and the file data 103 | var PAYLOAD_CURSOR = 0; 104 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0)); 105 | delete WA.payload; 106 | 107 | // sys_open call to open a file (can only be used to open payload here) 108 | env.__sys_open = function(pPath, flags, pMode) 109 | { 110 | // Opening just resets the seek cursor to 0 111 | PAYLOAD_CURSOR = 0; 112 | //var pathname = ReadHeapString(pPath); //read the file name passed to open 113 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]); 114 | return 9; //return dummy file number 115 | }; 116 | 117 | // fd_read call to read from a file (reads from payload) 118 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult) 119 | { 120 | for (var ret = 0, i = 0; i < iovcnt; i++) 121 | { 122 | // Process list of IO commands 123 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 124 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 125 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR); 126 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')'); 127 | 128 | // Write the requested data onto the heap and advance the seek cursor 129 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr); 130 | PAYLOAD_CURSOR += curr; 131 | 132 | ret += curr; 133 | if (curr < len) break; // nothing more to read 134 | } 135 | 136 | // Write the amount of data actually read to the result pointer 137 | HEAPU32[pOutResult>>2] = ret; 138 | //console.log('fd_read - ret: ' + ret); 139 | return 0; // no error 140 | }; 141 | 142 | // fd_seek call to seek in a file (seeks in payload) 143 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult) 144 | { 145 | // Move seek cursor according to fseek behavior 146 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set 147 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur 148 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end 149 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0; 150 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length; 151 | 152 | // Write the result back (write only lower 32-bit of 64-bit number) 153 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR; 154 | HEAPU32[(pOutResult+4)>>2] = 0; 155 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR); 156 | return 0; // no error 157 | }; 158 | 159 | // fd_write call to write to a file/pipe (can only be used to write to stdout here) 160 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult) 161 | { 162 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++) 163 | { 164 | // Process list of IO commands, read passed strings from heap 165 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 166 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 167 | if (len < 0) return -1; 168 | ret += len; 169 | str += ReadHeapString(ptr, len); 170 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n')); 171 | } 172 | 173 | // Print the passed string and write the number of bytes read to the result pointer 174 | WA.print(str); 175 | HEAPU32[pOutResult>>2] = ret; 176 | return 0; // no error 177 | }; 178 | 179 | // fd_close to close a file (no real file system emulation, so this does nothing) 180 | wasi.fd_close = function(fd) 181 | { 182 | //console.log('fd_close - fd: ' + fd); 183 | return 0; // no error 184 | }; 185 | 186 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here 187 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param) 188 | { 189 | return 0; // no error 190 | }; 191 | } 192 | 193 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript 194 | function MemorySetBufferViews() 195 | { 196 | var buf = WASM_MEMORY.buffer; 197 | HEAP32 = new Int32Array(buf); 198 | HEAPU8 = new Uint8Array(buf); 199 | HEAPU16 = new Uint16Array(buf); 200 | HEAPU32 = new Uint32Array(buf); 201 | HEAPF32 = new Float32Array(buf); 202 | } 203 | 204 | // Set up the env and wasi objects that contains the functions passed to the wasm module 205 | var env = 206 | { 207 | // sbrk gets called to increase the size of the memory heap by an increment 208 | sbrk: function(increment) 209 | { 210 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength; 211 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : '')); 212 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory'); 213 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); } 214 | WASM_HEAP = heapNew; 215 | return heapOld|0; 216 | }, 217 | 218 | // Functions querying the system time 219 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; }, 220 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; }, 221 | 222 | // Various functions thet can be called from wasm that abort the program 223 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); }, 224 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); }, 225 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); }, 226 | abort: function() { abort('CRASH', 'Abort called'); }, 227 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); }, 228 | }, wasi = {}; 229 | 230 | // Functions that do nothing in this wasm context 231 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {}; 232 | 233 | // Math functions 234 | env.ceil = env.ceilf = Math.ceil; 235 | env.exp = env.expf = Math.exp; 236 | env.floor = env.floorf = Math.floor; 237 | env.log = env.logf = Math.log; 238 | env.pow = env.powf = Math.pow; 239 | env.cos = env.cosf = Math.cos; 240 | env.sin = env.sinf = Math.sin; 241 | env.tan = env.tanf = Math.tan; 242 | env.acos = env.acosf = Math.acos; 243 | env.asin = env.asinf = Math.asin; 244 | env.sqrt = env.sqrtf = Math.sqrt; 245 | env.atan = env.atanf = Math.atan; 246 | env.atan2 = env.atan2f = Math.atan2; 247 | env.fabs = env.fabsf = env.abs = Math.abs; 248 | env.round = env.roundf = env.rint = env.rintf = Math.round; 249 | 250 | // Extend the objects with the syscall IO emulation 251 | SYSCALLS_WASM_IMPORTS(env, wasi); 252 | 253 | // Find the start point of the stack and the heap to calculate the initial memory requirements 254 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536; 255 | // This code goes through the wasm file sections according the binary encoding description 256 | // https://webassembly.org/docs/binary-encoding/ 257 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 258 | { 259 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 260 | function Get() { return wasmBytes[i++]; } 261 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 262 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 263 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 264 | if (type == 6) 265 | { 266 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 267 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 268 | wasmHeapBase = offset; 269 | } 270 | if (type == 11) 271 | { 272 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area 273 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++) 274 | { 275 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB(); 276 | wasmDataEnd = (doffset + dsize); 277 | wasmStackTop = (wasmDataEnd+15)>>4<<4; 278 | i += dsize; 279 | } 280 | } 281 | } 282 | 283 | // Validate the queried pointers 284 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')'); 285 | 286 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk) 287 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 288 | WASM_HEAP = wasmHeapBase; 289 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 }); 290 | MemorySetBufferViews(); 291 | 292 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module 293 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output) 294 | { 295 | // Store the list of the functions exported by the wasm module in WA.asm 296 | WA.asm = output.instance.exports; 297 | 298 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 299 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 300 | 301 | // If function 'main' exists, call it 302 | if (WA.asm.main) 303 | { 304 | // Store the argument list with 1 entry at the far end of the stack to pass to main 305 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe'; 306 | 307 | // Store the program name string after the argv list 308 | WriteHeapString(exe, (argv + 8)); 309 | 310 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer 311 | HEAPU32[(argv>>2) + 0] = (argv + 8) 312 | HEAPU32[(argv>>2) + 1] = 0; 313 | 314 | WA.asm.main(argc, argv); 315 | } 316 | 317 | // If the outer HTML file supplied a 'started' callback, call it 318 | if (WA.started) WA.started(); 319 | }) 320 | .catch(function (err) 321 | { 322 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 323 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 324 | }); 325 | 326 | }); 327 | -------------------------------------------------------------------------------- /Cpp/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | std::string string = "Hello C++"; 36 | string += " World"; 37 | printf("%s\n\n", string.c_str()); 38 | 39 | std::vector vec; 40 | vec.push_back(1); 41 | vec.push_back(2); 42 | vec.push_back(3); 43 | vec.erase(vec.begin() + 1); 44 | for (int i : vec) 45 | printf("Vector element: %d\n", i); 46 | printf("\n"); 47 | 48 | int* ptr = new int; 49 | printf("Allocated memory with new at %p\n\n", ptr); 50 | delete ptr; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /Cpp/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/Cpp/output.wasm -------------------------------------------------------------------------------- /Embed/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | PYTHON = D:/dev/python/python.exe 32 | 33 | PROJECT = test 34 | SOURCES = main.cpp 35 | EXPORTS = WAFNDraw WAFNAudio 36 | BUILD = RELEASE 37 | 38 | #------------------------------------------------------------------------------------------------------ 39 | 40 | SPACE := $(strip ) $(strip ) 41 | THIS_MAKEFILE := $(patsubst ./%,%,$(subst \,/,$(lastword $(MAKEFILE_LIST)))) 42 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 43 | 44 | ifeq ($(BUILD),RELEASE) 45 | SYSOUTDIR := $(dir $(THIS_MAKEFILE))system 46 | OUTDIR := Release-wasm 47 | DBGCFLAGS := -DNDEBUG 48 | LDFLAGS := -strip-all -gc-sections 49 | WOPTFLAGS := -O3 50 | LOADERJS := $(dir $(THIS_MAKEFILE))loader.minified.js 51 | else 52 | SYSOUTDIR := $(dir $(THIS_MAKEFILE))system 53 | OUTDIR := Debug-wasm 54 | DBGCFLAGS := -DDEBUG -D_DEBUG 55 | LDFLAGS := 56 | WOPTFLAGS := -g -O0 57 | LOADERJS := $(dir $(THIS_MAKEFILE))loader.js 58 | endif 59 | 60 | # Global compiler flags 61 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 62 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 63 | 64 | # Global compiler flags for Wasm targeting 65 | CLANGFLAGS := -target wasm32 -nostdinc 66 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 67 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 68 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 69 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 70 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 71 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 72 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 73 | 74 | # Flags for wasm-ld 75 | LDFLAGS += -no-entry -allow-undefined -import-memory 76 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 77 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 78 | 79 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 80 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 81 | 82 | # Check if there are any source files 83 | ifeq ($(SOURCES),) 84 | $(error No source files found for build) 85 | endif 86 | 87 | # Compute tool paths 88 | ifeq ($(wildcard $(subst $(SPACE),\ ,$(LLVM_ROOT))/clang*),) 89 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in $(THIS_MAKEFILE) with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 90 | endif 91 | ifeq ($(wildcard $(subst $(SPACE),\ ,$(WASMOPT))),) 92 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in $(THIS_MAKEFILE) with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 93 | endif 94 | PYTHON_FIND := $(if $(PYTHON),$(wildcard $(PYTHON)),$(if $(shell python -c "print 1" 2>$(if $(ISWIN),nul,/dev/null)),python)) 95 | ifeq ($(PYTHON_FIND),) 96 | $(error Python executable not found in PATH and not correctly set with PYTHON setting ($(PYTHON)). Set custom path in $(THIS_MAKEFILE) with PYTHON = $(if $(ISWIN),d:)/path/to/python/python$(if $(ISWIN),.exe)) 97 | endif 98 | 99 | # Surround used commands with double quotes 100 | CC := "$(LLVM_ROOT)/clang" 101 | CXX := "$(LLVM_ROOT)/clang" -x c++ 102 | LD := "$(LLVM_ROOT)/wasm-ld" 103 | WASMOPT := "$(WASMOPT)" 104 | PYTHON := "$(PYTHON_FIND)" 105 | 106 | # Python one liner to delete multiple files with existance check and no stdout output 107 | CMD_DEL_FILES := $(PYTHON) -c "import sys,os;[os.path.exists(a) and os.remove(a) for a in sys.argv[1:]]" 108 | 109 | # Python one liner generate an output loader js file with base64 encoded wasm file appended to the top 110 | CMD_MAKE_JS := $(PYTHON) -c "import sys,os,base64;b=open(sys.argv[3],'rb').read();open(sys.argv[1],'w').write('WA.wasm='+chr(39)+(base64.b64encode(b) if sys.version_info[0]<3 else base64.b64encode(b).decode('ascii'))+chr(39)+';'+chr(10)+open(sys.argv[2],'r').read())" 111 | 112 | # Python one liner to gzip a file 113 | CMD_MAKE_GZ := $(PYTHON) -c "import sys,gzip;gzip.GzipFile('','wb',9,open(sys.argv[1],'wb'),0).write(open(sys.argv[2],'rb').read())" 114 | 115 | # Python one liner to generate an output loader html file from the template with tags replaced 116 | CMD_MAKE_HTML := $(PYTHON) -c "import sys;open(sys.argv[1],'w').write(open(sys.argv[2],'r').read().replace('{{PROJECT}}','$(PROJECT)').replace('{{SCRIPT}}',''))" 117 | 118 | all: $(OUTDIR)/$(PROJECT).js$(if $(filter RELEASE,$(BUILD)),.gz) $(OUTDIR)/$(PROJECT).html #analyze #run 119 | .PHONY: clean cleanall run analyze 120 | 121 | clean: 122 | $(info Removing all build files ...) 123 | @$(CMD_DEL_FILES) $(OBJS) $(OBJS:%.o=%.d) $(OUTDIR)/$(PROJECT).wasm $(OUTDIR)/$(PROJECT).js $(OUTDIR)/$(PROJECT).js.gz \ 124 | 125 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 126 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 127 | -include $(OBJS:%.o=%.d) 128 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 129 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 130 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 131 | 132 | $(OUTDIR)/$(PROJECT).wasm : $(THIS_MAKEFILE) $(OBJS) $(SYSOUTDIR)/System.bc 133 | $(info Linking $@ ...) 134 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) $(SYSOUTDIR)/System.bc 135 | @$(WASMOPT) --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 136 | 137 | $(OUTDIR)/$(PROJECT).js : $(LOADERJS) $(OUTDIR)/$(PROJECT).wasm 138 | $(info Generating $@ from $^ ...) 139 | @$(CMD_MAKE_JS) $@ $^ 140 | 141 | $(OUTDIR)/%.js.gz : $(OUTDIR)/%.js 142 | $(info Compressing $^ to $@ ...) 143 | @$(if $(wildcard $@),$(if $(ISWIN),del "$(subst /,\,$@)" ,rm "$@" >/dev/null),) 144 | @$(CMD_MAKE_GZ) $@ $^ 145 | 146 | $(OUTDIR)/$(PROJECT).html : $(dir $(THIS_MAKEFILE))loader.html 147 | $(info $(if $(wildcard $@),Warning: Template $^ is newer than $@ - delete the local build file to have it regenerated,Generating $@ ...)) 148 | @$(if $(wildcard $@),,$(CMD_MAKE_HTML) "$@" "$^") 149 | 150 | run : $(OUTDIR)/$(PROJECT).js $(OUTDIR)/$(PROJECT).html 151 | $(if $(wildcard $(BROWSER)),,$(error browser not found in set BROWSER path ($(BROWSER)). Set custom path in $(THIS_MAKEFILE) with BROWSER = $(if $(ISWIN),c:)/path/to/browser$(if $(ISWIN),.exe))) 152 | $(info Running browser '$(BROWSER)' with output '$(OUTDIR)/$(PROJECT).html' ...) 153 | @$(BROWSER) "$(OUTDIR)/$(PROJECT).html" 154 | 155 | analyze : $(OUTDIR)/$(PROJECT).wasm 156 | $(if $(wildcard $(WABT_ROOT)/wasm-objdump*),,$(error WebAssembly Binary Toolkit not found in set WABT_ROOT path ($(WABT_ROOT)). Set custom path in $(THIS_MAKEFILE) with WABT_ROOT = $(if $(ISWIN),c:)/path/to/wabt)) 157 | $(info Creating $^.objdump, $^.decompile and $^.c) 158 | $(WABT_ROOT)/wasm-objdump -xd $^ >$^.objdump 159 | $(WABT_ROOT)/wasm-decompile $^ -o $^.decompile 160 | $(WABT_ROOT)/wasm2c $^ -o $^.c 161 | 162 | define COMPILE 163 | $(info $2) 164 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 165 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 166 | endef 167 | 168 | #------------------------------------------------------------------------------------------------------ 169 | #if System.bc exists, don't even bother checking sources, build once and forget for now 170 | ifeq ($(if $(wildcard $(SYSOUTDIR)/System.bc),1,0),0) 171 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 172 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 173 | 174 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 175 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 176 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 177 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 178 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 179 | 180 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 181 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 182 | 183 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 184 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 185 | endif 186 | 187 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 188 | ifeq ($(if $(SYS_MISSING),1,0),1) 189 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 190 | endif 191 | 192 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard $(SYSOUTDIR)/temp/*.o))) 193 | ifeq ($(if $(SYS_OLDFILES),1,0),1) 194 | $(shell $(CMD_DEL_FILES) $(addprefix $(SYSOUTDIR)/temp/,$(SYS_OLDFILES)) $(SYSOUTDIR)/System.bc) 195 | endif 196 | 197 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 198 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 199 | 200 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 201 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 202 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 203 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 204 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 205 | 206 | SYS_CPP_OBJS := $(addprefix $(SYSOUTDIR)/temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 207 | SYS_CC_OBJS := $(addprefix $(SYSOUTDIR)/temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 208 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst $(SYSOUTDIR)/temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 209 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst $(SYSOUTDIR)/temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 210 | 211 | define SYS_COMPILE 212 | $(info $2) 213 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 214 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 215 | endef 216 | 217 | $(SYSOUTDIR)/System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 218 | $(info Creating archive $@ ...) 219 | @$(LD) $(if $(ISWIN),"$(SYSOUTDIR)/temp/*.o",$(SYSOUTDIR)/temp/*.o) -r -o $@ 220 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(SYSOUTDIR)/temp" 221 | endif #need System.bc 222 | #------------------------------------------------------------------------------------------------------ 223 | -------------------------------------------------------------------------------- /Embed/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{PROJECT}} 7 | 8 | 9 |

{{PROJECT}}

10 |

Status: Loading...

11 | 12 |
13 | 38 | {{SCRIPT}} 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Embed/loader.minified.js: -------------------------------------------------------------------------------- 1 | !function(){'use strict';function e(e,r){throw _=!0,WA.error(e,r),'abort'}function r(e,r,t){var n,a,o,f,u,l,c;for(n=e,a=i,f=o=r,u=o+(t||i.length)-1,l=0;l=55296&&57343>=c&&(c=65536+((1023&c)<<10)|1023&n.charCodeAt(++l)),c>127)if(c>2047)if(c>65535)if(c>2097151)if(c>67108863){if(o+5>=u)break;a[o++]=252|c>>30,a[o++]=128|c>>24&63,a[o++]=128|c>>18&63,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+4>=u)break;a[o++]=248|c>>24,a[o++]=128|c>>18&63,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+3>=u)break;a[o++]=240|c>>18,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+2>=u)break;a[o++]=224|c>>12,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+1>=u)break;a[o++]=192|c>>6,a[o++]=128|63&c}else{if(o>=u)break;a[o++]=c}return a[o]=0,o-f}function t(e,r){var t,n,a,o,f,u,l,c,s,g,m,d,h,b;if(0===r||!e)return'';for(t=0,a=0;(!r||a!=r)&&(0!=(n=i[e+a>>0])||r);a++)t|=n;if(r||(r=a),128&t)for(o=i,f=e,u=e+r,l=String.fromCharCode,h='';;){if(f==u||!(c=o[f++]))return h;128&c?(s=63&o[f++],192!=(224&c)?(a=63&o[f++],224==(240&c)?c=(15&c)<<12|s<<6|a:(g=63&o[f++],240==(248&c)?c=(7&c)<<18|s<<12|a<<6|g:(m=63&o[f++],c=248==(252&c)?(3&c)<<24|s<<18|a<<12|g<<6|m:(1&c)<<30|s<<24|a<<18|g<<12|m<<6|(n=63&o[f++]))),h+=65536>c?l(c):l(55296|(d=c-65536)>>10,56320|1023&d)):h+=l((31&c)<<6|s)):h+=l(c)}for(b='';r>0;e+=1024,r-=1024)b+=String.fromCharCode.apply(String,i.subarray(e,e+Math.min(r,1024)));return b}function n(e){var r,t,n,a,o,i,f,u=new Uint8Array(128),l=function(t){return u[e.charCodeAt(r+t)]};for(r=0;64>r;r++)u['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(r)]=r;for(u[45]=62,u[95]=63,t=e.length,n='='===e[t-2]?2:'='===e[t-1]?1:0,a=new Uint8Array(3*t/4-n),o=0,i=n>0?t-4:t,f=0,r=0;i>r;r+=4)f=l(0)<<18|l(1)<<12|l(2)<<6|l(3),a[o++]=f>>16&255,a[o++]=f>>8&255,a[o++]=255&f;return 1===n?(f=l(0)<<10|l(1)<<4|l(2)>>2,a[o]=f>>8&255,a[o+1]=255&f):2===n&&(a[o]=255&(l(0)<<2|l(1)>>4)),a}function a(){var e=c.buffer;o=new Int32Array(e),i=new Uint8Array(e),f=new Uint16Array(e),u=new Uint32Array(e),l=new Float32Array(e)}var o,i,f,u,l,c,s,g,m,d,h,b,A,v,x,_=!1;WA.print=WA.print||function(e){console.log(e)},WA.error=WA.error||function(e,r){WA.print('[ERROR] '+e+': '+r+'\n')},d={},(m={sbrk:function(r){var t=s,n=t+r,o=n-c.buffer.byteLength;return n>268435456&&e('MEM','Out of memory'),o>0&&(c.grow(o+65535>>16),a()),s=n,0|t},time:function(e){var r=Date.now()/1e3|0;return e&&(u[e>>2]=r),r},gettimeofday:function(e){var r=Date.now();u[e>>2]=r/1e3|0,u[e+4>>2]=r%1e3*1e3|0},__assert_fail:function(r,n,a,o){e('CRASH','Assert '+t(r)+', at: '+(n?t(n):'unknown filename'),o&&t(o))},__cxa_uncaught_exception:function(){e('CRASH','Uncaught exception!')},__cxa_pure_virtual:function(){e('CRASH','pure virtual')},abort:function(){e('CRASH','Abort called')},longjmp:function(){e('CRASH','Unsupported longjmp called')}}).setjmp=m.__cxa_atexit=m.__lock=m.__unlock=function(){},m.ceil=m.ceilf=Math.ceil,m.exp=m.expf=Math.exp,m.floor=m.floorf=Math.floor,m.log=m.logf=Math.log,m.pow=m.powf=Math.pow,m.cos=m.cosf=Math.cos,m.sin=m.sinf=Math.sin,m.tan=m.tanf=Math.tan,m.acos=m.acosf=Math.acos,m.asin=m.asinf=Math.asin,m.sqrt=m.sqrtf=Math.sqrt,m.atan=m.atanf=Math.atan,m.atan2=m.atan2f=Math.atan2,m.fabs=m.fabsf=m.abs=Math.abs,m.round=m.roundf=m.rint=m.rintf=Math.round,function(e,r){var a=0,o=WA.payload?n(WA.payload):new Uint8Array(0);delete WA.payload,e.__sys_open=function(){return a=0,9},r.fd_read=function(e,r,t,n){var f,l,c,s,g;for(f=0,l=0;t>l&&(c=u[r+8*l>>2],s=u[r+(8*l+4)>>2],g=Math.min(s,o.length-a),i.set(o.subarray(a,a+g),c),a+=g,f+=g,g>=s);l++);return u[n>>2]=f,0},r.fd_seek=function(e,r,t,n,i){return 0==n&&(a=r),1==n&&(a+=r),2==n&&(a=o.length-r),0>a&&(a=0),a>o.length&&(a=o.length),u[i+0>>2]=a,u[i+4>>2]=0,0},r.fd_write=function(e,r,n,a){var o,i,f,l,c;if(0==n)return 0;for(o=0,i='',f=0;n>f;f++){if(l=u[r+8*f>>2],0>(c=u[r+(8*f+4)>>2]))return-1;o+=c,i+=t(l,c)}return WA.print(i),u[a>>2]=o,0},r.fd_close=function(){return 0},e.__sys_fcntl64=e.__sys_ioctl=function(){return 0}}(m,d),function(n){function a(e){var r,t=h++;for(r=e.length;t>r;r++)e[r]=null;return t}function c(e){GLlastError||(GLlastError=e)}function s(e,r,t,n,a){var o,s,g,m,d;switch(r){case 6406:case 6409:case 6402:s=1;break;case 6410:s=2;break;case 6407:case 35904:s=3;break;case 6408:case 35906:s=4;break;default:return c(1280),null}switch(e){case 5121:o=1*s;break;case 5123:case 36193:o=2*s;break;case 5125:case 5126:o=4*s;break;case 34042:o=4;break;case 33635:case 32819:case 32820:o=2;break;default:return c(1280),null}switch(g=t*o,d=y,m=n>0?Math.floor((g+d-1)/d)*d*(n-1)+g:0,e){case 5121:return i.subarray(a,a+m);case 5126:return l.subarray(a>>2,a+m>>2);case 5125:case 34042:return u.subarray(a>>2,a+m>>2);case 5123:case 33635:case 32819:case 32820:case 36193:return f.subarray(a>>1,a+m>>1);default:return c(1280),null}}var m,d,h=1,b=[],A=[],v=[],x=[],_=[],w=[],p={},y=4,S=null,W=[0];for(S=new Float32Array(256),d=0;256>d;d++)W[d]=S.subarray(0,d+1);g=function(r,t){var n,a,o,i,f,u,l,c;t={majorVersion:1,minorVersion:0,antialias:!0,alpha:!1},n='';try{let a=function(e){n=e.statusMessage||n};r.addEventListener('webglcontextcreationerror',a,!1);try{m=r.getContext('webgl',t)||r.getContext('experimental-webgl',t)}finally{r.removeEventListener('webglcontextcreationerror',a,!1)}if(!m)throw'Could not create context'}catch(r){e('WEBGL',r+(n?' ('+n+')':''))}return(a=m.getSupportedExtensions())&&a.length>0&&(c=[(i='OES_')+(u='texture_')+'float',i+u+'half_float',i+'standard_derivatives',i+'vertex_array_object',(o='WEBGL_')+(l='compressed_'+u)+'s3tc',o+'depth_texture',i+'element_index_uint',(f='EXT_')+u+'filter_anisotropic',f+'frag_depth',o+'draw_buffers','ANGLE_instanced_arrays',i+u+'float_linear',i+u+'half_float_linear',f+'blend_minmax',f+'shader_texture_lod',o+l+'pvrtc',f+'color_buffer_half_float',o+'color_buffer_float',f+'sRGB',o+l+'etc1',f+'disjoint_timer_query',o+l+'etc',o+l+'astc',f+'color_buffer_float',o+l+'s3tc_srgb',f+'disjoint_timer_query_webgl2'],a.forEach(function(e){-1!=c.indexOf(e)&&m.getExtension(e)})),!0},n.glActiveTexture=function(e){m.activeTexture(e)},n.glAttachShader=function(e,r){m.attachShader(A[e],w[r])},n.glBindAttribLocation=function(e,r,n){m.bindAttribLocation(A[e],r,t(n))},n.glBindBuffer=function(e,r){m.bindBuffer(e,r?b[r]:null)},n.glBindFramebuffer=function(e,r){m.bindFramebuffer(e,r?v[r]:null)},n.glBindTexture=function(e,r){m.bindTexture(e,r?x[r]:null)},n.glBlendFunc=function(e,r){m.blendFunc(e,r)},n.glBlendFuncSeparate=function(e,r,t,n){m.blendFuncSeparate(e,r,t,n)},n.glBlendColor=function(e,r,t,n){m.blendColor(e,r,t,n)},n.glBlendEquation=function(e){m.blendEquation(e)},n.glBlendEquationSeparate=function(e,r){m.blendEquationSeparate(e,r)},n.glBufferData=function(e,r,t,n){t?m.bufferData(e,i.subarray(t,t+r),n):m.bufferData(e,r,n)},n.glBufferSubData=function(e,r,t,n){m.bufferSubData(e,r,i.subarray(n,n+t))},n.glClear=function(e){m.clear(e)},n.glClearColor=function(e,r,t,n){m.clearColor(e,r,t,n)},n.glColorMask=function(e,r,t,n){m.colorMask(!!e,!!r,!!t,!!n)},n.glCompileShader=function(e){m.compileShader(w[e])},n.glCreateProgram=function(){var e=a(A),r=m.createProgram();return r.name=e,A[e]=r,e},n.glCreateShader=function(e){var r=a(w);return w[r]=m.createShader(e),r},n.glDeleteBuffers=function(e,r){var t,n,a;for(t=0;e>t;t++)n=o[r+4*t>>2],(a=b[n])&&(m.deleteBuffer(a),a.name=0,b[n]=null)},n.glDeleteFramebuffers=function(e,r){var t,n,a;for(t=0;e>t;++t)n=o[r+4*t>>2],(a=v[n])&&(m.deleteFramebuffer(a),a.name=0,v[n]=null)},n.glDeleteProgram=function(e){if(e){var r=A[e];r?(m.deleteProgram(r),r.name=0,A[e]=null,p[e]=null):c(1281)}},n.glDeleteShader=function(e){if(e){var r=w[e];r?(m.deleteShader(r),w[e]=null):c(1281)}},n.glDeleteTextures=function(e,r){var t,n,a;for(t=0;e>t;t++)n=o[r+4*t>>2],(a=x[n])&&(m.deleteTexture(a),a.name=0,x[n]=null)},n.glDepthFunc=function(e){m.depthFunc(e)},n.glDepthMask=function(e){m.depthMask(!!e)},n.glDetachShader=function(e,r){m.detachShader(A[e],w[r])},n.glDisable=function(e){m.disable(e)},n.glDisableVertexAttribArray=function(e){m.disableVertexAttribArray(e)},n.glDrawArrays=function(e,r,t){m.drawArrays(e,r,t)},n.glDrawElements=function(e,r,t,n){m.drawElements(e,r,t,n)},n.glEnable=function(e){m.enable(e)},n.glEnableVertexAttribArray=function(e){m.enableVertexAttribArray(e)},n.glFramebufferTexture2D=function(e,r,t,n,a){m.framebufferTexture2D(e,r,t,x[n],a)},n.glGenBuffers=function(e,r){var t,n,i;for(t=0;e>t;t++){if(!(n=m.createBuffer())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(b),n.name=i,b[i]=n,o[r+4*t>>2]=i}},n.glGenFramebuffers=function(e,r){var t,n,i;for(t=0;e>t;++t){if(!(n=m.createFramebuffer())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(v),n.name=i,v[i]=n,o[r+4*t>>2]=i}},n.glGenTextures=function(e,r){var t,n,i;for(t=0;e>t;t++){if(!(n=m.createTexture())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(x),n.name=i,x[i]=n,o[r+4*t>>2]=i}},n.glGetActiveUniform=function(e,t,n,a,i,f,u){var l,c;e=A[e],(l=m.getActiveUniform(e,t))&&(n>0&&u?(c=r(l.name,u,n),a&&(o[a>>2]=c)):a&&(o[a>>2]=0),i&&(o[i>>2]=l.size),f&&(o[f>>2]=l.type))},n.glGetAttribLocation=function(e,r){return e=A[e],r=t(r),m.getAttribLocation(e,r)},n.glGetError=function(){if(GLlastError){var e=GLlastError;return GLlastError=0,e}return m.getError()},n.glGetIntegerv=function(e,r){!function(e,r){var t,n,a;if(r){switch(t=void 0,e){case 36346:t=1;break;case 36344:return;case 36345:t=0;break;case 34466:t=m.getParameter(34467).length}if(void 0===t)switch(typeof(n=m.getParameter(e))){case'number':t=n;break;case'boolean':t=n?1:0;break;case'string':return void c(1280);case'object':if(null===n)switch(e){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34068:t=0;break;default:return void c(1280)}else{if(n instanceof Float32Array||n instanceof Uint32Array||n instanceof Int32Array||n instanceof Array){for(a=0;a>2]=n[a];return}if(!(n instanceof WebGLBuffer||n instanceof WebGLProgram||n instanceof WebGLFramebuffer||n instanceof WebGLRenderbuffer||n instanceof WebGLTexture))return void c(1280);t=0|n.name}break;default:return void c(1280)}o[r>>2]=t}else c(1281)}(e,r)},n.glGetProgramInfoLog=function(e,t,n,a){var i,f=m.getProgramInfoLog(A[e]);null===f&&(f='(unknown error)'),t>0&&a?(i=r(f,a,t),n&&(o[n>>2]=i)):n&&(o[n>>2]=0)},n.glGetProgramiv=function(e,r,t){var n,a,i,f,u,l,s;if(t)if(h>e)if(n=p[e])if(35716==r)null===(a=m.getProgramInfoLog(A[e]))&&(a='(unknown error)'),o[t>>2]=a.length+1;else if(35719==r)o[t>>2]=n.maxUniformLength;else if(35722==r){if(-1==n.maxAttributeLength)for(e=A[e],i=m.getProgramParameter(e,m.ACTIVE_ATTRIBUTES),n.maxAttributeLength=0,f=0;i>f;++f)u=m.getActiveAttrib(e,f),n.maxAttributeLength=Math.max(n.maxAttributeLength,u.name.length+1);o[t>>2]=n.maxAttributeLength}else if(35381==r){if(-1==n.maxUniformBlockNameLength)for(e=A[e],l=m.getProgramParameter(e,m.ACTIVE_UNIFORM_BLOCKS),n.maxUniformBlockNameLength=0,f=0;l>f;++f)s=m.getActiveUniformBlockName(e,f),n.maxUniformBlockNameLength=Math.max(n.maxUniformBlockNameLength,s.length+1);o[t>>2]=n.maxUniformBlockNameLength}else o[t>>2]=m.getProgramParameter(A[e],r);else c(1282);else c(1281);else c(1281)},n.glGetShaderInfoLog=function(e,t,n,a){var i,f=m.getShaderInfoLog(w[e]);null===f&&(f='(unknown error)'),t>0&&a?(i=r(f,a,t),n&&(o[n>>2]=i)):n&&(o[n>>2]=0)},n.glGetShaderiv=function(e,r,t){var n,a,i;t?35716==r?(null===(n=m.getShaderInfoLog(w[e]))&&(n='(unknown error)'),o[t>>2]=n.length+1):35720==r?(i=null===(a=m.getShaderSource(w[e]))||0==a.length?0:a.length+1,o[t>>2]=i):o[t>>2]=m.getShaderParameter(w[e],r):c(1281)},n.glGetUniformLocation=function(e,r){var n,a,o,i,f;if(n=0,-1!==(r=t(r)).indexOf(']',r.length-1)){if(a=r.lastIndexOf('['),(o=r.slice(a+1,-1)).length>0&&0>(n=parseInt(o)))return-1;r=r.slice(0,a)}return(i=p[e])&&(f=i.uniforms[r])&&no;++o)if(f=(i=m.getActiveUniform(d,o)).name,r.maxUniformLength=Math.max(r.maxUniformLength,f.length+1),-1!==f.indexOf(']',f.length-1)&&(u=f.lastIndexOf('['),f=f.slice(0,u)),null!=(l=m.getUniformLocation(d,f)))for(c=a(_),t[f]=[i.size,c],_[c]=l,s=1;si;++i)u+=a?0>(f=o[a+4*i>>2])?t(o[n+4*i>>2]):t(o[n+4*i>>2],f):t(o[n+4*i>>2]);return u}(0,r,n,a);m.shaderSource(w[e],i)},n.glTexImage2D=function(e,r,t,n,a,o,i,f,u){var l=null;u&&(l=s(f,i,n,a,u)),m.texImage2D(e,r,t,n,a,o,i,f,l)},n.glTexParameteri=function(e,r,t){m.texParameteri(e,r,t)},n.glTexSubImage2D=function(e,r,t,n,a,o,i,f,u){var l=null;u&&(l=s(f,i,a,o,u)),m.texSubImage2D(e,r,t,n,a,o,i,f,l)},n.glUniform1f=function(e,r){m.uniform1f(_[e],r)},n.glUniform1i=function(e,r){m.uniform1i(_[e],r)},n.glUniform2f=function(e,r,t){m.uniform2f(_[e],r,t)},n.glUniform3f=function(e,r,t,n){m.uniform3f(_[e],r,t,n)},n.glUniform3fv=function(e,r,t){var n,a,o;if(3*r>256)n=l.subarray(t>>2,t+12*r>>2);else for(n=W[3*r-1],a=t>>2,o=0;o!=3*r;o++)n[o]=l[a+o];m.uniform3fv(_[e],n)},n.glUniform4f=function(e,r,t,n,a){m.uniform4f(_[e],r,t,n,a)},n.glUniformMatrix4fv=function(e,r,t,n){var a,o,i;if((r<<=4)>256)a=l.subarray(n>>2,n+4*r>>2);else for(a=W[r-1],o=n>>2,i=0;i!=r;i+=4)a[i]=l[o+i],a[i+1]=l[o+i+1],a[i+2]=l[o+i+2],a[i+3]=l[o+i+3];m.uniformMatrix4fv(_[e],!!t,a)},n.glUseProgram=function(e){m.useProgram(e?A[e]:null)},n.glVertexAttrib4f=function(e,r,t,n,a){m.vertexAttrib4f(e,r,t,n,a)},n.glVertexAttrib4fv=function(e,r){m.vertexAttrib4f(e,l[r>>2],l[r+4>>2],l[r+8>>2],l[r+12>>2])},n.glVertexAttribPointer=function(e,r,t,n,a,o){m.vertexAttribPointer(e,r,t,!!n,a,o)},n.glViewport=function(e,r,t,n){m.viewport(e,r,t,n)}}(m),function(e){var r;e.WAJS_SetupCanvas=function(e,t){var n,a=WA.canvas;a.width=e,a.height=t,a.height=a.clientHeight,a.width=a.clientWidth,g(a)&&(r=Date.now(),n=function(){_||(window.requestAnimationFrame(n),WA.asm.WAFNDraw())},window.requestAnimationFrame(n))},e.WAJS_GetTime=function(){return Date.now()-r},e.WAJS_StartAudio=function(){var e,r,t,n,a,o,i,f,u,c;try{e=new((u=window)[c='AudioContext']||u['moz'+c]||u['webkit'+c]||u['ms'+c])}catch(e){}e?(r=0,n=(t=882)/44100,a=0,o=0,i=[{length:0}],f=0,setInterval(function(){var u,c,s,g;if(('suspended'!=e.state||(e.resume(),'suspended'!=e.state))&&(0==(u=e.currentTime)&&(r=0),n>=r-u)){if(i[0].length!=t)for(WA.asm.free(a),o=(a=WA.asm.malloc(t<<3))>>2,c=0;4!=c;c++)i[c]=e.createBuffer(2,t,44100);WA.asm.WAFNAudio(a,t)&&((s=i[f=(f+1)%4]).getChannelData(0).set(l.subarray(o,o+t)),s.getChannelData(1).set(l.subarray(o+t,o+(t<<1))),(g=e.createBufferSource()).connect(e.destination),g.buffer=s,g[g.start?'start':'noteOn'](.005+r)),u>r&&u>.5&&(10*n>u-r&&11025>t&&document.hasFocus()&&(n=(t+=441)/44100,WA.print('Warning: Audio callback had starved sending audio by '+(u-r)+' seconds. (extending samples to: '+t+')\n')),r=u+(document.hasFocus()?0:1.5)),r+=n}},10)):WA.print('Warning: WebAudio not supported\n')}}(m),WA.wasm||e('BOOT','Missing Wasm data'),h=n(WA.wasm),delete WA.wasm,b=64,A=4096,v=65536;for(let e,r,t,n=8;nr||r>11||0>=t||e>h.length)break;if(6==r){p(),w(),w(),p();let e=p();p(),v=e}if(11==r)for(let r=p(),t=0;t!=r&&e>n;t++){w(),p();let e=p(),r=(p(),p());A=(b=e+r)+15>>4<<4,n+=r}}b>0&&v>A||e('BOOT','Invalid memory layout ('+b+'/'+A+'/'+v+')'),x=262144+(v+65535>>16<<16),s=v,c=m.memory=new WebAssembly.Memory({initial:x>>16,maximum:4096}),a(),WebAssembly.instantiate(h,{env:m,wasi_unstable:d,wasi_snapshot_preview1:d,wasi:d}).then(function(e){if(WA.asm=e.instance.exports,WA.asm.__wasm_call_ctors&&WA.asm.__wasm_call_ctors(),WA.asm.main){var t=A;r('wasmexe',t+8),u[0+(t>>2)]=t+8,u[1+(t>>2)]=0,WA.asm.main(1,t)}WA.started&&WA.started()}).catch(function(r){'abort'!==r&&e('BOOT','WASM instiantate error: '+r+(r.stack?'\n'+r.stack:''))})}(); -------------------------------------------------------------------------------- /Embed/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #define GL_GLEXT_PROTOTYPES 33 | #define EGL_EGLEXT_PROTOTYPES 34 | #include 35 | #include 36 | 37 | // Functions defined in loader.js 38 | extern "C" void WAJS_SetupCanvas(int width, int height); 39 | extern "C" unsigned int WAJS_GetTime(); 40 | extern "C" void WAJS_StartAudio(); 41 | 42 | static const char* vertex_shader_text = 43 | "precision lowp float;" 44 | "uniform mat4 uMVP;" 45 | "attribute vec4 aPos;" 46 | "attribute vec3 aCol;" 47 | "varying vec3 vCol;" 48 | "void main()" 49 | "{" 50 | "vCol = aCol;" 51 | "gl_Position = uMVP * aPos;" 52 | "}"; 53 | 54 | static const char* fragment_shader_text = 55 | "precision lowp float;" 56 | "varying vec3 vCol;" 57 | "void main()" 58 | "{" 59 | "gl_FragColor = vec4(vCol, 1.0);" 60 | "}"; 61 | 62 | typedef struct Vertex { float x, y, r, g, b; } Vertex; 63 | static GLuint program, vertex_buffer; 64 | static GLint uMVP_location, aPos_location, aCol_location; 65 | 66 | // This function is called at startup 67 | int main(int argc, char *argv[]) 68 | { 69 | 70 | std::string string = "Hello C++"; 71 | string += " World"; 72 | printf("%s\n\n", string.c_str()); 73 | 74 | std::vector vec; 75 | vec.push_back(1); 76 | vec.push_back(2); 77 | vec.push_back(3); 78 | vec.erase(vec.begin() + 1); 79 | for (int i : vec) 80 | printf("Vector element: %d\n", i); 81 | printf("\n"); 82 | 83 | int* ptr = new int(); 84 | printf("Allocated memory with new at %p\n\n", ptr); 85 | delete ptr; 86 | 87 | printf("Setting up rendering canvas...\n\n", ptr); 88 | WAJS_SetupCanvas(640, 480); 89 | glViewport(0, 0, 640, 480); 90 | 91 | GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); 92 | glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); 93 | glCompileShader(vertex_shader); 94 | 95 | GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 96 | glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); 97 | glCompileShader(fragment_shader); 98 | 99 | program = glCreateProgram(); 100 | glAttachShader(program, vertex_shader); 101 | glAttachShader(program, fragment_shader); 102 | glLinkProgram(program); 103 | 104 | uMVP_location = glGetUniformLocation(program, "uMVP"); 105 | aPos_location = glGetAttribLocation(program, "aPos"); 106 | aCol_location = glGetAttribLocation(program, "aCol"); 107 | 108 | glGenBuffers(1, &vertex_buffer); 109 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 110 | 111 | glEnableVertexAttribArray(aPos_location); 112 | glVertexAttribPointer(aPos_location, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); 113 | glEnableVertexAttribArray(aCol_location); 114 | glVertexAttribPointer(aCol_location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 2)); 115 | 116 | printf("Starting audio output...\n\n", ptr); 117 | WAJS_StartAudio(); 118 | 119 | return 0; 120 | } 121 | 122 | // This function is called by loader.js every frame 123 | extern "C" void WAFNDraw() 124 | { 125 | float f = ((WAJS_GetTime() % 1000) / 1000.0f); 126 | 127 | glClear(GL_COLOR_BUFFER_BIT); 128 | 129 | Vertex vertices[3] = 130 | { 131 | { -0.6f, -0.4f, 1.f, 0.f, 0.f }, 132 | { 0.6f, -0.4f, 0.f, 1.f, 0.f }, 133 | { 0.f, 0.6f, 0.f, 0.f, 1.f }, 134 | }; 135 | vertices[0].x = sinf(f * 3.14159f) * 0.6f; 136 | vertices[1].x = sinf(f * 3.14159f) * -0.6f; 137 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 138 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 139 | 140 | GLfloat mvp[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 }; 141 | glUseProgram(program); 142 | glUniformMatrix4fv(uMVP_location, 1, GL_FALSE, mvp); 143 | glDrawArrays(GL_TRIANGLES, 0, 3); 144 | } 145 | 146 | // This function is called by loader.js to feed audio 147 | extern "C" bool WAFNAudio(float* sample_buffer, unsigned int samples) 148 | { 149 | // Render 220~440 HZ sine wave at 25% volume into both channels 150 | float f = ((WAJS_GetTime() % 1000) / 1000.0f); 151 | float delta = (220.0f * (1.5f + 0.5f * sinf(f * 3.14159f))) / 44100.0f; 152 | 153 | float *pLeft = sample_buffer, *pRight = sample_buffer + samples; 154 | for(unsigned int i = 0; i < samples; i++) 155 | { 156 | static float wave; 157 | wave = fmod(wave + delta, 1.0f); 158 | pLeft[i] = pRight[i] = sinf(2.0f * 3.14159f * wave) * 0.25f; 159 | } 160 | return true; 161 | } 162 | -------------------------------------------------------------------------------- /GenJS/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | SOURCES = main.c 33 | BUILD = RELEASE 34 | 35 | #------------------------------------------------------------------------------------------------------ 36 | 37 | ifeq ($(BUILD),RELEASE) 38 | OUTDIR := Release-wasm 39 | DBGCFLAGS := -DNDEBUG 40 | LDFLAGS := -strip-all -gc-sections 41 | WOPTFLAGS := -O3 42 | else 43 | OUTDIR := Debug-wasm 44 | DBGCFLAGS := -DDEBUG -D_DEBUG 45 | LDFLAGS := 46 | WOPTFLAGS := -g -O0 47 | endif 48 | 49 | # Global compiler flags 50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 52 | 53 | # Global compiler flags for Wasm targeting 54 | CLANGFLAGS := -target wasm32 -nostdinc 55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 62 | 63 | # Flags for wasm-ld 64 | LDFLAGS += -no-entry -allow-undefined -import-memory 65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 67 | 68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 70 | 71 | # Check if there are any source files 72 | ifeq ($(SOURCES),) 73 | $(error No source files found for build) 74 | endif 75 | 76 | # Compute tool paths 77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 81 | endif 82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 84 | endif 85 | 86 | # Surround used commands with double quotes 87 | CC := "$(LLVM_ROOT)/clang" 88 | CXX := "$(LLVM_ROOT)/clang" -x c++ 89 | LD := "$(LLVM_ROOT)/wasm-ld" 90 | 91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 92 | .PHONY: clean cleanall run analyze 93 | 94 | clean: 95 | $(info Removing all build files ...) 96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 97 | 98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 100 | -include $(OBJS:%.o=%.d) 101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 104 | 105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 106 | $(info Linking $@ ...) 107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 109 | 110 | $(OUTDIR)/loader.js : loader.js 111 | $(info Copying $^ to $@ ...) 112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 114 | 115 | $(OUTDIR)/loader.html : loader.html 116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 118 | 119 | define COMPILE 120 | $(info $2) 121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 123 | endef 124 | 125 | #------------------------------------------------------------------------------------------------------ 126 | #if System.bc exists, don't even bother checking sources, build once and forget for now 127 | ifeq ($(if $(wildcard System.bc),1,0),0) 128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 130 | 131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 136 | 137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 139 | 140 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 142 | endif 143 | 144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 145 | ifeq ($(if $(SYS_MISSING),1,0),1) 146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 147 | endif 148 | 149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 151 | 152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 154 | 155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 160 | 161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 165 | 166 | define SYS_COMPILE 167 | $(info $2) 168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 170 | endef 171 | 172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 173 | $(info Creating archive $@ ...) 174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 176 | endif #need System.bc 177 | #------------------------------------------------------------------------------------------------------ 178 | -------------------------------------------------------------------------------- /GenJS/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: Generate JavaScript Functions from C 7 | 8 | 9 |

WebAssembly Sample: Generate JavaScript Functions from C

10 |
11 |
Loading...

12 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /GenJS/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Some global state variables and max heap definition 32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32; 33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB 34 | 35 | // Define print and error functions if not yet defined by the outer html file 36 | WA.print = WA.print || function (msg) { console.log(msg); }; 37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 38 | 39 | // A generic abort function that if called stops the execution of the program and shows an error 40 | function abort(code, msg) 41 | { 42 | WA.error(code, msg); 43 | throw 'abort'; 44 | } 45 | 46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional) 47 | WA.WriteHeapString = function(str, ptr, max_length) 48 | { 49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;} 54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 58 | } 59 | return r[f]=0,f-a; 60 | } 61 | 62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8) 63 | WA.ReadHeapString = function(ptr, length) 64 | { 65 | if (length === 0 || !ptr) return ''; 66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++) 67 | { 68 | t = HEAPU8[((ptr)+(i))>>0]; 69 | if (t == 0 && !length) break; 70 | hasUtf |= t; 71 | } 72 | if (!length) length = i; 73 | if (hasUtf & 128) 74 | { 75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;) 76 | { 77 | if(o==p||(e=r[o++],!e)) return g; 78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e); 79 | } 80 | } 81 | // split up into chunks, because .apply on a huge string can overflow the stack 82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024) 83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024))); 84 | return ret; 85 | } 86 | 87 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript 88 | function MemorySetBufferViews() 89 | { 90 | var buf = WASM_MEMORY.buffer; 91 | HEAP32 = new Int32Array(buf); 92 | HEAPU8 = new Uint8Array(buf); 93 | HEAPU16 = new Uint16Array(buf); 94 | HEAPU32 = new Uint32Array(buf); 95 | HEAPF32 = new Float32Array(buf); 96 | } 97 | 98 | // Set up the env and wasi objects that contains the functions passed to the wasm module 99 | var env = 100 | { 101 | // sbrk gets called to increase the size of the memory heap by an increment 102 | sbrk: function(increment) 103 | { 104 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength; 105 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : '')); 106 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory'); 107 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); } 108 | WASM_HEAP = heapNew; 109 | return heapOld|0; 110 | }, 111 | 112 | // Functions querying the system time 113 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; }, 114 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; }, 115 | 116 | // Various functions thet can be called from wasm that abort the program 117 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + WA.ReadHeapString(condition) + ', at: ' + (filename ? WA.ReadHeapString(filename) : 'unknown filename'), line, (func ? WA.ReadHeapString(func) : 'unknown function')); }, 118 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); }, 119 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); }, 120 | abort: function() { abort('CRASH', 'Abort called'); }, 121 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); }, 122 | }; 123 | 124 | // Functions that do nothing in this wasm context 125 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {}; 126 | 127 | // Math functions 128 | env.ceil = env.ceilf = Math.ceil; 129 | env.exp = env.expf = Math.exp; 130 | env.floor = env.floorf = Math.floor; 131 | env.log = env.logf = Math.log; 132 | env.pow = env.powf = Math.pow; 133 | env.cos = env.cosf = Math.cos; 134 | env.sin = env.sinf = Math.sin; 135 | env.tan = env.tanf = Math.tan; 136 | env.acos = env.acosf = Math.acos; 137 | env.asin = env.asinf = Math.asin; 138 | env.sqrt = env.sqrtf = Math.sqrt; 139 | env.atan = env.atanf = Math.atan; 140 | env.atan2 = env.atan2f = Math.atan2; 141 | env.fabs = env.fabsf = env.abs = Math.abs; 142 | env.round = env.roundf = env.rint = env.rintf = Math.round; 143 | 144 | // The wasi object contains functions for the IO emulation 145 | var wasi = 146 | { 147 | // This function can only be used to write strings to stdout 148 | fd_write: function(fd, iov, iovcnt, pOutResult) 149 | { 150 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++) 151 | { 152 | // Process list of IO commands, read passed strings from heap 153 | var ptr = HEAPU32[(iov+(i*8))>>2], len = HEAPU32[(iov+(i*8+4))>>2]; 154 | if (len < 0) return -1; 155 | ret += len; 156 | str += WA.ReadHeapString(ptr, len); 157 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + WA.ReadHeapString(ptr, len).replace(/\n/g, '\\n')); 158 | } 159 | 160 | // Print the passed string and write the number of bytes read to the result pointer 161 | WA.print(str); 162 | HEAPU32[pOutResult>>2] = ret; 163 | return 0; // no error 164 | }, 165 | // Empty dummy functions for operations not emulated 166 | fd_read: function(fd, iov, iovcnt, pOutResult) { return 0; }, 167 | fd_seek: function(fd, offset_low, offset_high, whence, pOutResult) { return 0; }, 168 | fd_close: function(fd) { return 0; }, 169 | }; 170 | 171 | // Find the start point of the stack and the heap to calculate the initial memory requirements and load generated functions 172 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536, JS = {}; 173 | // This code goes through the wasm file sections according the binary encoding description 174 | // https://webassembly.org/docs/binary-encoding/ 175 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 176 | { 177 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 178 | function Get() { return wasmBytes[i++]; } 179 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 180 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 181 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 182 | if (type == 2) 183 | { 184 | //Section 2 'Imports' contains the list of JavaScript functions imported by the wasm module 185 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++) 186 | { 187 | let modlen = GetLEB(), modstr = i, fldlen = (i+=modlen,GetLEB()), fldstr = i, itype = (i+=fldlen,(Get()?Get():GetLEB())); 188 | if (modlen == 2 && wasmBytes[modstr] == 74 && wasmBytes[modstr+1] == 83) //JS module 189 | { 190 | // JavaScript functions can be generated by the compiled code (with WA_JS), their code is embedded in the field name 191 | let fld = new TextDecoder("utf-8").decode(new Uint8Array(wasmBytes.buffer, fldstr, fldlen)); 192 | let iarr = fld.split('|', 2), iname = iarr[0], iargs = iarr[1], icode = fld.substr(iname.length + iargs.length + 2); 193 | 194 | // strip C types out of params list (change '(float p1, unsigned int p2)' to 'p1,p2' (function pointers not supported) 195 | iargs = iargs.replace(/\[.*?\]|^\(\s*(void|)\s*\)$/g, '').replace(/.*?(\w+)\s*[,\)]/g, ',$1').substr(1); 196 | 197 | // fix escaped character sequences 198 | icode = icode.replace(/[\x00-\x1F]/g, (m)=>'\\'+[0,0,0,0,0,0,0,'a','b','t','n','v','f','r',0,0,0,0,0,0,0,0,0,0,0,0,0,'e',0,0,0,0][m.charCodeAt(0)]) 199 | 200 | // expose function with code to wasm module (but overwrite the source code in the name with whitespace) 201 | wasmBytes.fill(32, fldstr + iname.length, fldstr + fldlen) 202 | try { JS[iname + (' '.repeat(fldlen - iname.length))] = new Function(...(iargs ? iargs.split(',') : []).concat(icode)); } 203 | catch (err) { WA.error('BOOT', 'Error in WA_JS function ' + iname + ': ' + err); } 204 | } 205 | } 206 | } 207 | if (type == 6) 208 | { 209 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 210 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 211 | wasmHeapBase = offset; 212 | } 213 | if (type == 11) 214 | { 215 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area 216 | for (let count = GetLEB(), j = 0, dsize; j != count && i < sectionEnd; i += dsize, j++) 217 | { 218 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(); 219 | wasmDataEnd = (doffset + (dsize = GetLEB())); 220 | wasmStackTop = (wasmDataEnd+15)>>4<<4; 221 | } 222 | } 223 | } 224 | 225 | // Validate the queried pointers 226 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')'); 227 | 228 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk) 229 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 230 | WASM_HEAP = wasmHeapBase; 231 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 }); 232 | MemorySetBufferViews(); 233 | 234 | // Instantiate the wasm module by passing the prepared env, wasi and JS objects containing import functions for the wasm module 235 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi,JS:JS}).then(function (output) 236 | { 237 | // Store the list of the functions exported by the wasm module in WA.asm 238 | WA.asm = output.instance.exports; 239 | 240 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 241 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 242 | 243 | // If function 'main' exists, call it 244 | if (WA.asm.main) 245 | { 246 | // Store the argument list with 1 entry at the far end of the stack to pass to main 247 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe'; 248 | 249 | // Store the program name string after the argv list 250 | WA.WriteHeapString(exe, (argv + 8)); 251 | 252 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer 253 | HEAPU32[(argv>>2) + 0] = (argv + 8) 254 | HEAPU32[(argv>>2) + 1] = 0; 255 | 256 | WA.asm.main(argc, argv); 257 | } 258 | 259 | // If the outer HTML file supplied a 'started' callback, call it 260 | if (WA.started) WA.started(); 261 | }) 262 | .catch(function (err) 263 | { 264 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 265 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 266 | }); 267 | 268 | }); 269 | -------------------------------------------------------------------------------- /GenJS/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | 30 | #ifdef __cplusplus 31 | #define WA_EXTERN extern "C" 32 | #else 33 | #define WA_EXTERN extern 34 | #endif 35 | 36 | // Macro to make a C function available from JavaScript 37 | #define WA_EXPORT(name) __attribute__((used, visibility("default"), export_name(name))) 38 | 39 | // Macro to generate a JavaScript function that can be called from C 40 | #define WA_JS(ret, name, args, ...) WA_EXTERN __attribute__((import_module("JS"), import_name(#name "|" #args "|" #__VA_ARGS__))) ret name args; 41 | 42 | // Create a JavaScript function that writes to the wa_log div 43 | WA_JS(void, direct_print, (const char* pstr), 44 | { 45 | document.getElementById('wa_log').innerHTML += WA.ReadHeapString(pstr).replace(/\n/g, '
'); 46 | }); 47 | 48 | // C function 'add' that can be called from JavaScript 49 | WA_EXPORT("add") int add(int a, int b) 50 | { 51 | return a + b; 52 | } 53 | 54 | // Create a JavaScript function that calls the C function above 55 | WA_JS(void, call_add, (void), 56 | { 57 | WA.print('add(2, 3): ' + WA.asm.add(2, 3) + '\n\n'); 58 | }); 59 | 60 | // Create a JavaScript function that writes the content of document.location.href into the wasm memory 61 | WA_JS(int, get_document_location, (const char* pstr, int len), 62 | { 63 | return WA.WriteHeapString(document.location.href, pstr, len) 64 | }); 65 | 66 | // An unused JavaScript function which doesn't get included in the .wasm binary 67 | WA_JS(void, unused_wa_js_func, (), 68 | { 69 | WA.print('This text does not even get included in the .wasm file\n'); 70 | }); 71 | 72 | int main(int argc, char *argv[]) 73 | { 74 | char buf[256]; 75 | int bufret; 76 | 77 | printf("Printing through printf\n\n"); 78 | 79 | direct_print("Printing directly through WA_JS\n\n"); 80 | 81 | call_add(); 82 | 83 | printf("Requesting string document.location from JavaScript...\n"); 84 | bufret = get_document_location(buf, sizeof(buf)); 85 | printf("Got document.location: %s (len: %d)\n\n", buf, bufret); 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /GenJS/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/GenJS/output.wasm -------------------------------------------------------------------------------- /LibC/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | SOURCES = main.c 33 | BUILD = RELEASE 34 | 35 | #------------------------------------------------------------------------------------------------------ 36 | 37 | ifeq ($(BUILD),RELEASE) 38 | OUTDIR := Release-wasm 39 | DBGCFLAGS := -DNDEBUG 40 | LDFLAGS := -strip-all -gc-sections 41 | WOPTFLAGS := -O3 42 | else 43 | OUTDIR := Debug-wasm 44 | DBGCFLAGS := -DDEBUG -D_DEBUG 45 | LDFLAGS := 46 | WOPTFLAGS := -g -O0 47 | endif 48 | 49 | # Global compiler flags 50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 52 | 53 | # Global compiler flags for Wasm targeting 54 | CLANGFLAGS := -target wasm32 -nostdinc 55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 62 | 63 | # Flags for wasm-ld 64 | LDFLAGS += -no-entry -allow-undefined -import-memory 65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 67 | 68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 70 | 71 | # Check if there are any source files 72 | ifeq ($(SOURCES),) 73 | $(error No source files found for build) 74 | endif 75 | 76 | # Compute tool paths 77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 81 | endif 82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 84 | endif 85 | 86 | # Surround used commands with double quotes 87 | CC := "$(LLVM_ROOT)/clang" 88 | CXX := "$(LLVM_ROOT)/clang" -x c++ 89 | LD := "$(LLVM_ROOT)/wasm-ld" 90 | 91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 92 | .PHONY: clean cleanall run analyze 93 | 94 | clean: 95 | $(info Removing all build files ...) 96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 97 | 98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 100 | -include $(OBJS:%.o=%.d) 101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 104 | 105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 106 | $(info Linking $@ ...) 107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 109 | 110 | $(OUTDIR)/loader.js : loader.js 111 | $(info Copying $^ to $@ ...) 112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 114 | 115 | $(OUTDIR)/loader.html : loader.html 116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 118 | 119 | define COMPILE 120 | $(info $2) 121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 123 | endef 124 | 125 | #------------------------------------------------------------------------------------------------------ 126 | #if System.bc exists, don't even bother checking sources, build once and forget for now 127 | ifeq ($(if $(wildcard System.bc),1,0),0) 128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 130 | 131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 136 | 137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 139 | 140 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 142 | endif 143 | 144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 145 | ifeq ($(if $(SYS_MISSING),1,0),1) 146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 147 | endif 148 | 149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 151 | 152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 154 | 155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 160 | 161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 165 | 166 | define SYS_COMPILE 167 | $(info $2) 168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 170 | endef 171 | 172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 173 | $(info Creating archive $@ ...) 174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 176 | endif #need System.bc 177 | #------------------------------------------------------------------------------------------------------ 178 | -------------------------------------------------------------------------------- /LibC/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: C standard library 7 | 8 | 9 |

WebAssembly Sample: C standard library

10 |
11 |
Loading...

12 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LibC/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Some global state variables and max heap definition 32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32; 33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB 34 | 35 | // Define print and error functions if not yet defined by the outer html file 36 | WA.print = WA.print || function (msg) { console.log(msg); }; 37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 38 | 39 | // A generic abort function that if called stops the execution of the program and shows an error 40 | function abort(code, msg) 41 | { 42 | WA.error(code, msg); 43 | throw 'abort'; 44 | } 45 | 46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional) 47 | function WriteHeapString(str, ptr, max_length) 48 | { 49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;} 54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 58 | } 59 | return r[f]=0,f-a; 60 | } 61 | 62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8) 63 | function ReadHeapString(ptr, length) 64 | { 65 | if (length === 0 || !ptr) return ''; 66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++) 67 | { 68 | t = HEAPU8[((ptr)+(i))>>0]; 69 | if (t == 0 && !length) break; 70 | hasUtf |= t; 71 | } 72 | if (!length) length = i; 73 | if (hasUtf & 128) 74 | { 75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;) 76 | { 77 | if(o==p||(e=r[o++],!e)) return g; 78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e); 79 | } 80 | } 81 | // split up into chunks, because .apply on a huge string can overflow the stack 82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024) 83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024))); 84 | return ret; 85 | } 86 | 87 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module 88 | function SYSCALLS_WASM_IMPORTS(env, wasi) 89 | { 90 | // Function to decode Base64 encoded string to a byte array 91 | function Base64Decode(B) 92 | { 93 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];}; 94 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63; 95 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0; 96 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; } 97 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; } 98 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255; 99 | return a; 100 | } 101 | 102 | // For the file open/file reading emulation, keep a seek cursor and the file data 103 | var PAYLOAD_CURSOR = 0; 104 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0)); 105 | delete WA.payload; 106 | 107 | // sys_open call to open a file (can only be used to open payload here) 108 | env.__sys_open = function(pPath, flags, pMode) 109 | { 110 | // Opening just resets the seek cursor to 0 111 | PAYLOAD_CURSOR = 0; 112 | //var pathname = ReadHeapString(pPath); //read the file name passed to open 113 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]); 114 | return 9; //return dummy file number 115 | }; 116 | 117 | // fd_read call to read from a file (reads from payload) 118 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult) 119 | { 120 | for (var ret = 0, i = 0; i < iovcnt; i++) 121 | { 122 | // Process list of IO commands 123 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 124 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 125 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR); 126 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')'); 127 | 128 | // Write the requested data onto the heap and advance the seek cursor 129 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr); 130 | PAYLOAD_CURSOR += curr; 131 | 132 | ret += curr; 133 | if (curr < len) break; // nothing more to read 134 | } 135 | 136 | // Write the amount of data actually read to the result pointer 137 | HEAPU32[pOutResult>>2] = ret; 138 | //console.log('fd_read - ret: ' + ret); 139 | return 0; // no error 140 | }; 141 | 142 | // fd_seek call to seek in a file (seeks in payload) 143 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult) 144 | { 145 | // Move seek cursor according to fseek behavior 146 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set 147 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur 148 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end 149 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0; 150 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length; 151 | 152 | // Write the result back (write only lower 32-bit of 64-bit number) 153 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR; 154 | HEAPU32[(pOutResult+4)>>2] = 0; 155 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR); 156 | return 0; // no error 157 | }; 158 | 159 | // fd_write call to write to a file/pipe (can only be used to write to stdout here) 160 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult) 161 | { 162 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++) 163 | { 164 | // Process list of IO commands, read passed strings from heap 165 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 166 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 167 | if (len < 0) return -1; 168 | ret += len; 169 | str += ReadHeapString(ptr, len); 170 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n')); 171 | } 172 | 173 | // Print the passed string and write the number of bytes read to the result pointer 174 | WA.print(str); 175 | HEAPU32[pOutResult>>2] = ret; 176 | return 0; // no error 177 | }; 178 | 179 | // fd_close to close a file (no real file system emulation, so this does nothing) 180 | wasi.fd_close = function(fd) 181 | { 182 | //console.log('fd_close - fd: ' + fd); 183 | return 0; // no error 184 | }; 185 | 186 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here 187 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param) 188 | { 189 | return 0; // no error 190 | }; 191 | } 192 | 193 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript 194 | function MemorySetBufferViews() 195 | { 196 | var buf = WASM_MEMORY.buffer; 197 | HEAP32 = new Int32Array(buf); 198 | HEAPU8 = new Uint8Array(buf); 199 | HEAPU16 = new Uint16Array(buf); 200 | HEAPU32 = new Uint32Array(buf); 201 | HEAPF32 = new Float32Array(buf); 202 | } 203 | 204 | // Set up the env and wasi objects that contains the functions passed to the wasm module 205 | var env = 206 | { 207 | // sbrk gets called to increase the size of the memory heap by an increment 208 | sbrk: function(increment) 209 | { 210 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength; 211 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : '')); 212 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory'); 213 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); } 214 | WASM_HEAP = heapNew; 215 | return heapOld|0; 216 | }, 217 | 218 | // Functions querying the system time 219 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; }, 220 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; }, 221 | 222 | // Various functions thet can be called from wasm that abort the program 223 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); }, 224 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); }, 225 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); }, 226 | abort: function() { abort('CRASH', 'Abort called'); }, 227 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); }, 228 | }, wasi = {}; 229 | 230 | // Functions that do nothing in this wasm context 231 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {}; 232 | 233 | // Math functions 234 | env.ceil = env.ceilf = Math.ceil; 235 | env.exp = env.expf = Math.exp; 236 | env.floor = env.floorf = Math.floor; 237 | env.log = env.logf = Math.log; 238 | env.pow = env.powf = Math.pow; 239 | env.cos = env.cosf = Math.cos; 240 | env.sin = env.sinf = Math.sin; 241 | env.tan = env.tanf = Math.tan; 242 | env.acos = env.acosf = Math.acos; 243 | env.asin = env.asinf = Math.asin; 244 | env.sqrt = env.sqrtf = Math.sqrt; 245 | env.atan = env.atanf = Math.atan; 246 | env.atan2 = env.atan2f = Math.atan2; 247 | env.fabs = env.fabsf = env.abs = Math.abs; 248 | env.round = env.roundf = env.rint = env.rintf = Math.round; 249 | 250 | // Extend the objects with the syscall IO emulation 251 | SYSCALLS_WASM_IMPORTS(env, wasi); 252 | 253 | // Find the start point of the stack and the heap to calculate the initial memory requirements 254 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536; 255 | // This code goes through the wasm file sections according the binary encoding description 256 | // https://webassembly.org/docs/binary-encoding/ 257 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 258 | { 259 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 260 | function Get() { return wasmBytes[i++]; } 261 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 262 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 263 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 264 | if (type == 6) 265 | { 266 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 267 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 268 | wasmHeapBase = offset; 269 | } 270 | if (type == 11) 271 | { 272 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area 273 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++) 274 | { 275 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB(); 276 | wasmDataEnd = (doffset + dsize); 277 | wasmStackTop = (wasmDataEnd+15)>>4<<4; 278 | i += dsize; 279 | } 280 | } 281 | } 282 | 283 | // Validate the queried pointers 284 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')'); 285 | 286 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk) 287 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 288 | WASM_HEAP = wasmHeapBase; 289 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 }); 290 | MemorySetBufferViews(); 291 | 292 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module 293 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output) 294 | { 295 | // Store the list of the functions exported by the wasm module in WA.asm 296 | WA.asm = output.instance.exports; 297 | 298 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 299 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 300 | 301 | // If function 'main' exists, call it 302 | if (WA.asm.main) 303 | { 304 | // Store the argument list with 1 entry at the far end of the stack to pass to main 305 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe'; 306 | 307 | // Store the program name string after the argv list 308 | WriteHeapString(exe, (argv + 8)); 309 | 310 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer 311 | HEAPU32[(argv>>2) + 0] = (argv + 8) 312 | HEAPU32[(argv>>2) + 1] = 0; 313 | 314 | WA.asm.main(argc, argv); 315 | } 316 | 317 | // If the outer HTML file supplied a 'started' callback, call it 318 | if (WA.started) WA.started(); 319 | }) 320 | .catch(function (err) 321 | { 322 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 323 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 324 | }); 325 | 326 | }); 327 | -------------------------------------------------------------------------------- /LibC/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | printf("Hello printf World\n\n"); 36 | 37 | printf("main argc: %d - argv[0]: %s\n\n", argc, argv[0]); 38 | 39 | printf("sinf(1.0f): %f\n\n", sinf(1.0f)); 40 | 41 | char file_buf[20] = {0}; 42 | FILE* file = fopen("payload", "r"); 43 | printf("Opened payload file %p\n", file); 44 | fseek(file, 0, SEEK_END); 45 | long file_size = ftell(file); 46 | fseek(file, 0, SEEK_SET); 47 | printf("Size of payload is %d\n", file_size); 48 | size_t file_read = fread(file_buf, 1, sizeof(file_buf), file); 49 | fclose(file); 50 | printf("Read %d bytes from file '%s'\n\n", (int)file_read, file_buf); 51 | 52 | void* alloc_buf = malloc(1024); 53 | printf("Allocated 1KB at address %p\n", alloc_buf); 54 | alloc_buf = realloc(alloc_buf, 10*1024*1024); 55 | printf("Reallocated to 10MB at address %p\n\n", alloc_buf); 56 | free(alloc_buf); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /LibC/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/LibC/output.wasm -------------------------------------------------------------------------------- /LoadUrl/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | EXPORTS = WAFNHTTP 33 | SOURCES = main.cpp 34 | BUILD = RELEASE 35 | 36 | #------------------------------------------------------------------------------------------------------ 37 | 38 | ifeq ($(BUILD),RELEASE) 39 | OUTDIR := Release-wasm 40 | DBGCFLAGS := -DNDEBUG 41 | LDFLAGS := -strip-all -gc-sections 42 | WOPTFLAGS := -O3 43 | else 44 | OUTDIR := Debug-wasm 45 | DBGCFLAGS := -DDEBUG -D_DEBUG 46 | LDFLAGS := 47 | WOPTFLAGS := -g -O0 48 | endif 49 | 50 | # Global compiler flags 51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 53 | 54 | # Global compiler flags for Wasm targeting 55 | CLANGFLAGS := -target wasm32 -nostdinc 56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 63 | 64 | # Flags for wasm-ld 65 | LDFLAGS += -no-entry -allow-undefined -import-memory 66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 68 | 69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 71 | 72 | # Check if there are any source files 73 | ifeq ($(SOURCES),) 74 | $(error No source files found for build) 75 | endif 76 | 77 | # Compute tool paths 78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 82 | endif 83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 85 | endif 86 | 87 | # Surround used commands with double quotes 88 | CC := "$(LLVM_ROOT)/clang" 89 | CXX := "$(LLVM_ROOT)/clang" -x c++ 90 | LD := "$(LLVM_ROOT)/wasm-ld" 91 | 92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 93 | .PHONY: clean cleanall run analyze 94 | 95 | clean: 96 | $(info Removing all build files ...) 97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 98 | 99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 101 | -include $(OBJS:%.o=%.d) 102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 105 | 106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 107 | $(info Linking $@ ...) 108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 110 | 111 | $(OUTDIR)/loader.js : loader.js 112 | $(info Copying $^ to $@ ...) 113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 115 | 116 | $(OUTDIR)/loader.html : loader.html 117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 119 | 120 | define COMPILE 121 | $(info $2) 122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 124 | endef 125 | 126 | #------------------------------------------------------------------------------------------------------ 127 | #if System.bc exists, don't even bother checking sources, build once and forget for now 128 | ifeq ($(if $(wildcard System.bc),1,0),0) 129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 131 | 132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 137 | 138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 140 | 141 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 143 | endif 144 | 145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 146 | ifeq ($(if $(SYS_MISSING),1,0),1) 147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 148 | endif 149 | 150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 152 | 153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 155 | 156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 161 | 162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 166 | 167 | define SYS_COMPILE 168 | $(info $2) 169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 171 | endef 172 | 173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 174 | $(info Creating archive $@ ...) 175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 177 | endif #need System.bc 178 | #------------------------------------------------------------------------------------------------------ 179 | -------------------------------------------------------------------------------- /LoadUrl/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: Load URL 7 | 8 | 9 |

WebAssembly Sample: Load URL

10 |
11 |
Loading...

12 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LoadUrl/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes 29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes); 30 | 31 | // Some global state variables and max heap definition 32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32; 33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB 34 | 35 | // Define print and error functions if not yet defined by the outer html file 36 | WA.print = WA.print || function (msg) { console.log(msg); }; 37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); }; 38 | 39 | // A generic abort function that if called stops the execution of the program and shows an error 40 | function abort(code, msg) 41 | { 42 | WA.error(code, msg); 43 | throw 'abort'; 44 | } 45 | 46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional) 47 | function WriteHeapString(str, ptr, max_length) 48 | { 49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;} 54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;} 58 | } 59 | return r[f]=0,f-a; 60 | } 61 | 62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8) 63 | function ReadHeapString(ptr, length) 64 | { 65 | if (length === 0 || !ptr) return ''; 66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++) 67 | { 68 | t = HEAPU8[((ptr)+(i))>>0]; 69 | if (t == 0 && !length) break; 70 | hasUtf |= t; 71 | } 72 | if (!length) length = i; 73 | if (hasUtf & 128) 74 | { 75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;) 76 | { 77 | if(o==p||(e=r[o++],!e)) return g; 78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e); 79 | } 80 | } 81 | // split up into chunks, because .apply on a huge string can overflow the stack 82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024) 83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024))); 84 | return ret; 85 | } 86 | 87 | // Allocate and store a byte array on the wasm heap 88 | function malloc_array(a) 89 | { 90 | var ptr = WA.asm.malloc(Math.max(a.length, 1)); 91 | if (a.subarray || a.slice) HEAPU8.set(a, ptr); 92 | else HEAPU8.set(new Uint8Array(a), ptr); 93 | return ptr; 94 | } 95 | 96 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module 97 | function SYSCALLS_WASM_IMPORTS(env, wasi) 98 | { 99 | // Function to decode Base64 encoded string to a byte array 100 | function Base64Decode(B) 101 | { 102 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];}; 103 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63; 104 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0; 105 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; } 106 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; } 107 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255; 108 | return a; 109 | } 110 | 111 | // For the file open/file reading emulation, keep a seek cursor and the file data 112 | var PAYLOAD_CURSOR = 0; 113 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0)); 114 | delete WA.payload; 115 | 116 | // sys_open call to open a file (can only be used to open payload here) 117 | env.__sys_open = function(pPath, flags, pMode) 118 | { 119 | // Opening just resets the seek cursor to 0 120 | PAYLOAD_CURSOR = 0; 121 | //var pathname = ReadHeapString(pPath); //read the file name passed to open 122 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]); 123 | return 9; //return dummy file number 124 | }; 125 | 126 | // fd_read call to read from a file (reads from payload) 127 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult) 128 | { 129 | for (var ret = 0, i = 0; i < iovcnt; i++) 130 | { 131 | // Process list of IO commands 132 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 133 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 134 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR); 135 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')'); 136 | 137 | // Write the requested data onto the heap and advance the seek cursor 138 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr); 139 | PAYLOAD_CURSOR += curr; 140 | 141 | ret += curr; 142 | if (curr < len) break; // nothing more to read 143 | } 144 | 145 | // Write the amount of data actually read to the result pointer 146 | HEAPU32[pOutResult>>2] = ret; 147 | //console.log('fd_read - ret: ' + ret); 148 | return 0; // no error 149 | }; 150 | 151 | // fd_seek call to seek in a file (seeks in payload) 152 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult) 153 | { 154 | // Move seek cursor according to fseek behavior 155 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set 156 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur 157 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end 158 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0; 159 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length; 160 | 161 | // Write the result back (write only lower 32-bit of 64-bit number) 162 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR; 163 | HEAPU32[(pOutResult+4)>>2] = 0; 164 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR); 165 | return 0; // no error 166 | }; 167 | 168 | // fd_write call to write to a file/pipe (can only be used to write to stdout here) 169 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult) 170 | { 171 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++) 172 | { 173 | // Process list of IO commands, read passed strings from heap 174 | var ptr = HEAPU32[((iov)+(i*8))>>2]; 175 | var len = HEAPU32[((iov)+(i*8 + 4))>>2]; 176 | if (len < 0) return -1; 177 | ret += len; 178 | str += ReadHeapString(ptr, len); 179 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n')); 180 | } 181 | 182 | // Print the passed string and write the number of bytes read to the result pointer 183 | WA.print(str); 184 | HEAPU32[pOutResult>>2] = ret; 185 | return 0; // no error 186 | }; 187 | 188 | // fd_close to close a file (no real file system emulation, so this does nothing) 189 | wasi.fd_close = function(fd) 190 | { 191 | //console.log('fd_close - fd: ' + fd); 192 | return 0; // no error 193 | }; 194 | 195 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here 196 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param) 197 | { 198 | return 0; // no error 199 | }; 200 | } 201 | 202 | // Defines our custom functions in the env object that get passed to the wasm module 203 | function WAJS_WASM_IMPORTS(env) 204 | { 205 | // Load data from a URL and pass the result (or error) back to wasm with WAFNHTTP 206 | env.WAJS_AsyncLoad = function(url, userdata, postdata, postlength, timeout) 207 | { 208 | var xhr = new XMLHttpRequest(), WAFNHTTP = WA.asm.WAFNHTTP; 209 | xhr.open((postlength ? 'POST' : 'GET'), ReadHeapString(url), true); 210 | xhr.responseType = 'arraybuffer'; 211 | if (timeout) xhr.timeout = timeout; 212 | xhr.onload = function() 213 | { 214 | if (xhr.status == 200) 215 | { 216 | var b = malloc_array(new Uint8Array(xhr.response)); 217 | WAFNHTTP(200, b, xhr.response.byteLength, userdata); 218 | WA.asm.free(b); 219 | } 220 | else WAFNHTTP(xhr.status, 0, 0, userdata); 221 | }; 222 | xhr.ontimeout = xhr.onerror = function(event) 223 | { 224 | // This could be called synchronously by xhr.send() so force it to arrive async 225 | setTimeout(function() { WAFNHTTP(xhr.status||-1, 0, 0, userdata); }); 226 | }; 227 | if (postlength) try { xhr.send(HEAPU8.subarray(postdata, postdata+postlength)); } catch (e) { xhr.send(HEAPU8.buffer.slice(postdata, postdata+postlength)); } 228 | else xhr.send(null); 229 | }; 230 | } 231 | 232 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript 233 | function MemorySetBufferViews() 234 | { 235 | var buf = WASM_MEMORY.buffer; 236 | HEAP32 = new Int32Array(buf); 237 | HEAPU8 = new Uint8Array(buf); 238 | HEAPU16 = new Uint16Array(buf); 239 | HEAPU32 = new Uint32Array(buf); 240 | HEAPF32 = new Float32Array(buf); 241 | } 242 | 243 | // Set up the env and wasi objects that contains the functions passed to the wasm module 244 | var env = 245 | { 246 | // sbrk gets called to increase the size of the memory heap by an increment 247 | sbrk: function(increment) 248 | { 249 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength; 250 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : '')); 251 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory'); 252 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); } 253 | WASM_HEAP = heapNew; 254 | return heapOld|0; 255 | }, 256 | 257 | // Functions querying the system time 258 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; }, 259 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; }, 260 | 261 | // Various functions thet can be called from wasm that abort the program 262 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); }, 263 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); }, 264 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); }, 265 | abort: function() { abort('CRASH', 'Abort called'); }, 266 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); }, 267 | }, wasi = {}; 268 | 269 | // Functions that do nothing in this wasm context 270 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {}; 271 | 272 | // Math functions 273 | env.ceil = env.ceilf = Math.ceil; 274 | env.exp = env.expf = Math.exp; 275 | env.floor = env.floorf = Math.floor; 276 | env.log = env.logf = Math.log; 277 | env.pow = env.powf = Math.pow; 278 | env.cos = env.cosf = Math.cos; 279 | env.sin = env.sinf = Math.sin; 280 | env.tan = env.tanf = Math.tan; 281 | env.acos = env.acosf = Math.acos; 282 | env.asin = env.asinf = Math.asin; 283 | env.sqrt = env.sqrtf = Math.sqrt; 284 | env.atan = env.atanf = Math.atan; 285 | env.atan2 = env.atan2f = Math.atan2; 286 | env.fabs = env.fabsf = env.abs = Math.abs; 287 | env.round = env.roundf = env.rint = env.rintf = Math.round; 288 | 289 | // Extend the objects with the syscall IO emulation and our custom functions 290 | SYSCALLS_WASM_IMPORTS(env, wasi); 291 | WAJS_WASM_IMPORTS(env); 292 | 293 | // Find the start point of the stack and the heap to calculate the initial memory requirements 294 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536; 295 | // This code goes through the wasm file sections according the binary encoding description 296 | // https://webassembly.org/docs/binary-encoding/ 297 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd) 298 | { 299 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number 300 | function Get() { return wasmBytes[i++]; } 301 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; } 302 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length; 303 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break; 304 | if (type == 6) 305 | { 306 | //Section 6 'Globals', llvm places the heap base pointer into the first value here 307 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB(); 308 | wasmHeapBase = offset; 309 | } 310 | if (type == 11) 311 | { 312 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area 313 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++) 314 | { 315 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB(); 316 | wasmDataEnd = (doffset + dsize); 317 | wasmStackTop = (wasmDataEnd+15)>>4<<4; 318 | i += dsize; 319 | } 320 | } 321 | } 322 | 323 | // Validate the queried pointers 324 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')'); 325 | 326 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk) 327 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024); 328 | WASM_HEAP = wasmHeapBase; 329 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 }); 330 | MemorySetBufferViews(); 331 | 332 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module 333 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output) 334 | { 335 | // Store the list of the functions exported by the wasm module in WA.asm 336 | WA.asm = output.instance.exports; 337 | 338 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it 339 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors(); 340 | 341 | // If function 'main' exists, call it 342 | if (WA.asm.main) 343 | { 344 | // Store the argument list with 1 entry at the far end of the stack to pass to main 345 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe'; 346 | 347 | // Store the program name string after the argv list 348 | WriteHeapString(exe, (argv + 8)); 349 | 350 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer 351 | HEAPU32[(argv>>2) + 0] = (argv + 8) 352 | HEAPU32[(argv>>2) + 1] = 0; 353 | 354 | WA.asm.main(argc, argv); 355 | } 356 | 357 | // If the outer HTML file supplied a 'started' callback, call it 358 | if (WA.started) WA.started(); 359 | }) 360 | .catch(function (err) 361 | { 362 | // On an exception, if the err is 'abort' the error was already processed in the abort function above 363 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : '')); 364 | }); 365 | 366 | }); 367 | -------------------------------------------------------------------------------- /LoadUrl/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #include 29 | 30 | // Function defined in loader.js 31 | extern "C" void WAJS_AsyncLoad(const char* url, void* userdata = NULL, char* postdata = NULL, size_t postlength = 0, unsigned int timeout = 0); 32 | 33 | // This function is called at startup 34 | int main(int argc, char *argv[]) 35 | { 36 | const char* url = "http://zillalib.github.io/TEST.TXT"; 37 | printf("Requesting url '%s' ...\n", url); 38 | WAJS_AsyncLoad(url); 39 | printf("Sent async request, waiting for response\n"); 40 | 41 | return 0; 42 | } 43 | 44 | // This function is called by loader.js when the HTTP request finishes (or has an error) 45 | extern "C" void WAFNHTTP(int status, char* data, size_t length, void* userdata) 46 | { 47 | printf("Received response - status: %d - length: %d - data: '%.*s'\n", status, (int)length, (int)length, data); 48 | } 49 | -------------------------------------------------------------------------------- /LoadUrl/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/LoadUrl/output.wasm -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly without Emscripten 2 | 3 | This is the repository that goes along my blog post "WebAssembly without Emscripten" 4 | 5 | How to get rid of Emscripten and build and compile WebAssembly applications with ease 6 | 7 | [https://schellcode.github.io/webassembly-without-emscripten](https://schellcode.github.io/webassembly-without-emscripten) 8 | 9 | 10 | ## Demos 11 | 12 | Demo (Click to run) | Download | Explanation 13 | --------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------- 14 | 1 [Pure C function](https://schellingb.github.io/ClangWasm/Basic/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Basic.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-1-explaining-the-basic-process) 15 | 2 [With C Standard Library](https://schellingb.github.io/ClangWasm/LibC/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_LibC.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-2-using-the-c-standard-library) 16 | 3 [With C++](https://schellingb.github.io/ClangWasm/Cpp/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Cpp.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-3-using-c-and-the-c-standard-library) 17 | 4 [WebGL rendering](https://schellingb.github.io/ClangWasm/WebGL/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_WebGL.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-4-webgl-rendering) 18 | 5 [Audio output](https://schellingb.github.io/ClangWasm/Audio/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Audio.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-5-audio-output) 19 | 6 [Loading a URL](https://schellingb.github.io/ClangWasm/LoadUrl/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_LoadUrl.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-6-loading-data-from-url) 20 | 7 [Embedding WASM](https://schellingb.github.io/ClangWasm/Embed/output.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Embed.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-7-advanced-build-script-with-embedding) 21 | 8 [Generate JS from C](https://schellingb.github.io/ClangWasm/GenJS/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_GenJS.zip) | TODO 22 | 23 | 24 | ## License 25 | All code here available as [Public Domain](https://www.unlicense.org). 26 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /WebGL/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # 27 | 28 | LLVM_ROOT = D:/dev/wasm/llvm 29 | SYSTEM_ROOT = D:/dev/wasm/system 30 | WASMOPT = D:/dev/wasm/wasm-opt.exe 31 | 32 | EXPORTS = WAFNDraw 33 | SOURCES = main.cpp 34 | BUILD = RELEASE 35 | 36 | #------------------------------------------------------------------------------------------------------ 37 | 38 | ifeq ($(BUILD),RELEASE) 39 | OUTDIR := Release-wasm 40 | DBGCFLAGS := -DNDEBUG 41 | LDFLAGS := -strip-all -gc-sections 42 | WOPTFLAGS := -O3 43 | else 44 | OUTDIR := Debug-wasm 45 | DBGCFLAGS := -DDEBUG -D_DEBUG 46 | LDFLAGS := 47 | WOPTFLAGS := -g -O0 48 | endif 49 | 50 | # Global compiler flags 51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas 52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99 53 | 54 | # Global compiler flags for Wasm targeting 55 | CLANGFLAGS := -target wasm32 -nostdinc 56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2 57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics 58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx 59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat 60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include 61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc 62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten 63 | 64 | # Flags for wasm-ld 65 | LDFLAGS += -no-entry -allow-undefined -import-memory 66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main 67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS)))) 68 | 69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE) 70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)")) 71 | 72 | # Check if there are any source files 73 | ifeq ($(SOURCES),) 74 | $(error No source files found for build) 75 | endif 76 | 77 | # Compute tool paths 78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .))))) 79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null) 80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),) 81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang) 82 | endif 83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),) 84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe)) 85 | endif 86 | 87 | # Surround used commands with double quotes 88 | CC := "$(LLVM_ROOT)/clang" 89 | CXX := "$(LLVM_ROOT)/clang" -x c++ 90 | LD := "$(LLVM_ROOT)/wasm-ld" 91 | 92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm 93 | .PHONY: clean cleanall run analyze 94 | 95 | clean: 96 | $(info Removing all build files ...) 97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL)) 98 | 99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files 100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES))))) 101 | -include $(OBJS:%.o=%.d) 102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS)) 103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS)))) 104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS)))) 105 | 106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc 107 | $(info Linking $@ ...) 108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc 109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@ 110 | 111 | $(OUTDIR)/loader.js : loader.js 112 | $(info Copying $^ to $@ ...) 113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 115 | 116 | $(OUTDIR)/loader.html : loader.html 117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)")) 118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL) 119 | 120 | define COMPILE 121 | $(info $2) 122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2 124 | endef 125 | 126 | #------------------------------------------------------------------------------------------------------ 127 | #if System.bc exists, don't even bother checking sources, build once and forget for now 128 | ifeq ($(if $(wildcard System.bc),1,0),0) 129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c 130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd 131 | 132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb 133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp 134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c 135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c 136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c 137 | 138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c)))) 139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES)) 140 | 141 | ifeq ($(findstring !,$(SYS_SOURCES)),!) 142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue) 143 | endif 144 | 145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/)) 146 | ifeq ($(if $(SYS_MISSING),1,0),1) 147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING)) 148 | endif 149 | 150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o))) 151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL))) 152 | 153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include 154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 155 | 156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics 157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__ 158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal 159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int 160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign 161 | 162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES))))) 163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES))))) 164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS)) 165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS)) 166 | 167 | define SYS_COMPILE 168 | $(info $2) 169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)")) 170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2 171 | endef 172 | 173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS) 174 | $(info Creating archive $@ ...) 175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@ 176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp" 177 | endif #need System.bc 178 | #------------------------------------------------------------------------------------------------------ 179 | -------------------------------------------------------------------------------- /WebGL/loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebAssembly Sample: WebGL 7 | 8 | 9 |

WebAssembly Sample: WebGL

10 |

Status: Loading...

11 | 12 |
13 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /WebGL/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | #define GL_GLEXT_PROTOTYPES 29 | #define EGL_EGLEXT_PROTOTYPES 30 | #include 31 | #include 32 | 33 | // Functions defined in loader.js 34 | extern "C" void WAJS_SetupCanvas(int width, int height); 35 | extern "C" unsigned int WAJS_GetTime(); 36 | 37 | static const char* vertex_shader_text = 38 | "precision lowp float;" 39 | "uniform mat4 uMVP;" 40 | "attribute vec4 aPos;" 41 | "attribute vec3 aCol;" 42 | "varying vec3 vCol;" 43 | "void main()" 44 | "{" 45 | "vCol = aCol;" 46 | "gl_Position = uMVP * aPos;" 47 | "}"; 48 | 49 | static const char* fragment_shader_text = 50 | "precision lowp float;" 51 | "varying vec3 vCol;" 52 | "void main()" 53 | "{" 54 | "gl_FragColor = vec4(vCol, 1.0);" 55 | "}"; 56 | 57 | typedef struct Vertex { float x, y, r, g, b; } Vertex; 58 | static GLuint program, vertex_buffer; 59 | static GLint uMVP_location, aPos_location, aCol_location; 60 | 61 | // This function is called at startup 62 | int main(int argc, char *argv[]) 63 | { 64 | WAJS_SetupCanvas(640, 480); 65 | glViewport(0, 0, 640, 480); 66 | 67 | GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); 68 | glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); 69 | glCompileShader(vertex_shader); 70 | 71 | GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 72 | glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); 73 | glCompileShader(fragment_shader); 74 | 75 | program = glCreateProgram(); 76 | glAttachShader(program, vertex_shader); 77 | glAttachShader(program, fragment_shader); 78 | glLinkProgram(program); 79 | 80 | uMVP_location = glGetUniformLocation(program, "uMVP"); 81 | aPos_location = glGetAttribLocation(program, "aPos"); 82 | aCol_location = glGetAttribLocation(program, "aCol"); 83 | 84 | glGenBuffers(1, &vertex_buffer); 85 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 86 | 87 | glEnableVertexAttribArray(aPos_location); 88 | glVertexAttribPointer(aPos_location, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); 89 | glEnableVertexAttribArray(aCol_location); 90 | glVertexAttribPointer(aCol_location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 2)); 91 | 92 | return 0; 93 | } 94 | 95 | // This function is called by loader.js every frame 96 | extern "C" void WAFNDraw() 97 | { 98 | float f = ((WAJS_GetTime() % 1000) / 1000.0f); 99 | 100 | glClear(GL_COLOR_BUFFER_BIT); 101 | 102 | Vertex vertices[3] = 103 | { 104 | { -0.6f, -0.4f, 1.f, 0.f, 0.f }, 105 | { 0.6f, -0.4f, 0.f, 0.f, 1.f }, 106 | { 0.f, 0.6f, 1.f, 1.f, 1.f }, 107 | }; 108 | vertices[0].r = 0.5f + sinf(f * 3.14159f * 2.0f) * 0.5f; 109 | vertices[1].b = 0.5f + cosf(f * 3.14159f * 2.0f) * 0.5f; 110 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 111 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 112 | 113 | GLfloat mvp[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 }; 114 | glUseProgram(program); 115 | glUniformMatrix4fv(uMVP_location, 1, GL_FALSE, mvp); 116 | glDrawArrays(GL_TRIANGLES, 0, 3); 117 | } 118 | -------------------------------------------------------------------------------- /WebGL/output.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/WebGL/output.wasm -------------------------------------------------------------------------------- /showsource.js: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | 9 | In jurisdictions that recognize copyright laws, the author or authors 10 | of this software dedicate any and all copyright interest in the 11 | software to the public domain. We make this dedication for the benefit 12 | of the public at large and to the detriment of our heirs and 13 | successors. We intend this dedication to be an overt act of 14 | relinquishment in perpetuity of all present and future rights to this 15 | software under copyright law. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | For more information, please refer to 26 | */ 27 | 28 | // Helper script to show source code with highlight in the HTML pages 29 | (function(){'use strict'; 30 | var src = document.currentScript.getAttribute('data-source'); 31 | document.write('
' 32 | +'Download source '+src+' (License: Public Domain/Unlicense)' 33 | +'
Loading source code ...
'); 34 | if (!document.loadedPrettify) 35 | { 36 | document.write('' 37 | +''); 38 | document.loadedPrettify = true; 39 | } 40 | window.addEventListener('DOMContentLoaded',function() 41 | { 42 | var xhr = new XMLHttpRequest(); 43 | xhr.open('GET', src, true); 44 | xhr.onload = function() { document.getElementById('src'+src).innerHTML = prettyPrintOne(xhr.response.replace(//g, '>').replace(/[\s\S]*?\*\/\s*/,''), 'c'); }; 45 | xhr.send(); 46 | }); 47 | })(); 48 | --------------------------------------------------------------------------------