summaryrefslogtreecommitdiff
path: root/src/s2wasm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/s2wasm.h')
-rw-r--r--src/s2wasm.h103
1 files changed, 85 insertions, 18 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;