Skip to content

Commit

Permalink
So, big remaining issue I think was with Win32 (x86). Name mangling a…
Browse files Browse the repository at this point in the history
…lgo was removed, but was also not correct to begin with. Cleaned up and fixed. NativeLibrary.GetExport accepts size of arguments again.

Added a simple ConsoleApp, which doesn't really build by default, but which can be useful to debug.
  • Loading branch information
wasabii committed Sep 9, 2023
1 parent 4424e5e commit f31126a
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 24 deletions.
6 changes: 6 additions & 0 deletions IKVM.sln
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libfdlibm", "src\libfdlibm\
EndProject
Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libverify", "src\libverify\libverify.clangproj", "{61AD88EF-3D77-4BBE-94F9-6506428263D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IKVM.ConsoleApp", "src\IKVM.ConsoleApp\IKVM.ConsoleApp.csproj", "{E194D482-DAF3-43F3-9A76-D57F24403F89}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -699,6 +701,10 @@ Global
{61AD88EF-3D77-4BBE-94F9-6506428263D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61AD88EF-3D77-4BBE-94F9-6506428263D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61AD88EF-3D77-4BBE-94F9-6506428263D7}.Release|Any CPU.Build.0 = Release|Any CPU
{E194D482-DAF3-43F3-9A76-D57F24403F89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E194D482-DAF3-43F3-9A76-D57F24403F89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E194D482-DAF3-43F3-9A76-D57F24403F89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E194D482-DAF3-43F3-9A76-D57F24403F89}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
19 changes: 19 additions & 0 deletions src/IKVM.ConsoleApp/IKVM.ConsoleApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net481;net6.0</TargetFrameworks>
<LangVersion>11</LangVersion>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\IKVM.Java.Extensions\IKVM.Java.Extensions.csproj" />
<ProjectReference Include="..\IKVM.Image\IKVM.Image.csproj" />
<ProjectReference Include="..\IKVM.Tests.Util\IKVM.Tests.Util.csproj" />
<ProjectReference Include="..\IKVM.Tools.Runner\IKVM.Tools.Runner.csproj" />
<ProjectReference Include="..\IKVM.Util\IKVM.Util.csproj" />
</ItemGroup>

<Import Project="$(MSBuildThisFileDirectory)..\..\IKVM.deps.targets" />
<Import Project="$(MSBuildThisFileDirectory)..\..\IKVM.refs.targets" />
</Project>
16 changes: 16 additions & 0 deletions src/IKVM.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using IKVM.Runtime.JNI;

namespace IKVM.ConsoleApp
{
public static class Program
{

public static void Main(string[] args)
{
var f = new JNIFrame();
f.Enter(null);
}

}

}
67 changes: 52 additions & 15 deletions src/IKVM.Runtime/JNI/JNIFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ Jeroen Frijters

using IKVM.Internal;

using jarray = System.IntPtr;
using jboolean = System.SByte;
using jbooleanArray = System.IntPtr;
using jbyte = System.SByte;
using jbyteArray = System.IntPtr;
using jchar = System.UInt16;
using jcharArray = System.IntPtr;
using jclass = System.IntPtr;
using jdouble = System.Double;
using jdoubleArray = System.IntPtr;
using jfieldID = System.IntPtr;
using jfloat = System.Single;
using jfloatArray = System.IntPtr;
using jint = System.Int32;
using jintArray = System.IntPtr;
using jlong = System.Int64;
using jlongArray = System.IntPtr;
using jmethodID = System.IntPtr;
using jobject = System.IntPtr;
using jobjectArray = System.IntPtr;
using jshort = System.Int16;
using jshortArray = System.IntPtr;
using jsize = System.Int32;
using jstring = System.IntPtr;
using jthrowable = System.IntPtr;
using jweak = System.IntPtr;

namespace IKVM.Runtime.JNI
{

Expand Down Expand Up @@ -70,62 +97,72 @@ public void Leave()
}
}

public static IntPtr GetFuncPtr(ikvm.@internal.CallerID callerID, string clazz, string name, string sig)
public static nint GetFuncPtr(ikvm.@internal.CallerID callerID, string clazz, string name, string sig)
{
ClassLoaderWrapper loader = ClassLoaderWrapper.FromCallerID(callerID);
var loader = ClassLoaderWrapper.FromCallerID(callerID);
int sp = 0;
for (int i = 1; sig[i] != ')'; i++)
{
switch (sig[i])
{
case '[':
sp += IntPtr.Size;
sp += sizeof(jarray);
while (sig[++i] == '[') ;
if (sig[i] == 'L')
{
while (sig[++i] != ';') ;
}
break;
case 'L':
sp += IntPtr.Size;
sp += sizeof(jobject);
while (sig[++i] != ';') ;
break;
case 'J':
sp += sizeof(jlong);
break;
case 'D':
sp += 8;
sp += sizeof(jdouble);
break;
case 'F':
sp += sizeof(jfloat);
break;
case 'I':
sp += sizeof(jint);
break;
case 'C':
sp += sizeof(jchar);
break;
case 'Z':
sp += sizeof(jboolean);
break;
case 'S':
sp += sizeof(jshort);
break;
case 'B':
sp += 4;
sp += sizeof(jbyte);
break;
default:
Debug.Assert(false);
break;
throw new InternalException("Invalid JNI method signature.");
}
}

string mangledClass = JniMangle(clazz);
string mangledName = JniMangle(name);
string mangledSig = JniMangle(sig.Substring(1, sig.IndexOf(')') - 1));
string shortMethodName = $"Java_{mangledClass}_{mangledName}";
string longMethodName = $"Java_{mangledClass}_{mangledName}__{mangledSig}";
Tracer.Info(Tracer.Jni, "Linking native method: {0}.{1}{2}, class loader = {3}, short = {4}, long = {5}, args = {6}", clazz, name, sig, loader, shortMethodName, longMethodName, sp + 2 * IntPtr.Size);
Tracer.Info(Tracer.Jni, "Linking native method: {0}.{1}{2}, class loader = {3}, short = {4}, long = {5}, args = {6}", clazz, name, sig, loader, shortMethodName, longMethodName, sp + sizeof(nint) + sizeof(nint));

lock (JNINativeLoader.SyncRoot)
{
foreach (var p in loader.GetNativeLibraries())
{
var pfunc = NativeLibrary.GetExport(p, shortMethodName);
if (pfunc != IntPtr.Zero)
var pfunc = NativeLibrary.GetExport(p, shortMethodName, sp + sizeof(nint) + sizeof(nint));
if (pfunc != 0)
{
Tracer.Info(Tracer.Jni, "Native method {0}.{1}{2} found in library 0x{3:X} (short)", clazz, name, sig, p);
return pfunc;
}
pfunc = NativeLibrary.GetExport(p, longMethodName);
if (pfunc != IntPtr.Zero)
pfunc = NativeLibrary.GetExport(p, longMethodName, sp + sizeof(nint) + sizeof(nint));
if (pfunc != 0)
{
Tracer.Info(Tracer.Jni, "Native method {0}.{1}{2} found in library 0x{3:X} (long)", clazz, name, sig, p);
return pfunc;
Expand Down
4 changes: 2 additions & 2 deletions src/IKVM.Runtime/JNI/JNINativeLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public static long LoadLibrary(string filename, ClassLoaderWrapper loader)

try
{
var onload = NativeLibrary.GetExport(p, "JNI_OnLoad");
var onload = NativeLibrary.GetExport(p, "JNI_OnLoad", sizeof(nint) + sizeof(nint));
if (onload != 0)
{
Tracer.Info(Tracer.Jni, "Calling JNI_OnLoad on: {0}", filename);
Expand Down Expand Up @@ -163,7 +163,7 @@ public static void UnloadLibrary(long handle, ClassLoaderWrapper loader)

try
{
var onunload = NativeLibrary.GetExport(p, "JNI_OnUnload");
var onunload = NativeLibrary.GetExport(p, "JNI_OnUnload", sizeof(nint) + sizeof(nint));
if (onunload != 0)
{
Tracer.Info(Tracer.Jni, "Calling JNI_OnUnload on: handle = 0x{0:X}", handle);
Expand Down
6 changes: 3 additions & 3 deletions src/IKVM.Runtime/JNI/JNIVM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ static LibJvm()
if (p == 0)
throw new InternalException("Could not locate JVM library.");

set_JNI_GetDefaultJavaVMInitArgs = Marshal.GetDelegateForFunctionPointer<Set_JNI_GetDefaultJavaVMInitArgsDelegate>(NativeLibrary.GetExport(p, "Set_JNI_GetDefaultJavaVMInitArgs"));
set_JNI_GetCreatedJavaVMs = Marshal.GetDelegateForFunctionPointer<Set_JNI_GetCreatedJavaVMsDelegate>(NativeLibrary.GetExport(p, "Set_JNI_GetCreatedJavaVMs"));
set_JNI_CreateJavaVM = Marshal.GetDelegateForFunctionPointer<Set_JNI_CreateJavaVMDelegate>(NativeLibrary.GetExport(p, "Set_JNI_CreateJavaVM"));
set_JNI_GetDefaultJavaVMInitArgs = Marshal.GetDelegateForFunctionPointer<Set_JNI_GetDefaultJavaVMInitArgsDelegate>(NativeLibrary.GetExport(p, "Set_JNI_GetDefaultJavaVMInitArgs", sizeof(nint)));
set_JNI_GetCreatedJavaVMs = Marshal.GetDelegateForFunctionPointer<Set_JNI_GetCreatedJavaVMsDelegate>(NativeLibrary.GetExport(p, "Set_JNI_GetCreatedJavaVMs", sizeof(nint)));
set_JNI_CreateJavaVM = Marshal.GetDelegateForFunctionPointer<Set_JNI_CreateJavaVMDelegate>(NativeLibrary.GetExport(p, "Set_JNI_CreateJavaVM", sizeof(nint)));
}

public static void Set_JNI_GetDefaultJavaVMInitArgs(JNI_GetDefaultJavaVMInitArgsFunc func) => set_JNI_GetDefaultJavaVMInitArgs(func);
Expand Down
35 changes: 31 additions & 4 deletions src/IKVM.Runtime/NativeLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static class NativeLibrary
/// <param name="handle"></param>
/// <param name="name"></param>
/// <returns></returns>
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress", SetLastError = true)]
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern nint GetProcAddress(nint handle, string name);

const int RTLD_NOW = 2;
Expand Down Expand Up @@ -158,15 +158,43 @@ public static void Free(nint handle)
#endif
}

/// <summary>
/// Returns the Win32 mangled procedure name.
/// </summary>
/// <param name="name"></param>
/// <param name="argl"></param>
/// <returns></returns>
static string MangleWin32ExportName(string name, int argl)
{
return argl == -1 ? name : $"_{name}@{argl}";
}

/// <summary>
/// Returns the mangled procedure name.
/// </summary>
/// <param name="name"></param>
/// <param name="argl"></param>
/// <returns></returns>
static string MangleExportName(string name, int argl)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X86)
return MangleWin32ExportName(name, argl);
else
return name;
}

/// <summary>
/// Gets a function pointer to the given named function.
/// </summary>
/// <param name="handle"></param>
/// <param name="name"></param>
/// <param name="argl"></param>
/// <returns></returns>
/// <exception cref="PlatformNotSupportedException"></exception>
public static unsafe nint GetExport(nint handle, string name)
public static unsafe nint GetExport(nint handle, string name, int argl = -1)
{
name = MangleExportName(name, argl);

try
{
#if NETFRAMEWORK
Expand All @@ -175,8 +203,7 @@ public static unsafe nint GetExport(nint handle, string name)
else
return dlsym(handle, name);
#else
if (System.Runtime.InteropServices.NativeLibrary.TryGetExport(handle, name, out var h))
return h;
return System.Runtime.InteropServices.NativeLibrary.TryGetExport(handle, name, out var h) ? h : 0;
#endif
}
catch (EntryPointNotFoundException)
Expand Down

0 comments on commit f31126a

Please sign in to comment.