在 .net4 中尝试 Dll 变基似乎不起作用



我正在尝试基于运行在.net上的一个小测试解决方案的Dll重设,该解决方案由一个小的。exe和三个小的。Dll组成。程序集引用已正确设置,程序编译和运行正常。

这个练习的目的是检查rebase是如何工作的,以便我可以将它与ngen结合起来,并在我正在进行的大型项目中获得性能提升。

我尝试了许多不同的方法来重新设置dll,并使用vmmap, visual studio模块调试器窗口和进程资源管理器来监控结果;到目前为止还没有成功:

  1. 我已经分别为Dll1.dll, Dll2.dll和Dll3.dll设置了Build->Advanced->DLL Base Address设置为0x41000000, 0x42000000和0x43000000。这些地址肯定被保存为每个dll中的首选基址,但是每次运行dll时,dll会不稳定地将它们的映像重定向到内存中的许多不同位置。

  2. 我试过使用这个应用程序。它生成的日志显示dll确实内置了首选基址(由我选择),但是在运行时结果仍然不稳定

  3. 我试过使用ngen。这导致dll的。ni版本与原始dll一起加载,并且所有6个dll的内存位置都不稳定,无法接近我要求的内存位置。

  4. 我试过把我的图像粘在GAC上。令人鼓舞的是,只有GAC版本的dll被加载,但是它们的内存位置仍然不稳定。

  5. 我已经尝试了上面的每一个组合。没有成功。

在运行时使用VMMap显示,在0x10000000和0x50000000之间的地址空间中存在巨大的可用内存缺口,因此不应该发生冲突,也不需要发生Dll重基。dll也非常小,我在它们之间留下的0x01000000间隙非常大,所以它们不应该相互碰撞。

我错过了什么?

我在这个练习中的主要参考是这篇文章,这篇文章信息量很大,但写于2006年的。net 2:从那时到现在,有什么根本的变化吗?

我非常怀疑这有多大区别,但以防万一,我使用了下面的代码:

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Dll1;
using Dll2;
using Dll3;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "Poodle";
            Console.ReadLine();
            //Thread.Sleep(10000);
            Blah();
        }
        static void Blah()
        {
            Console.WriteLine(Class2.shrooms(5, 'h'));
            Class3.teenAngst();
            Class1.Wait();
        }
    }
}

Class1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Dll1
{
    public static class Class1
    {
        public static void Wait()
        {
            Console.ReadLine();
            Console.Write("   ");
        }
    }
}

Class2.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Dll2
{
    public static class Class2
    {
        public static string shrooms(int argc, char argv) 
        {
            return "Ranchdaddyx   ";
        }
    }
}

Class3.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Dll3
{
    public static class Class3
    {
        public static void teenAngst()
        {
            Console.Write("Belonging   ");
        }
    }
}

没有必要重新编译JIT编译的代码:

jit编译的代码没有重基问题,因为地址在运行时根据代码在内存中的位置生成。此外,MSIL很少受到基址丢失的影响引用是基于标记的,而不是基于地址的。因此,当采用JIT编译器,系统对基址具有弹性碰撞。

。. NET程序集和DLL重基

如果我想重置我的DLL's,我该怎么做呢?

http://msdn.microsoft.com/en-us/magazine/cc163610.aspx

http://support.microsoft.com/kb/969305

原来ASLR(地址空间布局随机化)是我困惑的罪魁祸首。显然你可以关掉它,但你牺牲了安全/给自己做了很多工作。我认为整个冒险是一次失败的实验。

。. Net .dll与它们的非托管等价物是非常不同的。老实说,我不认为重新定位是相关的。

查看这篇MSDN文章。在其他事情中,这鼓励你不要重新定位。并给出至少一个令人信服的不这样做的理由(它可能使强签名程序集的签名无效)。文章还讨论了NGEN的潜在好处(链接也是如此):