Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/wapython
Path: blob/main/core/dylink/src/metadata.ts
1067 views
1
/*
2
This is inspired by emscripten's MIT-licensed src/library_dylink.js.
3
*/
4
5
interface Metadata {
6
neededDynlibs: string[];
7
tlsExports: Set<string>;
8
weakImports: Set<string>;
9
memorySize?: number;
10
memoryAlign?: number;
11
tableSize?: number;
12
tableAlign?: number;
13
}
14
15
export default function getMetadata(binary: Uint8Array): Metadata {
16
let offset = 0;
17
let end = 0;
18
19
function getU8() {
20
return binary[offset++];
21
}
22
23
function getLEB() {
24
let ret = 0;
25
let mul = 1;
26
while (1) {
27
const byte = binary[offset++];
28
ret += (byte & 0x7f) * mul;
29
mul *= 0x80;
30
if (!(byte & 0x80)) break;
31
}
32
return ret;
33
}
34
35
function getString() {
36
const len = getLEB();
37
offset += len;
38
return UTF8ArrayToString(binary, offset - len, len);
39
}
40
41
function failIf(condition: boolean, message: string): void {
42
if (condition) throw new Error(message);
43
}
44
45
let name = "dylink.0";
46
const int32View = new Uint32Array(
47
new Uint8Array(binary.subarray(0, 24)).buffer
48
);
49
const magicNumberFound = int32View[0] == 0x6d736100;
50
failIf(!magicNumberFound, "need to see wasm magic number"); // \0asm
51
// we should see the dylink custom section right after the magic number and wasm version
52
failIf(binary[8] !== 0, "need the dylink section to be first");
53
offset = 9;
54
const section_size = getLEB(); //section size
55
end = offset + section_size;
56
name = getString();
57
58
const customSection: Partial<Metadata> = {
59
neededDynlibs: [],
60
tlsExports: new Set(),
61
weakImports: new Set(),
62
};
63
if (customSection.neededDynlibs == null) throw Error("bug: typescript");
64
if (customSection.tlsExports == null) throw Error("bug: typescript");
65
if (customSection.weakImports == null) throw Error("bug: typescript");
66
67
if (name == "dylink") {
68
customSection.memorySize = getLEB();
69
customSection.memoryAlign = getLEB();
70
customSection.tableSize = getLEB();
71
customSection.tableAlign = getLEB();
72
// shared libraries this module needs. We need to load them first, so that
73
// current module could resolve its imports. (see tools/shared.py
74
// WebAssembly.make_shared_library() for "dylink" section extension format)
75
let neededDynlibsCount = getLEB();
76
for (let i = 0; i < neededDynlibsCount; ++i) {
77
const libname = getString();
78
customSection.neededDynlibs.push(libname);
79
}
80
} else {
81
failIf(
82
name !== "dylink.0",
83
"invalid format -- name must be dylink.0 or dylink"
84
);
85
const WASM_DYLINK_MEM_INFO = 0x1;
86
const WASM_DYLINK_NEEDED = 0x2;
87
const WASM_DYLINK_EXPORT_INFO = 0x3;
88
const WASM_DYLINK_IMPORT_INFO = 0x4;
89
const WASM_SYMBOL_TLS = 0x100;
90
const WASM_SYMBOL_BINDING_MASK = 0x3;
91
const WASM_SYMBOL_BINDING_WEAK = 0x1;
92
while (offset < end) {
93
const subsectionType = getU8();
94
const subsectionSize = getLEB();
95
if (subsectionType === WASM_DYLINK_MEM_INFO) {
96
customSection.memorySize = getLEB();
97
customSection.memoryAlign = getLEB();
98
customSection.tableSize = getLEB();
99
customSection.tableAlign = getLEB();
100
} else if (subsectionType === WASM_DYLINK_NEEDED) {
101
const neededDynlibsCount = getLEB();
102
for (let i = 0; i < neededDynlibsCount; ++i) {
103
const libname = getString();
104
customSection.neededDynlibs.push(libname);
105
}
106
} else if (subsectionType === WASM_DYLINK_EXPORT_INFO) {
107
let count = getLEB();
108
while (count--) {
109
const symname = getString();
110
const flags = getLEB();
111
if (flags & WASM_SYMBOL_TLS) {
112
customSection.tlsExports.add(symname);
113
}
114
}
115
} else if (subsectionType === WASM_DYLINK_IMPORT_INFO) {
116
let count = getLEB();
117
while (count--) {
118
getString(); // module name -- not used, but have to read to get offset right.
119
const symname = getString();
120
const flags = getLEB();
121
if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
122
customSection.weakImports.add(symname);
123
}
124
}
125
} else {
126
// unknown subsection
127
offset += subsectionSize;
128
}
129
}
130
}
131
return customSection as Metadata;
132
}
133
134
// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array
135
// that contains uint8 values, returns a copy of that string as a Javascript
136
// string object.
137
const UTF8Decoder = new TextDecoder();
138
function UTF8ArrayToString(
139
binary: Uint8Array,
140
ptr: number,
141
maxBytesToRead: number
142
): string {
143
const endIdx = ptr + maxBytesToRead;
144
let endPtr = ptr;
145
while (binary[endPtr] && endPtr < endIdx) {
146
endPtr++;
147
}
148
const slice = binary.slice(ptr, endPtr);
149
return UTF8Decoder.decode(slice);
150
}
151
152