diff options
author | Dominic Chen <d.c.ddcc@gmail.com> | 2016-07-11 14:29:59 -0700 |
---|---|---|
committer | Derek Schuff <dschuff@chromium.org> | 2016-07-11 14:29:59 -0700 |
commit | 8e936ce0635b66a3b2754292bab7c6c262b0bb1f (patch) | |
tree | 888a2a6bbd4b8555f9041adf1d7285444016267e /src | |
parent | 8c2ef78baf1bd93afe48a9112eda56aea6cb884d (diff) | |
download | binaryen-8e936ce0635b66a3b2754292bab7c6c262b0bb1f.tar.gz binaryen-8e936ce0635b66a3b2754292bab7c6c262b0bb1f.tar.bz2 binaryen-8e936ce0635b66a3b2754292bab7c6c262b0bb1f.zip |
add support for symbol assignments, closes #4422 (#615)
Adds support for aliases to objects, to go along with the existing support for aliases to functions.
Diffstat (limited to 'src')
-rw-r--r-- | src/s2wasm.h | 103 | ||||
-rw-r--r-- | src/support/file.cpp | 2 | ||||
-rw-r--r-- | src/wasm-linker.cpp | 17 | ||||
-rw-r--r-- | src/wasm-linker.h | 29 | ||||
-rw-r--r-- | src/wasm.h | 3 |
5 files changed, 122 insertions, 32 deletions
diff --git a/src/s2wasm.h b/src/s2wasm.h index bf66f4407..8f429f96c 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -101,6 +101,14 @@ class S2WasmBuilder { return true; } + bool skipEqual() { + skipWhitespace(); + if (*s != '=') return false; + s++; + skipWhitespace(); + return true; + } + #define abort_on(why) { \ dump(why ":"); \ abort(); \ @@ -370,22 +378,60 @@ class S2WasmBuilder { s = inputStart; while (*s) { skipWhitespace(); - s = strstr(s, ".type"); - if (!s) break; - mustMatch(".type"); - Name name = getCommaSeparated(); - skipComma(); - if (!match("@function")) continue; - if (match(".hidden")) mustMatch(name.str); - mustMatch(name.str); - if (match(":")) { - info->implementedFunctions.insert(name); - } else if (match("=")) { - Name alias = getAtSeparated(); - mustMatch("@FUNCTION"); - info->aliasedFunctions.insert({name, alias}); + + // add function definitions and aliases + if (match(".type")) { + Name name = getCommaSeparated(); + skipComma(); + if (!match("@function")) continue; + if (match(".hidden")) mustMatch(name.str); + mustMatch(name.str); + if (match(":")) { + info->implementedFunctions.insert(name); + } else if (match("=")) { + Name alias = getAtSeparated(); + mustMatch("@FUNCTION"); + info->aliasedSymbols.insert({name, LinkerObject::SymbolAlias(alias, LinkerObject::Relocation::kFunction, 0)}); + } else { + abort_on("unknown directive"); + } + // add data aliases } else { - abort_on("unknown directive"); + Name lhs = getStrToSep(); + if (!skipEqual()){ + s = strchr(s, '\n'); + if (!s) break; + continue; + } + + // get the original name + Name rhs = getStrToSep(); + assert(!isFunctionName(rhs)); + Offset offset = 0; + if (*s == '+') { + s++; + offset = getInt(); + } + skipWhitespace(); + + // get the data size + mustMatch(".size"); + mustMatch(lhs.str); + mustMatch(","); + wasm::Address size = atoi(getStr().str); + WASM_UNUSED(size); + skipWhitespace(); + + // check if the rhs is already an alias + const auto alias = symbolInfo->aliasedSymbols.find(rhs); + if (alias != symbolInfo->aliasedSymbols.end() && alias->second.kind == LinkerObject::Relocation::kData) { + offset += alias->second.offset; + rhs = alias->second.symbol; + } + + // add the new alias + symbolInfo->aliasedSymbols.insert({lhs, LinkerObject::SymbolAlias(rhs, + LinkerObject::Relocation::kData, offset)}); } } } @@ -395,7 +441,7 @@ class S2WasmBuilder { skipWhitespace(); if (debug) dump("process"); if (!*s) break; - if (*s != '.') break; + if (*s != '.') skipObjectAlias(false); s++; if (match("text")) parseText(); else if (match("type")) parseType(); @@ -407,10 +453,31 @@ class S2WasmBuilder { else if (match("align") || match("p2align")) skipToEOL(); else if (match("globl")) parseGlobl(); else if (match("functype")) parseFuncType(); - else abort_on("process"); + else skipObjectAlias(true); } } + void skipObjectAlias(bool prefix) { + if (debug) dump("object_alias"); + + // grab the dot that was consumed earlier + if (prefix) s--; + Name lhs = getStrToSep(); + WASM_UNUSED(lhs); + if (!skipEqual()) abort_on("object_alias"); + + Name rhs = getStr(); + WASM_UNUSED(rhs); + skipWhitespace(); + + mustMatch(".size"); + mustMatch(lhs.str); + mustMatch(","); + Name size = getStr(); + WASM_UNUSED(size); + skipWhitespace(); + } + void parseToplevelSection() { auto section = getCommaSeparated(); // Skipping .debug_ sections @@ -804,7 +871,7 @@ class S2WasmBuilder { } else { // non-indirect call Name assign = getAssign(); - Name target = linkerObj->resolveAlias(cleanFunction(getCommaSeparated())); + Name target = linkerObj->resolveAlias(cleanFunction(getCommaSeparated()), LinkerObject::Relocation::kFunction); Call* curr = allocator->alloc<Call>(); curr->target = target; diff --git a/src/support/file.cpp b/src/support/file.cpp index 296fd6dbe..666c07b87 100644 --- a/src/support/file.cpp +++ b/src/support/file.cpp @@ -52,7 +52,7 @@ wasm::Output::Output(const std::string &filename, Flags::BinaryOption binary, Fl : outfile(), out([this, filename, binary, debug]() { std::streambuf *buffer; if (filename.size()) { - if (debug == Flags::Debug) std::cerr << "Opening '" << filename << std::endl; + if (debug == Flags::Debug) std::cerr << "Opening '" << filename << "'" << std::endl; auto flags = std::ofstream::out | std::ofstream::trunc; if (binary == Flags::Binary) flags |= std::ofstream::binary; outfile.open(filename, flags); diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp index 34dbc7f9c..a2e88cfb3 100644 --- a/src/wasm-linker.cpp +++ b/src/wasm-linker.cpp @@ -123,9 +123,16 @@ void Linker::layout() { } }; for (auto& relocation : out.relocations) { + auto *alias = out.getAlias(relocation->symbol, relocation->kind); Name name = relocation->symbol; + if (debug) std::cerr << "fix relocation " << name << '\n'; + if (alias) { + name = alias->symbol; + relocation->addend += alias->offset; + } + if (relocation->kind == LinkerObject::Relocation::kData) { const auto& symbolAddress = staticAddresses.find(name); if (symbolAddress == staticAddresses.end()) Fatal() << "Unknown relocation: " << name << '\n'; @@ -133,7 +140,6 @@ void Linker::layout() { if (debug) std::cerr << " ==> " << *(relocation->data) << '\n'; } else { // function address - name = out.resolveAlias(name); if (!out.wasm.checkFunction(name)) { if (FunctionType* f = out.getExternType(name)) { // Address of an imported function is taken, but imports do not have addresses in wasm. @@ -208,11 +214,12 @@ bool Linker::linkObject(S2WasmBuilder& builder) { // Allow duplicate aliases only if they refer to the same name. For now we // do not expect aliases in compiler-rt files. // TODO: figure out what the semantics of merging aliases should be. - for (const auto& alias : newSymbols->aliasedFunctions) { - if (out.symbolInfo.aliasedFunctions.count(alias.first) && - out.symbolInfo.aliasedFunctions[alias.first] != alias.second) { + for (const auto& alias : newSymbols->aliasedSymbols) { + if (out.symbolInfo.aliasedSymbols.count(alias.first) && + (out.symbolInfo.aliasedSymbols.at(alias.first).symbol != alias.second.symbol || + out.symbolInfo.aliasedSymbols.at(alias.first).kind != alias.second.kind)) { std::cerr << "Error: conflicting definitions for alias " - << alias.first.c_str() << "\n"; + << alias.first.c_str() << "of type " << alias.second.kind << "\n"; return false; } } diff --git a/src/wasm-linker.h b/src/wasm-linker.h index 97e1c9cd5..535b5dc55 100644 --- a/src/wasm-linker.h +++ b/src/wasm-linker.h @@ -47,12 +47,19 @@ class LinkerObject { Relocation(Kind kind, uint32_t* data, Name symbol, int addend) : kind(kind), data(data), symbol(symbol), addend(addend) {} }; + struct SymbolAlias { + Name symbol; + Relocation::Kind kind; + Offset offset; + SymbolAlias(Name symbol, Relocation::Kind kind, Offset offset) : + symbol(symbol), kind(kind), offset(offset) {} + }; // Information about symbols struct SymbolInfo { std::unordered_set<cashew::IString> implementedFunctions; std::unordered_set<cashew::IString> undefinedFunctions; // TODO: it's not clear that this really belongs here. - std::unordered_map<cashew::IString, Name> aliasedFunctions; + std::unordered_map<cashew::IString, SymbolAlias> aliasedSymbols; // For now, do not support weak symbols or anything special. Just directly // merge the functions together, and remove any newly-defined functions @@ -63,8 +70,8 @@ class LinkerObject { } implementedFunctions.insert(other.implementedFunctions.begin(), other.implementedFunctions.end()); - aliasedFunctions.insert(other.aliasedFunctions.begin(), - other.aliasedFunctions.end()); + aliasedSymbols.insert(other.aliasedSymbols.begin(), + other.aliasedSymbols.end()); } }; @@ -82,22 +89,28 @@ class LinkerObject { void addRelocation(Relocation::Kind kind, uint32_t* target, Name name, int addend) { relocations.emplace_back(new Relocation(kind, target, name, addend)); } + Relocation* getCurrentRelocation() { return relocations.back().get(); } - bool isFunctionImplemented(Name name) { return symbolInfo.implementedFunctions.count(name) != 0; } - // If name is an alias, return what it points to. Otherwise return name - Name resolveAlias(Name name) { - auto aliased = symbolInfo.aliasedFunctions.find(name); - if (aliased != symbolInfo.aliasedFunctions.end()) return aliased->second; + // If name is an alias, return what it points to. Otherwise return name. + Name resolveAlias(Name name, Relocation::Kind kind) { + auto aliased = symbolInfo.aliasedSymbols.find(name); + if (aliased != symbolInfo.aliasedSymbols.end() && aliased->second.kind == kind) return aliased->second.symbol; return name; } + SymbolAlias *getAlias(Name name, Relocation::Kind kind) { + auto aliased = symbolInfo.aliasedSymbols.find(name); + if (aliased != symbolInfo.aliasedSymbols.end() && aliased->second.kind == kind) return &aliased->second; + return nullptr; + } + // Add an initializer segment for the named static variable. void addSegment(Name name, const char* data, Address size) { segments[name] = wasm.memory.segments.size(); diff --git a/src/wasm.h b/src/wasm.h index a71e09d19..40728de50 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -108,6 +108,9 @@ struct Address { Address& operator++() { ++addr; return *this; } }; +// An offset into memory +typedef int32_t Offset; + // Types enum WasmType { |