I'm currently writing a new frontend for LLVM, and I've come across a problem when using large arrays on the stack. Apparently the compiler inserts references to __chkstk in functions that have a large stack, which is fine, but results in a linker error:
lld-link: error: undefined symbol: __chkstk
I see the purpose of __chkstk, and I don't want to do workarounds, like implementing dummy functions, setting /Gs9999999... or any of the other workarounds I've seen on forum posts. Instead, I would like to actually just link to this function, wherever it may be. Actually, I've even removed my own code from the equation, and am just using clang and other llvm tools, and can show the following:
PS> cat hello.c
int main()
{
char buffer[10000000];
}
PS> clang -S -emit-llvm hello.c
PS> cat hello.ll ; ModuleID = 'hello.c'
source_filename = "hello.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-pc-windows-msvc19.29.30038"
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca [10000000 x i8], align 16
ret i32 0
}
attributes #0 = { noinline nounwind optnone uwtable "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0, !1}
!llvm.ident = !{!2}
!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{!"clang version 12.0.1"}
PS> llc -o hello.obj --filetype=obj hello.ll
PS> lld-link /out:hello.exe /entry:main hello.obj lld-link: error: undefined symbol: __chkstk
>>> referenced by hello.obj:(main)
Actually, I get the same error when I use link.exe instead of lld-link.
error LNK2001: unresolved external symbol __chkstk
When I compile directly to an executable, clang hello.c -o hello.exe
, this works just fine, so I suppose that under the hood, clang is doing something special with the linker options, or maybe it's just preventing insertion of the __chkstk symbol in the first place? I would generally like to take the same approach as clang if I don't have a good reason not to, but this area of clang is opaque to me.
So my question then, is what lib files (or other linker options) is clang doing here? Or how do I otherwise include the header/lib file which contains __chkstk?
After a lot of back and forth, I've finally figured it out, in what I think is the correct way. I was using just Windows SDK, which is not enough to build on Windows, you also need Visual Studio, or at least just the Build Tools. So as part of my toolchain installation, I now install both of these, and use these parameters to the linker:
/defaultlib:C:\Program Files (x86)\Windows Kits\10\Lib\${sdkVersion}\ucrt\${targetDepth}\ucrt.lib
and add "msvcrt.lib" and "libcmt.lib", located in C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\${msvcVersion}\lib\
I do not distribute any of these files myself, rather, I just run the installers for Windows SDK and the MSVC Build Tools, and then expect the correct lib files to exist in those locations.
One good hint I got, was to look at the verbose output of the clang command, clang hello.c -o hello.exe -v
which shows the full set of arguments being sent to the linker, and gives a good template to start from.