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

Easier method of executing Rust code from C# #32

Open
SeanOMik opened this issue Nov 21, 2023 · 2 comments
Open

Easier method of executing Rust code from C# #32

SeanOMik opened this issue Nov 21, 2023 · 2 comments

Comments

@SeanOMik
Copy link

Hello, I was wondering of an easier method to execute Rust code (unmanaged) from C# (managed). I already know of the return-string-from-managed example and was able to easily get it working, but it required a field and two methods to be created for a single unmanaged method:

// Required since only unsafe code can use function pointers.
private static unsafe void DoRustyThings() {
    DoRustyThingsPtr();
}

private static unsafe delegate*<void> DoRustyThingsPtr;

[UnmanagedCallersOnly]
public static unsafe void SetDoRustyThingsPtr(delegate*<void> doRustyThingsPtr) => DoRustyThingsPtr = doRustyThingsPtr;

Mono has a really simple way to call managed code from unmanaged code by adding an attribute:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static void DoRustyThings();

Is there anyway that running managed code from unmanaged code could become easier and lead to less boilerplate? If its not implemented just yet, I may be able to mess around with implementing it and make a PR, or just hack something up to get it working for me. Thanks!

@D3lta-2-1
Copy link

You have 2 options :

Calling rust from C# allow you to use unmanaged structs as function paramter, and all kind of references will be marshall as pointer (or rust references).

[MethodImplAttribute(MethodImplOptions.InternalCall)] is only available when you make a fork of CoreClr (not loading it from another executable), or when you use Mono.

hope this helps

@ignatz
Copy link

ignatz commented Apr 17, 2024

Hi @D3lta-2-1 , I was very happy to find your instructions because your second option was exactly what I was trying to do, i.e.: call rust code from my managed code.

I did recompile my host application binary with -Zexport-executable-symbols and then used a cutsom DllImportResolver, however when NativeLibrary.Loading the binary itself, I'm just getting: "target/debug/test_wgpu_sdl: cannot dynamically load position-independent executable".

Now, looking at the binary itself, I seem to be missing an .edata section despite the-Zexport-executable-symbols despite what https://doc.rust-lang.org/beta/unstable-book/compiler-flags/export-executable-symbols.html is claiming. Is that the culprit or merely a platform difference (I'm on x86 linux)? Am I holding it wrong? Do you have an example you could point me to?

EDIT: FTR, I also tried NativeLibrary.GetExport(NativeLibrary.GetMainProgramHandle(), <functionname>) w/o success, I assume MainProgram her refers to the dotnet program rather than the rust host binary. I also checked that "" is available and exported in the programs symbols, which is the case:

0000000000117b40 g     F .text  0000000000000032       functionname

EDIT2: I wrote a small C program that dlopens itself to see if a .edata section would need to be present and the answer is: it doesn't need to be there. My program can happily dlopen itself. If I NativeLibrary.Load the same binary from dotnet, I still get: "Unhandled exception. System.DllNotFoundException: Unable to load shared library './main' or one of its dependencies. In order to help diagnose loading problems, consider using a tool like strace. If you're using glibc, consider setting the LD_DEBUG environment variable:
./main: cannot dynamically load position-independent executable" :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants