diff --git a/docs/design/coreclr/botr/readytorun-format.md b/docs/design/coreclr/botr/readytorun-format.md index 47894bb514aae5..6541e16b383cfb 100644 --- a/docs/design/coreclr/botr/readytorun-format.md +++ b/docs/design/coreclr/botr/readytorun-format.md @@ -34,7 +34,7 @@ native envelope. Moving forward we [plan to gradually add support for platform-n executable formats](./readytorun-platform-native-envelope.md) (ELF on Linux, MachO on OSX) as the native envelopes. There is a global CLI / COR header in the file, but it only exists to facilitate pdb generation, and does not participate in any usages by the CoreCLR runtime. The ReadyToRun header structure is pointed to -by the well-known export symbol `RTR_HEADER` and has the `READYTORUN_FLAG_COMPOSITE` flag set. +by the well-known export symbol `RTR_HEADER` (customizable via the `--rtr-header-symbol-name` crossgen2 option — see below) and has the `READYTORUN_FLAG_COMPOSITE` flag set. Input MSIL metadata and IL streams can be either embedded in the composite R2R file or left as separate files on disk. In case of embedded MSIL, the "actual" metadata for the individual @@ -71,8 +71,11 @@ The structures and accompanying constants are defined in the [readytorun.h](https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/readytorun.h) header file. Basically the entire R2R executable image is addressed through the READYTORUN_HEADER singleton -pointed to by the well-known export RTR_HEADER in the export section of the native executable -envelope. +pointed to by the well-known export `RTR_HEADER` in the export section of the native executable +envelope. For composite images, this export symbol name can be customized using the +`--rtr-header-symbol-name` option in `crossgen2`, which is useful for custom hosts that +directly link against multiple R2R images (instead of loading them dynamically via `dlopen` or +equivalent) and therefore need distinct symbol names to avoid collisions. For single-file R2R executables, there's just one header representing all image sections. For composite and single exe, the global `READYTORUN_HEADER` includes a section of the type diff --git a/docs/design/coreclr/botr/readytorun-platform-native-envelope.md b/docs/design/coreclr/botr/readytorun-platform-native-envelope.md index 9bd1410420ff37..6fcca59bf56cdf 100644 --- a/docs/design/coreclr/botr/readytorun-platform-native-envelope.md +++ b/docs/design/coreclr/botr/readytorun-platform-native-envelope.md @@ -18,11 +18,15 @@ Mach‑O support will only be supported for composite ReadyToRun when the target `crossgen2` will: -- Produce a Mach-O object file as the composite R2R image with the `RTR_HEADER` export for the `READYTORUN_HEADER`. +- Produce a Mach-O object file as the composite R2R image with the `RTR_HEADER` export for the `READYTORUN_HEADER`. The export symbol name defaults to `RTR_HEADER` but can be overridden with the `--rtr-header-symbol-name` option (see below). - Mark each input IL assembly as a component R2R assembly: `READYTORUN_FLAG_COMPONENT`. - 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` -`crossgen2` does not produce the final shared library. A separate SDK / build linking step must preserve the `RTR_HEADER` export in the final `dylib`. +`crossgen2` does not produce the final shared library. A separate SDK / build linking step must preserve the `RTR_HEADER` export (or the custom name if `--rtr-header-symbol-name` was used) in the final `dylib`. + +### Customizing the RTR_HEADER symbol name + +The `crossgen2` `--rtr-header-symbol-name ` option overrides the exported symbol name for the `READYTORUN_HEADER`. This is intended for custom hosts that directly link against multiple R2R images — rather than loading them dynamically via `dlopen` or equivalent — where each image needs a distinct export symbol name to avoid collisions. The runtime or host must then use the matching custom name when locating the header. ### Mach-O Emitter Decisions diff --git a/docs/design/features/readytorun-composite-format-design.md b/docs/design/features/readytorun-composite-format-design.md index afa7a4ed157450..40306af9cfa08b 100644 --- a/docs/design/features/readytorun-composite-format-design.md +++ b/docs/design/features/readytorun-composite-format-design.md @@ -77,7 +77,7 @@ COR header of the input MSIL metadata which then points at the R2R header (via t `ManagedNativeHeaderDirectory` field). In composite R2R files there is no global COR header and the R2R header is located through the -well-known export symbol `RTR_HEADER`. The "actual" input assemblies are tracked under the new +well-known export symbol `RTR_HEADER` (customizable via the `--rtr-header-symbol-name` crossgen2 option). The "actual" input assemblies are tracked under the new R2R header table `READYTORUN_SECTION_ASSEMBLIES`. ## Manifest metadata and component assembly table @@ -128,7 +128,7 @@ properly look up methods stored in this section in the composite R2R case. # CoreCLR runtime changes CoreCLR runtime will need to become able to recognize the new composite R2R format by means -of locating the well-known export `RTR_HEADER` and validating the ReadyToRun header (magic +of locating the well-known export `RTR_HEADER` (or a custom symbol name if `--rtr-header-symbol-name` was specified) and validating the ReadyToRun header (magic constant, version number and the `READYTORUN_FLAG_COMPOSITE` flag) and behave accordingly: * For composite files with embedded MSIL, we shouldn't need MVID checks for reference diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index d0cd1542163e5c..c83fce292bf3f0 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -288,7 +288,9 @@ private PEObjectWriter CreatePEObjectWriter() if (_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode && _componentModule == null) { - objectWriter.AddExportedSymbol("RTR_HEADER"); + string configuredSymbolName = _nodeFactory.CompositeImageSettings?.ReadyToRunHeaderSymbolName; + string symbolName = string.IsNullOrWhiteSpace(configuredSymbolName) ? "RTR_HEADER" : configuredSymbolName; + objectWriter.AddExportedSymbol(symbolName); } return objectWriter; } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompositeImageSettings.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompositeImageSettings.cs index 7a54bf7fefc982..9057dc6eed0828 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompositeImageSettings.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompositeImageSettings.cs @@ -10,5 +10,6 @@ public class CompositeImageSettings { public ImmutableArray PublicKey; public Version AssemblyVersion; + public string ReadyToRunHeaderSymbolName; } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 88278fc10f707f..3236e93c9e888d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -1179,7 +1179,8 @@ public Utf8String GetSymbolAlternateName(ISymbolNode node, out bool isHidden) isHidden = false; if (node == Header) { - return new Utf8String("RTR_HEADER"u8); + string symbolName = CompositeImageSettings?.ReadyToRunHeaderSymbolName; + return new Utf8String(string.IsNullOrEmpty(symbolName) ? "RTR_HEADER" : symbolName); } return default; } diff --git a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs index ada92cd4d77f93..41f5967f980bd1 100644 --- a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs +++ b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs @@ -54,6 +54,8 @@ internal class Crossgen2RootCommand : RootCommand new("--composite") { Description = SR.CompositeBuildMode }; public Option CompositeKeyFile { get; } = new("--compositekeyfile") { Description = SR.CompositeKeyFile }; + public Option ReadyToRunHeaderSymbolName { get; } = + new("--rtr-header-symbol-name") { Description = SR.ReadyToRunHeaderSymbolName }; public Option CompileNoMethods { get; } = new("--compile-no-methods") { Description = SR.CompileNoMethodsOption }; public Option OutNearInput { get; } = @@ -179,6 +181,7 @@ public Crossgen2RootCommand(string[] args) : base(SR.Crossgen2BannerText) Options.Add(InputBubbleReferenceFilePaths); Options.Add(Composite); Options.Add(CompositeKeyFile); + Options.Add(ReadyToRunHeaderSymbolName); Options.Add(CompileNoMethods); Options.Add(OutNearInput); Options.Add(SingleFileCompilation); diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index 0f2a6e027f3a71..03181e2ade4c7c 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -411,12 +411,27 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru throw new Exception(string.Format(SR.ErrorMultipleInputFilesCompositeModeOnly, string.Join("; ", inputModules))); } + string rtrHeaderSymbolName = Get(_command.ReadyToRunHeaderSymbolName); + ReadyToRunContainerFormat format = Get(_command.OutputFormat); if (!composite && format != ReadyToRunContainerFormat.PE && format != ReadyToRunContainerFormat.Wasm) { throw new Exception(string.Format(SR.ErrorContainerFormatRequiresComposite, format)); } + if (rtrHeaderSymbolName is not null) + { + if (!composite) + { + throw new Exception(SR.ErrorReadyToRunHeaderSymbolNameRequiresComposite); + } + + if (string.IsNullOrWhiteSpace(rtrHeaderSymbolName)) + { + throw new Exception(SR.ErrorReadyToRunHeaderSymbolNameEmpty); + } + } + bool compileBubbleGenerics = Get(_command.CompileBubbleGenerics); ReadyToRunCompilationModuleGroupBase compilationGroup; List compilationRoots = new List(); @@ -604,6 +619,11 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru compositeImageSettings.PublicKey = compositeStrongNameKey.ToImmutableArray(); } + if (rtrHeaderSymbolName != null) + { + compositeImageSettings.ReadyToRunHeaderSymbolName = rtrHeaderSymbolName; + } + // // Compile // diff --git a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx index b21edaf9f22af1..2e25120f950e7e 100644 --- a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx +++ b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx @@ -168,6 +168,15 @@ --CompositeKeyFile does not specify a valid public key + + For custom hosts only: the name to use for the exported ReadyToRun header symbol (default: RTR_HEADER). Requires --composite. + + + Error: --rtr-header-symbol-name requires --composite. + + + Error: --rtr-header-symbol-name must not be empty or whitespace. + Input file(s) to compile