我想问关于 .NET 可执行文件的两件事:
.NET 可执行文件为 PE 格式。这是否意味着CIL编译器生成的地址是从文件的开头(
address+size_of_headers
)开始的?或者这些地址仅在内存中执行图像时使用?是否可以(通过 CIL 编译器)生成大小大于 4GB 的可执行文件?如果是,如果编译器必须从文件末尾调用方法或分支到超过 4GB 限制的字节,编译器会做什么?
确实,我从未见过任何大于 4GB 的 C# 可执行文件,我只是好奇。
我想问关于 .NET 可执行文件的两件事:
.NET 可执行文件为 PE 格式。这是否意味着CIL编译器生成的地址是从文件的开头(address+size_of_headers
)开始的?或者这些地址仅在内存中执行图像时使用?
是否可以(通过 CIL 编译器)生成大小大于 4GB 的可执行文件?如果是,如果编译器必须从文件末尾调用方法或分支到超过 4GB 限制的字节,编译器会做什么?
确实,我从未见过任何大于 4GB 的 C# 可执行文件,我只是好奇。
我认为您将执行 CIL 的工作方式与执行本机代码的工作方式混淆了。
使用 CIL,可执行文件中的代码不会实际执行。通常(使用桌面 CLR 而没有 ngen)CLR 读取 CIL 并动态生成实际的可执行代码(这就是为什么 CLR 的这一部分被称为“即时编译器”的原因)。
CIL 操作码喜欢call
使用标记来引用方法和其他成员。在生成的本机代码中,这些被翻译成该方法的本机代码的地址。
像这样的操作码br
包含相对于下一条 CIL 指令的偏移量,它们只能在当前方法内跳转。在 x86 上,它们被编译为类似 的指令jne
,其中包含相对于下一个 x86 指令的偏移量。
但是表中描述了方法的元数据MethodDef
,其中包含对该方法的 IL 流的引用,作为 4 字节的相对虚拟地址(并且 RVA 也用于文件的其他部分)。我认为这意味着可执行文件的大小实际上不能超过 4 GB。
我试图通过使用 Reflection.Emit 创建一个大型可执行文件来验证这一点。但是我在 8 GB RAM 的系统上能做的最好的事情是创建一个 1.5 GB 的大文件(这已经使计算机由于交换而无法使用)。