From 02729a12e1735f629d3066b51c96a056f712b080 Mon Sep 17 00:00:00 2001 From: Jacob Gravelle Date: Mon, 22 Jan 2018 12:50:36 -0800 Subject: First pass at LLD support for Emscripten (#1346) * Skeleton of a beginning of o2wasm, WIP and probably not going to be used * Get building post-cherry-pick * ast->ir, remove commented out code, include a debug module print because linking * Read linking section, print emscripten metadata json * WasmBinaryWriter emits user sections on Module * Remove debugging prints, everything that isn't needed to build metadata * Rename o2wasm to lld-metadata * lld-metadata support for outputting to file * Use tables index instead of function index for initializer functions * Add lld-emscripten tool to add emscripten-runtime functions to wasm modules (built with lld) * Handle EM_ASM in lld-emscripten * Add a list of functions to forcibly export (for initializer functions) * Disable incorrect initializer function reading * Add error printing when parsing .o files in lld-metadata * Remove ';; METADATA: ' prefix from lld-metadata, output is now standalone json * Support em_asm consts that aren't at the start of a segment * Initial test framework for lld-metadata tool * Add em_asm test * Add support for WASM_INIT_FUNCS in the linking section * Remove reloc section parsing because it's unused * lld-emscripten can read and write text * Add test harness for lld-emscripten * Export all functions for now * Add missing lld test output * Add support for reading object files differently Only difference so far is in importing mutable globals being an object file representation for symbols, but invalid wasm. * Update help strings * Update linking tests for stackAlloc fix * Rename lld-emscripten,lld-metadata to wasm-emscripten-finalize,wasm-link-metadata * Add help text to header comments * auto& instead of auto & * Extract LinkType to abi/wasm-object.h * Remove special handling for wasm object file reading, allow mutable globals * Add braces around default switch case * Fix flake8 errors * Handle generating dyncall thunks for imports as well * Use explicit bool for stackPointerGlobal * Use glob patterns for lld file iteration * Use __wasm_call_ctors for all initializer functions --- src/tools/s2wasm.cpp | 2 +- src/tools/wasm-emscripten-finalize.cpp | 103 ++++++++++++++++++++++++++++ src/tools/wasm-link-metadata.cpp | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/tools/wasm-emscripten-finalize.cpp create mode 100644 src/tools/wasm-link-metadata.cpp (limited to 'src/tools') diff --git a/src/tools/s2wasm.cpp b/src/tools/s2wasm.cpp index 6e7b2c05e..32af57dba 100644 --- a/src/tools/s2wasm.cpp +++ b/src/tools/s2wasm.cpp @@ -184,7 +184,7 @@ int main(int argc, const char *argv[]) { std::cerr << "Emscripten gluing..." << std::endl; WasmPrinter::printModule(&wasm, std::cerr); } - metadata = emscriptenGlue( + metadata = ";; METADATA: " + emscriptenGlue( wasm, allowMemoryGrowth, linker.getStackPointerAddress(), diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp new file mode 100644 index 000000000..87505748c --- /dev/null +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm-emscripten-finalize console tool +// Performs Emscripten-specific transforms on .wasm files +// + +#include + +#include "ir/trapping.h" +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-emscripten.h" +#include "wasm-io.h" +#include "wasm-linker.h" +#include "wasm-printing.h" +#include "wasm-validator.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + std::string infile; + std::string outfile; + bool emitBinary = true; + std::vector forcedExports; + Options options("wasm-emscripten-finalize", + "Performs Emscripten-specific transforms on .wasm files"); + options + .add("--output", "-o", "Output file", + Options::Arguments::One, + [&outfile](Options*, const std::string &argument) { + outfile = argument; + Colors::disable(); + }) + .add("--emit-text", "-S", "Emit text instead of binary for the output file", + Options::Arguments::Zero, + [&emitBinary](Options*, const std::string &) { + emitBinary = false; + }) + .add_positional("INFILE", Options::Arguments::One, + [&infile](Options *o, const std::string &argument) { + infile = argument; + }); + options.parse(argc, argv); + + if (infile == "") { + Fatal() << "Need to specify an infile\n"; + } + if (outfile == "" && emitBinary) { + Fatal() << "Need to specify an outfile, or use text output\n"; + } + + Module wasm; + ModuleReader reader; + reader.read(infile, wasm); + + if (options.debug) { + std::cerr << "Module before:\n"; + WasmPrinter::printModule(&wasm, std::cerr); + } + + EmscriptenGlueGenerator generator(wasm); + generator.generateRuntimeFunctions(); + generator.generateMemoryGrowthFunction(); + generator.generateDynCallThunks(); + generator.fixEmAsmConsts(); + + if (options.debug) { + std::cerr << "Module after:\n"; + WasmPrinter::printModule(&wasm, std::cerr); + } + + ModuleWriter writer; + // writer.setDebug(options.debug); + writer.setDebugInfo(true); + // writer.setDebugInfo(options.passOptions.debugInfo); + // writer.setSymbolMap(symbolMap); + writer.setBinary(emitBinary); + // if (emitBinary) { + // writer.setSourceMapFilename(sourceMapFilename); + // writer.setSourceMapUrl(sourceMapUrl); + // } + writer.write(wasm, outfile); + + return 0; +} diff --git a/src/tools/wasm-link-metadata.cpp b/src/tools/wasm-link-metadata.cpp new file mode 100644 index 000000000..1ca64880f --- /dev/null +++ b/src/tools/wasm-link-metadata.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm-link-metadata console tool +// Reads wasm .o file and emits .json metadata +// + +#include + +#include "abi/wasm-object.h" +#include "ir/trapping.h" +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-emscripten.h" +#include "wasm-io.h" +#include "wasm-linker.h" +#include "wasm-printing.h" +#include "wasm-validator.h" + +using namespace cashew; +using namespace wasm; + +void parseLinkingSection(std::vector const& data, uint32_t &dataSize) { + unsigned idx = 0; + auto get = [&idx, &data](){ return data[idx++]; }; + auto readNext = [get](){ + U32LEB leb; + leb.read(get); + return leb.value; + }; + + while (idx < data.size()) { + ABI::LinkType type = static_cast(readNext()); + uint32_t size = readNext(); + uint32_t startIdx = idx; + + switch(type) { + case ABI::WASM_DATA_SIZE: { + dataSize = readNext(); + break; + } + default: { + break; + } + } + // Always go to the end of the subsection based on size, not contents. + idx = startIdx + size; + } +} + +int main(int argc, const char *argv[]) { + std::string infile; + std::string outfile; + Options options("wasm-link-metadata", + "Reads wasm .o file and emits .json metadata"); + options + .add("--output", "-o", "Output file", + Options::Arguments::One, + [&outfile](Options *o, const std::string &argument) { + outfile = argument; + Colors::disable(); + }) + .add_positional("INFILE", Options::Arguments::One, + [&infile](Options *o, const std::string &argument) { + infile = argument; + }); + options.parse(argc, argv); + + if (infile == "") { + Fatal() << "Need to specify an infile\n"; + } + + Module wasm; + try { + ModuleReader reader; + reader.readBinary(infile, wasm); + } catch (ParseException& p) { + p.dump(std::cerr); + Fatal() << "error in parsing wasm binary"; + } + + if (options.debug) { + WasmPrinter::printModule(&wasm, std::cerr); + } + + uint32_t dataSize = 0; + for (auto §ion : wasm.userSections) { + if (section.name == "linking") { + parseLinkingSection(section.data, dataSize); + } + } + + std::vector initializerFunctions; + initializerFunctions.push_back("__wasm_call_ctors"); + + EmscriptenGlueGenerator generator(wasm); + std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions); + Output output(outfile, Flags::Text, Flags::Release); + output << metadata; + + return 0; +} -- cgit v1.2.3