summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/s2wasm.h103
-rw-r--r--src/support/file.cpp2
-rw-r--r--src/wasm-linker.cpp17
-rw-r--r--src/wasm-linker.h29
-rw-r--r--src/wasm.h3
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 {