From 733ef8c0468c3e855b084baedb36c78ab2aed592 Mon Sep 17 00:00:00 2001 From: vsadov <8218165+VSadov@users.noreply.github.com> Date: Thu, 12 Jan 2023 15:13:58 -0800 Subject: [PATCH 1/5] Set AssemblyName.ProcessorArchitecture for compatibility. --- .../Metadata/MetadataReader.netstandard.cs | 68 +++++++++++++++++++ .../tests/Metadata/MetadataReaderTests.cs | 7 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs index 49406b39dec156..eee234704d22a6 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs @@ -85,6 +85,13 @@ public static unsafe AssemblyName GetAssemblyName(string assemblyFile) peReader = new PEReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength); MetadataReader mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); AssemblyName assemblyName = mdReader.GetAssemblyDefinition().GetAssemblyName(); + + GetPEKind(peReader, out PortableExecutableKinds peKind, out ImageFileMachine machine); + AssemblyFlags aFlags = mdReader.AssemblyTable.GetFlags(); +#pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete + assemblyName.ProcessorArchitecture = CalculateProcArchIndex(peKind, machine, aFlags); +#pragma warning restore SYSLIB0037 + return assemblyName; } finally @@ -101,6 +108,67 @@ public static unsafe AssemblyName GetAssemblyName(string assemblyFile) } } + private static void GetPEKind(PEReader peReader, out PortableExecutableKinds peKind, out ImageFileMachine machine) + { + PEHeaders peHeaders = peReader.PEHeaders; + PEMagic peMagic = peHeaders.PEHeader!.Magic; + Machine coffMachine = peHeaders.CoffHeader.Machine; + CorFlags corFlags = peHeaders.CorHeader!.Flags; + + peKind = default; + if ((corFlags & CorFlags.ILOnly) != 0) + peKind |= PortableExecutableKinds.ILOnly; + + if ((corFlags & CorFlags.Prefers32Bit) != 0) + peKind |= PortableExecutableKinds.Preferred32Bit; + else if ((corFlags & CorFlags.Requires32Bit) != 0) + peKind |= PortableExecutableKinds.Required32Bit; + + if (peMagic == PEMagic.PE32Plus) + peKind |= PortableExecutableKinds.PE32Plus; + + machine = (ImageFileMachine)coffMachine; + } + + private static ProcessorArchitecture CalculateProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyFlags flags) + { + if (((uint)flags & 0xF0) == 0x70) + return ProcessorArchitecture.None; + + if ((pek & PortableExecutableKinds.PE32Plus) == PortableExecutableKinds.PE32Plus) + { + switch (ifm) + { + case ImageFileMachine.IA64: + return ProcessorArchitecture.IA64; + case ImageFileMachine.AMD64: + return ProcessorArchitecture.Amd64; + case ImageFileMachine.I386: + if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) + return ProcessorArchitecture.MSIL; + break; + } + } + else + { + if (ifm == ImageFileMachine.I386) + { + if ((pek & PortableExecutableKinds.Required32Bit) == PortableExecutableKinds.Required32Bit) + return ProcessorArchitecture.X86; + + if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) + return ProcessorArchitecture.MSIL; + + return ProcessorArchitecture.X86; + } + if (ifm == ImageFileMachine.ARM) + { + return ProcessorArchitecture.Arm; + } + } + return ProcessorArchitecture.None; + } + private static AssemblyNameFlags GetAssemblyNameFlags(AssemblyFlags flags) { AssemblyNameFlags assemblyNameFlags = AssemblyNameFlags.None; diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs index dad27d509ac645..a30606af963bf8 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs @@ -3091,7 +3091,12 @@ public void GetAssemblyName() if (PlatformDetection.HasAssemblyFiles) { Assembly a = typeof(MetadataReaderTests).Assembly; - Assert.Equal(new AssemblyName(a.FullName).ToString(), MetadataReader.GetAssemblyName(AssemblyPathHelper.GetAssemblyLocation(a)).ToString()); + AssemblyName name = MetadataReader.GetAssemblyName(AssemblyPathHelper.GetAssemblyLocation(a)); + Assert.Equal(new AssemblyName(a.FullName).ToString(), name.ToString()); + +#pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete + Assert.Equal(ProcessorArchitecture.MSIL, name.ProcessorArchitecture); +#pragma warning restore SYSLIB0037 } } } From c22d17fbe89125e89fc1fbfd4289c2890bf60fc3 Mon Sep 17 00:00:00 2001 From: vsadov <8218165+VSadov@users.noreply.github.com> Date: Tue, 17 Jan 2023 17:42:33 -0800 Subject: [PATCH 2/5] Simplified ProcArch computation. --- .../System/Reflection/AssemblyName.CoreCLR.cs | 55 ++++++------- .../Metadata/MetadataReader.netstandard.cs | 80 +++++++------------ 2 files changed, 52 insertions(+), 83 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs index 6d02f9d8ed6f81..48396e6dd42ef9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs @@ -106,46 +106,41 @@ internal AssemblyNameFlags RawFlags internal void SetProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm) { #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - ProcessorArchitecture = CalculateProcArchIndex(pek, ifm, _flags); + ProcessorArchitecture = CalculateProcArch(pek, ifm, _flags); #pragma warning restore SYSLIB0037 } - private static ProcessorArchitecture CalculateProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyNameFlags flags) + private static ProcessorArchitecture CalculateProcArch(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyNameFlags aFlags) { - if (((uint)flags & 0xF0) == 0x70) + // 0x70 specifies "reference assembly". + // For these, CLR wants to return None as arch so they can be always loaded, regardless of process type. + if (((uint)aFlags & 0xF0) == 0x70) return ProcessorArchitecture.None; - if ((pek & PortableExecutableKinds.PE32Plus) == PortableExecutableKinds.PE32Plus) + switch (ifm) { - switch (ifm) - { - case ImageFileMachine.IA64: - return ProcessorArchitecture.IA64; - case ImageFileMachine.AMD64: - return ProcessorArchitecture.Amd64; - case ImageFileMachine.I386: - if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) + case ImageFileMachine.IA64: + return ProcessorArchitecture.IA64; + case ImageFileMachine.ARM: + return ProcessorArchitecture.Arm; + case ImageFileMachine.AMD64: + return ProcessorArchitecture.Amd64; + case ImageFileMachine.I386: + { + if ((pek & PortableExecutableKinds.ILOnly) != 0 && + (pek & PortableExecutableKinds.Required32Bit) == 0) + { + // platform neutral. return ProcessorArchitecture.MSIL; - break; - } - } - else - { - if (ifm == ImageFileMachine.I386) - { - if ((pek & PortableExecutableKinds.Required32Bit) == PortableExecutableKinds.Required32Bit) - return ProcessorArchitecture.X86; + } - if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) - return ProcessorArchitecture.MSIL; - - return ProcessorArchitecture.X86; - } - if (ifm == ImageFileMachine.ARM) - { - return ProcessorArchitecture.Arm; - } + // requires x86 + return ProcessorArchitecture.X86; + } } + + // ProcessorArchitecture is a legacy API and does not cover other Machine kinds. + // For example ARM64 is not expressible return ProcessorArchitecture.None; } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs index eee234704d22a6..37c4c197a68e9a 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs @@ -86,10 +86,9 @@ public static unsafe AssemblyName GetAssemblyName(string assemblyFile) MetadataReader mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); AssemblyName assemblyName = mdReader.GetAssemblyDefinition().GetAssemblyName(); - GetPEKind(peReader, out PortableExecutableKinds peKind, out ImageFileMachine machine); AssemblyFlags aFlags = mdReader.AssemblyTable.GetFlags(); #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - assemblyName.ProcessorArchitecture = CalculateProcArchIndex(peKind, machine, aFlags); + assemblyName.ProcessorArchitecture = CalculateProcArch(peReader, aFlags); #pragma warning restore SYSLIB0037 return assemblyName; @@ -108,64 +107,39 @@ public static unsafe AssemblyName GetAssemblyName(string assemblyFile) } } - private static void GetPEKind(PEReader peReader, out PortableExecutableKinds peKind, out ImageFileMachine machine) + private static ProcessorArchitecture CalculateProcArch(PEReader peReader, AssemblyFlags aFlags) { - PEHeaders peHeaders = peReader.PEHeaders; - PEMagic peMagic = peHeaders.PEHeader!.Magic; - Machine coffMachine = peHeaders.CoffHeader.Machine; - CorFlags corFlags = peHeaders.CorHeader!.Flags; - - peKind = default; - if ((corFlags & CorFlags.ILOnly) != 0) - peKind |= PortableExecutableKinds.ILOnly; - - if ((corFlags & CorFlags.Prefers32Bit) != 0) - peKind |= PortableExecutableKinds.Preferred32Bit; - else if ((corFlags & CorFlags.Requires32Bit) != 0) - peKind |= PortableExecutableKinds.Required32Bit; - - if (peMagic == PEMagic.PE32Plus) - peKind |= PortableExecutableKinds.PE32Plus; - - machine = (ImageFileMachine)coffMachine; - } - - private static ProcessorArchitecture CalculateProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyFlags flags) - { - if (((uint)flags & 0xF0) == 0x70) + // 0x70 specifies "reference assembly". + // For these, CLR wants to return None as arch so they can be always loaded, regardless of process type. + if (((uint)aFlags & 0xF0) == 0x70) return ProcessorArchitecture.None; - if ((pek & PortableExecutableKinds.PE32Plus) == PortableExecutableKinds.PE32Plus) + PEHeaders peHeaders = peReader.PEHeaders; + switch (peHeaders.CoffHeader.Machine) { - switch (ifm) - { - case ImageFileMachine.IA64: - return ProcessorArchitecture.IA64; - case ImageFileMachine.AMD64: - return ProcessorArchitecture.Amd64; - case ImageFileMachine.I386: - if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) + case Machine.IA64: + return ProcessorArchitecture.IA64; + case Machine.Arm: + return ProcessorArchitecture.Arm; + case Machine.Amd64: + return ProcessorArchitecture.Amd64; + case Machine.I386: + { + CorFlags flags = peHeaders.CorHeader!.Flags; + if ((flags & CorFlags.ILOnly) != 0 && + (flags & CorFlags.Requires32Bit) == 0) + { + // platform neutral. return ProcessorArchitecture.MSIL; - break; - } - } - else - { - if (ifm == ImageFileMachine.I386) - { - if ((pek & PortableExecutableKinds.Required32Bit) == PortableExecutableKinds.Required32Bit) - return ProcessorArchitecture.X86; - - if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) - return ProcessorArchitecture.MSIL; + } - return ProcessorArchitecture.X86; - } - if (ifm == ImageFileMachine.ARM) - { - return ProcessorArchitecture.Arm; - } + // requires x86 + return ProcessorArchitecture.X86; + } } + + // ProcessorArchitecture is a legacy API and does not cover other Machine kinds. + // For example ARM64 is not expressible return ProcessorArchitecture.None; } From 3338accbdd5404fbdfb88e15ff10776db6c055b1 Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Fri, 20 Jan 2023 15:38:03 -0800 Subject: [PATCH 3/5] Make GetAssemblyName test more robust (#80878) --- .../tests/Metadata/MetadataReaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs index a30606af963bf8..3b946e5a807795 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs @@ -3090,7 +3090,7 @@ public void GetAssemblyName() if (PlatformDetection.HasAssemblyFiles) { - Assembly a = typeof(MetadataReaderTests).Assembly; + Assembly a = typeof(MetadataReader).Assembly; AssemblyName name = MetadataReader.GetAssemblyName(AssemblyPathHelper.GetAssemblyLocation(a)); Assert.Equal(new AssemblyName(a.FullName).ToString(), name.ToString()); From b1332708bcae92bb3a8c286a1ccb14ab48909dc8 Mon Sep 17 00:00:00 2001 From: vsadov <8218165+VSadov@users.noreply.github.com> Date: Tue, 24 Jan 2023 09:58:34 -0800 Subject: [PATCH 4/5] undo AssemblyName.CoreCLR change --- .../System/Reflection/AssemblyName.CoreCLR.cs | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs index 48396e6dd42ef9..6d02f9d8ed6f81 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs @@ -106,41 +106,46 @@ internal AssemblyNameFlags RawFlags internal void SetProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm) { #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - ProcessorArchitecture = CalculateProcArch(pek, ifm, _flags); + ProcessorArchitecture = CalculateProcArchIndex(pek, ifm, _flags); #pragma warning restore SYSLIB0037 } - private static ProcessorArchitecture CalculateProcArch(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyNameFlags aFlags) + private static ProcessorArchitecture CalculateProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm, AssemblyNameFlags flags) { - // 0x70 specifies "reference assembly". - // For these, CLR wants to return None as arch so they can be always loaded, regardless of process type. - if (((uint)aFlags & 0xF0) == 0x70) + if (((uint)flags & 0xF0) == 0x70) return ProcessorArchitecture.None; - switch (ifm) + if ((pek & PortableExecutableKinds.PE32Plus) == PortableExecutableKinds.PE32Plus) { - case ImageFileMachine.IA64: - return ProcessorArchitecture.IA64; - case ImageFileMachine.ARM: - return ProcessorArchitecture.Arm; - case ImageFileMachine.AMD64: - return ProcessorArchitecture.Amd64; - case ImageFileMachine.I386: - { - if ((pek & PortableExecutableKinds.ILOnly) != 0 && - (pek & PortableExecutableKinds.Required32Bit) == 0) - { - // platform neutral. + switch (ifm) + { + case ImageFileMachine.IA64: + return ProcessorArchitecture.IA64; + case ImageFileMachine.AMD64: + return ProcessorArchitecture.Amd64; + case ImageFileMachine.I386: + if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) return ProcessorArchitecture.MSIL; - } - - // requires x86 - return ProcessorArchitecture.X86; - } + break; + } } + else + { + if (ifm == ImageFileMachine.I386) + { + if ((pek & PortableExecutableKinds.Required32Bit) == PortableExecutableKinds.Required32Bit) + return ProcessorArchitecture.X86; + + if ((pek & PortableExecutableKinds.ILOnly) == PortableExecutableKinds.ILOnly) + return ProcessorArchitecture.MSIL; - // ProcessorArchitecture is a legacy API and does not cover other Machine kinds. - // For example ARM64 is not expressible + return ProcessorArchitecture.X86; + } + if (ifm == ImageFileMachine.ARM) + { + return ProcessorArchitecture.Arm; + } + } return ProcessorArchitecture.None; } From 6decafcf2948ed2eab73ea53e3b6007527c1f385 Mon Sep 17 00:00:00 2001 From: vsadov <8218165+VSadov@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:24:26 -0800 Subject: [PATCH 5/5] Library servicing steps. --- .../src/System.Reflection.Metadata.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index 73a99e80c14fed..ae0cd121a97b6c 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -9,6 +9,8 @@ The System.Reflection.Metadata library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks. README.md + 1 + true