Skip to content

Commit

Permalink
Identify OSArchitecture at run-time (#60910)
Browse files Browse the repository at this point in the history
* Identify OSArchitecture at run-time

* Move ProcessArchitecture in common partial

* Add a comment in ntimage.h about its source

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
am11 and jkotas committed Apr 25, 2022
1 parent 47d9c43 commit cb5f0af
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 51 deletions.
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);
}
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;
}
}
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;

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;
}
}
}
}
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 (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
}
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,
};

0 comments on commit cb5f0af

Please sign in to comment.