diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 75249bea3ad1c6..b8682fa5798c41 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -187,6 +187,7 @@ typedef struct MonoAotOptions { char *outfile; char *llvm_outfile; char *data_outfile; + char *export_symbols_outfile; GList *profile_files; GList *mibc_profile_files; gboolean save_temps; @@ -5103,6 +5104,7 @@ add_wrappers (MonoAotCompile *acfg) } } + GString *export_symbols = g_string_new (""); /* native-to-managed wrappers */ rows = table_info_get_rows (&acfg->image->tables [MONO_TABLE_METHOD]); for (int i = 0; i < rows; ++i) { @@ -5252,8 +5254,10 @@ MONO_RESTORE_WARNING mono_error_assert_ok (error); add_method (acfg, wrapper); - if (export_name) + if (export_name) { g_hash_table_insert (acfg->export_names, wrapper, export_name); + g_string_append_printf (export_symbols, "%s%s\n", acfg->user_symbol_prefix, export_name); + } } g_free (cattr); @@ -5265,6 +5269,19 @@ MONO_RESTORE_WARNING } } + if (acfg->aot_opts.export_symbols_outfile) { + char *export_symbols_out = g_string_free (export_symbols, FALSE); + FILE* export_symbols_outfile = fopen (acfg->aot_opts.export_symbols_outfile, "w"); + if (!export_symbols_outfile) { + fprintf (stderr, "Unable to open specified export_symbols_outfile '%s' to append symbols '%s': %s\n", acfg->aot_opts.export_symbols_outfile, export_symbols_out, strerror (errno)); + g_free (export_symbols_out); + exit (1); + } + fprintf (export_symbols_outfile, "%s", export_symbols_out); + g_free (export_symbols_out); + fclose (export_symbols_outfile); + } + /* StructureToPtr/PtrToStructure wrappers */ rows = table_info_get_rows (&acfg->image->tables [MONO_TABLE_TYPEDEF]); for (int i = 0; i < rows; ++i) { @@ -8445,6 +8462,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->outfile = g_strdup (arg + strlen ("outfile=")); } else if (str_begins_with (arg, "llvm-outfile=")) { opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile=")); + } else if (str_begins_with (arg, "export-symbols-outfile=")) { + opts->export_symbols_outfile = g_strdup (arg + strlen ("export-symbols-outfile=")); } else if (str_begins_with (arg, "temp-path=")) { opts->temp_path = clean_path (g_strdup (arg + strlen ("temp-path="))); } else if (str_begins_with (arg, "save-temps")) { diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 113ed9addafc12..5b3e6b8ad62af4 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -163,6 +163,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task /// public string LibraryFilePrefix { get; set; } = ""; + /// + /// Enables exporting symbols of methods decorated with UnmanagedCallersOnly Attribute containing a specified EntryPoint + /// + public bool EnableUnmanagedCallersOnlyMethodsExport { get; set; } + /// /// Path to the directory where LLVM binaries (opt and llc) are found. /// It's required if UseLLVM is set @@ -478,6 +483,7 @@ all assigned to that one partition. } } + CheckExportSymbolsFile(_assembliesToCompile); CompiledAssemblies = ConvertAssembliesDictToOrderedList(compiledAssemblies, _assembliesToCompile).ToArray(); return !Log.HasLoggedErrors; } @@ -729,6 +735,16 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st } } + if (EnableUnmanagedCallersOnlyMethodsExport) + { + string exportSymbolsFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".exportsymbols")); + ProxyFile proxyFile = _cache.NewFile(exportSymbolsFile); + proxyFiles.Add(proxyFile); + + aotArgs.Add($"export-symbols-outfile={proxyFile.TempFile}"); + aotAssembly.SetMetadata("ExportSymbolsFile", proxyFile.TargetFile); + } + // pass msym-dir if specified if (MsymPath != null) { @@ -1040,6 +1056,21 @@ private bool TryGetAssemblyName(string asmPath, [NotNullWhen(true)] out string? } } + private void CheckExportSymbolsFile(IList assemblies) + { + if (!EnableUnmanagedCallersOnlyMethodsExport) + return; + + foreach (var assemblyItem in assemblies) + { + string assembly = assemblyItem.GetMetadata("FullPath"); + string assemblyFilename = Path.GetFileName(assembly); + string exportSymbolsFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".exportsymbols")); + if (!File.Exists(exportSymbolsFile)) + Log.LogWarning($"EnableUnmanagedCallersOnlyMethodsExport is true, but no .exportsymbols file generated for assembly '{assemblyFilename}'. Check that the AOT compilation mode is full."); + } + } + private static IList ConvertAssembliesDictToOrderedList(ConcurrentDictionary dict, IList originalAssemblies) { List outItems = new(originalAssemblies.Count);