From cb5f0afd7fa056ee720864985da424090183d7d8 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Mon, 25 Apr 2022 07:04:00 +0300 Subject: [PATCH] Identify OSArchitecture at run-time (#60910) * Identify OSArchitecture at run-time * Move ProcessArchitecture in common partial * Add a comment in ntimage.h about its source Co-authored-by: Jan Kotas --- src/coreclr/pal/inc/rt/ntimage.h | 3 + .../Interop.GetOSArchitecture.cs | 1 - .../System.Private.CoreLib.Shared.projitems | 1 - .../RuntimeInformation.ProcessArchitecture.cs | 29 ------ .../RuntimeInformation.Windows.cs | 51 +++++++++-- .../InteropServices/RuntimeInformation.cs | 21 +++++ .../System.Native/pal_runtimeinformation.c | 90 ++++++++++++++++++- .../System.Native/pal_runtimeinformation.h | 13 --- 8 files changed, 158 insertions(+), 51 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs diff --git a/src/coreclr/pal/inc/rt/ntimage.h b/src/coreclr/pal/inc/rt/ntimage.h index e6970cca7cd38..f722da0e4b1af 100644 --- a/src/coreclr/pal/inc/rt/ntimage.h +++ b/src/coreclr/pal/inc/rt/ntimage.h @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // +// This file is a verbatim copy of the Windows OS header with PE file structure definitions. + + // // =========================================================================== // File: ntimage.h 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.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index f300f866f91a7..b2a4460e5909e 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -885,7 +885,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs deleted file mode 100644 index d11391a001ef9..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.InteropServices -{ - public static partial class RuntimeInformation - { - public static Architecture ProcessArchitecture -#if TARGET_X86 - => Architecture.X86; -#elif TARGET_AMD64 - => Architecture.X64; -#elif TARGET_ARMV6 - => Architecture.Armv6; -#elif TARGET_ARM - => Architecture.Arm; -#elif TARGET_ARM64 - => Architecture.Arm64; -#elif TARGET_WASM - => Architecture.Wasm; -#elif TARGET_S390X - => Architecture.S390x; -#elif TARGET_LOONGARCH64 - => Architecture.LoongArch64; -#else -#error Unknown Architecture -#endif - } -} 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..57339fdca2275 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. Falling back to ProcessArchitecture"); + osArch = (int)ProcessArchitecture; + } + } + else + { + 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,27 @@ private static Architecture Map(int processorArchitecture) return Architecture.X86; } } + + private static Architecture MapMachineConstant(ushort processMachine) + { + switch (processMachine) + { + 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/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.cs index 46f80f2dfc16d..2d24563212bb5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.cs @@ -50,5 +50,26 @@ public static string FrameworkDescription /// Indicates whether the current application is running on the specified platform. /// public static bool IsOSPlatform(OSPlatform osPlatform) => OperatingSystem.IsOSPlatform(osPlatform.Name); + + public static Architecture ProcessArchitecture +#if TARGET_X86 + => Architecture.X86; +#elif TARGET_AMD64 + => Architecture.X64; +#elif TARGET_ARMV6 + => Architecture.Armv6; +#elif TARGET_ARM + => Architecture.Arm; +#elif TARGET_ARM64 + => Architecture.Arm64; +#elif TARGET_WASM + => Architecture.Wasm; +#elif TARGET_S390X + => Architecture.S390x; +#elif TARGET_LOONGARCH64 + => Architecture.LoongArch64; +#else +#error Unknown Architecture +#endif } } diff --git a/src/native/libs/System.Native/pal_runtimeinformation.c b/src/native/libs/System.Native/pal_runtimeinformation.c index 0551351b3520f..a2a8fb225ba60 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,89 @@ 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, -};