You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[NativeAOT] Decorating functions with UnmanagedCallersOnlyAttribute does not export them for executables #78663
NativeAOT conveniently enables Class Library projects to export native symbols in the export table of the PE, typically functions, which is an excellent asset for interoperability with unmanaged software.
In native applications (e.g., written in C/C++), using the directive extern __declspec(dllexport) similarly creates an entry in the export table for the given function. This capability works for both unmanaged libraries (.dll) and unmanaged executables (.exe).
Currently, when decorating a function with the attribute UnmanagedCallersOnlyAttrribute does not insert a symbol in the export table when the managed project is an application (.exe). Copy/paste the definition of the same function in a project of type Class Library works.
Motivation
I'm looking forward to similarly exporting functions in the export table of my managed applications (.exe) for interoperability reasons.
Admittedly, the use case of exporting functions for executables is small compared to libraries. Nonetheless, I find this is a valuable capability on my end, where I mainly work on low-level forms of interoperability (i.e., creating threads in other processes for code execution).
Furthermore, I would expect the compiler to honor the attribute UnmanagedCallersOnlyAttribute for exporting the function in the export table since both libraries (.dll) and executables (.exe) use the PE file format, which enables the export of symbol of functions.
Bug report
Version Used: Retail .NET SDK 7.0.100 with Visual Studio 17.4.0
Steps to Reproduce:
Create a Console Application application using the default template in Visual Studio 2022.
Write a function decorated with the attribute, e.g.:
Compile with the application for win-x64 using NativeAOT.
Inspect the export table of the resulting executable, for example, using CFF Explorer.
Expected Behavior:
The export table of the PE format shows the FancyName2 function.
Actual Behavior
The function FancyName2 is not present. Note that performing the same operation for a project of type Class Library correctly exports the function.
Additional details
Inspecting a running application compiled using NativeAOT, I could notice various symbols present in the memory of the process. As an example, the picture below highlights a static function called FancyName2 in the class Program, from a Windows Forms application.
Creating a thread at this address properly invokes the managed function. Hence, I think tagging this location in the export table using the same logic as for managed libraries should be doable.
I agree that this is niche. You can work around this by passing the .def file with the list of entrypoints to the linker yourself.
I expect that most uses of UnmanagedCallersOnlyAttribute for interopability would not want the entrypoints to be automatically exported in .exe. If the option for dllexporting is added, it should be off by default.
I expect that most uses of UnmanagedCallersOnlyAttribute for interopability would not want the entrypoints to be automatically exported in .exe. If the option for dllexporting is added, it should be off by default.
I think the request is to only expose those that specify the EntryPoint property - the uses for interoperability wouldn't specify an EntryPoint.
@JamesMenetrey you can already do this today if you add:
First, thanks for your detailed input and insight that allowed me to understand the underlying mechanism works better.
@MichalStrehovsky Many thanks for pointing me to a working workaround. Adding this line in the project file correctly exports the symbols as annotated with UnmanagedCallersOnlyAttribute for executables.
I have reviewed the many files in the link you provided to me and created a PR fixing the issue (#78738).
After further testing with both a .NET library and two .NET executables (a console and Windows Forms application), I noticed that decorating a function with UnmanagedCallersOnlyAttribute without specifying the property EntryPoint does not export the symbol. This behavior goes in the direction of @jkotas, who stated that the usage of UnmanagedCallersOnlyAttribute should not export that symbol by default.
Filling the property EntryPoint adds a symbol for both libraries and executables once the PR is applied (tested on my Windows machine).
Could you please review my PR (#78738) and provide feedback if this change is sound?
Activity
agocke commentedon Nov 22, 2022
Seems reasonable, but a little niche. Would take a PR if there were one ready.
jkotas commentedon Nov 22, 2022
I agree that this is niche. You can work around this by passing the .def file with the list of entrypoints to the linker yourself.
I expect that most uses of
UnmanagedCallersOnlyAttributefor interopability would not want the entrypoints to be automatically exported in .exe. If the option for dllexporting is added, it should be off by default.MichalStrehovsky commentedon Nov 22, 2022
I think the request is to only expose those that specify the
EntryPointproperty - the uses for interoperability wouldn't specify anEntryPoint.@JamesMenetrey you can already do this today if you add:
To a PropertyGroup in your project file. It's a bit of a backhanded way to exploit the way things are set up in the targets.
The actual product change to fix this in a more supportable way would be a change to the targets in https://github.com/dotnet/runtime/tree/main/src/coreclr/nativeaot/BuildIntegration.
jkotas commentedon Nov 22, 2022
Consider statically linking some extra C code into the exe and calling between C# and C in both directions.
NativeAOT exports marked functions for exe apps.
JamesMenetrey commentedon Nov 22, 2022
Dear all,
First, thanks for your detailed input and insight that allowed me to understand the underlying mechanism works better.
@MichalStrehovsky Many thanks for pointing me to a working workaround. Adding this line in the project file correctly exports the symbols as annotated with
UnmanagedCallersOnlyAttributefor executables.I have reviewed the many files in the link you provided to me and created a PR fixing the issue (#78738).
After further testing with both a .NET library and two .NET executables (a console and Windows Forms application), I noticed that decorating a function with
UnmanagedCallersOnlyAttributewithout specifying the propertyEntryPointdoes not export the symbol. This behavior goes in the direction of @jkotas, who stated that the usage ofUnmanagedCallersOnlyAttributeshould not export that symbol by default.Filling the property
EntryPointadds a symbol for both libraries and executables once the PR is applied (tested on my Windows machine).Could you please review my PR (#78738) and provide feedback if this change is sound?
Thanks!