const_cstr!("wasm-import-module"),
&module,
);
+
+ let name = codegen_fn_attrs.link_name.unwrap_or_else(|| {
+ cx.tcx.item_name(instance.def_id())
+ });
+ let name = CString::new(&name.as_str()[..]).unwrap();
+ llvm::AddFunctionAttrStringValue(
+ llfn,
+ llvm::AttributePlace::Function,
+ const_cstr!("wasm-import-name"),
+ &name,
+ );
}
}
}
};
let attrs = tcx.codegen_fn_attrs(def_id);
+
+ // Foreign items by default use no mangling for their symbol name. There's a
+ // few exceptions to this rule though:
+ //
+ // * This can be overridden with the `#[link_name]` attribute
+ //
+ // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the
+ // same-named symbol when imported from different wasm modules will get
+ // hooked up incorectly. As a result foreign symbols, on the wasm target,
+ // with a wasm import module, get mangled. Additionally our codegen will
+ // deduplicate symbols based purely on the symbol name, but for wasm this
+ // isn't quite right because the same-named symbol on wasm can come from
+ // different modules. For these reasons if `#[link(wasm_import_module)]`
+ // is present we mangle everything on wasm because the demangled form will
+ // show up in the `wasm-import-name` custom attribute in LLVM IR.
+ //
+ // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
if is_foreign {
- if let Some(name) = attrs.link_name {
- return name;
+ if tcx.sess.target.target.arch != "wasm32" ||
+ !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
+ {
+ if let Some(name) = attrs.link_name {
+ return name;
+ }
+ return tcx.item_name(def_id);
}
- // Don't mangle foreign items.
- return tcx.item_name(def_id);
}
if let Some(name) = attrs.export_name {
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# only-wasm32-bare
+
+all:
+ $(RUSTC) foo.rs --target wasm32-unknown-unknown
+ $(NODE) verify-imports.js $(TMPDIR)/foo.wasm a/foo b/foo
+ $(RUSTC) foo.rs --target wasm32-unknown-unknown -C lto
+ $(NODE) verify-imports.js $(TMPDIR)/foo.wasm a/foo b/foo
+ $(RUSTC) foo.rs --target wasm32-unknown-unknown -O
+ $(NODE) verify-imports.js $(TMPDIR)/foo.wasm a/foo b/foo
+ $(RUSTC) foo.rs --target wasm32-unknown-unknown -O -C lto
+ $(NODE) verify-imports.js $(TMPDIR)/foo.wasm a/foo b/foo
+
+ $(RUSTC) bar.rs --target wasm32-unknown-unknown
+ $(NODE) verify-imports.js $(TMPDIR)/bar.wasm m1/f m1/g m2/f
+ $(RUSTC) bar.rs --target wasm32-unknown-unknown -C lto
+ $(NODE) verify-imports.js $(TMPDIR)/bar.wasm m1/f m1/g m2/f
+ $(RUSTC) bar.rs --target wasm32-unknown-unknown -O
+ $(NODE) verify-imports.js $(TMPDIR)/bar.wasm m1/f m1/g m2/f
+ $(RUSTC) bar.rs --target wasm32-unknown-unknown -O -C lto
+ $(NODE) verify-imports.js $(TMPDIR)/bar.wasm m1/f m1/g m2/f
+
+ $(RUSTC) baz.rs --target wasm32-unknown-unknown
+ $(NODE) verify-imports.js $(TMPDIR)/baz.wasm sqlite/allocate sqlite/deallocate
+
+ $(RUSTC) log.rs --target wasm32-unknown-unknown
+ $(NODE) verify-imports.js $(TMPDIR)/log.wasm test/log
--- /dev/null
+//! Issue #50021
+
+#![crate_type = "cdylib"]
+
+mod m1 {
+ #[link(wasm_import_module = "m1")]
+ extern "C" {
+ pub fn f();
+ }
+ #[link(wasm_import_module = "m1")]
+ extern "C" {
+ pub fn g();
+ }
+}
+
+mod m2 {
+ #[link(wasm_import_module = "m2")]
+ extern "C" {
+ pub fn f(_: i32);
+ }
+}
+
+#[no_mangle]
+pub unsafe fn run() {
+ m1::f();
+ m1::g();
+
+ // In generated code, expected:
+ // (import "m2" "f" (func $f (param i32)))
+ // but got:
+ // (import "m1" "f" (func $f (param i32)))
+ m2::f(0);
+}
--- /dev/null
+//! Issue #63562
+
+#![crate_type = "cdylib"]
+
+mod foo {
+ #[link(wasm_import_module = "sqlite")]
+ extern "C" {
+ pub fn allocate(size: usize) -> i32;
+ pub fn deallocate(ptr: i32, size: usize);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn allocate() {
+ unsafe {
+ foo::allocate(1);
+ foo::deallocate(1, 2);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn deallocate() {}
--- /dev/null
+#![crate_type = "cdylib"]
+
+mod a {
+ #[link(wasm_import_module = "a")]
+ extern "C" {
+ pub fn foo();
+ }
+}
+
+mod b {
+ #[link(wasm_import_module = "b")]
+ extern "C" {
+ pub fn foo();
+ }
+}
+
+#[no_mangle]
+pub fn start() {
+ unsafe {
+ a::foo();
+ b::foo();
+ }
+}
--- /dev/null
+//! Issue #56309
+
+#![crate_type = "cdylib"]
+
+#[link(wasm_import_module = "test")]
+extern "C" {
+ fn log(message_data: u32, message_size: u32);
+}
+
+#[no_mangle]
+pub fn main() {
+ let message = "Hello, world!";
+ unsafe {
+ log(message.as_ptr() as u32, message.len() as u32);
+ }
+}
--- /dev/null
+const fs = require('fs');
+const process = require('process');
+const assert = require('assert');
+const buffer = fs.readFileSync(process.argv[2]);
+
+let m = new WebAssembly.Module(buffer);
+let list = WebAssembly.Module.imports(m);
+console.log('imports', list);
+if (list.length !== process.argv.length - 3)
+ throw new Error("wrong number of imports")
+
+const imports = new Map();
+for (let i = 3; i < process.argv.length; i++) {
+ const [module, name] = process.argv[i].split('/');
+ if (!imports.has(module))
+ imports.set(module, new Map());
+ imports.get(module).set(name, true);
+}
+
+for (let i of list) {
+ if (imports.get(i.module) === undefined || imports.get(i.module).get(i.name) === undefined)
+ throw new Error(`didn't find import of ${i.module}::${i.name}`);
+ imports.get(i.module).delete(i.name);
+
+ if (imports.get(i.module).size === 0)
+ imports.delete(i.module);
+}
+
+console.log(imports);
+if (imports.size !== 0) {
+ throw new Error('extra imports');
+}