Need help debugging a potential bug when compiling for wasm32 targets

I’m currently trying to debug a bug in a LLVM-generated Wasm code. The bug could be in the code that generates LLVM (rustc) or in the LLVM, I’m not sure yet. LLVM IR and Wasm are here.

The problem is this line:

(import "GOT.func" "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E" (global (;3;) (mut i32)))

The same symbol is already imported from “env” in the same module:

(import "env" "_ZN5core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E" (func (;4;) (type 1)))

So there’s no need to import it from “GOT.func” and I want to get rid of that “GOT.func” import.

(To be more specific, this is generated when compiling Rust code to a “staticlib”, which should include all dependencies of the code so that it’ll be linkable with code for other languages. Because of the “GOT.func” import this modules is not linkable, it needs to resolve that “GOT.func” import in runtime using dynamic linking for Wasm)

I’m trying to understand whether this is a rustc bug or an LLVM bug. I’m using LLVM 10 downloaded from the official web page and rustc nightly. Questions:

  • Given a reference to a symbol, how does LLVM decide how to import it? Currently I see these uses of the problematic symbol in LLVM IR:

    • store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)* @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E" to i8*), i8** %11, align 4
    • store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)* @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E" to i8*), i8** %14, align 4
    • store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)* @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E" to i8*), i8** %17, align 4
    • declare zeroext i1 @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"(i32* noalias readonly align 4 dereferenceable(4), %"core::fmt::Formatter"* align 4 dereferenceable(36)) unnamed_addr #1
      First three look very similar so I’m guessing the first three causing one of those imports, and the last one is causing the other import, but I’m not sure which one is generating which import. Any ideas?
  • I’m confused about the i1s in the code listed above. As far as I understand i1 is the type for one-bit information, but the first three are storing a function pointer, and the last one is declaring type of the function? The function address should have a word-sized type, no? I don’t understand why we have those i1s there. (figured this one out)

  • Any suggestions on how to debug this? Just knowing which line in the LLVM IR listed above causes this “GOT.func” import would be helpful.


Forgot to mention: the reproducer is here. Make sure you have rustc, xargo, and LLVM 10 installed, and run ./ You’ll see a file named libfinal.wat which will have the problematic “GOT.func” import line.