|
| 1 | +# ReadyToRun Platform Native Envelope |
| 2 | + |
| 3 | +Up through .NET 10, ReadyToRun (R2R) uses the Windows PE format as the native envelope on every platform. Non‑Windows platforms therefore load a PE file with the .NET loader performing the required fixups and code activation. |
| 4 | + |
| 5 | +In .NET 11, we plan to start adding support beyond the PE format. We will target support for: |
| 6 | +- Composite R2R only |
| 7 | +- Mach-O object files emitted by `crossgen2` |
| 8 | +- Runtime using a composite R2R image that is a Mach-O shared library |
| 9 | + - Linking the object files into a shared library is expected to be handled by the SDK and is not covered in this document. |
| 10 | + |
| 11 | +The tentative high-level design is outlined below. As we implement this support, this document should be updated with more details and the [ReadyToRun overview](./readytorun-overview.md) and [ReadyToRun format](./readytorun-format.md) should be updated to reflect the changes. |
| 12 | + |
| 13 | +## crossgen2: producing Mach-O object files |
| 14 | + |
| 15 | +Mach‑O support will only be supported for composite ReadyToRun when the target OS is macOS. It will be opt-in via a new `crossgen2` flag: |
| 16 | +- `--obj-format macho` |
| 17 | + |
| 18 | +`crossgen2` will: |
| 19 | +- Produce a Mach-O object file as the composite R2R image with the `RTR_HEADER` export for the `READYTORUN_HEADER`. |
| 20 | +- Mark each input IL assembly as a component R2R assembly: `READYTORUN_FLAG_COMPONENT`. |
| 21 | +- Mark each input IL assembly with a new flag indicating that the associated composite image is in the platform-native format: `READYTORUN_FLAG_PLATFORM_NATIVE_IMAGE` |
| 22 | + |
| 23 | +`crossgen2` does not produce the final shared library. A separate SDK / build linking step must preserve the `RTR_HEADER` export in the final `dylib`. |
| 24 | + |
| 25 | +## Runtime: consuming a platform-native R2R image |
| 26 | + |
| 27 | +The runtime will be updated to handle platform-native R2R images during assembly load. |
| 28 | + |
| 29 | +1. Load IL assembly and determine if it is a R2R assembly. |
| 30 | +2. If it is not a component R2R assembly, proceed with existing R2R load logic. |
| 31 | + - We will not have platform-native support for this scenario |
| 32 | +3. If it is a component R2R assembly with the new `READYTORUN_FLAG_PLATFORM_NATIVE_IMAGE` flag set: |
| 33 | + a. Read `OwnerCompositeExecutable` value. |
| 34 | + b. Invoke host callback with component assembly path and owner composite name. |
| 35 | + c. On success, obtain pointer to composite `READYTORUN_HEADER` and use it for native method lookup / fixups. |
| 36 | + d. On failure, fall back to IL/JIT path. |
| 37 | +4. If the platform-native flag is not set, proceed with existing R2R load logic (PE assembly lookup and load). |
| 38 | + |
| 39 | +### Host callback |
| 40 | + |
| 41 | +The [`host_runtime_contract`](/src/native/corehost/host_runtime_contract.h) will be updated with a new callback for getting native code information. |
| 42 | + |
| 43 | +```c |
| 44 | +struct native_code_context |
| 45 | +{ |
| 46 | + size_t size; // size of this struct |
| 47 | + const char* assembly_path; // component assembly path |
| 48 | + const char* owner_composite_name; // name from component R2R header |
| 49 | +}; |
| 50 | + |
| 51 | +struct native_code_data |
| 52 | +{ |
| 53 | + size_t size; // size of this struct |
| 54 | + void* r2r_header_ptr; // ReadyToRun header |
| 55 | + size_t image_size; // size of the image |
| 56 | + void* image_base; // base address where the image was loaded |
| 57 | +}; |
| 58 | + |
| 59 | +bool get_native_code_data( |
| 60 | + const struct native_code_context* context, |
| 61 | + /*out*/ struct native_code_data* data |
| 62 | +); |
| 63 | +``` |
| 64 | + |
| 65 | +This leaves it to the host to do the actual load (for example, `dlopen` of a shared library, using something statically linked into the host itself) of the platform-native image. It is also responsible for any caching desired. |
0 commit comments