2

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

这个练习的目的是检查变基是如何工作的,以便我可以将它与 ngen 联系起来,并在我正在从事的大型项目中提高性能。

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

  1. 我已将Dll1.dll、Dll2.dll 和 Dll3.dll 的 Build- >Advanced->DLL Base Address设置分别设置为 0x41000000、0x42000000 和 0x43000000。这些地址肯定被保存为每个 Dll 中的首选基地址,但对于每次运行,Dll 都会不规则地将其图像重新定位到内存中的许多不同位置。

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

  3. 我试过使用ngen。这导致 .ni 版本的 Dll 与原始 Dll 一起加载,并且所有 6 个版本的内存位置都与我要求的位置相去甚远。

  4. 我已经尝试将我的图像粘贴在 GAC 中。令人振奋的是,只有 GAC 版本的 Dll 被加载,但它们的内存位置仍然不稳定。

  5. 我已经尝试过上述每种组合的感觉。没有成功。

在运行时使用 VMMap 进行检查表明,在 0x10000000 和 0x50000000 之间的地址空间中存在巨大的可用内存差距,因此应该没有冲突,也不需要发生 Dll 变基。Dll 也非常小,我在它们之间留下的 0x01000000 间隙非常大,所以它们不应该相互碰撞。

我错过了什么?

在此练习中,我的主要参考资料是这篇文章,该文章信息量很大,但它是在 2006 年为 .Net2 编写的:从那时到现在,有什么根本性的变化吗?

我严重怀疑它是否有很大的不同,但这是我正在使用的代码以防万一:

程序.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   ");
        }
    }
}
4

3 回答 3

4

没有必要对 JIT 编译代码进行变基:

JIT 编译的代码没有变基问题,因为地址是在运行时根据代码在内存中的位置生成的。此外,MSIL 很少受到基地址未命中的影响,因为 MSIL 引用是基于令牌的,而不是基于地址的。因此,当使用 JIT 编译器时,系统对基地址冲突具有弹性。

.NET 程序集和 DLL 变基

如果我想 rebase 我的 DLL,我该怎么做呢?

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

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

于 2011-09-12T02:07:32.953 回答
2

事实证明,ASLR(地址空间布局随机化)是我困惑的罪魁祸首。显然您可以将其关闭,但您正在牺牲安全/为自己做很多工作。我认为整个冒险都是一次失败的实验。

于 2011-12-08T09:04:33.927 回答
1

.Net .dll 与它们的非托管等价物完全不同。老实说,我不认为变基是相关的。

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

CLR 由内而外

于 2011-09-12T01:59:41.080 回答