AsmResolver
AsmResolver copied to clipboard
Support for ReadyToRun (R2R) Format
Problem Description
ReadyToRun (R2R) is one of the native executable code formats that was introduced in .NET Core 3.1. It is used to store precompiled CIL code to avoid overhead introduced by the JIT compiler, thus improving startup times of applications. Since support for self-contained application bundles got recently added to AsmResolver (#279), and assemblies within these bundles often contain R2R content, this is probably something we should add first-class support for in AsmResolver as well.
Proposal
Add read/write support for the R2R file format, by changing the IDotNetDirectory.ManagedNativeHeader
to something that exposes the R2R structures stored in the PE image. AsmResolver should then expose the native code within these structures as byte[]
, ISegment
or even CodeSegment
. Note that AsmResolver should not be responsible for actually generating native code; its only task is to expose it and make it possible add/modify/remove pieces.
Additional context
Since we probably want to support other types of native headers (e.g. NGEN images) we should keep this in mind when deciding the type of IDotNetDirectory.ManagedNativeHeader
. Since the type of header is identified by a signature at the very beginning, we can probably adopt a similar structure that was used in e.g. CodeViewDataSegment
, where we define one base ISegment
class with a Signature
property used to distinguish between different implementations of the native header.
any update on this? as with single file host binaries, now we can read the bundle, but if the binaries inside are r2r we cant modify then and repackage the bundle.
any update on this? as with single file host binaries, now we can read the bundle, but if the binaries inside are r2r we cant modify then and repackage the bundle.
No updates yet. I hope to get this done in 5.0.
However, as far as I am aware, r2r binaries are just normal binaries with some extra metadata holding the prejitted code. The original is still present, and it should be possible to read, modify and repackage them by normal means. You might just have to update a few flags in the headers of the PE to make the executable runnable.
Also, keep in mind that AsmResolver will not do a rerun of the r2r compiler to regen native code, even if this feature is in place.
can u point out to the flags, as of now if just reading and writing them back results in unusable binary.
You would probably want to make sure the ILOnly flag is set and the ILLibrary flag is unset in the .NET data directory. One way of doing that would be the following:
using AsmResolver.DotNet;
using AsmResolver.DotNet.Bundles;
using AsmResolver.PE.DotNet;
var manifest = BundleManifest.FromFile(...);
var file = manifest.Files.First(x => ...);
var module = ModuleDefinition.FromBytes(file.GetData());
module.Attributes &= ~DotNetDirectoryFlags.ILLibrary;
module.Attributes |= DotNetDirectoryFlags.ILOnly;
module.Write("modified.dll");
Keep in mind that this will strip out any r2r metadata. Related: #267
exactly it makes the file run, but as r2r metadata is not there, it will not run directly but by using the jit
Initial prototypes for first-class R2R metadata support can be found in #495.
Turns out, the file format specification/documentation has a lot of gaps (flashbacks to PDBv7). Especially for some of the important internal data structures like NativeArray are not documented well. We will have to resort in some cases to the dotnet/runtime source code itself, and/or maybe even "borrow" some code every now and then.