Unable to link C runtime library (libcmt.lib) using lld-link.exe (Windows)

江枫思渺然 提交于 2020-08-08 04:29:05

问题


I'm writing a language using LLVM. I'd like to avoid having to package clang and simply use the LLVM tools (ex. lld, lld-link). I've been trying to invoke the printf function from my simple IR code (testinput.ll):

; ModuleID = 'Test2'
source_filename = "entry"

@str_0 = private unnamed_addr constant [13 x i8] c"Hello world!\00"

declare i32 @printf(i8*, ...)

define i32 @main() {
entry:
  %anonymous_10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @str_0, i32 0, i32 0))
  ret i32 1234
}

But I keep receiving errors no matter what I try:

$ clang-cl -fuse-ld=lld-link testinput.ll "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\spectre\x64\libcmt.lib"

Note: I've chosen the link randomly "... spectre\x64\libcmt.lib ..." by simply searching for libcmt.lib on the system.

Error:

C:\Program Files\LLVM\bin\lld-link: warning: libcmt.lib(loadcfg.obj): undefined symbol: __enclave_config
error: link failed
clang-cl.exe: error: linker command failed with exit code 1 (use -v to see invocation)

I'm using Windows 10 (x64) with LLVM 5.0. Interestingly, using link.exe (Windows' VS tools' linker) everything works fine (which is what clang uses under the hood in my case).

I've read in this article:

... As I wrote earlier, __enclave_config is a variable that is filled in by the linker, but you have to use the VC linker, and a linker new enough to be able to automatically fill it in. ...

I believe the problem here is libcmt.lib and the lld-link linker. Is the lld-link version (LLVM 5.0) incompatible with the libcmt.lib that I'm using, is that the problem?

Edit: I've managed to track down what clang does behind the scenes, and have found it using the following command:

lld-link -out:a.exe -defaultlib:libcmt "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.16.27023\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\ucrt\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\um\\x64" -nologo "test.obj"

Clearly it's using lld-link, and it's working. However, strangely enough, it only compiles without errors if the input object file was compiled to .LL (LLVM IR) using clang (maybe using -fuse-ld=lld -v options?).

What's weird about this, is that upon inspection of the output .LL file from clang (test.ll) the full, source code (in IR) definitions of printf (and some other *printf functions used by it) is present (in the output .LL file).

So, somehow it's getting the definitions of printf itself inside the output .LL, IR code file.

As far as I know, you can't just $ llc libcmt.lib testinput.ll? That'd be the linker's job... (llc accepts only one positional argument)

The error that I'm getting once I try the same lld-link command and arguments with my testinput.ll file (not outputted from clang) is the following:

lld-link: error: <root>: undefined symbol: _mainCRTStartup
lld-link: error: undefined symbol: _printf

回答1:


Turns out, it was much much more simple than I anticipated. Maybe if the errors were at least somewhat helpful, I could have avoided all this confusion...

I've figured it out by comparing clang's output LL file, and noticed a curious line at the beginning:

target triple = "x86_64-pc-windows-msvc"

Once I added it to my testinput.ll file, everything worked flawlessly with lld-link. Hurray!



来源:https://stackoverflow.com/questions/56160307/unable-to-link-c-runtime-library-libcmt-lib-using-lld-link-exe-windows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!