[WebAssembly] Fix shared library loading (#17)

Loading of shared libraries was broken back in:
39fde60

This change restores the ability for shared libraries to
be loaded such that they can share memory and provide
function exports to the main executable.

However the executable that libraries still need to built
in a specific way (i.e. all importing the same sized memory)
and their static globals need to be in the different address
range. This has the complication that the executables won't
run the wasm spec interpreter (since it doesn't pass in a
memory to the executables it runs). So although I'm fixing this
here in the musl repo I'm also proposiing that we remove the
continuous testing of this configurations on the wasm waterfall
in favor of concentrating on the statically linking lld case:
WebAssembly/waterfall#271
This commit is contained in:
Sam Clegg
2017-11-06 14:18:53 -08:00
committed by GitHub
parent dafacbdab0
commit 8116ebcd0c
2 changed files with 25 additions and 12 deletions

View File

@ -21,15 +21,17 @@
* both as a hobbling libc and a linker/loader, including dynamic linking. * both as a hobbling libc and a linker/loader, including dynamic linking.
*/ */
var heap_size_bytes; var heap_size_bytes = 16 * 1024 * 1024;
var heap; var heap_size_pages = heap_size_bytes / (64 * 1024);
var heap_uint8; var memory = new WebAssembly.Memory({initial: heap_size_pages, maximum: heap_size_pages})
var heap = memory.buffer;
var heap_uint8 = new Uint8Array(heap);
// Heap access helpers. // Heap access helpers.
function charFromHeap(ptr) { return String.fromCharCode(heap_uint8[ptr]); } function charFromHeap(ptr) { return String.fromCharCode(heap_uint8[ptr]); }
function stringFromHeap(ptr) { function stringFromHeap(ptr) {
var str = ''; var str = '';
for (var i = ptr; heap_uint8[i] != 0; ++i) for (var i = ptr; i < heap_size_bytes && heap_uint8[i] != 0; ++i)
str += charFromHeap(i); str += charFromHeap(i);
return str; return str;
} }
@ -522,9 +524,12 @@ var string = (function() {
strchr: function(str, character) { strchr: function(str, character) {
character &= 0xff; character &= 0xff;
var i = 0; var i = 0;
for (; heap_uint8[str + i] != 0; ++i) for (; heap_uint8[str + i] != 0; ++i) {
if (str + i >= heap_size_bytes)
return 0;
if (heap_uint8[str + i] == character) if (heap_uint8[str + i] == character)
return str + i; return str + i;
}
return character == 0 ? str + i : 0; return character == 0 ? str + i : 0;
}, },
strcspn: NYI('strcspn'), strcspn: NYI('strcspn'),
@ -930,7 +935,7 @@ var syscall = (function() {
// Start with the stub implementations. Further module loads may shadow them. // Start with the stub implementations. Further module loads may shadow them.
var ffi = (function() { var ffi = (function() {
var functions = {env:{}}; var functions = {env:{memory: memory}};
var libraries = [ var libraries = [
musl_hack, // Keep first, overriden later. musl_hack, // Keep first, overriden later.
builtins, ctype, math, runtime, stdio, stdlib, string, unix, builtins, ctype, math, runtime, stdio, stdlib, string, unix,
@ -959,9 +964,14 @@ if (arguments[0] == '--dump-ffi-symbols') {
? new Uint8Array(readbuffer(file_path)) ? new Uint8Array(readbuffer(file_path))
: read(file_path, 'binary'); : read(file_path, 'binary');
instance = new WebAssembly.Instance(new WebAssembly.Module(buf), ffi) instance = new WebAssembly.Instance(new WebAssembly.Module(buf), ffi)
heap = instance.exports.memory.buffer; // For the application exports its memory, we use that rather than
heap_uint8 = new Uint8Array(heap); // the one we created. In this way this code works with modules that
heap_size_bytes = heap.byteLength; // import or export their memory.
if (instance.exports.memory) {
heap = instance.exports.memory.buffer;
heap_uint8 = new Uint8Array(heap);
heap_size_bytes = heap.byteLength;
}
return instance; return instance;
} }
@ -973,12 +983,13 @@ if (arguments[0] == '--dump-ffi-symbols') {
for (var i = arguments.length - 1; i > 0; --i) { for (var i = arguments.length - 1; i > 0; --i) {
var path = arguments[i]; var path = arguments[i];
modules[i] = load_wasm(path); modules[i] = load_wasm(path);
for (var f in modules[i]) { for (var f in modules[i].exports) {
// TODO wasm modules don't have hasOwnProperty. They probably should. // TODO wasm modules don't have hasOwnProperty. They probably should.
// The code should look like: // The code should look like:
// if (modules[i].hasOwnProperty(f) && // if (modules[i].hasOwnProperty(f) &&
// modules[i][f] instanceof Function) // modules[i][f] instanceof Function)
ffi[f] = modules[i][f]; if (modules[i].exports[f] instanceof Function)
ffi['env'][f] = modules[i].exports[f];
} }
} }

View File

@ -171,6 +171,7 @@ class AsmCompiler(Compiler):
return os.path.basename(src)[:-1] + 'll' # .c -> .ll return os.path.basename(src)[:-1] + 'll' # .c -> .ll
def binary(self): def binary(self):
max_memory = str(16 * 1024 * 1024)
bytecode = change_extension(self.out, '.bc') bytecode = change_extension(self.out, '.bc')
assembly = os.path.join(self.tmpdir, self.outbase + '.s') assembly = os.path.join(self.tmpdir, self.outbase + '.s')
check_output([os.path.join(self.clang_dir, 'llvm-link'), check_output([os.path.join(self.clang_dir, 'llvm-link'),
@ -180,7 +181,8 @@ class AsmCompiler(Compiler):
bytecode, '-o', assembly], bytecode, '-o', assembly],
cwd=self.tmpdir) cwd=self.tmpdir)
check_output([os.path.join(self.binaryen_dir, 's2wasm'), check_output([os.path.join(self.binaryen_dir, 's2wasm'),
assembly, '--ignore-unknown', '-o', self.out], assembly, '--ignore-unknown', '-o', self.out,
'--import-memory', '-m', max_memory],
cwd=self.tmpdir) cwd=self.tmpdir)
if self.sexpr_wasm: if self.sexpr_wasm: