summaryrefslogtreecommitdiff
path: root/src/s2wasm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/s2wasm.h')
-rw-r--r--src/s2wasm.h126
1 files changed, 97 insertions, 29 deletions
diff --git a/src/s2wasm.h b/src/s2wasm.h
index c5b502c6d..faa31ae92 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -229,29 +229,68 @@ class S2WasmBuilder {
// gets a constant, which may be a relocation for later.
// returns whether this is a relocation
// TODO: Clean up this and the way relocs are created from parsed objects
- bool getRelocatableConst(uint32_t* target) {
+ LinkerObject::Relocation* getRelocatableConst(uint32_t* target) {
if (isdigit(*s) || *s == '-') {
int32_t val = getInt();
memcpy(target, &val, sizeof(val));
- return false;
- } else {
- // a global constant, we need to fix it up later
- Name name = getStrToSep();
- LinkerObject::Relocation::Kind kind = isFunctionName(name) ?
- LinkerObject::Relocation::kFunction :
- LinkerObject::Relocation::kData;
- int offset = 0;
- if (*s == '+') {
- s++;
- offset = getInt();
- } else if (*s == '-') {
- s++;
- offset = -getInt();
- }
- linkerObj->addRelocation(kind, target,
- fixEmLongjmp(cleanFunction(name)), offset);
- return true;
+ return nullptr;
+ }
+
+ // a global constant, we need to fix it up later
+ Name name = getStrToSep();
+ LinkerObject::Relocation::Kind kind = isFunctionName(name) ?
+ LinkerObject::Relocation::kFunction :
+ LinkerObject::Relocation::kData;
+ int offset = 0;
+ if (*s == '+') {
+ s++;
+ offset = getInt();
+ } else if (*s == '-') {
+ s++;
+ offset = -getInt();
+ }
+ return new LinkerObject::Relocation(
+ kind, target, fixEmLongjmp(cleanFunction(name)), offset);
+ }
+ Expression* relocationToGetGlobal(LinkerObject::Relocation* relocation) {
+ if (!relocation) {
+ return nullptr;
+ }
+
+ auto name = relocation->symbol;
+ auto g = allocator->alloc<GetGlobal>();
+ g->name = name;
+ g->type = i32;
+
+ // Optimization: store any nonnegative addends in their natural place.
+ // Only do this for positive addends because load/store offsets cannot be
+ // negative.
+ if (relocation->addend >= 0) {
+ *relocation->data = relocation->addend;
+ return g;
+ }
+
+ auto c = allocator->alloc<Const>();
+ c->type = i32;
+ c->value = Literal(relocation->addend);
+
+ auto add = allocator->alloc<Binary>();
+ add->type = i32;
+ add->op = AddInt32;
+ add->left = c;
+ add->right = g;
+ return add;
+ }
+ Expression* getRelocatableExpression(uint32_t* target) {
+ auto relocation = std::unique_ptr<LinkerObject::Relocation>(getRelocatableConst(target));
+ if (!relocation) {
+ return nullptr;
+ }
+ if (linkerObj->isObjectImplemented(relocation->symbol)) {
+ linkerObj->addRelocation(relocation.release());
+ return nullptr;
}
+ return relocationToGetGlobal(relocation.get());
}
int64_t getInt64() {
@@ -415,8 +454,12 @@ class S2WasmBuilder {
} else {
abort_on("unknown directive");
}
- // add data aliases
+ } else if (match(".import_global")) {
+ Name name = getStr();
+ info->importedObjects.insert(name);
+ s = strchr(s, '\n');
} else {
+ // add data aliases
Name lhs = getStrToSep();
// When the current line contains only one word, e.g.".text"
if (match("\n"))
@@ -466,7 +509,8 @@ class S2WasmBuilder {
else if (match("data")) {}
else if (match("ident")) skipToEOL();
else if (match("section")) parseToplevelSection();
- else if (match("align") || match("p2align")) skipToEOL();
+ else if (match("align") || match("p2align") || match("import_global"))
+ skipToEOL();
else if (match("globl")) parseGlobl();
else if (match("functype")) parseFuncType();
else skipObjectAlias(true);
@@ -834,6 +878,24 @@ class S2WasmBuilder {
curr->finalize();
setOutput(curr, assign);
};
+ auto useRelocationExpression = [&](Expression *expr, Expression *reloc) {
+ if (!reloc) {
+ return expr;
+ }
+ // Optimization: if the given expr is (i32.const 0), ignore it
+ if (expr->_id == Expression::ConstId &&
+ ((Const*)expr)->value.getInteger() == 0) {
+ return reloc;
+ }
+
+ // Otherwise, need to add relocation expr to given expr
+ auto add = allocator->alloc<Binary>();
+ add->type = i32;
+ add->op = AddInt32;
+ add->left = expr;
+ add->right = reloc;
+ return (Expression*)add;
+ };
auto makeLoad = [&](WasmType type) {
skipComma();
auto curr = allocator->alloc<Load>();
@@ -843,10 +905,10 @@ class S2WasmBuilder {
curr->signed_ = match("_s");
match("_u");
Name assign = getAssign();
- getRelocatableConst(&curr->offset.addr);
+ auto relocation = getRelocatableExpression(&curr->offset.addr);
mustMatch("(");
auto attributes = getAttributes(1);
- curr->ptr = getInput();
+ curr->ptr = useRelocationExpression(getInput(), relocation);
curr->align = curr->bytes;
if (attributes[0]) {
assert(strncmp(attributes[0], "p2align=", 8) == 0);
@@ -864,11 +926,11 @@ class S2WasmBuilder {
curr->bytes = getWasmTypeSize(type);
}
skipWhitespace();
- getRelocatableConst(&curr->offset.addr);
+ auto relocation = getRelocatableExpression(&curr->offset.addr);
mustMatch("(");
auto attributes = getAttributes(2);
auto inputs = getInputs(2);
- curr->ptr = inputs[0];
+ curr->ptr = useRelocationExpression(inputs[0], relocation);
curr->align = curr->bytes;
if (attributes[0]) {
assert(strncmp(attributes[0], "p2align=", 8) == 0);
@@ -946,8 +1008,9 @@ class S2WasmBuilder {
// may be a relocation
auto curr = allocator->alloc<Const>();
curr->type = curr->value.type = i32;
- getRelocatableConst((uint32_t*)curr->value.geti32Ptr());
- setOutput(curr, assign);
+ auto relocation = getRelocatableExpression((uint32_t*)curr->value.geti32Ptr());
+ auto expr = useRelocationExpression(curr, relocation);
+ setOutput(expr, assign);
} else {
cashew::IString str = getStr();
setOutput(parseConst(str, type, *allocator), assign);
@@ -1307,8 +1370,13 @@ class S2WasmBuilder {
} else if (match(".int32")) {
Address size = raw.size();
raw.resize(size + 4);
- if (getRelocatableConst((uint32_t*)&raw[size])) { // just the size, as we may reallocate; we must fix this later, if it's a relocation
- currRelocations.emplace_back(linkerObj->getCurrentRelocation(), size);
+ auto relocation = getRelocatableConst((uint32_t*)&raw[size]); // just the size, as we may reallocate; we must fix this later, if it's a relocation
+ if (relocation) {
+ if (!linkerObj->isObjectImplemented(relocation->symbol)) {
+ abort_on("s2wasm is currently unable to model imported globals in data segment initializers");
+ }
+ linkerObj->addRelocation(relocation);
+ currRelocations.emplace_back(relocation, size);
}
zero = false;
} else if (match(".int64")) {