-
Notifications
You must be signed in to change notification settings - Fork 586
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
dnlib fails to resolve types according to framework version #20
Comments
What fails, the resolver? Does it work if you force the assembly resolver to only resolve .NET 4.0 assemblies by updating the search paths? Also, do you have a simple test program? |
I do have a test program, however it's quite complex: using System;
public class TestA {
public static void Test(Action act) {
act();
}
} Second, create an application in .NET 4.0, referencing the first library: using System;
public class TestB {
public static void Main() {
TestA.Test(() => Console.WriteLine("OK"));
}
} Then the following code would demonstrate the issue: using System;
using System.Diagnostics;
using dnlib;
using dnlib.DotNet;
class Program {
static void Main(string[] args) {
var module = ModuleDefMD.Load(@"SampleB.exe");
var type = module.Find("TestB", true);
var method = type.FindMethod("Main");
foreach (var instr in method.Body.Instructions) {
if (instr.Operand is IMethod && ((IMethod)instr.Operand).Name == "Test") {
var methodRef = (IMethod)instr.Operand;
var methodDef = methodRef.ResolveMethodDef();
Debug.Assert(methodDef != null);
}
}
}
} The assertion failed here. It should be able to resolve to TestA.Test in the first library.
However, I'm unable to find where this 'framework config' is located. |
Yes, and make sure they're empty first so it won't try to keep looking if it doesn't find the exact assembly (correct name + version). FindExactMatch prop should also be false. |
It works when I use the following module loading code: var resolver = new AssemblyResolver();
resolver.PreSearchPaths.Clear();
resolver.PreSearchPaths.Add(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\");
resolver.FindExactMatch = false;
var moduleCtx = ModuleDefMD.CreateModuleContext(false);
moduleCtx.AssemblyResolver = resolver;
var module = ModuleDefMD.Load(@"SampleB.exe", moduleCtx); |
Cool, I might add some code (simple methods to call) to make that easier so you don't have to add the paths yourself like above. FindExactMatch should be false by default though, but I mentioned it above just in case you had set it to true. |
So does it mean there should be 2 different assembly resolvers, one for .NET 3.5, one for .NET 4, for dnlib to resolve the references correctly? |
No, but if you have 2+ assemblies and you know that the main exe will use .NET 4.0, then you might need to make sure only .NET 4.0 search paths are used if the other one uses another earlier .NET version, as in your example above. This would match the runtime's behaviour: .NET 4.0 runtime only searches for .NET 4.0 DLLs. By default, dnlib will try to use the exact DLL file because I think this is what most people would want and expect. |
Okay, thanks for your help! |
Looks good! I'll add those to my dnlib too probably tomorrow. I noticed that you used default arguments, and I'll add a commmit that undoes that by adding extension methods or extra methods because VS2008 doesn't support default arguments (AFAICR). BTW, are those redirects hardcoded or do they exist in some XML file? |
These redirects are hardcoded into clr.dll/mscorwks.dll, I extract them using the following code: static unsafe void frRedirV2() {
// .NET 3.5, x86
var clrBase = (byte*)Process.GetCurrentProcess().Modules.OfType<ProcessModule>().Single(m => m.ModuleName == "mscorwks.dll").BaseAddress;
IntPtr* fXPolicy = (IntPtr*)(clrBase + 0xB98A0); // g_arFxPolicy
var frRedirs = new List<Tuple<string, string, string>>();
while (((uint)fXPolicy[0] & 0xff000000) == ((uint)fXPolicy[1] & 0xff000000)) {
var frName = Marshal.PtrToStringUni(fXPolicy[0]);
var frKey = Marshal.PtrToStringUni(fXPolicy[1]);
var frVer = Marshal.PtrToStringUni(fXPolicy[2]);
frRedirs.Add(Tuple.Create(frName, frKey, frVer));
fXPolicy += 3;
}
var list = string.Join(Environment.NewLine, frRedirs.Select(redir => redir.ToString()).ToArray());
}
static unsafe void frRedirV4() {
// .NET 4.5, x86
var clrBase =
(byte*)Process.GetCurrentProcess().Modules.OfType<ProcessModule>().Single(m => m.ModuleName == "clr.dll").BaseAddress;
byte* fXPolicy = clrBase + 0x54380; // g_arFxPolicy
IntPtr* partStrs = (IntPtr*)(clrBase + 0x54850); // g_rgAssemblyNamePartStrings
IntPtr* kVerStrs = (IntPtr*)(clrBase + 0x553D4); // g_rgAssemblyKeyVersionStrings
var frRedirs = new List<Tuple<string, string, string, bool>>();
while (fXPolicy[5] != 0) {
var frName = new StringBuilder();
for (int i = 0; i < 4; i++) {
if (fXPolicy[i] != 0)
frName.Append(Marshal.PtrToStringAnsi(partStrs[fXPolicy[i]]) + ".");
else
break;
}
var frKey = Marshal.PtrToStringUni(kVerStrs[fXPolicy[4]]);
var frVer = Marshal.PtrToStringUni(kVerStrs[fXPolicy[5] & 0x7f]);
var flag = (fXPolicy[5] >> 7) != 0;
frRedirs.Add(Tuple.Create(frName.ToString().Trim('.'), frKey, frVer, flag));
fXPolicy += 6;
}
var list = string.Join(Environment.NewLine, frRedirs);
} Your addresses may vary. |
I've now added your two commits |
For example, suppose I have a library in .NET 3.5. There is a method taking an argument of System.Action in System.Core. Then I created an application in .NET 4 to use that library's method.
In this application, the argument's type is System.Action in mscorlib, since it has moved to mscorlib in .NET 4. The runtime will use .NET 4's System.Core, which has exported System.Action to mscorlib and has no problem. However, dnlib will use .NET 3.5's System.Core and cannot match the reference in the application.
The text was updated successfully, but these errors were encountered: