# How VMAware Handles 32-bit and 64-bit System Compatibility

> Discover how VMAware ensures 32-bit and 64-bit system compatibility using preprocessor macros and architecture detection. Learn about its efficient approach to cross-compatibility.

- Repository: [Louis/vmaware](https://github.com/kernelwernel/vmaware)
- Tags: internals
- Published: 2026-03-05

---

**VMAware achieves 32-bit and 64-bit system compatibility through compile-time preprocessor macros that detect the target architecture and conditionally include CPU-specific detection techniques.**

VMAware is a cross-platform virtual machine detection library supporting Windows, Linux, and macOS across x86 and ARM processors. Handling 32-bit and 64-bit system compatibility requires strict management of instruction-set differences to prevent illegal operations on incompatible hardware. According to the kernelwernel/vmaware source code, the library solves this entirely at compile-time using architecture detection macros defined in [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp).

## Compile-Time Architecture Detection

The foundation of VMAware's compatibility layer rests on standard compiler-provided macros. In [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) (lines 281-291), the header checks for `__x86_64__`, `_M_X64`, `__i386__`, and `_M_IX86` to determine the target architecture.

If a 64-bit x86 macro is present, the library defines `x86_64` as `1`; otherwise, it sets `x86_32` to `1` for 32-bit targets. This logic creates boolean flags that the entire codebase uses to toggle architecture-specific code paths.

At line 293, a generic `x86` flag is defined as the logical OR of `x86_32` and `x86_64`, allowing any x86-compatible CPU to be tested with a single macro while preserving the granularity needed for bit-specific operations.

## Conditional Compilation of Detection Techniques

Every detection technique that depends on register size or instruction set availability is wrapped in preprocessor guards. This prevents the compiler from emitting illegal instructions for the target architecture.

### 32-bit Specific Techniques

Certain x86 instructions are unavailable or behave differently in 64-bit long mode. VMAware wraps these in `#if (x86_32)` blocks:

- **SLDT (Store Local Descriptor Table)**: Only compiled for 32-bit targets at lines 6655-6661. This instruction does not exist in x86-64 long mode and would cause a crash if executed.
- **SMSW (Store Machine Status Word)**: Restricted to 32-bit builds at lines 6728-6732 for similar compatibility reasons.

### 64-bit and Shared Techniques

RDTSC-based hypervisor checks are compiled for both architectures, though the 64-bit implementation may use `rdtsc`-ordered instructions with adjusted register handling. The conditional compilation ensures that a binary built for 64-bit systems never contains 32-bit-only instructions that would trigger an illegal instruction exception at runtime.

## ARM Architecture Support

Parallel to the x86 logic, VMAware supports ARM processors through the same macro-based approach. Lines 299-311 define `ARM32`, `ARM64`, and `ARM` using compiler macros like `__aarch64__`, `_M_ARM64`, and `__arm__`. This allows the library to handle ARM-only techniques—such as Apple VZ detection mentioned in [`src/cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/src/cli.cpp)—while keeping x86 logic untouched and preventing cross-platform instruction-set pollution.

## Platform Range Integration

The library defines platform-wide flag ranges (e.g., `WINDOWS_START`, `WINDOWS_END`) that automatically respect architecture flags (lines 559-566). When a technique is enabled for Windows, the range includes both `x86_32` and `x86_64` entries within the Windows block, ensuring consistent API behavior across architectures while maintaining internal separation of concerns.

## Runtime Capability Guards

Although most compatibility checks occur at compile-time, VMAware includes runtime safety mechanisms for edge cases. The `cpu::is_leaf_supported` function (lines 985-1005) queries processor capabilities at runtime, ensuring that a 32-bit binary running on a 64-bit CPU—or other similar scenarios—behaves correctly even when compile-time detection might suggest otherwise.

```cpp
// Example conditional compilation from vmaware.hpp
// SLDT technique only builds for 32-bit x86
#if (x86_32)
bool technique_sldt() {
    unsigned int value = 0;
    __asm__ volatile("sldt %0" : "=r"(value));
    return (value & 0xFF) == 0xFF;   // hypervisor signature check
}
#endif

```

The `x86_32` macro ensures this block is completely omitted from 64-bit builds, preventing runtime crashes on CPUs that do not support the `sldt` instruction in long mode.

## Summary

- **VMAware** uses preprocessor macros (`__x86_64__`, `__i386__`, etc.) at lines 281-291 of [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) to detect the target architecture during compilation.
- **Architecture flags** (`x86_32`, `x86_64`, `ARM32`, `ARM64`) enable conditional compilation of platform-specific code paths.
- **32-bit only instructions** like SLDT and SMSW are wrapped in `#if (x86_32)` guards at lines 6655-6661 and 6728-6732 to prevent illegal instruction exceptions on 64-bit systems.
- **Platform ranges** (lines 559-566) integrate architecture flags into broader platform detection logic for Windows, Linux, and macOS.
- **Runtime guards** such as `cpu::is_leaf_supported` (lines 985-1005) provide additional safety for capability detection at execution time.

## Frequently Asked Questions

### How does VMAware detect whether to compile for 32-bit or 64-bit systems?

VMAware checks standard compiler-provided macros in [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) (lines 281-291). It looks for `__x86_64__` or `_M_X64` to set `x86_64=1` for 64-bit targets, or `__i386__` and `_M_IX86` to set `x86_32=1` for 32-bit targets. These definitions occur before any platform-specific code is compiled, ensuring the correct instruction set is used throughout the build.

### Why are certain techniques like SLDT restricted to 32-bit builds only?

The SLDT and SMSW x86 instructions are not valid in 64-bit long mode. If compiled into a 64-bit binary, these instructions would generate an illegal instruction exception (SIGILL) when executed. By wrapping these techniques in `#if (x86_32)` blocks at lines 6655-6661 and 6728-6732, VMAware ensures they only exist in 32-bit executables where the hardware supports them.

### Does VMAware support processors other than x86?

Yes. Lines 299-311 of [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) define parallel architecture flags for ARM processors (`ARM32`, `ARM64`, `ARM`) using macros like `__aarch64__` and `__arm__`. This allows the same conditional compilation strategy to work for ARM-specific detection techniques while maintaining separation from x86 logic, enabling the library to run natively on Apple Silicon and other ARM platforms.

### What happens if a 32-bit VMAware binary runs on a 64-bit CPU?

The 32-bit binary contains only instructions compatible with its target architecture due to compile-time filtering. However, if runtime capability detection is needed, the `cpu::is_leaf_supported` function (lines 985-1005) queries actual processor features at execution time. This ensures correct behavior even when the compile-time target differs from the physical CPU capabilities, preventing false positives in virtual machine detection.