diff --git a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
index cff47e9ba910..795573e32150 100644
--- a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
+++ b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
@@ -3913,13 +3913,15 @@
"System.Reflection.MetadataLoadContext": {
"StableVersions": [
"4.6.0",
- "4.7.0"
+ "4.7.0",
+ "4.7.1"
],
"BaselineVersion": "4.7.0",
"InboxOn": {},
"AssemblyVersionInPackageVersion": {
"4.0.0.0": "4.6.0",
- "4.0.1.0": "4.7.0"
+ "4.0.1.0": "4.7.0",
+ "4.0.1.1": "4.7.1"
}
},
"System.Reflection.Primitives": {
diff --git a/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets b/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets
index 42748342b17e..fe177695deb9 100644
--- a/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets
+++ b/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets
@@ -1,25 +1,9 @@
- netcoreapp3.1
- 3.1
$(MicrosoftNETCoreAppPackageVersion)
-
-
-
-
-
diff --git a/src/System.Reflection.MetadataLoadContext/Directory.Build.props b/src/System.Reflection.MetadataLoadContext/Directory.Build.props
index 75494287ea74..6ad1324afccd 100644
--- a/src/System.Reflection.MetadataLoadContext/Directory.Build.props
+++ b/src/System.Reflection.MetadataLoadContext/Directory.Build.props
@@ -1,7 +1,8 @@
- 4.0.1.0
+ 4.7.1
+ 4.0.1.1
Open
\ No newline at end of file
diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs
index 6dbfe2dc1fb8..30baa5eec352 100644
--- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs
+++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs
@@ -36,7 +36,7 @@ private RoAssembly LoadFromStreamCore(Stream peStream)
{
pkt = defNameData.PublicKey.ComputePublicKeyToken();
}
- RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt);
+ RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt, defNameData.Flags);
RoAssembly winner = _loadedAssemblies.GetOrAdd(defName, candidate);
if (winner == candidate)
diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs
index c2c7948c46c5..94bea3a5ffd3 100644
--- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs
+++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs
@@ -77,8 +77,10 @@ public override Assembly Resolve(MetadataLoadContext context, AssemblyName assem
candidateWithSamePkt = assemblyFromPath;
}
}
- // If assemblyName does not specify a PublicKeyToken, then still consider those with a PublicKeyToken.
- else if (candidateWithSamePkt == null && pktFromName.IsEmpty)
+ // If assemblyName does not specify a PublicKeyToken, or assemblyName is marked 'Retargetable',
+ // then still consider those with a PublicKeyToken and take the highest version available.
+ else if ((candidateWithSamePkt == null && pktFromName.IsEmpty) ||
+ ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0))
{
// Pick the highest version.
if (candidateIgnoringPkt == null || assemblyNameFromPath.Version > candidateIgnoringPkt.GetName().Version)
diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs
index a6ecedc4d220..f84ce3b9c61b 100644
--- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs
+++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs
@@ -20,12 +20,13 @@ public static RoAssemblyName ToRoAssemblyName(this AssemblyReferenceHandle h, Me
string culture = a.Culture.GetStringOrNull(reader);
byte[] pkOrPkt = a.PublicKeyOrToken.GetBlobBytes(reader);
AssemblyFlags flags = a.Flags;
+ AssemblyNameFlags assemblyNameFlags = Helpers.ConvertAssemblyFlagsToAssemblyNameFlags(flags);
if ((flags & AssemblyFlags.PublicKey) != 0)
{
pkOrPkt = pkOrPkt.ComputePublicKeyToken();
}
- return new RoAssemblyName(name, version, culture, pkOrPkt);
+ return new RoAssemblyName(name, version, culture, pkOrPkt, assemblyNameFlags);
}
public static CoreType ToCoreType(this PrimitiveTypeCode typeCode)
diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs
index 78f1e50174cf..c633fc029fd2 100644
--- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs
+++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs
@@ -154,6 +154,18 @@ public static byte[] ComputePublicKeyToken(this byte[] pkt)
return an.GetPublicKeyToken();
}
+ public static AssemblyNameFlags ConvertAssemblyFlagsToAssemblyNameFlags(AssemblyFlags assemblyFlags)
+ {
+ AssemblyNameFlags assemblyNameFlags = AssemblyNameFlags.None;
+
+ if ((assemblyFlags & AssemblyFlags.Retargetable) != 0)
+ {
+ assemblyNameFlags |= AssemblyNameFlags.Retargetable;
+ }
+
+ return assemblyNameFlags;
+ }
+
//
// Note that for a top level type, the resulting ns is string.Empty, *not* null.
// This is a concession to the fact that MetadataReader's fast String equal methods
@@ -350,7 +362,7 @@ public static RoAssemblyName ToRoAssemblyName(this AssemblyName assemblyName)
// as the original is wide open to tampering by anyone.
byte[] pkt = assemblyName.GetPublicKeyToken().CloneArray();
- return new RoAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, pkt);
+ return new RoAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, pkt, assemblyName.Flags);
}
public static byte[] ToUtf8(this string s) => Encoding.UTF8.GetBytes(s);
diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs
index 1d787dd427a1..67631b7720d8 100644
--- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs
+++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs
@@ -25,13 +25,14 @@ internal sealed class RoAssemblyName : IEquatable
public string CultureName { get; }
public byte[] PublicKeyToken;
- // We don't need to store the flags. The only flag allowed in an ECMA-335 AssemblyReference is the "PublicKey" bit. Since
- // RoAssemblyName always normalizes to the short form public key token, that bit would always be 0, and hence the flag enum as a whole
- // would always be zero.
+ // We store the flags to support "Retargetable".
+ // The only flag allowed in an ECMA-335 AssemblyReference is the "PublicKey" bit. Since
+ // RoAssemblyName always normalizes to the short form public key token, that bit would always be 0.
+ public AssemblyNameFlags Flags { get; }
private static readonly Version s_Version0000 = new Version(0, 0, 0, 0);
- public RoAssemblyName(string name, Version version, string cultureName, byte[] publicKeyToken)
+ public RoAssemblyName(string name, Version version, string cultureName, byte[] publicKeyToken, AssemblyNameFlags flags)
{
// We forcefully normalize the representation so that Equality is dependable and fast.
Debug.Assert(name != null);
@@ -40,6 +41,7 @@ public RoAssemblyName(string name, Version version, string cultureName, byte[] p
Version = version ?? s_Version0000;
CultureName = cultureName ?? string.Empty;
PublicKeyToken = publicKeyToken ?? Array.Empty();
+ Flags = flags;
}
public string FullName => ToAssemblyName().FullName;
@@ -57,6 +59,9 @@ public bool Equals(RoAssemblyName other)
return false;
if (!(((ReadOnlySpan)PublicKeyToken).SequenceEqual(other.PublicKeyToken)))
return false;
+
+ // Do not compare Flags; we do not want to treat AssemblyNames as not being equal due to Flags.
+
return true;
}
@@ -71,6 +76,7 @@ public AssemblyName ToAssemblyName()
Name = Name,
Version = Version,
CultureName = CultureName,
+ Flags = Flags,
};
// We must not hand out our own copy of the PKT to AssemblyName as AssemblyName is amazingly trusting and gives untrusted callers
diff --git a/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs b/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs
index ea532403db41..940624bcfefa 100644
--- a/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs
+++ b/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs
@@ -3011,5 +3011,69 @@ internal static class TestData
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"AAAAAAAAAAAAAAAA"
);
+
+ //// Metadata version: v4.0.30319
+ //.assembly extern retargetable mscorlib
+ // {
+ // .publickeytoken = (7C EC 85 D7 BE A7 79 8E ) // |.....y.
+ // .ver 2:0:5:0
+ //}
+ //.assembly SimpleAssembly
+ // {
+ // .custom instance void [mscorlib]
+ // System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
+ // .custom instance void [mscorlib]
+ // System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
+ // 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
+ // // --- The following custom attribute is added automatically, do not uncomment -------
+ // // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
+ // .hash algorithm 0x00008004
+ // .ver 0:0:0:0
+ //}
+ //.module SimpleAssembly.dll
+ //// MVID: {DCD1E0C4-4B2E-4E02-952F-DA6B0600F478}
+ //.imagebase 0x10000000
+ //.file alignment 0x00000200
+ //.stackreserve 0x00100000
+ //.subsystem 0x0003 // WINDOWS_CUI
+ //.corflags 0x00000001 // ILONLY
+ //// Image base: 0x03550000
+ public static readonly string s_RetargetableAssemblySimpleName = "SimpleAssembly";
+ public static readonly byte[] s_RetargetableImage = Convert.FromBase64String(
+ "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFt" +
+ "IGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEDAP1PYF0AAAAAAAAAAOAAIiALATAAAAQAAAAGAAAAAAAAfiMAAAAgAAAAQAAA" +
+ "AAAAEAAgAAAAAgAABAAAAAAAAAAEAAAAAAAAAACAAAAAAgAAAAAAAAMAQIUAABAAABAAAAAAEAAAEAAAAAAAABAAAAAAAAAAAAAAACwjAABPAAAAAEAAAMAC" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAGAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAACAAAAAAAAAAAAAAA" +
+ "CCAAAEgAAAAAAAAAAAAAAC50ZXh0AAAAhAMAAAAgAAAABAAAAAIAAAAAAAAAAAAAAAAAACAAAGAucnNyYwAAAMACAAAAQAAAAAQAAAAGAAAAAAAAAAAAAAAA" +
+ "AABAAABALnJlbG9jAAAMAAAAAGAAAAACAAAACgAAAAAAAAAAAAAAAAAAQAAAQgAAAAAAAAAAAAAAAAAAAABgIwAAAAAAAEgAAAACAAUAXCAAANACAAABAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACICKAQAAAoAKgAAAEJTSkIBAAEAAAAAAAwAAAB2NC4wLjMwMzE5" +
+ "AAAAAAUAbAAAAPAAAAAjfgAAXAEAABABAAAjU3RyaW5ncwAAAABsAgAABAAAACNVUwBwAgAAEAAAACNHVUlEAAAAgAIAAFAAAAAjQmxvYgAAAAAAAAACAAAB" +
+ "VxQAAAkAAAAA+gEzABYAAAEAAAAGAAAAAgAAAAEAAAABAAAABAAAAAMAAAABAAAAAQAAAAAAdAABAAAAAAAGADAApwAGAFAApwAGABwAlAAPAMcAAAAGAPEA" +
+ "hwAGAPgA1gAAAAAAAQAAAAAAAQABAAEAEADpABMAFQABAAEAFgBuABkAUCAAAAAAhhiOAAYAAQAJAI4AAQARAI4ABgAZAI4ACgApAI4ABgAuAAsAHQAuABMA" +
+ "JgAuABsARQAEgAAAAAAAAAAAAAAAAAAAAAABAQAAAgAAAAUAAAAAAQAAEAAKAAAAAAAAAAA8TW9kdWxlPgBtc2NvcmxpYgBSZWxvY2F0ZQBEZWJ1Z2dhYmxl" +
+ "QXR0cmlidXRlAENvbXBpbGF0aW9uUmVsYXhhdGlvbnNBdHRyaWJ1dGUAUnVudGltZUNvbXBhdGliaWxpdHlBdHRyaWJ1dGUATXlPYmoAU2ltcGxlQXNzZW1i" +
+ "bHkuZGxsAFN5c3RlbQAuY3RvcgBTeXN0ZW0uRGlhZ25vc3RpY3MAU3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcwBEZWJ1Z2dpbmdNb2RlcwBTeXN0" +
+ "ZW0uQ29sbGVjdGlvbnMATXlDbGFzcwBPYmplY3QAQml0QXJyYXkAU2ltcGxlQXNzZW1ibHkAAAAAAMTg0dwuSwJOlS/aawYA9HgABCABAQgDIAABBSABARER" +
+ "CHzshde+p3mOAwYSGQgBAAgAAAAAAB4BAAEAVAIWV3JhcE5vbkV4Y2VwdGlvblRocm93cwEIAQAHAQAAAAAAAFQjAAAAAAAAAAAAAG4jAAAAIAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAABgIwAAAAAAAAAAAAAAAF9Db3JEbGxNYWluAG1zY29yZWUuZGxsAAAAAAD/JQAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAAAYAACAAAAAAAAAAAAAAAAAAAABAAEAAAAwAACAAAAAAAAAAAAAAAAAAAABAAAAAABIAAAAWEAAAGQCAAAAAAAA" +
+ "AAAAAGQCNAAAAFYAUwBfAFYARQBSAFMASQBPAE4AXwBJAE4ARgBPAAAAAAC9BO/+AAABAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAQAAAACAAAAAAAAAAAA" +
+ "AAAAAAAARAAAAAEAVgBhAHIARgBpAGwAZQBJAG4AZgBvAAAAAAAkAAQAAABUAHIAYQBuAHMAbABhAHQAaQBvAG4AAAAAAAAAsATEAQAAAQBTAHQAcgBpAG4A" +
+ "ZwBGAGkAbABlAEkAbgBmAG8AAACgAQAAAQAwADAAMAAwADAANABiADAAAAAsAAIAAQBGAGkAbABlAEQAZQBzAGMAcgBpAHAAdABpAG8AbgAAAAAAIAAAADAA" +
+ "CAABAEYAaQBsAGUAVgBlAHIAcwBpAG8AbgAAAAAAMAAuADAALgAwAC4AMAAAAEYAEwABAEkAbgB0AGUAcgBuAGEAbABOAGEAbQBlAAAAUwBpAG0AcABsAGUA" +
+ "QQBzAHMAZQBtAGIAbAB5AC4AZABsAGwAAAAAACgAAgABAEwAZQBnAGEAbABDAG8AcAB5AHIAaQBnAGgAdAAAACAAAABOABMAAQBPAHIAaQBnAGkAbgBhAGwA" +
+ "RgBpAGwAZQBuAGEAbQBlAAAAUwBpAG0AcABsAGUAQQBzAHMAZQBtAGIAbAB5AC4AZABsAGwAAAAAADQACAABAFAAcgBvAGQAdQBjAHQAVgBlAHIAcwBpAG8A" +
+ "bgAAADAALgAwAC4AMAAuADAAAAA4AAgAAQBBAHMAcwBlAG0AYgBsAHkAIABWAGUAcgBzAGkAbwBuAAAAMAAuADAALgAwAC4AMAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAMAAAAgDMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
+ "AAAAAAAAAAAAAAAA");
}
}
diff --git a/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs b/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs
index 4cc6fcf5d1b1..0675f651eef7 100644
--- a/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs
+++ b/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs
@@ -245,7 +245,7 @@ public static void DuplicateUnsignedAssembliesSameVersions()
}
}
- [Fact]
+ [Fact]
public static void DuplicateUnsignedAssembliesSameVersionsDifferentLocale()
{
using (TempDirectory dir = new TempDirectory())
@@ -324,5 +324,54 @@ public static void DuplicateSignedAndUnsignedAssemblies()
}
}
}
+
+ [Fact]
+ public static void RelocatableAssembly()
+ {
+ string coreAssemblyPath = TestUtils.GetPathToCoreAssembly();
+ string coreAssemblyName = Path.GetFileNameWithoutExtension(coreAssemblyPath);
+
+ // Ensure mscorlib is specified since we want to relocate an older mscorlib later.
+ string coreDirectory = Path.GetDirectoryName(coreAssemblyPath);
+ string mscorLibPath = Path.Combine(coreDirectory, "mscorlib.dll");
+
+ using (TempDirectory dir = new TempDirectory())
+ using (TempFile relocatableAsmFile = new TempFile(Path.Combine(dir.Path, TestData.s_RetargetableAssemblySimpleName), TestData.s_RetargetableImage))
+ {
+ var resolver = new PathAssemblyResolver(new string[] { coreAssemblyPath, mscorLibPath, relocatableAsmFile.Path });
+
+ using (MetadataLoadContext lc = new MetadataLoadContext(resolver, coreAssemblyName))
+ {
+ Assembly retargetableAssembly = lc.LoadFromAssemblyName(TestData.s_RetargetableAssemblySimpleName);
+ Assert.NotNull(retargetableAssembly);
+
+ // The assembly only contains a reference to an older, retargetable mscorlib.
+ AssemblyName[] assemblyNames = retargetableAssembly.GetReferencedAssemblies();
+ AssemblyName retargetableAssemblyName = assemblyNames[0];
+ Assert.Equal(AssemblyNameFlags.Retargetable, retargetableAssemblyName.Flags);
+ Assert.Equal(new Version(2,0,5,0), retargetableAssemblyName.Version);
+
+ // Trigger PathAssemblyResolver.Resolve for the older mscorlib.
+ Type myType = retargetableAssembly.GetType("Relocate.MyClass");
+ FieldInfo[] fields = myType.GetFields();
+ Assert.Equal(1, fields.Length);
+ FieldInfo field = fields[0];
+ Assert.Equal("MyObj", field.Name);
+
+ // Verify that LoadFromAssemblyName also finds the newer mscorlib.
+ Assembly mscorlib = lc.LoadFromAssemblyName(retargetableAssemblyName);
+ Assert.True(mscorlib.GetName().Version > retargetableAssemblyName.Version);
+
+ // The older reference has a different public key token, which requires AssemblyNameFlags.Retargetable to find the newer assembly.
+ byte[] newerPKT = mscorlib.GetName().GetPublicKeyToken();
+ Assert.NotEmpty(newerPKT);
+
+ byte[] olderPKT = retargetableAssemblyName.GetPublicKeyToken();
+ Assert.NotEmpty(olderPKT);
+
+ Assert.False(Enumerable.SequenceEqual(newerPKT, olderPKT));
+ }
+ }
+ }
}
}
diff --git a/src/packages.builds b/src/packages.builds
index 55f7886509ec..54efe3c3736c 100644
--- a/src/packages.builds
+++ b/src/packages.builds
@@ -26,6 +26,9 @@
$(AdditionalProperties)
+
+ $(AdditionalProperties)
+