Skip to content

Support new dylink.0 custom section format #15019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 76 additions & 32 deletions src/library_dylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,60 +256,104 @@ var LibraryDylink = {
// returns the side module metadata as an object
// { memorySize, memoryAlign, tableSize, tableAlign, neededDynlibs}
$getDylinkMetadata: function(binary) {
var next = 0;
var offset = 0;
var end = 0;

function getU8() {
return binary[offset++];
}

function getLEB() {
var ret = 0;
var mul = 1;
while (1) {
var byte = binary[next++];
var byte = binary[offset++];
ret += ((byte & 0x7f) * mul);
mul *= 0x80;
if (!(byte & 0x80)) break;
}
return ret;
}

function getString() {
var len = getLEB();
offset += len;
return UTF8ArrayToString(binary, offset - len, len);
}

var name = 'dylink.0';
if (binary instanceof WebAssembly.Module) {
var dylinkSection = WebAssembly.Module.customSections(binary, "dylink");
var dylinkSection = WebAssembly.Module.customSections(binary, name);
if (dylinkSection.length === 0) {
name = 'dylink'
dylinkSection = WebAssembly.Module.customSections(binary, name);
}
assert(dylinkSection.length != 0, 'need dylink section');
binary = new Uint8Array(dylinkSection[0]);
end = binary.length
} else {
var int32View = new Uint32Array(new Uint8Array(binary.subarray(0, 24)).buffer);
assert(int32View[0] == 0x6d736100, 'need to see wasm magic number'); // \0asm
// we should see the dylink section right after the magic number and wasm version
// we should see the dylink custom section right after the magic number and wasm version
assert(binary[8] === 0, 'need the dylink section to be first')
next = 9;
getLEB(); //section size
assert(binary[next] === 6); next++; // size of "dylink" string
assert(binary[next] === 'd'.charCodeAt(0)); next++;
assert(binary[next] === 'y'.charCodeAt(0)); next++;
assert(binary[next] === 'l'.charCodeAt(0)); next++;
assert(binary[next] === 'i'.charCodeAt(0)); next++;
assert(binary[next] === 'n'.charCodeAt(0)); next++;
assert(binary[next] === 'k'.charCodeAt(0)); next++;
}

var customSection = {};
customSection.memorySize = getLEB();
customSection.memoryAlign = getLEB();
customSection.tableSize = getLEB();
customSection.tableAlign = getLEB();
offset = 9;
var section_size = getLEB(); //section size
end = offset + section_size;
name = getString();
}

var customSection = { neededDynlibs: [] };
if (name == 'dylink') {
customSection.memorySize = getLEB();
customSection.memoryAlign = getLEB();
customSection.tableSize = getLEB();
customSection.tableAlign = getLEB();
// shared libraries this module needs. We need to load them first, so that
// current module could resolve its imports. (see tools/shared.py
// WebAssembly.make_shared_library() for "dylink" section extension format)
var neededDynlibsCount = getLEB();
for (var i = 0; i < neededDynlibsCount; ++i) {
var name = getString();
customSection.neededDynlibs.push(name);
}
} else {
assert(name === 'dylink.0');
var WASM_DYLINK_MEM_INFO = 0x1;
var WASM_DYLINK_NEEDED = 0x2;
while (offset < end) {
var subsectionType = getU8();
var subsectionSize = getLEB();
if (subsectionType === WASM_DYLINK_MEM_INFO) {
customSection.memorySize = getLEB();
customSection.memoryAlign = getLEB();
customSection.tableSize = getLEB();
customSection.tableAlign = getLEB();
} else if (subsectionType === WASM_DYLINK_NEEDED) {
var neededDynlibsCount = getLEB();
for (var i = 0; i < neededDynlibsCount; ++i) {
var name = getString();
customSection.neededDynlibs.push(name);
}
} else {
#if ASSERTIONS
err('unknown dylink.0 subsection: ' + subsectionType)
#endif
// unknown subsection
offset += subsectionSize;
}
}
}

#if ASSERTIONS
var tableAlign = Math.pow(2, customSection.tableAlign);
assert(tableAlign === 1, 'invalid tableAlign ' + tableAlign);
#endif
// shared libraries this module needs. We need to load them first, so that
// current module could resolve its imports. (see tools/shared.py
// WebAssembly.make_shared_library() for "dylink" section extension format)
var neededDynlibsCount = getLEB();
customSection.neededDynlibs = [];
for (var i = 0; i < neededDynlibsCount; ++i) {
var nameLen = getLEB();
var nameUTF8 = binary.subarray(next, next + nameLen);
next += nameLen;
var name = UTF8ArrayToString(nameUTF8, 0);
customSection.neededDynlibs.push(name);
}

#if DYLINK_DEBUG
err('dylink needed:' + customSection.neededDynlibs);
#endif

assert(offset == end);
return customSection;
},

Expand Down
2 changes: 1 addition & 1 deletion tools/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ def is_wasm_dylib(filename):
section = next(module.sections())
if section.type == webassembly.SecType.CUSTOM:
module.seek(section.offset)
if module.readString() == 'dylink':
if module.readString() in ('dylink', 'dylink.0'):
return True
return False

Expand Down
60 changes: 48 additions & 12 deletions tools/webassembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ class ExternType(IntEnum):
EVENT = 4


class DylinkType(IntEnum):
MEM_INFO = 1
NEEDED = 2


Section = namedtuple('Section', ['type', 'size', 'offset'])
Limits = namedtuple('Limits', ['flags', 'initial', 'maximum'])
Import = namedtuple('Import', ['kind', 'module', 'field'])
Expand Down Expand Up @@ -178,7 +183,13 @@ def readLimits(self):
return Limits(flags, initial, maximum)

def seek(self, offset):
self.buf.seek(offset)
return self.buf.seek(offset)

def tell(self):
return self.buf.tell()

def skip(self, count):
self.buf.seek(count, os.SEEK_CUR)

def sections(self):
"""Generator that lazily returns sections from the wasm file."""
Expand All @@ -200,18 +211,43 @@ def parse_dylink_section(wasm_file):
module.seek(dylink_section.offset)
# section name
section_name = module.readString()
assert section_name == 'dylink'
mem_size = module.readULEB()
mem_align = module.readULEB()
table_size = module.readULEB()
table_align = module.readULEB()

needed = []
needed_count = module.readULEB()
while needed_count:
libname = module.readString()
needed.append(libname)
needed_count -= 1

if section_name == 'dylink':
mem_size = module.readULEB()
mem_align = module.readULEB()
table_size = module.readULEB()
table_align = module.readULEB()

needed_count = module.readULEB()
while needed_count:
libname = module.readString()
needed.append(libname)
needed_count -= 1
elif section_name == 'dylink.0':
section_end = dylink_section.offset + dylink_section.size
while module.tell() < section_end:
subsection_type = module.readULEB()
subsection_size = module.readULEB()
end = module.tell() + subsection_size
if subsection_type == DylinkType.MEM_INFO:
mem_size = module.readULEB()
mem_align = module.readULEB()
table_size = module.readULEB()
table_align = module.readULEB()
elif subsection_type == DylinkType.NEEDED:
needed_count = module.readULEB()
while needed_count:
libname = module.readString()
needed.append(libname)
needed_count -= 1
else:
print(f'unknown subsection: {subsection_type}')
# ignore unknown subsections
module.skip(subsection_size)
assert(module.tell() == end)
else:
utils.exit_with_error('error parsing shared library')

return Dylink(mem_size, mem_align, table_size, table_align, needed)

Expand Down