Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identify OSArchitecture at run-time #60910

Merged
merged 10 commits into from
Apr 25, 2022
3 changes: 3 additions & 0 deletions src/coreclr/pal/inc/rt/ntimage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PreserveSigAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ProgIdAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\RuntimeInformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\RuntimeInformation.ProcessArchitecture.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\SafeArrayRankMismatchException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\SafeArrayTypeMismatchException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\SafeBuffer.cs" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,44 @@ public static string OSDescription
}
}

public static Architecture OSArchitecture
public static unsafe Architecture OSArchitecture
{
get
{
int osArch = s_osArchPlusOne - 1;

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<IntPtr, ushort*, ushort*, int>)isWow64Process2Ptr;
if (isWow64Process2(Interop.Kernel32.GetCurrentProcess(), &processMachine, &nativeMachine) != 0)
{
osArch = (int)MapMachineConstant(nativeMachine);
}
am11 marked this conversation as resolved.
Show resolved Hide resolved
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any meed to moving this line? - It will be optimised out in Release/retail builds anyway during compilation.

}

Debug.Assert(osArch >= 0);
return (Architecture)osArch;
}
}
Expand All @@ -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;

am11 marked this conversation as resolved.
Show resolved Hide resolved
case 0x014C: // IMAGE_FILE_MACHINE_I386
return Architecture.X86;
am11 marked this conversation as resolved.
Show resolved Hide resolved

default: // IMAGE_FILE_MACHINE_UNKNOWN etc.
Debug.Fail("Unidentified OS Architecture. Falling back to ProcessArchitecture");
return ProcessArchitecture;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,26 @@ public static string FrameworkDescription
/// Indicates whether the current application is running on the specified platform.
/// </summary>
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
}
}
90 changes: 88 additions & 2 deletions src/native/libs/System.Native/pal_runtimeinformation.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
#include "pal_config.h"
#include "pal_runtimeinformation.h"
#include "pal_types.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>
#if defined(TARGET_ANDROID)
#include <sys/system_properties.h>
#elif defined(TARGET_OSX)
#include <sys/sysctl.h>
#elif defined(TARGET_SUNOS)
#include <sys/systeminfo.h>
#endif

char* SystemNative_GetUnixRelease()
Expand Down Expand Up @@ -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 (isa[0] == 'i' && isa[2] == '8' && isa[3] == '6')
am11 marked this conversation as resolved.
Show resolved Hide resolved
{
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
}
13 changes: 0 additions & 13 deletions src/native/libs/System.Native/pal_runtimeinformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};