summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--test/dot_s/alias.s27
-rw-r--r--test/dot_s/alias.wast18
7 files changed, 158 insertions, 41 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 {
diff --git a/test/dot_s/alias.s b/test/dot_s/alias.s
index 85a89a16f..449e33f0e 100644
--- a/test/dot_s/alias.s
+++ b/test/dot_s/alias.s
@@ -5,9 +5,13 @@
.globl __exit
.type __exit,@function
__exit: # @__exit
- .local i32
+ i32.const $push0=, _A
+ i32.load $push1=, 0($pop0)
+ i32.const $push2=, ._B
+ i32.load $push3=, 0($pop2)
+ i32.add $push4=, $pop1, $pop3
# BB#0: # %entry
- return
+ return $pop4
.endfunc
.Lfunc_end0:
.size __exit, .Lfunc_end0-__exit
@@ -16,10 +20,10 @@ __exit: # @__exit
.globl __needs_exit
.type __needs_exit,@function
__needs_exit: # @__needs_exit
- .result i32
+ .result i32
# BB#0: # %entry
- call __exit_needed@FUNCTION
- i32.const $push0=, __exit_needed@FUNCTION
+ call __exit_needed@FUNCTION
+ i32.const $push0=, __exit_needed@FUNCTION
return $pop0
.endfunc
.Lfunc_end1:
@@ -29,3 +33,16 @@ __needs_exit: # @__needs_exit
.type __exit_needed,@function
.hidden __exit_needed
__exit_needed = __exit@FUNCTION
+
+ .type .L__unnamed_1,@object
+ .p2align 4
+.L__unnamed_1:
+ .int32 1234
+ .skip 4
+ .int32 2345
+ .size .L__unnamed_1, 12
+
+_A = .L__unnamed_1
+ .size _A, 12
+._B = _A+8
+ .size ._B, 4
diff --git a/test/dot_s/alias.wast b/test/dot_s/alias.wast
index d1e08e136..6221a2232 100644
--- a/test/dot_s/alias.wast
+++ b/test/dot_s/alias.wast
@@ -1,5 +1,7 @@
(module
- (memory 1)
+ (memory 1
+ (segment 16 "\d2\04\00\00\00\00\00\00)\t\00\00")
+ )
(export "memory" memory)
(type $FUNCSIG$v (func))
(export "__exit" $__exit)
@@ -7,8 +9,16 @@
(export "dynCall_v" $dynCall_v)
(table $__exit)
(func $__exit (type $FUNCSIG$v)
- (local $0 i32)
- (return)
+ (return
+ (i32.add
+ (i32.load
+ (i32.const 16)
+ )
+ (i32.load
+ (i32.const 24)
+ )
+ )
+ )
)
(func $__needs_exit (result i32)
(call $__exit)
@@ -22,4 +32,4 @@
)
)
)
-;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [] }
+;; METADATA: { "asmConsts": {},"staticBump": 28, "initializers": [] }