summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/table-utils.h15
-rw-r--r--src/passes/Print.cpp17
-rw-r--r--src/wasm-binary.h3
-rw-r--r--src/wasm.h10
-rw-r--r--src/wasm/wasm-binary.cpp56
-rw-r--r--test/dylib.wasmbin306 -> 433 bytes
-rw-r--r--test/dylib.wasm.fromBinary101
-rw-r--r--test/passes/multi_line_table.bin.txt6
8 files changed, 160 insertions, 48 deletions
diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h
index 3c49ab16a..e0453dece 100644
--- a/src/ir/table-utils.h
+++ b/src/ir/table-utils.h
@@ -67,10 +67,23 @@ inline Table::Segment& ensureTableWithOneSegment(Table& table, Module& wasm) {
// Appends a name to the table. This assumes the table has 0 or 1 segments,
// as with 2 or more it's ambiguous what we should do (use a hole in the middle
// or not).
+// This works on code from wasm-ld, but on arbitrary code it may not be valid
+// in the presence of a dynamic linking section. Specifically, we assume the
+// module has a single table segment, and that the dylink section indicates
+// we can validly append to that segment, see the check below.
inline Index append(Table& table, Name name, Module& wasm) {
auto& segment = ensureTableWithOneSegment(table, wasm);
- table.segments[0];
auto tableIndex = segment.data.size();
+ if (wasm.dylinkSection) {
+ if (segment.data.size() != wasm.dylinkSection->tableSize) {
+ Fatal() << "Appending to the table in a module with a dylink section "
+ "that has tableSize which indicates it wants to reserve more "
+ "table space than the actual table elements in the module. "
+ "We don't know how to correctly update the dylink section in "
+ "that case.";
+ }
+ wasm.dylinkSection->tableSize++;
+ }
segment.data.push_back(name);
table.initial = table.initial + 1;
return tableIndex;
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index daa7e7ac6..d6dbb3300 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2340,6 +2340,20 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
o << "\")" << maybeNewLine;
}
}
+ void printDylinkSection(const std::unique_ptr<DylinkSection>& dylinkSection) {
+ doIndent(o, indent) << ";; dylink section\n";
+ doIndent(o, indent) << ";; memorysize: " << dylinkSection->memorySize
+ << '\n';
+ doIndent(o, indent) << ";; memoryalignment: "
+ << dylinkSection->memoryAlignment << '\n';
+ doIndent(o, indent) << ";; tablesize: " << dylinkSection->tableSize
+ << '\n';
+ doIndent(o, indent) << ";; tablealignment: "
+ << dylinkSection->tableAlignment << '\n';
+ for (auto& neededDynlib : dylinkSection->neededDynlibs) {
+ doIndent(o, indent) << ";; needed dynlib: " << neededDynlib << '\n';
+ }
+ }
void visitModule(Module* curr) {
currModule = curr;
o << '(';
@@ -2388,6 +2402,9 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
}
ModuleUtils::iterDefinedFunctions(
*curr, [&](Function* func) { visitFunction(func); });
+ if (curr->dylinkSection) {
+ printDylinkSection(curr->dylinkSection);
+ }
for (auto& section : curr->userSections) {
doIndent(o, indent);
o << ";; custom section \"" << section.name << "\", size "
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index a90d5fb5f..1a13dbb75 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1011,10 +1011,10 @@ public:
void writeNames();
void writeSourceMapUrl();
void writeSymbolMap();
- void writeEarlyUserSections();
void writeLateUserSections();
void writeUserSection(const UserSection& section);
void writeFeaturesSection();
+ void writeDylinkSection();
void initializeDebugInfo();
void writeSourceMapProlog();
@@ -1257,6 +1257,7 @@ public:
static Name escape(Name name);
void readNames(size_t);
void readFeatures(size_t);
+ void readDylink(size_t);
// Debug information reading helpers
void setDebugLocations(std::istream* sourceMap_) { sourceMap = sourceMap_; }
diff --git a/src/wasm.h b/src/wasm.h
index 21fef1049..73f22e7d7 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1460,6 +1460,13 @@ public:
std::vector<char> data;
};
+// The optional "dylink" section is used in dynamic linking.
+class DylinkSection {
+public:
+ Index memorySize, memoryAlignment, tableSize, tableAlignment;
+ std::vector<Name> neededDynlibs;
+};
+
class Module {
public:
// wasm contents (generally you shouldn't access these from outside, except
@@ -1475,6 +1482,9 @@ public:
std::vector<UserSection> userSections;
+ // Optional user section IR representation.
+ std::unique_ptr<DylinkSection> dylinkSection;
+
// Source maps debug info.
std::vector<std::string> debugInfoFileNames;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 8d9696aa2..c36789828 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -38,7 +38,7 @@ void WasmBinaryWriter::prepare() {
void WasmBinaryWriter::write() {
writeHeader();
- writeEarlyUserSections();
+ writeDylinkSection();
initializeDebugInfo();
if (sourceMap) {
@@ -632,16 +632,6 @@ void WasmBinaryWriter::writeSourceMapEpilog() {
*sourceMap << "\"}";
}
-void WasmBinaryWriter::writeEarlyUserSections() {
- // The dylink section must be the first in the module, per
- // the spec, to allow simple parsing by loaders.
- for (auto& section : wasm->userSections) {
- if (section.name == BinaryConsts::UserSections::Dylink) {
- writeUserSection(section);
- }
- }
-}
-
void WasmBinaryWriter::writeLateUserSections() {
for (auto& section : wasm->userSections) {
if (section.name != BinaryConsts::UserSections::Dylink) {
@@ -707,6 +697,24 @@ void WasmBinaryWriter::writeFeaturesSection() {
finishSection(start);
}
+void WasmBinaryWriter::writeDylinkSection() {
+ if (!wasm->dylinkSection) {
+ return;
+ }
+
+ auto start = startSection(BinaryConsts::User);
+ writeInlineString(BinaryConsts::UserSections::Dylink);
+ o << U32LEB(wasm->dylinkSection->memorySize);
+ o << U32LEB(wasm->dylinkSection->memoryAlignment);
+ o << U32LEB(wasm->dylinkSection->tableSize);
+ o << U32LEB(wasm->dylinkSection->tableAlignment);
+ o << U32LEB(wasm->dylinkSection->neededDynlibs.size());
+ for (auto& neededDynlib : wasm->dylinkSection->neededDynlibs) {
+ writeInlineString(neededDynlib.c_str());
+ }
+ finishSection(start);
+}
+
void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) {
if (loc == lastDebugLocation) {
return;
@@ -963,6 +971,8 @@ void WasmBinaryBuilder::readUserSection(size_t payloadLen) {
readNames(payloadLen);
} else if (sectionName.equals(BinaryConsts::UserSections::TargetFeatures)) {
readFeatures(payloadLen);
+ } else if (sectionName.equals(BinaryConsts::UserSections::Dylink)) {
+ readDylink(payloadLen);
} else {
// an unfamiliar custom section
if (sectionName.equals(BinaryConsts::UserSections::Linking)) {
@@ -2122,8 +2132,8 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
wasm.features = FeatureSet::MVP;
auto sectionPos = pos;
- size_t num_feats = getU32LEB();
- for (size_t i = 0; i < num_feats; ++i) {
+ size_t numFeatures = getU32LEB();
+ for (size_t i = 0; i < numFeatures; ++i) {
uint8_t prefix = getInt8();
if (prefix != BinaryConsts::FeatureUsed) {
if (prefix == BinaryConsts::FeatureRequired) {
@@ -2171,6 +2181,26 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
}
}
+void WasmBinaryBuilder::readDylink(size_t payloadLen) {
+ wasm.dylinkSection = make_unique<DylinkSection>();
+
+ auto sectionPos = pos;
+
+ wasm.dylinkSection->memorySize = getU32LEB();
+ wasm.dylinkSection->memoryAlignment = getU32LEB();
+ wasm.dylinkSection->tableSize = getU32LEB();
+ wasm.dylinkSection->tableAlignment = getU32LEB();
+
+ size_t numNeededDynlibs = getU32LEB();
+ for (size_t i = 0; i < numNeededDynlibs; ++i) {
+ wasm.dylinkSection->neededDynlibs.push_back(getInlineString());
+ }
+
+ if (pos != sectionPos + payloadLen) {
+ throwError("bad features section size");
+ }
+}
+
BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (pos == endOfFunction) {
throwError("Reached function end without seeing End opcode");
diff --git a/test/dylib.wasm b/test/dylib.wasm
index 06ac55e86..ba62a3bef 100644
--- a/test/dylib.wasm
+++ b/test/dylib.wasm
Binary files differ
diff --git a/test/dylib.wasm.fromBinary b/test/dylib.wasm.fromBinary
index 45d64fb67..23db9fe85 100644
--- a/test/dylib.wasm.fromBinary
+++ b/test/dylib.wasm.fromBinary
@@ -1,50 +1,87 @@
(module
- (type $none_=>_none (func))
(type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
(type $i32_=>_i32 (func (param i32) (result i32)))
- (import "env" "memory" (memory $2 256))
- (data (global.get $gimport$0) "hello, world!")
- (import "env" "table" (table $timport$3 0 funcref))
- (import "env" "memoryBase" (global $gimport$0 i32))
- (import "env" "tableBase" (global $gimport$4 i32))
- (import "env" "_puts" (func $fimport$1 (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (import "env" "memory" (memory $5 0))
+ (data (global.get $gimport$4) "*\00\00\00")
+ (import "env" "__memory_base" (global $gimport$4 i32))
+ (import "env" "g$waka_mine" (func $fimport$0 (result i32)))
+ (import "env" "g$waka_others" (func $fimport$1 (result i32)))
+ (import "env" "fp$_Z16waka_func_theirsi$ii" (func $fimport$2 (result i32)))
+ (import "env" "fp$_Z14waka_func_minei$ii" (func $fimport$3 (result i32)))
(global $global$0 (mut i32) (i32.const 0))
(global $global$1 (mut i32) (i32.const 0))
- (global $global$2 i32 (i32.const 0))
- (export "__post_instantiate" (func $2))
- (export "_main" (func $0))
- (export "runPostSets" (func $1))
- (export "_str" (global $global$2))
- (func $0 (; 1 ;) (result i32)
- (block $label$1 (result i32)
- (drop
- (call $fimport$1
- (global.get $gimport$0)
- )
- )
- (i32.const 0)
- )
- )
- (func $1 (; 2 ;)
+ (global $global$2 (mut i32) (i32.const 0))
+ (global $global$3 (mut i32) (i32.const 0))
+ (global $global$4 i32 (i32.const 0))
+ (global $global$5 i32 (i32.const 0))
+ (export "__wasm_apply_relocs" (func $0))
+ (export "_Z14waka_func_minei" (func $1))
+ (export "__original_main" (func $2))
+ (export "waka_mine" (global $global$4))
+ (export "main" (func $3))
+ (export "__dso_handle" (global $global$5))
+ (export "__post_instantiate" (func $4))
+ (func $0 (; 4 ;)
(nop)
)
- (func $2 (; 3 ;)
- (block $label$1
- (global.set $global$0
+ (func $1 (; 5 ;) (param $0 i32) (result i32)
+ (i32.add
+ (local.get $0)
+ (i32.const 1)
+ )
+ )
+ (func $2 (; 6 ;) (result i32)
+ (i32.add
+ (i32.load
+ (global.get $global$3)
+ )
+ (i32.add
+ (i32.load
+ (global.get $global$2)
+ )
(i32.add
- (global.get $gimport$0)
- (i32.const 16)
+ (global.get $global$0)
+ (global.get $global$1)
)
)
- (global.set $global$1
+ )
+ )
+ (func $3 (; 7 ;) (param $0 i32) (param $1 i32) (result i32)
+ (i32.add
+ (i32.load
+ (global.get $global$3)
+ )
+ (i32.add
+ (i32.load
+ (global.get $global$2)
+ )
(i32.add
(global.get $global$0)
- (i32.const 5242880)
+ (global.get $global$1)
)
)
- (call $1)
)
)
- ;; custom section "dylink", size 5
+ (func $4 (; 8 ;)
+ (global.set $global$2
+ (call $fimport$0)
+ )
+ (global.set $global$3
+ (call $fimport$1)
+ )
+ (global.set $global$0
+ (call $fimport$2)
+ )
+ (global.set $global$1
+ (call $fimport$3)
+ )
+ )
+ ;; dylink section
+ ;; memorysize: 4
+ ;; memoryalignment: 2
+ ;; tablesize: 0
+ ;; tablealignment: 0
)
diff --git a/test/passes/multi_line_table.bin.txt b/test/passes/multi_line_table.bin.txt
index 3212e1c14..c4fd4d013 100644
--- a/test/passes/multi_line_table.bin.txt
+++ b/test/passes/multi_line_table.bin.txt
@@ -466,7 +466,11 @@ file_names[ 1]:
(local.get $0)
)
)
- ;; custom section "dylink", size 5
+ ;; dylink section
+ ;; memorysize: 0
+ ;; memoryalignment: 0
+ ;; tablesize: 0
+ ;; tablealignment: 0
;; custom section ".debug_info", size 130
;; custom section ".debug_abbrev", size 100
;; custom section ".debug_line", size 145