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

Implement NativeLibrary.GetEntryPointModuleHandle #57610

Merged
merged 42 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e4e799c
Bring in some more QCall infrastructure that matches the CoreCLR desi…
jkoritzinsky Aug 10, 2021
5f16ec8
Expose method from CoreRun for use in testing for desktop scenarios.
jkoritzinsky Aug 10, 2021
e0542ee
Refactor out the implementation of the lookup for "__Internal" so it …
jkoritzinsky Aug 10, 2021
57643bc
First pass implementing API on corelcr and mono.
jkoritzinsky Aug 10, 2021
4843165
Fix build and test failures.
jkoritzinsky Aug 17, 2021
376cd45
Fix typos and do basic cleanup.
jkoritzinsky Aug 18, 2021
d19ed4a
Enhance testing.
jkoritzinsky Aug 18, 2021
d50f07f
Update comment for mono QCalls so the comment explains how to define …
jkoritzinsky Aug 18, 2021
d338682
Fix corerun build on non-Windows.
jkoritzinsky Aug 18, 2021
3710af5
Move API implementation to libraries.
jkoritzinsky Aug 18, 2021
93fc783
Make netcore_lookup_self_native_handle static so it doesn't require a…
jkoritzinsky Aug 18, 2021
58554e0
Compile pal_dl.c in the System.Native shim
jkoritzinsky Aug 18, 2021
952903e
Add `void` to make the C compiler happy.
jkoritzinsky Aug 18, 2021
9087136
Make the cached local static
jkoritzinsky Aug 18, 2021
071b119
Add to entrypoints.c
jkoritzinsky Aug 18, 2021
af32231
Remove unused variable.
jkoritzinsky Aug 19, 2021
d71bc7b
Set the right flags to enable loading symbols from corerun with the n…
jkoritzinsky Aug 19, 2021
4db27cb
Add tests that actually pass for the global symbol lookup.
jkoritzinsky Aug 19, 2021
5c61dfb
Merge branch 'nativelibrary_entrymodule' of github.com:jkoritzinsky/r…
jkoritzinsky Aug 19, 2021
9c41825
Rename API based on offline conversation.
jkoritzinsky Aug 23, 2021
5f36838
Add some scenario names for the API testing to help make debugging is…
jkoritzinsky Aug 23, 2021
e9b70ae
Use Win32Exception for the native error code.
jkoritzinsky Aug 24, 2021
4d58716
Merge branch 'nativelibrary_entrymodule' of github.com:jkoritzinsky/r…
jkoritzinsky Sep 1, 2021
31fe53b
Merge branch 'main' into nativelibrary_entrymodule
jkoritzinsky Sep 2, 2021
19bd0a9
Fix Windows test build.
jkoritzinsky Sep 2, 2021
b31fd00
Merge branch 'main' of github.com:dotnet/runtime into nativelibrary_e…
jkoritzinsky Jan 20, 2022
d191560
Merge branch 'main' of github.com:dotnet/runtime into nativelibrary_e…
jkoritzinsky Feb 11, 2022
745c9bc
Rewrite NativeLibrary tests to use the new xunit generator model so w…
jkoritzinsky Feb 11, 2022
efc285f
Fix typo
jkoritzinsky Feb 12, 2022
3f020e8
Clean up some code and move the new P/Invoke over to be generated.
jkoritzinsky Mar 15, 2022
c9a9dba
Merge branch 'main' of github.com:jkoritzinsky/runtime into nativelib…
jkoritzinsky Mar 15, 2022
7ffac68
Rename attribute
jkoritzinsky Mar 15, 2022
a175e5c
Fix duplicate source file include
jkoritzinsky Mar 15, 2022
81f9daa
Fix allocation in NativeLibrary.Free to handle the raw lib handle cas…
jkoritzinsky Mar 16, 2022
a6117ba
Fix Apple test builds
jkoritzinsky Mar 16, 2022
2d4959a
Merge branch 'nativelibrary_entrymodule' of github.com:jkoritzinsky/r…
jkoritzinsky Mar 16, 2022
f17ec5a
Fix typo in ConditionalFact condition
jkoritzinsky Mar 16, 2022
b8aa4fe
Don't P/Invoke into the same NativeLibrary that we're testing our dou…
jkoritzinsky Mar 16, 2022
4e7a69c
Fix GetCurrentClrDetails exporting on win x86
jkoritzinsky Mar 17, 2022
c58228b
Use delegate interop to avoid hitting issues with function pointers a…
jkoritzinsky Mar 17, 2022
6bc7f4c
Clean up CMakeLists.txt for NativeLibrary tests
jkoritzinsky Mar 18, 2022
4266aab
Add a test for freeing the result of GetMainProgramHandle
jkoritzinsky Mar 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,16 +555,13 @@ int MAIN(const int argc, const char_t* argv[])
return exit_code;
}

#ifdef TARGET_WINDOWS
// Used by CoreShim to determine running CoreCLR details.
extern "C" __declspec(dllexport) HRESULT __cdecl GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId)
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
{
assert(clrInstance != nullptr && appDomainId != nullptr);
*clrInstance = CurrentClrInstance;
*appDomainId = CurrentAppDomainId;
return S_OK;
}
#endif // TARGET_WINDOWS

//
// Self testing for corerun.
Expand Down
8 changes: 7 additions & 1 deletion src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace pal
#ifdef TARGET_WINDOWS
#include <Windows.h>

#define DLL_EXPORT __declspec(dllexport)
#define MAIN __cdecl wmain
#define W(str) L ## str

Expand Down Expand Up @@ -307,6 +308,11 @@ class platform_specific_actions final
#include <config.h>
#include <getexepath.h>

#if __GNUC__ >= 4
#define DLL_EXPORT __attribute__ ((visibility ("default")))
#else
#define DLL_EXPORT
#endif
#define MAIN main
#define W(str) str
#define FAILED(result) (result < 0)
Expand Down Expand Up @@ -573,7 +579,7 @@ namespace pal
pal::ensure_trailing_delimiter(coreclr_path);
coreclr_path.append(pal::coreclr_lib);
coreclr_path.append(pal::nativelib_ext);

hMod = (pal::mod_t)dlopen(coreclr_path.c_str(), RTLD_NOW | RTLD_LOCAL);
if (hMod == nullptr)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ FCFuncStart(gInteropNativeLibraryFuncs)
QCFuncElement("LoadByName", NativeLibraryNative::LoadByName)
QCFuncElement("FreeLib", NativeLibraryNative::FreeLib)
QCFuncElement("GetSymbol", NativeLibraryNative::GetSymbol)
QCFuncElement("GetEntryPointModuleHandleInternal", NativeLibraryNative::GetEntryPointModuleHandle)
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
FCFuncEnd()

FCFuncStart(gTypeLoadExceptionFuncs)
Expand Down
42 changes: 42 additions & 0 deletions src/coreclr/vm/nativelibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,28 @@ namespace
return hmod;
}

// Load the library directly and return the raw system handle
NATIVE_LIBRARY_HANDLE GetEntryPointModuleHandleHelper(LoadLibErrorTracker *pErrorTracker )
{
STANDARD_VM_CONTRACT;

NATIVE_LIBRARY_HANDLE hmod = NULL;

#ifndef TARGET_UNIX
hmod = GetModuleHandleW(NULL);

#else // !TARGET_UNIX
hmod = PAL_LoadLibraryDirect(NULL);
#endif // !TARGET_UNIX

if (hmod == NULL)
{
pErrorTracker->TrackErrorCode();
}

return hmod;
}

// DllImportSearchPathFlags is a special enumeration, whose values are tied closely with LoadLibrary flags.
// There is no "default" value DllImportSearchPathFlags. In the absence of DllImportSearchPath attribute,
// CoreCLR's LoadLibrary implementation uses the following defaults.
Expand Down Expand Up @@ -907,3 +929,23 @@ NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryFromMethodDesc(NDirectMethodDesc

RETURN hmod;
}

NATIVE_LIBRARY_HANDLE NativeLibrary::GetEntryPointModuleHandle()
{
CONTRACT(NATIVE_LIBRARY_HANDLE)
{
STANDARD_VM_CHECK;
POSTCONDITION(RETVAL != NULL);
}
CONTRACT_END;

LoadLibErrorTracker errorTracker;
NATIVE_LIBRARY_HANDLE hmod = GetEntryPointModuleHandleHelper(&errorTracker);
if (hmod == NULL)
{
StackSString ssLibName(SString::Utf8, "Entry Point Handle");
errorTracker.Throw(ssLibName);
}

RETURN hmod;
}
2 changes: 2 additions & 0 deletions src/coreclr/vm/nativelibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class NativeLibrary
static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError);

static NATIVE_LIBRARY_HANDLE LoadLibraryFromMethodDesc(NDirectMethodDesc *pMD);

static NATIVE_LIBRARY_HANDLE GetEntryPointModuleHandle();
};

#endif // _NATIVELIBRARY_H_
15 changes: 15 additions & 0 deletions src/coreclr/vm/nativelibrarynative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,18 @@ INT_PTR QCALLTYPE NativeLibraryNative::GetSymbol(INT_PTR handle, LPCWSTR symbolN
return address;
}

//static
INT_PTR QCALLTYPE NativeLibraryNative::GetEntryPointModuleHandle()
{
QCALL_CONTRACT;

NATIVE_LIBRARY_HANDLE handle = NULL;

BEGIN_QCALL;

handle = NativeLibrary::GetEntryPointModuleHandle();

END_QCALL;

return reinterpret_cast<INT_PTR>(handle);
}
2 changes: 1 addition & 1 deletion src/coreclr/vm/nativelibrarynative.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class NativeLibraryNative
BOOL throwOnError);
static void QCALLTYPE FreeLib(INT_PTR handle);
static INT_PTR QCALLTYPE GetSymbol(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError);

static INT_PTR QCALLTYPE GetEntryPointModuleHandle();
};

#endif // __NATIVELIBRARYNATIVE_H__
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
Expand Down Expand Up @@ -256,5 +257,24 @@ internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly asse

return resolver(libraryName, assembly, hasDllImportSearchPathFlags ? (DllImportSearchPath?)dllImportSearchPathFlags : null);
}

[DllImport(RuntimeHelpers.QCall, SetLastError = true)]
private static extern IntPtr GetEntryPointModuleHandleInternal();

jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Get a handle that can be used with <see cref="GetExport" /> or <see cref="TryGetExport" /> to resolve exports from the entry point module.
/// </summary>
/// <returns> The handle that can be used to resolve exports from the entry point module.</returns>
public static IntPtr GetEntryPointModuleHandle()
{
IntPtr result = GetEntryPointModuleHandleInternal();
// I don't know when a failure case can occur here, but checking for it and throwing an exception
// if we encounter it.
if (result == IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
}
return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ public MarshalDirectiveException(string? message, System.Exception? inner) { }
public static partial class NativeLibrary
{
public static void Free(System.IntPtr handle) { }
public static System.IntPtr GetEntryPointModuleHandle() { throw null; }
public static System.IntPtr GetExport(System.IntPtr handle, string name) { throw null; }
public static System.IntPtr Load(string libraryPath) { throw null; }
public static System.IntPtr Load(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath) { throw null; }
Expand Down
20 changes: 19 additions & 1 deletion src/mono/mono/metadata/native-library-qcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,33 @@ enum {
func_flag_end_of_array = 0x01,
func_flag_has_signature = 0x02,
func_flag_unreferenced = 0x04, // Suppress unused fcall check
func_flag_qcall = 0x08, // QCall - mscorlib.dll to mscorwks.dll transition implemented as PInvoke
func_flag_qcall = 0x08, // QCall - System.Private.CoreLib.dll to native runtime transition implemented as PInvoke
};

#ifndef DISABLE_QCALLS
#define FCFuncStart(name) static const MonoQCallFunc name[] = {
#define FCFuncEnd() { func_flag_end_of_array, NULL, NULL } };
#define QCFuncElement(name,impl) { func_flag_qcall, (void*)(impl), name },
#define FCClassElement(name, namespace, funcs)
#include "mono/metadata/qcall-def.h"
#undef FCClassElement
#undef QCFuncElement
#undef FCFuncEnd
#undef FCFuncStart
#endif

static const MonoQCallDef c_qcalls[] =
{
#ifndef DISABLE_QCALLS
#define FCFuncStart(name)
#define FCFuncEnd()
#define QCFuncElement(name,impl)
#define FCClassElement(name,namespace,funcs) {name, namespace, funcs},
#include "mono/metadata/qcall-def.h"
#undef FCClassElement
#undef QCFuncElement
#undef FCFuncEnd
#undef FCFuncStart
#endif
};

Expand Down
28 changes: 16 additions & 12 deletions src/mono/mono/metadata/native-library.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,21 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope)
return result;
}

MonoDl*
netcore_lookup_self_native_handle()
{
char *error_msg = NULL;
if (!internal_module)
internal_module = mono_dl_open_self (&error_msg);

if (!internal_module) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
g_free (error_msg);
}
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal.");
return internal_module;
}

static MonoDl *
netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, const char *scope, guint32 flags)
{
Expand All @@ -770,18 +785,7 @@ netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, c

// We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR
if (strcmp (scope, "__Internal") == 0) {
if (!internal_module)
internal_module = mono_dl_open_self (&error_msg);
module = internal_module;

if (!module) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
g_free (error_msg);
}

mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal: '%s'.", scope);

return module;
return netcore_lookup_self_native_handle();
}

/*
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/metadata/native-library.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ typedef struct MonoQCallFunc {
void
mono_loader_install_pinvoke_override (PInvokeOverrideFn override_fn);

MonoDl*
netcore_lookup_self_native_handle();
#endif
6 changes: 5 additions & 1 deletion src/mono/mono/metadata/qcall-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
* have to end with a func_flag_end_of_array (0x01) entry.
**/

FCClassElement("", "", NULL)
FCFuncStart(gInteropNativeLibraryFuncs)
QCFuncElement("GetEntryPointModuleHandleInternal", netcore_lookup_self_native_handle)
FCFuncEnd()

FCClassElement("NativeLibary", "System.Runtime.InteropServices", gInteropNativeLibraryFuncs)
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 20 additions & 0 deletions src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ public static int Main()
success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure);

NativeLibrary.Free(handle);

// -----------------------------------------------
// GetLibraryExport Tests
// -----------------------------------------------
success &= EXPECT(GetEntryPointModuleHandle());
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
}
catch (Exception e)
{
Expand Down Expand Up @@ -365,6 +370,21 @@ static TestResult TryGetLibraryExport(IntPtr handle, string name)
});
}

static TestResult GetEntryPointModuleHandle()
{
CurrentTest = nameof(GetEntryPointModuleHandle);
return Run(() => {
IntPtr moduleHandle = NativeLibrary.GetEntryPointModuleHandle();
// Get a well-known export name from corerun to validate that we have a valid handle.
bool success = NativeLibrary.TryGetExport(moduleHandle, "GetCurrentClrDetails", out IntPtr address);
if (!success)
return TestResult.ReturnFailure;
if (address == IntPtr.Zero)
return TestResult.ReturnNull;
return TestResult.Success;
});
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
}

[DllImport(NativeLibraryToLoad.Name)]
static extern int RunExportedFunction(IntPtr address, int arg1, int arg2);
}