From abe8ec8eb42717b8bc1bf750686546230809f376 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Mon, 25 Apr 2022 00:39:23 +0300 Subject: [PATCH] Identify OSArchitecture at run-time --- .../Interop.GetOSArchitecture.cs | 1 - .../RuntimeInformation.Windows.cs | 53 ++++++++++- .../System.Native/pal_runtimeinformation.c | 94 ++++++++++++++++++- .../System.Native/pal_runtimeinformation.h | 13 --- 4 files changed, 140 insertions(+), 21 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetOSArchitecture.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetOSArchitecture.cs index 023a4c830fcb8..f521c7a049cb4 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetOSArchitecture.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetOSArchitecture.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Windows.cs index 594b6cddcfc16..9382e0357d00f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Windows.cs @@ -31,7 +31,7 @@ public static string OSDescription } } - public static Architecture OSArchitecture + public static unsafe Architecture OSArchitecture { get { @@ -39,17 +39,36 @@ public static Architecture OSArchitecture if (osArch < 0) { - Interop.Kernel32.SYSTEM_INFO sysInfo; - unsafe + // If we are running an x64 process on a non-x64 windows machine, we will report x64 as OS architecutre. + // + // IsWow64Process2 is only available on Windows 10+, so we will perform run-time introspection via indirect load + if (NativeLibrary.TryGetExport(NativeLibrary.Load(Interop.Libraries.Kernel32), "IsWow64Process2", out IntPtr isWow64Process2Ptr)) { + ushort processMachine, nativeMachine; + var isWow64Process2 = (delegate* unmanaged)isWow64Process2Ptr; + if (isWow64Process2(Interop.Kernel32.GetCurrentProcess(), &processMachine, &nativeMachine) != 0) + { + osArch = (int)MapMachineConstant(nativeMachine); + } + else + { + Debug.Fail("Call to IsWow64Process2() failed unexpectedly."); + } + } + + if (osArch == -1) + { + Interop.Kernel32.SYSTEM_INFO sysInfo; Interop.Kernel32.GetNativeSystemInfo(&sysInfo); + + osArch = (int)Map(sysInfo.wProcessorArchitecture); } - osArch = (int)Map(sysInfo.wProcessorArchitecture); s_osArchPlusOne = osArch + 1; + + Debug.Assert(osArch >= 0); } - Debug.Assert(osArch >= 0); return (Architecture)osArch; } } @@ -70,5 +89,29 @@ private static Architecture Map(int processorArchitecture) return Architecture.X86; } } + + private static Architecture MapMachineConstant(ushort processMachine) + { + switch (processMachine) + { + case 0x01C0: // IMAGE_FILE_MACHINE_ARM + case 0x01C2: // IMAGE_FILE_MACHINE_THUMB + case 0x01C4: // IMAGE_FILE_MACHINE_ARMNT + return Architecture.Arm; + + case 0x8664: // IMAGE_FILE_MACHINE_AMD64 + return Architecture.X64; + + case 0xAA64: // IMAGE_FILE_MACHINE_ARM64 + return Architecture.Arm64; + + case 0x014C: // IMAGE_FILE_MACHINE_I386 + return Architecture.X86; + + default: // IMAGE_FILE_MACHINE_UNKNOWN etc. + Debug.Fail("Unidentified OS Architecture. Falling back to ProcessArchitecture"); + return ProcessArchitecture; + } + } } } diff --git a/src/native/libs/System.Native/pal_runtimeinformation.c b/src/native/libs/System.Native/pal_runtimeinformation.c index 0551351b3520f..f4ba91ad49b15 100644 --- a/src/native/libs/System.Native/pal_runtimeinformation.c +++ b/src/native/libs/System.Native/pal_runtimeinformation.c @@ -4,11 +4,16 @@ #include "pal_config.h" #include "pal_runtimeinformation.h" #include "pal_types.h" +#include #include #include #include #if defined(TARGET_ANDROID) #include +#elif defined(TARGET_OSX) +#include +#elif defined(TARGET_SUNOS) +#include #endif char* SystemNative_GetUnixRelease() @@ -48,8 +53,93 @@ int32_t SystemNative_GetUnixVersion(char* version, int* capacity) return 0; } -/* Returns an int representing the OS Architecture. -1 if same as process architecture. */ +// Keep in sync with System.Runtime.InteropServices.Architecture enum +enum +{ + ARCH_X86, + ARCH_X64, + ARCH_ARM, + ARCH_ARM64, + ARCH_WASM, + ARCH_S390X, + ARCH_LOONGARCH64, + ARCH_ARMV6, +}; + int32_t SystemNative_GetOSArchitecture() { - return -1; +#ifdef TARGET_WASM + return ARCH_WASM; +#else + int32_t result = -1; +#ifdef TARGET_SUNOS + // On illumos/Solaris, the recommended way to obtain machine + // architecture is using `sysinfo` rather than `utsname.machine`. + + char isa[32]; + if (sysinfo(SI_ARCHITECTURE_K, isa, sizeof(isa)) > -1) + { + { +#else + { + struct utsname _utsname; + if (uname(&_utsname) > -1) + { + char* isa = _utsname.machine; +#endif + // aarch64 or arm64: arm64 + if (strcmp("aarch64", isa) == 0 || strcmp("arm64", isa) == 0) + { + result = ARCH_ARM64; + } + + // starts with "armv6" (armv6h or armv6l etc.): armv6 + else if (strncmp("armv6", isa, strlen("armv6")) == 0) + { + result = ARCH_ARMV6; + } + + // starts with "arm": arm + else if (strncmp("arm", isa, strlen("arm")) == 0) + { + result = ARCH_ARM; + } + + // x86_64 or amd64: x64 + else if (strcmp("x86_64", isa) == 0 || + strcmp("amd64", isa) == 0) + { +#ifdef TARGET_OSX + int is_translated_process = 0; + size_t size = sizeof(is_translated_process); + if (sysctlbyname("sysctl.proc_translated", &is_translated_process, &size, NULL, 0) == 0 && is_translated_process == 1) + result = ARCH_ARM64; + else +#endif + result = ARCH_X64; + } + + // ix86 (possible values are i286, i386, i486, i586 and i686): x86 + else if (strlen(isa) == strlen("i386") && isa[0] == 'i' && isa[2] == '8' && isa[3] == '6') + { + result = ARCH_X86; + } + + else if (strcmp("s390x", isa) == 0) + { + result = ARCH_S390X; + } + + else if (strcmp("loongarch64", isa) == 0) + { + result = ARCH_LOONGARCH64; + } + } + } + + // catch if we have missed a pattern above. + assert(result != -1); + + return result; +#endif } diff --git a/src/native/libs/System.Native/pal_runtimeinformation.h b/src/native/libs/System.Native/pal_runtimeinformation.h index b03f7c8e9a0dc..5f6dc7ab8e2d9 100644 --- a/src/native/libs/System.Native/pal_runtimeinformation.h +++ b/src/native/libs/System.Native/pal_runtimeinformation.h @@ -11,16 +11,3 @@ PALEXPORT char* SystemNative_GetUnixRelease(void); PALEXPORT int32_t SystemNative_GetUnixVersion(char* version, int* capacity); PALEXPORT int32_t SystemNative_GetOSArchitecture(void); - -// Keep in sync with System.Runtime.InteropServices.Architecture enum -enum -{ - ARCH_X86, - ARCH_X64, - ARCH_ARM, - ARCH_ARM64, - ARCH_WASM, - ARCH_S390X, - ARCH_LOONGARCH64, - ARCH_ARMV6, -};