diff --git a/src/library_dylink.js b/src/library_dylink.js index 368c5387abdfe..9b5bf745dc85f 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -256,12 +256,18 @@ 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; @@ -269,47 +275,85 @@ var LibraryDylink = { 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; }, diff --git a/tools/building.py b/tools/building.py index f17d371a6265b..c94ccf67482f6 100644 --- a/tools/building.py +++ b/tools/building.py @@ -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 diff --git a/tools/webassembly.py b/tools/webassembly.py index 83b520bccece4..d7868aac6d5cb 100644 --- a/tools/webassembly.py +++ b/tools/webassembly.py @@ -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']) @@ -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.""" @@ -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)