Skip to content

Commit

Permalink
Implement NativeLibrary.GetEntryPointModuleHandle (dotnet#57610)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Mar 21, 2022
1 parent a1bf79e commit e22ebdf
Show file tree
Hide file tree
Showing 24 changed files with 591 additions and 313 deletions.
5 changes: 5 additions & 0 deletions src/coreclr/hosts/corerun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ else(CLR_CMAKE_HOST_WIN32)
include(configure.cmake)
endif(CLR_CMAKE_HOST_WIN32)

#Required to expose symbols for global symbol discovery.
set(CLR_CMAKE_KEEP_NATIVE_SYMBOLS TRUE)

add_executable_clr(corerun
corerun.cpp
dotenv.cpp
Expand All @@ -25,6 +28,8 @@ if(CLR_CMAKE_HOST_WIN32)
)
else(CLR_CMAKE_HOST_WIN32)
target_link_libraries(corerun ${CMAKE_DL_LIBS})
# Required to expose symbols for global symbol discovery
target_link_libraries(corerun -rdynamic)

# Android implements pthread natively
if(NOT CLR_CMAKE_TARGET_ANDROID)
Expand Down
5 changes: 1 addition & 4 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,16 +564,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)
extern "C" DLL_EXPORT HRESULT CDECL GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId)
{
assert(clrInstance != nullptr && appDomainId != nullptr);
*clrInstance = CurrentClrInstance;
*appDomainId = CurrentAppDomainId;
return S_OK;
}
#endif // TARGET_WINDOWS

//
// Self testing for corerun.
Expand Down
14 changes: 12 additions & 2 deletions src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ namespace pal
}

#ifdef TARGET_WINDOWS
#define CDECL __cdecl
#include <Windows.h>

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

Expand Down Expand Up @@ -316,17 +318,25 @@ class platform_specific_actions final
#include <config.h>
#include <minipal/getexepath.h>

#if __GNUC__ >= 4
#define DLL_EXPORT __attribute__ ((visibility ("default")))
#else
#define DLL_EXPORT
#endif
#define CDECL
#define MAIN main
#define W(str) str
#define FAILED(result) (result < 0)

#define S_OK 0
#define FAILED(result) (result < S_OK)
#if !HAVE_DIRENT_D_TYPE
#define DT_UNKNOWN 0
#define DT_DIR 4
#define DT_REG 8
#define DT_LNK 10
#endif

typedef int HRESULT;

namespace pal
{
using char_t = char;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,6 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SchedGetCpu.cs">
<Link>Interop\Unix\System.Native\Interop.SchedGetCpu.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DynamicLoad.cs">
<Link>Interop\Unix\System.Native\Interop.DynamicLoad.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Threading.cs">
<Link>Interop\Unix\System.Native\Interop.Threading.cs</Link>
</Compile>
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/nativelibrarynative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,3 @@ extern "C" INT_PTR QCALLTYPE NativeLibrary_GetSymbol(INT_PTR handle, LPCWSTR sym

return address;
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@ internal unsafe partial class Sys

[LibraryImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_FreeLibrary")]
internal static partial void FreeLibrary(IntPtr handle);

[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetDefaultSearchOrderPseudoHandle", SetLastError = true)]
internal static partial IntPtr GetDefaultSearchOrderPseudoHandle();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1827,6 +1827,9 @@
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs">
<Link>Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetModuleHandle.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs</Link>
</Compile>
<Compile Include="$(CommonPath)System\IO\FileSystem.Attributes.Windows.cs">
<Link>Common\System\IO\FileSystem.Attributes.Windows.cs</Link>
</Compile>
Expand Down Expand Up @@ -1969,6 +1972,9 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.CopyFile.cs">
<Link>Common\Interop\Unix\System.Native\Interop.CopyFile.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.DynamicLoad.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DynamicLoad.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.ErrNo.cs">
<Link>Common\Interop\Unix\System.Native\Interop.ErrNo.cs</Link>
</Compile>
Expand Down
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;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
Expand Down Expand Up @@ -231,5 +232,26 @@ internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly asse

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

/// <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 GetMainProgramHandle()
{
IntPtr result = IntPtr.Zero;
#if TARGET_WINDOWS
result = Interop.Kernel32.GetModuleHandle(null);
#else
result = Interop.Sys.GetDefaultSearchOrderPseudoHandle();
#endif
// 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)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ public MarshalDirectiveException(string? message, System.Exception? inner) { }
public static partial class NativeLibrary
{
public static void Free(System.IntPtr handle) { }
public static System.IntPtr GetMainProgramHandle() { 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
35 changes: 19 additions & 16 deletions src/mono/mono/metadata/native-library.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,32 +757,35 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope)
return result;
}

static 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)
{
MonoDl *module = NULL;
MonoDl *cached;
MonoAssembly *assembly = mono_image_get_assembly (image);
char *error_msg = NULL;

MONO_REQ_GC_UNSAFE_MODE;

mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "DllImport attempting to load: '%s'.", scope);

// 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 Expand Up @@ -1219,9 +1222,9 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, Mo
g_hash_table_add (native_library_module_blocklist, module);
mono_dl_close (module);
} else {
MonoDl raw_module = { { 0 } };
raw_module.handle = lib;
mono_dl_close (&raw_module);
MonoDl* raw_module = g_new0(MonoDl, 1);
raw_module->handle = lib;
mono_dl_close (raw_module);
}

leave:
Expand Down
1 change: 1 addition & 0 deletions src/native/libs/System.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_LoadLibrary)
DllImportEntry(SystemNative_GetProcAddress)
DllImportEntry(SystemNative_FreeLibrary)
DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle)
DllImportEntry(SystemNative_SchedGetCpu)
DllImportEntry(SystemNative_Exit)
DllImportEntry(SystemNative_Abort)
Expand Down
17 changes: 17 additions & 0 deletions src/native/libs/System.Native/pal_dynamicload.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,20 @@ void SystemNative_FreeLibrary(void* handle)
{
dlclose(handle);
}

#ifdef TARGET_ANDROID
void* SystemNative_GetDefaultSearchOrderPseudoHandle(void)
{
return (void*)RTLD_DEFAULT;
}
#else
static void* g_defaultSearchOrderPseudoHandle = NULL;
void* SystemNative_GetDefaultSearchOrderPseudoHandle(void)
{
if (g_defaultSearchOrderPseudoHandle == NULL)
{
g_defaultSearchOrderPseudoHandle = dlopen(NULL, RTLD_LAZY);
}
return g_defaultSearchOrderPseudoHandle;
}
#endif
2 changes: 2 additions & 0 deletions src/native/libs/System.Native/pal_dynamicload.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ PALEXPORT void* SystemNative_LoadLibrary(const char* filename);
PALEXPORT void* SystemNative_GetProcAddress(void* handle, const char* symbol);

PALEXPORT void SystemNative_FreeLibrary(void* handle);

PALEXPORT void* SystemNative_GetDefaultSearchOrderPseudoHandle(void);
1 change: 1 addition & 0 deletions src/tests/Common/CoreCLRTestLibrary/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static bool Verbose
}

public static bool IsX86 => (RuntimeInformation.ProcessArchitecture == Architecture.X86);
public static bool IsNotX86 => !IsX86;
public static bool IsX64 => (RuntimeInformation.ProcessArchitecture == Architecture.X64);
public static bool IsArm => (RuntimeInformation.ProcessArchitecture == Architecture.Arm);
public static bool IsArm64 => (RuntimeInformation.ProcessArchitecture == Architecture.Arm64);
Expand Down
96 changes: 96 additions & 0 deletions src/tests/Interop/NativeLibrary/API/GetLibraryExportTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Xunit;
using static TestHelpers;

class GetLibraryExportTests : IDisposable
{
private readonly IntPtr handle;

public GetLibraryExportTests()
{
handle = NativeLibrary.Load(NativeLibraryToLoad.GetFullPath());
}

[ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsX86))]
public void GetValidExport_ManualMangling()
{
EXPECT(GetLibraryExport(handle, "_NativeSum@8"));
EXPECT(TryGetLibraryExport(handle, "_NativeSum@8"));
}

[ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotX86))]
public void GetValidExport()
{
EXPECT(GetLibraryExport(handle, "NativeSum"));
EXPECT(TryGetLibraryExport(handle, "NativeSum"));
}

[Fact]
public void NullHandle()
{
EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
}

[Fact]
public void NullExport()
{
EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull);
EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull);
}

[Fact]
public void ExportDoesNotExist()
{
EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound);
EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure);
}


public void Dispose() => NativeLibrary.Free(handle);

static TestResult GetLibraryExport(IntPtr handle, string name)
{
return Run(() => {
IntPtr address = NativeLibrary.GetExport(handle, name);
if (address == IntPtr.Zero)
return TestResult.ReturnNull;
if (RunExportedFunction(address, 1, 1) != 2)
return TestResult.IncorrectEvaluation;
return TestResult.Success;
});
}

static TestResult TryGetLibraryExport(IntPtr handle, string name)
{
return Run(() => {
IntPtr address = IntPtr.Zero;
bool success = NativeLibrary.TryGetExport(handle, name, out address);
if (!success)
return TestResult.ReturnFailure;
if (address == IntPtr.Zero)
return TestResult.ReturnNull;
if (RunExportedFunction(address, 1, 1) != 2)
return TestResult.IncorrectEvaluation;
return TestResult.Success;
});
}

private static unsafe int RunExportedFunction(IntPtr address, int arg1, int arg2)
{
// We use a delegate here instead of a function pointer to avoid hitting issues
// where Mono AOT doesn't generate the managed->native wrapper and then fails
// when in AOT-only mode.
NativeFunctionWrapper wrapper = Marshal.GetDelegateForFunctionPointer<NativeFunctionWrapper>(address);
return wrapper(arg1, arg2);
}

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate int NativeFunctionWrapper(int arg1, int arg2);
}
Loading

0 comments on commit e22ebdf

Please sign in to comment.