Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net7/8-ios: EntryPointNotFoundException on remapped DllImports, even when #19624

Open
kiddkaffeine opened this issue Dec 12, 2023 · 8 comments
Open
Labels
bug If an issue is a bug or a pull request a bug fix
Milestone

Comments

@kiddkaffeine
Copy link

This is a followup to #19599. We've migrated to using NativeLibrary.SetDllImportResolver; however, this results in "EntryPointNotFound" unless the function is statically referenced elsewhere.

In legacy Xamarin, using the "Do not strip native debugging symbols." and -force_load flags would preserve all the entry points but it appears that no longer works as expected.

Steps to Reproduce

  1. Link with a static library in net8.0-ios.

  2. Make sure to check "Do not strip native debugging symbols."

  3. Add force_load to the builder flags, --cxx --gcc_flags "-L$(MSBuildProjectDirectory) -force_load $(MSBuildProjectDirectory)/libSDL2.a"

  4. Create a DllImport which is rewritten, example:

    [DllImport("RemapMe", EntryPoint = "SDL_SetHint", CallingConvention = CallingConvention.Cdecl)]
    private static extern unsafe SDL_bool Internal_SDL_SetHint(
    byte* name,
    byte* value
    );

    NativeLibrary.SetDllImportResolver(assembly, MapAndLoad);

    private static IntPtr MapAndLoad(
    string libraryName,
    Assembly assembly,
    DllImportSearchPath? dllImportSearchPath
    ) {
    return NativeLibrary.GetMainProgramHandle();
    }

(A sample .cs and library are attached.)

Expected Behavior

Native function can be invoked.

Actual Behavior

Native function fails with "EntryPointNotFound" exception.

In the associated test file, we see:
Hello world!
Assembly is TestProj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Attempting to call SDL_SetHint using DllImportResolver with __Internal...
Received request to map UseInternal TestProj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null AssemblyDirectory...
Rewriting to __Internal
Received request to map UseInternal TestProj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null AssemblyDirectory...
Rewriting to __Internal
System.DllNotFoundException: UseInternal
at Program.Main(String[] args) in /Users/miles/Projects/TestProj/Main.cs:line 40
Attempting to call SDL_SetHint using DllImportResolver with GetProgramHandle...
Received request to map UseProgramHandle TestProj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null AssemblyDirectory...
Rewriting using MainProgramHandle
System.EntryPointNotFoundException: SDL_SetHint
at Program.Main(String[] args) in /Users/miles/Projects/TestProj/Main.cs:line 52
Test complete.

Workaround

If the entry point is directly referenced elsewhere in the project, i.e.,

[DllImport("__Internal", EntryPoint = "SDL_SetHint", CallingConvention = CallingConvention.Cdecl)]
private static extern void DoNotUse();

then the remapped calls will function correctly, but any remapped calls to other entry points will still fail.

Environment

net8.0-ios. This worked fine with .dll.config files in legacy Xamarin.

sample.zip

@rolfbjarne rolfbjarne added the bug If an issue is a bug or a pull request a bug fix label Dec 14, 2023
@rolfbjarne rolfbjarne added this to the .NET 9 milestone Dec 14, 2023
@rolfbjarne
Copy link
Member

I can reproduce. Complete test project: sample-8e39058.zip

I've found a couple of workarounds, which may or may not work in a bigger project:

  • Add -dlsym:false to the MtouchExtraArgs. This won't work if you have DllImports to functions that don't exist.

  • Set _ExportSymbolsExplicitly=false in the project file (this may increase the app size, but should otherwise work):

    <PropertyGroup>
        <_ExportSymbolsExplicitly>false</_ExportSymbolsExplicitly>
    </PropertyGroup>

@najak3d
Copy link

najak3d commented May 10, 2024

I can reproduce. Complete test project: sample-8e39058.zip

I've found a couple of workarounds, which may or may not work in a bigger project:

  • Add -dlsym:false to the MtouchExtraArgs. This won't work if you have DllImports to functions that don't exist.
  • Set _ExportSymbolsExplicitly=false in the project file (this may increase the app size, but should otherwise work):
    <PropertyGroup>
        <_ExportSymbolsExplicitly>false</_ExportSymbolsExplicitly>
    </PropertyGroup>
    

Even as of May 10, 2024, with .NET 8.0, we are stuck on this issue. With your sample project zip, it fails as you reported (i.e. "EntryPointNotFoundException")

If fails even when MtouchExtraArgs looks like this (with 'dlsym:false'):
--cxx --gcc_flags "-LC:/sample/ -force_load C:/sample/libSDL2.a -framework AudioToolbox -framework AVFoundation -framework AVFAudio -framework OpenGLES -framework CoreBluetooth -framework CoreHaptics -framework GameController -framework QuartzCore -framework Metal -framework CoreMotion" -dlsym:false

And it still fails even when adding these 3 lines to the csproj:

<_ExportSymbolsExplicitly>false</_ExportSymbolsExplicitly>

The 'Internal_SDL_SetHint' fails with DllNotFoundException.

The 'Internal_SDL_SetHint' call fails with "EntryPointNotFoundException" for "_SDL_SetHint"

We're wondering if the failure might have something to do with "_" underscore prefix.

@rolfbjarne
Copy link
Member

If fails even when MtouchExtraArgs looks like this (with 'dlsym:false'):
--cxx --gcc_flags "-LC:/sample/ -force_load C:/sample/libSDL2.a -framework AudioToolbox -framework AVFoundation -framework AVFAudio -framework OpenGLES -framework CoreBluetooth -framework CoreHaptics -framework GameController -framework QuartzCore -framework Metal -framework CoreMotion" -dlsym:false

There are Windows-style paths in there, so I'm assuming you're building from Windows.

Do you see the same behavior if you're building on a Mac?

@najak3d
Copy link

najak3d commented May 20, 2024

Thank you for your response. We are building on Windows now, as seems to be what .NET 8 wants us to do. We resolved this by eliminating our need for the C++ DLL on the Mac, porting that code back to C# (where it runs slower, but still runs fast enough).

So for us, this issue was resolved by avoidance (i.e. eliminating usage of our C++ DLL), after spinning our wheels for about 2 days.

@ryancheung
Copy link

ryancheung commented Jul 7, 2024

I can reproduce. Complete test project: sample-8e39058.zip

I've found a couple of workarounds, which may or may not work in a bigger project:

  • Add -dlsym:false to the MtouchExtraArgs. This won't work if you have DllImports to functions that don't exist.
  • Set _ExportSymbolsExplicitly=false in the project file (this may increase the app size, but should otherwise work):
    <PropertyGroup>
        <_ExportSymbolsExplicitly>false</_ExportSymbolsExplicitly>
    </PropertyGroup>
    

After hours testing, the _ExportSymbolsExplicitly workaround works only for simulator, but not ios-arm64 in real iPhone device. Upgraded to .net 9 preview 5 and still not working.

So, are there any workaround for real iPhone device that don't need change code?

ryancheung added a commit to FNA-NET/FNA that referenced this issue Jul 7, 2024
This patch can be deleted after dotnet/macios#19624 done.
ryancheung added a commit to FNA-NET/FNA that referenced this issue Jul 7, 2024
This patch can be deleted after dotnet/macios#19624 done.
ryancheung added a commit to FNA-NET/FNA that referenced this issue Jul 7, 2024
This patch can be deleted after dotnet/macios#19624 done.
@rolfbjarne
Copy link
Member

I can reproduce. Complete test project: sample-8e39058.zip
I've found a couple of workarounds, which may or may not work in a bigger project:

  • Add -dlsym:false to the MtouchExtraArgs. This won't work if you have DllImports to functions that don't exist.
  • Set _ExportSymbolsExplicitly=false in the project file (this may increase the app size, but should otherwise work):
    <PropertyGroup>
        <_ExportSymbolsExplicitly>false</_ExportSymbolsExplicitly>
    </PropertyGroup>
    

After hours testing, the _ExportSymbolsExplicitly workaround works only for simulator, but not ios-arm64 in real iPhone device. Upgraded to .net 9 preview 5 and still not working.

So, are there any workaround for real iPhone device that don't need change code?

It should work just as well on device as well, so maybe something else is going on.

Can you file a new issue and if possible attach a test project - but at the very least we'll need a build log (https://github.com/xamarin/xamarin-macios/wiki/Diagnosis#binary-build-logs) - then we can have a look and try to figure out what's going on.

@ryancheung
Copy link

Here is the repro project https://github.com/FNA-NET/Samples/tree/dllimport-repro/iOSGame1
Run dotnet build -t:Run and get the error:

  Launched application 'org.FNA-NET.iOSGame1' on 'iPhone' with pid 1413
2024-07-08 21:56:23.480 iOSGame1[1413:365494] 
Unhandled Exception:
System.EntryPointNotFoundException: SDL_SetHint
   at SDL2.SDL.SDL_SetHint(String name, String value) in /Users/ryan/FNA/FNA-NET.Samples/FNA/lib/SDL2-CS/src/SDL2.cs:line 845
   at iOSGame1.Program.Main(String[] args) in /Users/ryan/FNA/FNA-NET.Samples/iOSGame1/Program.cs:line 28
2024-07-08 21:56:23.481 iOSGame1[1413:365494] Unhandled managed exception: SDL_SetHint (System.EntryPointNotFoundException)
   at SDL2.SDL.SDL_SetHint(String name, String value) in /Users/ryan/FNA/FNA-NET.Samples/FNA/lib/SDL2-CS/src/SDL2.cs:line 845
   at iOSGame1.Program.Main(String[] args) in /Users/ryan/FNA/FNA-NET.Samples/iOSGame1/Program.cs:line 28

=================================================================
        Native Crash Reporting
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
        Native stacktrace:
=================================================================
        0x1021c42a8 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : mono_dump_native_crash_info
        0x1021af194 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : mono_handle_native_crash
        0x10220815c - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : sigabrt_signal_handler.cold.1
        0x1021c3a98 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : mono_runtime_setup_stat_profiler
        0x20219b2f4 - /usr/lib/system/libsystem_platform.dylib : <redacted>
        0x20223e5f8 - /usr/lib/system/libsystem_pthread.dylib : pthread_kill
        0x1be2f84b8 - /usr/lib/system/libsystem_c.dylib : abort
        0x101efbf48 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : xamarin_find_protocol_wrapper_type
        0x1020f9ecc - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : mono_invoke_unhandled_exception_hook
        0x102199cb4 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : mono_jit_exec
        0x101f0e484 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : xamarin_main
        0x102202458 - /private/var/containers/Bundle/Application/4C14CAD4-5C5B-4911-934D-82BA8A5ECA72/PublicStaging.app/iOSGame1 : main
        0x1d4cbc344 - /usr/lib/dyld : <redacted>

=================================================================
        Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x1f2caf198):0x1f2caf188  c0 03 5f d6 c0 03 5f d6 10 29 80 d2 01 10 00 d4  .._..._..)......
0x1f2caf198  e3 00 00 54 fd 7b bf a9 fd 03 00 91 73 ee ff 97  ...T.{......s...
0x1f2caf1a8  bf 03 00 91 fd 7b c1 a8 c0 03 5f d6 c0 03 5f d6  .....{...._..._.
0x1f2caf1b8  fd 7b bf a9 fd 03 00 91 50 00 80 d2 01 10 00 d4  .{......P.......

=================================================================
        Managed Stacktrace:
=================================================================
=================================================================
  Application 'org.FNA-NET.iOSGame1' terminated (with exit code '' and/or crashing signal '6).

And the binary build log:
msbuild.binlog.zip

@rolfbjarne
Copy link
Member

I can reproduce the problem, thanks for the test case.

The problem is that we pass -dead_strip to the native linker, and that ends up removing the native functions that are required at runtime.

As a workaround, you can add this to the csproj:

<MtouchExtraArgs>-gcc_flags -v</MtouchExtraArgs>

This doesn't do anything (except ask the native compiler to be more verbose when compiling), and it works because we disable dead stripping if any value of -gcc_flags is passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug If an issue is a bug or a pull request a bug fix
Projects
None yet
Development

No branches or pull requests

4 participants