JIT session error while using lli on Windows

I am following the steps to use the LLVM toolchain at the end of this Getting Started with the LLVM System page.

I built my LLVM toolchain on a MinGW64 host, and everything in the example above worked fine except the lli command. I could successfully compile my target C program, as well as executing the native hello.exe to print hello world. But I couldn’t jit the bitcode.

The target code test.c is very primitive:

int main(void)
{
  return 0;
}

I followed the steps in the tutorial to produce the bitcode and assembly:

$ clang -emit-llvm -c test.c -o test.bc
$ llc test.bc -o test.s
$ clang test.s  -o test

When I use lli to jit the bitcode, an error occurred saying the __main symbols is not found:

$ lli test.bc
JIT session error: Symbols not found: [ __main ]
C:/msys64/home/xxx/llvm-project/build/bin/lli.exe: Failed to materialize symbols: { (main, { main }) }

However, the linux build on my Ubuntu machine works just fine. Why is this happening?

__main – It looks like we’re getting the mangling wrong and putting an extra ‘_’ on that name.

Could you share the target triple and data layout for your module? (You can disassemble it from the bitcode with llvm-dis)

Here is the dump of my module:

; ModuleID = '<stdin>'
source_filename = "test.c"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu"

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, ptr %1, align 4
  ret i32 0
}

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{!"clang version 15.0.6"}

Below is my test.s:

        .text
        .def    @feat.00;
        .scl    3;
        .type   0;
        .endef
        .globl  @feat.00
.set @feat.00, 0
        .file   "test.c"
        .def    main;
        .scl    2;
        .type   32;
        .endef
        .globl  main                            # -- Begin function main
        .p2align        4, 0x90
main:                                   # @main
.seh_proc main
# %bb.0:
        pushq   %rbp
        .seh_pushreg %rbp
        subq    $48, %rsp
        .seh_stackalloc 48
        leaq    48(%rsp), %rbp
        .seh_setframe %rbp, 48
        .seh_endprologue
        callq   __main
        movl    $0, -4(%rbp)
        xorl    %eax, %eax
        addq    $48, %rsp
        popq    %rbp
        retq
        .seh_endproc
                                        # -- End function

It looks like we’re getting the mangling wrong and putting an extra ‘_’ on that name.

My educational guess is that it has something to do with MinGW’s dynamic library loading issue on Windows. When I followed the original “hello world” tutorial, the same JIT error occurred with an extra missing symbol __mingw_vfprintf, while my target program just used printf. This doesn’t look like mangling to me. Please correct me if I am wrong though.

I tried to search some similar post and found this one. One of the replies below said lli has a --load option. But the lli --help says it’s used to load plugins, which doesn’t look right either :frowning:

Alright, after a whole day’s research, I finally found the solution. Reference here (at the bottom of this website).

The symbol __main is defined in libgcc.a, and if I printf hello world, the __mingw_vfprintf symbol is defined in libmingwex.a. So all I need to do is to provide these extra archives while executing lli.

$ lli --extra-archive=/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/libgcc.a --extra-archive=/mingw64/lib/libmingwex.a hello.bc
hello world

As a newbie who is new to everything, I’ve found it genuinely uncomfortable to develop on Windows. Maybe I will just switch to my Ubuntu machine to save all the hassles I’ve been experiencing.

BTW, do I have to put two --extra-archive= in the command line like above? Comma separated directories surrounded by double quotes didn’t work.

Apologies for the delayed reply.

I’m glad that you were able to track this down – thank you very much for sharing the solution!

As a newbie who is new to everything, I’ve found it genuinely uncomfortable to develop on Windows. Maybe I will just switch to my Ubuntu machine to save all the hassles I’ve been experiencing.

You’ll definitely have a smoother experience on Linux for now. We’re working on improved native windows support too, but it’s not yet as friendly as Linux or Darwin.

BTW, do I have to put two --extra-archive= in the command line like above? Comma separated directories surrounded by double quotes didn’t work.

Yes – lli has grown organically over the years and we haven’t done much to make it ergonomic, since it’s usually used as a test tool.

It might be nice if we detected the platform from the triple and tried to install common runtime libraries. I’ve filed `lli` and `llvm-jitlink` ergonomics -- automatically search for common platform runtime archives. · Issue #60034 · llvm/llvm-project · GitHub to track that. I don’t have time to look into it at the moment, but if it’s something that you’d be interested in looking at please let me know. :slight_smile: