我想询问有关 .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 的大文件(这已经使计算机由于交换而无法使用)。