Teknogrebo
Teknogrebo

Reputation: 1247

Problems linking msvc intrinsics using clang on windows

I'm swapping over a large codebase from using msvc to clang for a windows product. This product uses a large number of the msvc compiler intrinsics such as _InterlockedOr etc. If I build a little test program using clang on windows it builds, links and runs just fine, but if I build a library from our product that uses an intrinsics it comes up as a missing symbol.

I've tried compiling both the test code and our product using the --verbose option and can't spot anything different between the two. The only difference in the way they are called is that the large product is built using fastbuild which necessitates the use of -c to prevent the compiler calling the linker as well. Clang obviously adds in some libraries that are missing when I call the linker manually myself, so can anybody let me know what they might be? (I'm already linking in the crt library (libcmt, msvcrt) so it's not that.

I've started writing my own library of intrinsics in assembly which is fun, but shouldn't be necessary. Any one?

As per request, compiling the following code with clang works when using it directly, i.e. clang IntrinsicsTest.cppproduces an exe.

IntrinsicsTest.cpp
#include "stdio.h"
#include "intrin.h"

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned long long r = __rdtsc();
    printf("Intrinsic: %llu\n", r);
}

Yet fails to link when called via fastbuild: FBuild.exe -showcmds -clean IntrinsicsTest_debug_x86

clang.exe "\IntrinsicsTest.cpp" -D_WINDOWS -c -m32 -mfpmath=sse -D_UNICODE -DUNICODE -fno-rtti -fexceptions -E ...\IntrinsicsTest.debug.Win32.lib

lib.exe /NOLOGO /OUT:"...\IntrinsicsTest.debug.Win32.lib" "...\IntrinsicsTest.obj" ...\IntrinsicsTest.debug.Win32.exe

link.exe /NOLOGO /INCREMENTAL:NO /OUT:"...\IntrinsicsTest.debug.Win32.exe" "...\IntrinsicsTest.obj" -defaultlib:libcmt.lib -INCREMENTAL -MANIFEST /MACHINE:X86 /SUBSYSTEM:CONSOLE /OPT:NOICF /OPT:NOREF

IntrinsicsTest.obj : error LNK2019: unresolved external symbol ___rdtsc referenced in function _wmain ...\IntrinsicsTest.debug.Win32.exe

fatal error LNK1120: 1 unresolved externals

Upvotes: 4

Views: 5041

Answers (2)

Teknogrebo
Teknogrebo

Reputation: 1247

I have resolved the issue. There were several contributing factors all to do with how fastbuild, clang and msvc were interacting.

a/ With Clang on Windows there is no need to specify "system" includes. In our project we had the include paths as:

-I"C:/Program Files/LLVM/lib/clang/3.8.0/include" 
-I"C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/include/" 
-I"C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/atlmfc/include" 
-I"C:/Program Files (x86)/Windows Kits/8.1/include/um" 
-I"C:/Program Files (x86)/Windows Kits/8.1/include/shared"
-I"C:/Program Files (x86)/Windows Kits/8.1/include/winrt"

The clang version of xmmintrin declares the intrinsics inline and thus if this header is used then the test program compiles fine. The Windows xmmintrin declares the intrinsics as extern functions, hence the program compiles, but doesn't link - where an msvc build gets these symbols from is irrelevant now.

However, even with the clang include path first, when <intrin.h> is included by anything, it pulls in the windows header.

b/ Fastbuild allows you to set up environment variables for the build env. Our scripts have INCLUDE and PATH defined with msvc paths. Removing these helped.

c/ As well as clang, I have several versions of msvc installed on my machine. Clang was picking up on MSVC14 whereas fastbuild was trying to get clang to use MSVC 12. By changing fastbuild to use MSVC14 I was finally able to get past the problem with the intrinsics.

Upvotes: 7

Peter Cordes
Peter Cordes

Reputation: 365322

Intrinsics aren't supposed to be function calls, they're supposed to inline to one or a couple instructions. Or in some cases, no instructions (e.g. a compiler memory barrier, like c++'s std::atomic_signal_fence).

MSVC and GNU C are separate flavours of C. clang implements GNU C, and AFAIK doesn't support MSVC intrinsics.

When there's a GNU C __builtin_something equivalent to an MSVC intrinsic, use it via a wrapper function.

mingw-w64 apparently does support _Interlocked???, via <winnt.h>. This mailing list post is a patch that switched over the implementation from inline asm to GNU C __sync_fetch_and_??? functions. IDK if that's shipping with current mingw, or if there's a mingw version of clang. But that's what you should be looking for. I'm sure you're not the first person to want to compile an MSVC codebase using a different compiler.

Upvotes: 1

Related Questions