Should sanitizers be able to be built with msvc\cl and further for arm64 windows?

In the process of trying to get address sanitizer building for arm64 using cl as a cross compiler I encountered a number of issues.

First there isn’t consistent use of _M_ARM64
for example compiler-rt/lib/builtins/cpu_model/aarch64.c:17 should be adapted to

#if !defined(__aarch64__) && !defined(_M_ARM64)
#error This file is intended only for aarch64-based targets
#endif

compiler-rt\lib\builtins\aarch64\lse.S:23

#ifdef __aarch64__ || _M_ARM64

A second issue was the use of __attribute__

for example in compiler-rt\lib\builtins\cpu_model\aarch64.c:33

_Bool __aarch64_have_lse_atomics
    __attribute__((visibility("hidden"), nocommon)) = false;

aarch64.c:130

struct {
  unsigned long long features;
  // As features grows new fields could be added
} __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon));

and
compiler-rt\lib\builtins\aarch64\fp_mode.c lines 26

CRT_FE_ROUND_MODE __attribute__((weak)) __aarch64_fe_default_rmode =
      CRT_FE_TONEAREST;

probably need a _MSC_VER with __declspec versions like
__declspec(selectany)

Then there are arm64 specific issues:
compiler-rt\lib\sanitizer_common\sanitizer_atomic_msvc.h
has x86 specific intrinsics it is invoking like _mm_mfence and _mm_pause

that should probably be __builtin_arm_dmb and __builtin_arm_yield.

Similarly, compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h uses the __ud2 x86 intrinsic that will need an arm64 equivalent for the Trap call.

What is the right approach for inclusion of arm64 intrinsics?

I’m assuming we don’t want something things like

#if defined(__i386__) || defined(__x86_64__)
  extern "C" void _mm_mfence();
  #pragma intrinsic(_mm_mfence)
  extern "C" void _mm_pause();
  #pragma intrinsic(_mm_pause)
#endif

#if defined(__aarch64__) || defined(_M_ARM64)
  extern "C" void __builtin_arm_dmb();
  #pragma intrinsic(__builtin_arm_dmb)
  extern "C" void __builtin_arm_yield();
  #pragma intrinsic(__builtin_arm_yield)
#endif

#if defined(__i386__) || defined(__x86_64__)
    extern "C" void __ud2(void);
    #  pragma intrinsic(__ud2)
    inline void Trap() {
      __ud2();
    }
  #elif defined(__aarch64__) || defined(_M_ARM64)
    extern "C" void __builtin_arm_nop(void);
    #  pragma intrinsic(__builtin_arm_nop)
    inline void Trap() {
      __builtin_arm_nop();
    }
  #endif
inline void atomic_thread_fence(memory_order) {
#if defined(__i386__) || defined(__x86_64__)
  _mm_mfence();
#elif defined(__aarch64__) || defined(_M_ARM64)
  __builtin_arm_dmb();
#endif
}

inline void proc_yield(int cnt) {
  for (int i = 0; i < cnt; i++) {
#if defined(__i386__) || defined(__x86_64__)
    _mm_pause();
#elif defined(__aarch64__) || defined(_M_ARM64)
    __builtin_arm_yield();
#endif
  }
}

after all these changes there are a few remaining build issues
Cmake setting:

cmake -G Ninja -DCOMPILER_RT_BUILD_SANITIZERS=ON  \
-DCOMPILER_RT_SANITIZERS_TO_BUILD="asan"  \
-DLLVM_DEFAULT_TARGET_TRIPLE="aarch64-pc-windows-msvc"  \
-S compiler-rt -B ..\build-compiler-rt-cl -DCMAKE_BUILD_TYPE=Debug  \
-DCMAKE_C_COMPILER_TARGET="aarch64-pc-windows-msvc"  \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=YES  \
-DCOMPILER_RT_INCLUDE_TESTS=FALSE -DCMAKE_SYSTEM_NAME=Windows

ninja -C ..\build-compiler-rt-cl

Almost every line looks something like this:>

cl : Command line warning D9035 : option ‘o’ has been deprecated and will be removed in a future release
cl : Command line warning D9024 : unrecognized source file type ‘D:\projects\build-compiler-rt-cl\lib\builtins\outline_atomic_helpers.dir\outline_atomic_ldclr4_3.S’, object file assumed
cl : Command line warning D9027 : source file ‘D:\projects\build-compiler-rt-cl\lib\builtins\outline_atomic_helpers.dir\outline_atomic_ldclr4_3.S’ ignored
cl : Command line warning D9021 : no action performed

Eventually the build will fail just because of the warnings
ninja: build stopped: subcommand failed.

If you want to build with cl you want -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe

Just changing the compiler target might give you a clang compiler with gnu-like command line that targets the msvc abi.

In any case, asan is meant to be buildable with cl.exe, but ARM is not supported yet. Basic things on pure arm64 might work OK, but arm64ec code probably won’t.

Hi @barcharcraz thanks for your response.
I applogize if it seemed like I was having a cmake issue. this isn’t a matter of setting DCMAKE_CXX_COMPILER and DCMAKE_C_COMPILER as those default to cl.exe if you don’t specify them on windows.

I was on the Edge Security team working with Linaro to scope out a work package to port ASAN to arm64 Windows. In the process of scoping out that work I was able to cross build clang_rt.asan_dynamic-aarch64.dll using clang\clang-cl. however when I tried the same cmake with cl.exe I ran into the compiler errors mentioned in the post.

This isn’t a blocking issue for the work because we don’t use cl in our build system. I use vs for my own projects so thought it would be interesting to figure out. I just found it as an oddity\curiosity why cl couldn’t build the dll and wanted to document what I ran into.