Skip to content

Commit e22ebdf

Browse files
authored
Implement NativeLibrary.GetEntryPointModuleHandle (#57610)
1 parent a1bf79e commit e22ebdf

File tree

24 files changed

+591
-313
lines changed

24 files changed

+591
-313
lines changed

src/coreclr/hosts/corerun/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ else(CLR_CMAKE_HOST_WIN32)
88
include(configure.cmake)
99
endif(CLR_CMAKE_HOST_WIN32)
1010

11+
#Required to expose symbols for global symbol discovery.
12+
set(CLR_CMAKE_KEEP_NATIVE_SYMBOLS TRUE)
13+
1114
add_executable_clr(corerun
1215
corerun.cpp
1316
dotenv.cpp
@@ -25,6 +28,8 @@ if(CLR_CMAKE_HOST_WIN32)
2528
)
2629
else(CLR_CMAKE_HOST_WIN32)
2730
target_link_libraries(corerun ${CMAKE_DL_LIBS})
31+
# Required to expose symbols for global symbol discovery
32+
target_link_libraries(corerun -rdynamic)
2833

2934
# Android implements pthread natively
3035
if(NOT CLR_CMAKE_TARGET_ANDROID)

src/coreclr/hosts/corerun/corerun.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -564,16 +564,13 @@ int MAIN(const int argc, const char_t* argv[])
564564
return exit_code;
565565
}
566566

567-
#ifdef TARGET_WINDOWS
568-
// Used by CoreShim to determine running CoreCLR details.
569-
extern "C" __declspec(dllexport) HRESULT __cdecl GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId)
567+
extern "C" DLL_EXPORT HRESULT CDECL GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId)
570568
{
571569
assert(clrInstance != nullptr && appDomainId != nullptr);
572570
*clrInstance = CurrentClrInstance;
573571
*appDomainId = CurrentAppDomainId;
574572
return S_OK;
575573
}
576-
#endif // TARGET_WINDOWS
577574

578575
//
579576
// Self testing for corerun.

src/coreclr/hosts/corerun/corerun.hpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ namespace pal
4747
}
4848

4949
#ifdef TARGET_WINDOWS
50+
#define CDECL __cdecl
5051
#include <Windows.h>
5152

53+
#define DLL_EXPORT __declspec(dllexport)
5254
#define MAIN __cdecl wmain
5355
#define W(str) L ## str
5456

@@ -316,17 +318,25 @@ class platform_specific_actions final
316318
#include <config.h>
317319
#include <minipal/getexepath.h>
318320

321+
#if __GNUC__ >= 4
322+
#define DLL_EXPORT __attribute__ ((visibility ("default")))
323+
#else
324+
#define DLL_EXPORT
325+
#endif
326+
#define CDECL
319327
#define MAIN main
320328
#define W(str) str
321-
#define FAILED(result) (result < 0)
322-
329+
#define S_OK 0
330+
#define FAILED(result) (result < S_OK)
323331
#if !HAVE_DIRENT_D_TYPE
324332
#define DT_UNKNOWN 0
325333
#define DT_DIR 4
326334
#define DT_REG 8
327335
#define DT_LNK 10
328336
#endif
329337

338+
typedef int HRESULT;
339+
330340
namespace pal
331341
{
332342
using char_t = char;

src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj

-3
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,6 @@
323323
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SchedGetCpu.cs">
324324
<Link>Interop\Unix\System.Native\Interop.SchedGetCpu.cs</Link>
325325
</Compile>
326-
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DynamicLoad.cs">
327-
<Link>Interop\Unix\System.Native\Interop.DynamicLoad.cs</Link>
328-
</Compile>
329326
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Threading.cs">
330327
<Link>Interop\Unix\System.Native\Interop.Threading.cs</Link>
331328
</Compile>

src/coreclr/vm/nativelibrarynative.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,3 @@ extern "C" INT_PTR QCALLTYPE NativeLibrary_GetSymbol(INT_PTR handle, LPCWSTR sym
7070

7171
return address;
7272
}
73-

src/libraries/Common/src/Interop/Unix/System.Native/Interop.DynamicLoad.cs

+3
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@ internal unsafe partial class Sys
1919

2020
[LibraryImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_FreeLibrary")]
2121
internal static partial void FreeLibrary(IntPtr handle);
22+
23+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetDefaultSearchOrderPseudoHandle", SetLastError = true)]
24+
internal static partial IntPtr GetDefaultSearchOrderPseudoHandle();
2225
}
2326
}

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

+6
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,9 @@
18271827
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs">
18281828
<Link>Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs</Link>
18291829
</Compile>
1830+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetModuleHandle.cs">
1831+
<Link>Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs</Link>
1832+
</Compile>
18301833
<Compile Include="$(CommonPath)System\IO\FileSystem.Attributes.Windows.cs">
18311834
<Link>Common\System\IO\FileSystem.Attributes.Windows.cs</Link>
18321835
</Compile>
@@ -1969,6 +1972,9 @@
19691972
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.CopyFile.cs">
19701973
<Link>Common\Interop\Unix\System.Native\Interop.CopyFile.cs</Link>
19711974
</Compile>
1975+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.DynamicLoad.cs">
1976+
<Link>Common\Interop\Unix\System.Native\Interop.DynamicLoad.cs</Link>
1977+
</Compile>
19721978
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.ErrNo.cs">
19731979
<Link>Common\Interop\Unix\System.Native\Interop.ErrNo.cs</Link>
19741980
</Compile>

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.ComponentModel;
45
using System.Reflection;
56
using System.Runtime.CompilerServices;
67
using System.Threading;
@@ -231,5 +232,26 @@ internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly asse
231232

232233
return resolver(libraryName, assembly, hasDllImportSearchPathFlags ? (DllImportSearchPath?)dllImportSearchPathFlags : null);
233234
}
235+
236+
/// <summary>
237+
/// Get a handle that can be used with <see cref="GetExport" /> or <see cref="TryGetExport" /> to resolve exports from the entry point module.
238+
/// </summary>
239+
/// <returns> The handle that can be used to resolve exports from the entry point module.</returns>
240+
public static IntPtr GetMainProgramHandle()
241+
{
242+
IntPtr result = IntPtr.Zero;
243+
#if TARGET_WINDOWS
244+
result = Interop.Kernel32.GetModuleHandle(null);
245+
#else
246+
result = Interop.Sys.GetDefaultSearchOrderPseudoHandle();
247+
#endif
248+
// I don't know when a failure case can occur here, but checking for it and throwing an exception
249+
// if we encounter it.
250+
if (result == IntPtr.Zero)
251+
{
252+
throw new Win32Exception(Marshal.GetLastPInvokeError());
253+
}
254+
return result;
255+
}
234256
}
235257
}

src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs

+1
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ public MarshalDirectiveException(string? message, System.Exception? inner) { }
784784
public static partial class NativeLibrary
785785
{
786786
public static void Free(System.IntPtr handle) { }
787+
public static System.IntPtr GetMainProgramHandle() { throw null; }
787788
public static System.IntPtr GetExport(System.IntPtr handle, string name) { throw null; }
788789
public static System.IntPtr Load(string libraryPath) { throw null; }
789790
public static System.IntPtr Load(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath) { throw null; }

src/mono/mono/metadata/native-library.c

+19-16
Original file line numberDiff line numberDiff line change
@@ -757,32 +757,35 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope)
757757
return result;
758758
}
759759

760+
static MonoDl*
761+
netcore_lookup_self_native_handle()
762+
{
763+
char *error_msg = NULL;
764+
if (!internal_module)
765+
internal_module = mono_dl_open_self (&error_msg);
766+
767+
if (!internal_module) {
768+
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
769+
g_free (error_msg);
770+
}
771+
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal.");
772+
return internal_module;
773+
}
774+
760775
static MonoDl *
761776
netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, const char *scope, guint32 flags)
762777
{
763778
MonoDl *module = NULL;
764779
MonoDl *cached;
765780
MonoAssembly *assembly = mono_image_get_assembly (image);
766-
char *error_msg = NULL;
767781

768782
MONO_REQ_GC_UNSAFE_MODE;
769783

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

772786
// We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR
773787
if (strcmp (scope, "__Internal") == 0) {
774-
if (!internal_module)
775-
internal_module = mono_dl_open_self (&error_msg);
776-
module = internal_module;
777-
778-
if (!module) {
779-
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
780-
g_free (error_msg);
781-
}
782-
783-
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal: '%s'.", scope);
784-
785-
return module;
788+
return netcore_lookup_self_native_handle();
786789
}
787790

788791
/*
@@ -1219,9 +1222,9 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, Mo
12191222
g_hash_table_add (native_library_module_blocklist, module);
12201223
mono_dl_close (module);
12211224
} else {
1222-
MonoDl raw_module = { { 0 } };
1223-
raw_module.handle = lib;
1224-
mono_dl_close (&raw_module);
1225+
MonoDl* raw_module = g_new0(MonoDl, 1);
1226+
raw_module->handle = lib;
1227+
mono_dl_close (raw_module);
12251228
}
12261229

12271230
leave:

src/native/libs/System.Native/entrypoints.c

+1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ static const Entry s_sysNative[] =
234234
DllImportEntry(SystemNative_LoadLibrary)
235235
DllImportEntry(SystemNative_GetProcAddress)
236236
DllImportEntry(SystemNative_FreeLibrary)
237+
DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle)
237238
DllImportEntry(SystemNative_SchedGetCpu)
238239
DllImportEntry(SystemNative_Exit)
239240
DllImportEntry(SystemNative_Abort)

src/native/libs/System.Native/pal_dynamicload.c

+17
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,20 @@ void SystemNative_FreeLibrary(void* handle)
5050
{
5151
dlclose(handle);
5252
}
53+
54+
#ifdef TARGET_ANDROID
55+
void* SystemNative_GetDefaultSearchOrderPseudoHandle(void)
56+
{
57+
return (void*)RTLD_DEFAULT;
58+
}
59+
#else
60+
static void* g_defaultSearchOrderPseudoHandle = NULL;
61+
void* SystemNative_GetDefaultSearchOrderPseudoHandle(void)
62+
{
63+
if (g_defaultSearchOrderPseudoHandle == NULL)
64+
{
65+
g_defaultSearchOrderPseudoHandle = dlopen(NULL, RTLD_LAZY);
66+
}
67+
return g_defaultSearchOrderPseudoHandle;
68+
}
69+
#endif

src/native/libs/System.Native/pal_dynamicload.h

+2
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ PALEXPORT void* SystemNative_LoadLibrary(const char* filename);
1111
PALEXPORT void* SystemNative_GetProcAddress(void* handle, const char* symbol);
1212

1313
PALEXPORT void SystemNative_FreeLibrary(void* handle);
14+
15+
PALEXPORT void* SystemNative_GetDefaultSearchOrderPseudoHandle(void);

src/tests/Common/CoreCLRTestLibrary/Utilities.cs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public static bool Verbose
5959
}
6060

6161
public static bool IsX86 => (RuntimeInformation.ProcessArchitecture == Architecture.X86);
62+
public static bool IsNotX86 => !IsX86;
6263
public static bool IsX64 => (RuntimeInformation.ProcessArchitecture == Architecture.X64);
6364
public static bool IsArm => (RuntimeInformation.ProcessArchitecture == Architecture.Arm);
6465
public static bool IsArm64 => (RuntimeInformation.ProcessArchitecture == Architecture.Arm64);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
using System;
4+
using System.Diagnostics;
5+
using System.IO;
6+
using System.Reflection;
7+
using System.Runtime.InteropServices;
8+
using Xunit;
9+
using static TestHelpers;
10+
11+
class GetLibraryExportTests : IDisposable
12+
{
13+
private readonly IntPtr handle;
14+
15+
public GetLibraryExportTests()
16+
{
17+
handle = NativeLibrary.Load(NativeLibraryToLoad.GetFullPath());
18+
}
19+
20+
[ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsX86))]
21+
public void GetValidExport_ManualMangling()
22+
{
23+
EXPECT(GetLibraryExport(handle, "_NativeSum@8"));
24+
EXPECT(TryGetLibraryExport(handle, "_NativeSum@8"));
25+
}
26+
27+
[ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotX86))]
28+
public void GetValidExport()
29+
{
30+
EXPECT(GetLibraryExport(handle, "NativeSum"));
31+
EXPECT(TryGetLibraryExport(handle, "NativeSum"));
32+
}
33+
34+
[Fact]
35+
public void NullHandle()
36+
{
37+
EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
38+
EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
39+
}
40+
41+
[Fact]
42+
public void NullExport()
43+
{
44+
EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull);
45+
EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull);
46+
}
47+
48+
[Fact]
49+
public void ExportDoesNotExist()
50+
{
51+
EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound);
52+
EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure);
53+
}
54+
55+
56+
public void Dispose() => NativeLibrary.Free(handle);
57+
58+
static TestResult GetLibraryExport(IntPtr handle, string name)
59+
{
60+
return Run(() => {
61+
IntPtr address = NativeLibrary.GetExport(handle, name);
62+
if (address == IntPtr.Zero)
63+
return TestResult.ReturnNull;
64+
if (RunExportedFunction(address, 1, 1) != 2)
65+
return TestResult.IncorrectEvaluation;
66+
return TestResult.Success;
67+
});
68+
}
69+
70+
static TestResult TryGetLibraryExport(IntPtr handle, string name)
71+
{
72+
return Run(() => {
73+
IntPtr address = IntPtr.Zero;
74+
bool success = NativeLibrary.TryGetExport(handle, name, out address);
75+
if (!success)
76+
return TestResult.ReturnFailure;
77+
if (address == IntPtr.Zero)
78+
return TestResult.ReturnNull;
79+
if (RunExportedFunction(address, 1, 1) != 2)
80+
return TestResult.IncorrectEvaluation;
81+
return TestResult.Success;
82+
});
83+
}
84+
85+
private static unsafe int RunExportedFunction(IntPtr address, int arg1, int arg2)
86+
{
87+
// We use a delegate here instead of a function pointer to avoid hitting issues
88+
// where Mono AOT doesn't generate the managed->native wrapper and then fails
89+
// when in AOT-only mode.
90+
NativeFunctionWrapper wrapper = Marshal.GetDelegateForFunctionPointer<NativeFunctionWrapper>(address);
91+
return wrapper(arg1, arg2);
92+
}
93+
94+
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
95+
private delegate int NativeFunctionWrapper(int arg1, int arg2);
96+
}

0 commit comments

Comments
 (0)