Add some draft work for supporting sysv <-> msabi interop. I wonder if we'll ever use this? I'd put it on a separate branch but it would be merge hell.

This commit is contained in:
nattthebear 2017-06-18 08:49:55 -04:00
parent d7423d45a0
commit 1292b27163
24 changed files with 2596 additions and 1361 deletions

View File

@ -73,7 +73,10 @@
<Compile Include="BizInvoke\BizExvoker.cs" />
<Compile Include="BizInvoke\BizInvoker.cs" />
<Compile Include="BizInvoke\BizInvokeUtilities.cs" />
<Compile Include="BizInvoke\CallingConventionAdapter.cs" />
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
<Compile Include="BizInvoke\MemoryBlock.cs" />
<Compile Include="BizInvoke\WaterboxUtils.cs" />
<Compile Include="Buffer.cs" />
<Compile Include="Colors.cs" />
<Compile Include="CustomCollections.cs" />

View File

@ -87,13 +87,13 @@ namespace BizHawk.Common.BizInvoke
private readonly List<Delegate> Delegates = new List<Delegate>();
public ExvokerImpl(object o, DelegateStorage d)
public ExvokerImpl(object o, DelegateStorage d, ICallingConventionAdapter a)
{
foreach (var sdt in d.DelegateTypes)
{
var del = Delegate.CreateDelegate(sdt.DelegateType, o, sdt.Method);
Delegates.Add(del); // prevent garbage collection of the delegate, which would invalidate the pointer
EntryPoints.Add(sdt.EntryPointName, Marshal.GetFunctionPointerForDelegate(del));
EntryPoints.Add(sdt.EntryPointName, a.GetFunctionPointerForDelegate(del));
}
}
@ -108,7 +108,7 @@ namespace BizHawk.Common.BizInvoke
static readonly Dictionary<Type, DelegateStorage> Impls = new Dictionary<Type, DelegateStorage>();
public static IImportResolver GetExvoker(object o)
public static IImportResolver GetExvoker(object o, ICallingConventionAdapter a)
{
DelegateStorage ds;
lock (Impls)
@ -121,7 +121,7 @@ namespace BizHawk.Common.BizInvoke
}
}
return new ExvokerImpl(o, ds);
return new ExvokerImpl(o, ds, a);
}
}

View File

@ -17,17 +17,18 @@ namespace BizHawk.Common.BizInvoke
private class InvokerImpl
{
public Type ImplType;
public List<Action<object, IImportResolver>> Hooks;
public List<Action<object, IImportResolver, ICallingConventionAdapter>> Hooks;
public Action<object, IMonitor> ConnectMonitor;
public Action<object, ICallingConventionAdapter> ConnectCallingConventionAdapter;
public object Create(IImportResolver dll, IMonitor monitor)
public object Create(IImportResolver dll, IMonitor monitor, ICallingConventionAdapter adapter)
{
var ret = Activator.CreateInstance(ImplType);
ConnectCallingConventionAdapter(ret, adapter);
foreach (var f in Hooks)
{
f(ret, dll);
f(ret, dll, adapter);
}
ConnectMonitor?.Invoke(ret, monitor);
return ret;
}
@ -59,7 +60,7 @@ namespace BizHawk.Common.BizInvoke
/// get an implementation proxy for an interop class
/// </summary>
/// <typeparam name="T">The class type that represents the DLL</typeparam>
public static T GetInvoker<T>(IImportResolver dll)
public static T GetInvoker<T>(IImportResolver dll, ICallingConventionAdapter adapter)
where T : class
{
InvokerImpl impl;
@ -78,10 +79,10 @@ namespace BizHawk.Common.BizInvoke
throw new InvalidOperationException("Class was previously proxied with a monitor!");
}
return (T)impl.Create(dll, null);
return (T)impl.Create(dll, null, adapter);
}
public static T GetInvoker<T>(IImportResolver dll, IMonitor monitor)
public static T GetInvoker<T>(IImportResolver dll, IMonitor monitor, ICallingConventionAdapter adapter)
where T : class
{
InvokerImpl impl;
@ -100,7 +101,7 @@ namespace BizHawk.Common.BizInvoke
throw new InvalidOperationException("Class was previously proxied without a monitor!");
}
return (T)impl.Create(dll, monitor);
return (T)impl.Create(dll, monitor, adapter);
}
private static InvokerImpl CreateProxy(Type baseType, bool monitor)
@ -153,19 +154,21 @@ namespace BizHawk.Common.BizInvoke
}
// hooks that will be run on the created proxy object
var postCreateHooks = new List<Action<object, IImportResolver>>();
var postCreateHooks = new List<Action<object, IImportResolver, ICallingConventionAdapter>>();
var type = ImplModuleBuilder.DefineType("Bizhawk.BizInvokeProxy" + baseType.Name, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, baseType);
var monitorField = monitor ? type.DefineField("MonitorField", typeof(IMonitor), FieldAttributes.Public) : null;
var adapterField = type.DefineField("CallingConvention", typeof(ICallingConventionAdapter), FieldAttributes.Public);
foreach (var mi in baseMethods)
{
var entryPointName = mi.Attr.EntryPoint ?? mi.Info.Name;
var hook = mi.Attr.Compatibility
? ImplementMethodDelegate(type, mi.Info, mi.Attr.CallingConvention, entryPointName, monitorField)
: ImplementMethodCalli(type, mi.Info, mi.Attr.CallingConvention, entryPointName, monitorField);
: ImplementMethodCalli(type, mi.Info, mi.Attr.CallingConvention, entryPointName, monitorField, adapterField);
postCreateHooks.Add(hook);
}
@ -179,6 +182,7 @@ namespace BizHawk.Common.BizInvoke
{
ret.ConnectMonitor = (o, m) => o.GetType().GetField(monitorField.Name).SetValue(o, m);
}
ret.ConnectCallingConventionAdapter = (o, a) => o.GetType().GetField(adapterField.Name).SetValue(o, a);
return ret;
}
@ -186,7 +190,8 @@ namespace BizHawk.Common.BizInvoke
/// <summary>
/// create a method implementation that uses GetDelegateForFunctionPointer internally
/// </summary>
private static Action<object, IImportResolver> ImplementMethodDelegate(TypeBuilder type, MethodInfo baseMethod, CallingConvention nativeCall, string entryPointName, FieldInfo monitorField)
private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodDelegate(
TypeBuilder type, MethodInfo baseMethod, CallingConvention nativeCall, string entryPointName, FieldInfo monitorField)
{
// create the delegate type
MethodBuilder delegateInvoke;
@ -196,6 +201,13 @@ namespace BizHawk.Common.BizInvoke
var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
var returnType = baseMethod.ReturnType;
if (paramTypes.Concat(new[] { returnType }).Any(typeof(Delegate).IsAssignableFrom))
{
// this isn't a problem if CallingConventionAdapters.Waterbox is a no-op
if (CallingConventionAdapters.Waterbox.GetType() != CallingConventionAdapters.Native.GetType())
throw new InvalidOperationException("Compatibility call mode cannot use ICallingConventionAdapters!");
}
// define a field on the class to hold the delegate
var field = type.DefineField(
"DelegateField" + baseMethod.Name,
@ -255,10 +267,10 @@ namespace BizHawk.Common.BizInvoke
type.DefineMethodOverride(method, baseMethod);
return (o, dll) =>
return (o, dll, adapter) =>
{
var entryPtr = dll.SafeResolve(entryPointName);
var interopDelegate = Marshal.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType());
var interopDelegate = adapter.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType());
o.GetType().GetField(field.Name).SetValue(o, interopDelegate);
};
}
@ -266,7 +278,9 @@ namespace BizHawk.Common.BizInvoke
/// <summary>
/// create a method implementation that uses calli internally
/// </summary>
private static Action<object, IImportResolver> ImplementMethodCalli(TypeBuilder type, MethodInfo baseMethod, CallingConvention nativeCall, string entryPointName, FieldInfo monitorField)
private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodCalli(
TypeBuilder type, MethodInfo baseMethod,
CallingConvention nativeCall, string entryPointName, FieldInfo monitorField, FieldInfo adapterField)
{
var paramInfos = baseMethod.GetParameters();
var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
@ -304,7 +318,7 @@ namespace BizHawk.Common.BizInvoke
for (int i = 0; i < paramTypes.Length; i++)
{
// arg 0 is this, so + 1
nativeParamTypes.Add(EmitParamterLoad(il, i + 1, paramTypes[i]));
nativeParamTypes.Add(EmitParamterLoad(il, i + 1, paramTypes[i], adapterField));
}
il.Emit(OpCodes.Ldarg_0);
@ -342,10 +356,11 @@ namespace BizHawk.Common.BizInvoke
type.DefineMethodOverride(method, baseMethod);
return (o, dll) =>
return (o, dll, adapter) =>
{
var entryPtr = dll.SafeResolve(entryPointName);
o.GetType().GetField(field.Name).SetValue(o, entryPtr);
o.GetType().GetField(field.Name).SetValue(
o, adapter.GetDepartureFunctionPointer(entryPtr, new ParameterInfo(returnType, paramTypes), o));
};
}
@ -394,7 +409,7 @@ namespace BizHawk.Common.BizInvoke
/// <summary>
/// emit a single parameter load with unmanaged conversions
/// </summary>
private static Type EmitParamterLoad(ILGenerator il, int idx, Type type)
private static Type EmitParamterLoad(ILGenerator il, int idx, Type type, FieldInfo adapterField)
{
if (type.IsGenericType)
{
@ -460,13 +475,15 @@ namespace BizHawk.Common.BizInvoke
if (typeof(Delegate).IsAssignableFrom(type))
{
var mi = typeof(Marshal).GetMethod("GetFunctionPointerForDelegate", new[] { typeof(Delegate) });
var mi = typeof(ICallingConventionAdapter).GetMethod("GetFunctionPointerForDelegate");
var end = il.DefineLabel();
var isNull = il.DefineLabel();
il.Emit(OpCodes.Ldarg, (short)idx);
il.Emit(OpCodes.Brfalse, isNull);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, adapterField);
il.Emit(OpCodes.Ldarg, (short)idx);
il.Emit(OpCodes.Call, mi);
il.Emit(OpCodes.Br, end);

View File

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Common.BizInvoke
{
/// <summary>
/// create interop delegates and function pointers for a particular calling convention
/// </summary>
public interface ICallingConventionAdapter
{
IntPtr GetFunctionPointerForDelegate(Delegate d);
IntPtr GetArrivalFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime);
Delegate GetDelegateForFunctionPointer(IntPtr p, Type delegateType);
IntPtr GetDepartureFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime);
}
public static class CallingConventionAdapterExtensions
{
public static T GetDelegateForFunctionPointer<T>(this ICallingConventionAdapter a, IntPtr p)
where T: class
{
return (T)(object)a.GetDelegateForFunctionPointer(p, typeof(T));
}
}
public class ParameterInfo
{
public Type ReturnType { get; }
public IReadOnlyList<Type> ParameterTypes { get; }
public ParameterInfo(Type returnType, IEnumerable<Type> parameterTypes)
{
ReturnType = returnType;
ParameterTypes = parameterTypes.ToList().AsReadOnly();
}
public ParameterInfo(Type delegateType)
{
if (!typeof(Delegate).IsAssignableFrom(delegateType))
throw new InvalidOperationException("Must be a delegate type!");
var invoke = delegateType.GetMethod("Invoke");
ReturnType = invoke.ReturnType;
ParameterTypes = invoke.GetParameters().Select(p => p.ParameterType).ToList().AsReadOnly();
}
}
public static class CallingConventionAdapters
{
private class NativeConvention : ICallingConventionAdapter
{
public IntPtr GetArrivalFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime)
{
return p;
}
public Delegate GetDelegateForFunctionPointer(IntPtr p, Type delegateType)
{
return Marshal.GetDelegateForFunctionPointer(p, delegateType);
}
public IntPtr GetDepartureFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime)
{
return p;
}
public IntPtr GetFunctionPointerForDelegate(Delegate d)
{
return Marshal.GetFunctionPointerForDelegate(d);
}
}
/// <summary>
/// native (pass-through) calling convention
/// </summary>
public static ICallingConventionAdapter Native { get; } = new NativeConvention();
/// <summary>
/// convention appropriate for waterbox guests
/// </summary>
public static ICallingConventionAdapter Waterbox { get; } =
#if true
new NativeConvention();
#else
new SysVHostMsGuest();
#endif
private class SysVHostMsGuest : ICallingConventionAdapter
{
private const ulong Placeholder = 0xdeadbeeffeedface;
private const byte Padding = 0x06;
private const int BlockSize = 256;
private static readonly byte[][] Depart =
{
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x8b, 0x55, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x48, 0x89, 0xd1, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x4c, 0x89, 0x4d, 0xd0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd0, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
};
private static readonly byte[][] Arrive =
{
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x8b, 0x55, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x48, 0x89, 0xd1, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x4c, 0x89, 0x4d, 0xd0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd0, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
};
private static readonly int[] DepartPlaceholderIndices;
private static readonly int[] ArrivePlaceholderIndices;
private static int FindPlaceholderIndex(byte[] data)
{
return Enumerable.Range(0, data.Length - 7)
.Single(i => BitConverter.ToUInt64(data, i) == Placeholder);
}
static SysVHostMsGuest()
{
DepartPlaceholderIndices = Depart.Select(FindPlaceholderIndex).ToArray();
ArrivePlaceholderIndices = Arrive.Select(FindPlaceholderIndex).ToArray();
if (Depart.Any(b => b.Length > BlockSize) || Arrive.Any(b => b.Length > BlockSize))
throw new InvalidOperationException();
}
private readonly MemoryBlock _memory;
private readonly object _sync = new object();
private readonly WeakReference[] _refs;
public SysVHostMsGuest()
{
int size = 4 * 1024 * 1024;
_memory = new MemoryBlock((ulong)size);
_memory.Activate();
_refs = new WeakReference[size / BlockSize];
}
private int FindFreeIndex()
{
for (int i = 0; i < _refs.Length; i++)
{
if (_refs[i] == null || !_refs[i].IsAlive)
return i;
}
throw new InvalidOperationException("Out of Thunk memory");
}
private static void VerifyParameter(Type type)
{
if (type == typeof(float) || type == typeof(double))
throw new NotSupportedException("floating point not supported");
if (type == typeof(void) || type.IsPrimitive)
return;
if (type.IsByRef || type.IsClass)
return;
throw new NotSupportedException("Unknown type. Possibly supported?");
}
private static int VerifyDelegateSignature(ParameterInfo pp)
{
VerifyParameter(pp.ReturnType);
foreach (var ppp in pp.ParameterTypes)
VerifyParameter(ppp);
return pp.ParameterTypes.Count;
}
private void WriteThunk(byte[] data, int placeholderIndex, IntPtr p, int index)
{
_memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RW);
var ss = _memory.GetStream(_memory.Start + (ulong)index * BlockSize, BlockSize, true);
ss.Write(data, 0, data.Length);
for (int i = data.Length; i < BlockSize; i++)
ss.WriteByte(Padding);
ss.Position = placeholderIndex;
var bw = new BinaryWriter(ss);
bw.Write((long)p);
_memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RX);
}
private IntPtr GetThunkAddress(int index)
{
return Z.US(_memory.Start + (ulong)index * BlockSize);
}
private void SetLifetime(int index, object lifetime)
{
if (_refs[index] == null)
_refs[index] = new WeakReference(lifetime);
else
_refs[index].Target = lifetime;
}
public IntPtr GetFunctionPointerForDelegate(Delegate d)
{
return GetArrivalFunctionPointer(
Marshal.GetFunctionPointerForDelegate(d), new ParameterInfo(d.GetType()), d);
}
public IntPtr GetArrivalFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime)
{
lock (_sync)
{
var index = FindFreeIndex();
var count = VerifyDelegateSignature(pp);
WriteThunk(Arrive[count], ArrivePlaceholderIndices[count], p, index);
SetLifetime(index, lifetime);
return GetThunkAddress(index);
}
}
public Delegate GetDelegateForFunctionPointer(IntPtr p, Type delegateType)
{
lock (_sync)
{
var index = FindFreeIndex();
var count = VerifyDelegateSignature(new ParameterInfo(delegateType));
WriteThunk(Depart[count], DepartPlaceholderIndices[count], p, index);
var ret = Marshal.GetDelegateForFunctionPointer(GetThunkAddress(index), delegateType);
SetLifetime(index, ret);
return ret;
}
}
public IntPtr GetDepartureFunctionPointer(IntPtr p, ParameterInfo pp, object lifetime)
{
lock (_sync)
{
var index = FindFreeIndex();
var count = VerifyDelegateSignature(pp);
WriteThunk(Depart[count], DepartPlaceholderIndices[count], p, index);
SetLifetime(index, lifetime);
return GetThunkAddress(index);
}
}
}
}
}

View File

@ -5,7 +5,7 @@ using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace BizHawk.Emulation.Cores.Waterbox
namespace BizHawk.Common.BizInvoke
{
public sealed class MemoryBlock : IDisposable
{

View File

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace BizHawk.Common.BizInvoke
{
public static class WaterboxUtils
{
/// <summary>
/// copy `len` bytes from `src` to `dest`
/// </summary>
/// <param name="src"></param>
/// <param name="dst"></param>
/// <param name="len"></param>
public static void CopySome(Stream src, Stream dst, long len)
{
var buff = new byte[4096];
while (len > 0)
{
int r = src.Read(buff, 0, (int)Math.Min(len, 4096));
dst.Write(buff, 0, r);
len -= r;
}
}
public static byte[] Hash(byte[] data)
{
using (var h = SHA1.Create())
{
return h.ComputeHash(data);
}
}
public static byte[] Hash(Stream s)
{
using (var h = SHA1.Create())
{
return h.ComputeHash(s);
}
}
public static unsafe void ZeroMemory(IntPtr mem, long length)
{
byte* p = (byte*)mem;
byte* end = p + length;
while (p < end)
{
*p++ = 0;
}
}
public static long Timestamp()
{
return DateTime.UtcNow.Ticks;
}
/// <summary>
/// system page size
/// </summary>
public static int PageSize { get; private set; }
/// <summary>
/// bitshift corresponding to PageSize
/// </summary>
public static int PageShift { get; private set; }
/// <summary>
/// bitmask corresponding to PageSize
/// </summary>
public static ulong PageMask { get; private set; }
static WaterboxUtils()
{
int p = PageSize = Environment.SystemPageSize;
while (p != 1)
{
p >>= 1;
PageShift++;
}
PageMask = (ulong)(PageSize - 1);
}
/// <summary>
/// true if addr is aligned
/// </summary>
public static bool Aligned(ulong addr)
{
return (addr & PageMask) == 0;
}
/// <summary>
/// align address down to previous page boundary
/// </summary>
public static ulong AlignDown(ulong addr)
{
return addr & ~PageMask;
}
/// <summary>
/// align address up to next page boundary
/// </summary>
public static ulong AlignUp(ulong addr)
{
return ((addr - 1) | PageMask) + 1;
}
/// <summary>
/// return the minimum number of pages needed to hold size
/// </summary>
public static int PagesNeeded(ulong size)
{
return (int)((size + PageMask) >> PageShift);
}
}
// C# is annoying: arithmetic operators for native ints are not exposed.
// So we store them as long/ulong instead in many places, and use these helpers
// to convert to IntPtr when needed
public static class Z
{
public static IntPtr US(ulong l)
{
if (IntPtr.Size == 8)
return (IntPtr)(long)l;
else
return (IntPtr)(int)l;
}
public static UIntPtr UU(ulong l)
{
if (UIntPtr.Size == 8)
return (UIntPtr)l;
else
return (UIntPtr)(uint)l;
}
public static IntPtr SS(long l)
{
if (IntPtr.Size == 8)
return (IntPtr)l;
else
return (IntPtr)(int)l;
}
public static UIntPtr SU(long l)
{
if (UIntPtr.Size == 8)
return (UIntPtr)(ulong)l;
else
return (UIntPtr)(uint)l;
}
}
}

View File

@ -1278,7 +1278,6 @@
<Compile Include="Waterbox\Heap.cs" />
<Compile Include="Waterbox\LibWaterboxCore.cs" />
<Compile Include="Waterbox\MapHeap.cs" />
<Compile Include="Waterbox\MemoryBlock.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sound\CDAudio.cs" />
<Compile Include="Sound\HuC6280PSG.cs" />

View File

@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
PlainHeapSizeKB = 16 * 1024,
MmapHeapSizeKB = 32 * 1024
});
_pizza = BizInvoker.GetInvoker<LibPizza>(_exe, _exe);
_pizza = BizInvoker.GetInvoker<LibPizza>(_exe, _exe, CallingConventionAdapters.Waterbox);
if (!_pizza.Init(rom, rom.Length))
{
throw new InvalidOperationException("Core rejected the rom!");

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
static QuickNES()
{
Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname);
QN = BizInvoker.GetInvoker<LibQuickNES>(Resolver);
QN = BizInvoker.GetInvoker<LibQuickNES>(Resolver, CallingConventionAdapters.Native);
}
[CoreConstructor("NES")]

View File

@ -69,7 +69,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
// Marshal checks that function pointers passed to GetDelegateForFunctionPointer are
// _currently_ valid when created, even though they don't need to be valid until
// the delegate is later invoked. so GetInvoker needs to be acquired within a lock.
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe);
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe, CallingConventionAdapters.Waterbox);
_comm = (CommStruct*)_core.DllInit().ToPointer();
}
}

View File

@ -207,7 +207,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
_core = core;
_push = push;
_pull = pull;
_exporter = BizExvoker.GetExvoker(this);
_exporter = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox);
_readcb = _exporter.SafeResolve("CommsReadCallback");
_pollcb = _exporter.SafeResolve("CommsPollCallback");
_writecb = _exporter.SafeResolve("CommsWriteCallback");

View File

@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
using (_elf.EnterExit())
{
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf, CallingConventionAdapters.Waterbox);
_syncSettings = (GPGXSyncSettings)syncSettings ?? new GPGXSyncSettings();
_settings = (GPGXSettings)settings ?? new GPGXSettings();

View File

@ -13,6 +13,7 @@ using System.IO;
using System.Collections.Concurrent;
using System.Threading;
using BizHawk.Emulation.Common;
using BizHawk.Common.BizInvoke;
namespace BizHawk.Emulation.Cores.Waterbox
{

View File

@ -1,4 +1,5 @@
using BizHawk.Emulation.Common;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
using System;
using System.Collections.Generic;
using System.IO;

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
using BizHawk.Common.BizInvoke;
namespace BizHawk.Emulation.Cores.Waterbox
{

View File

@ -107,7 +107,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
throw new InvalidOperationException(s);
};
_traps.Add(del);
ptr = Marshal.GetFunctionPointerForDelegate(del);
ptr = CallingConventionAdapters.Waterbox.GetFunctionPointerForDelegate(del);
}
return ptr;
}).ToArray();
@ -355,7 +355,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
[BizExport(CallingConvention.Cdecl, EntryPoint = "start_main")]
public unsafe int StartMain(IntPtr main, int argc, IntPtr argv, IntPtr libc_start_main)
{
//var del = (LibcStartMain)Marshal.GetDelegateForFunctionPointer(libc_start_main, typeof(LibcStartMain));
//var del = (LibcStartMain)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libc_start_main, typeof(LibcStartMain));
// this will init, and then call user main, and then call exit()
//del(main, argc, argv);
//int* foobar = stackalloc int[128];
@ -676,11 +676,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
// load any predefined exports
_psx = new Psx(this);
_exports.Add("libpsxscl.so", BizExvoker.GetExvoker(_psx));
_exports.Add("libpsxscl.so", BizExvoker.GetExvoker(_psx, CallingConventionAdapters.Waterbox));
_emu = new Emu(this);
_exports.Add("libemuhost.so", BizExvoker.GetExvoker(_emu));
_exports.Add("libemuhost.so", BizExvoker.GetExvoker(_emu, CallingConventionAdapters.Waterbox));
_syscalls = new Syscalls(this);
_exports.Add("__syscalls", BizExvoker.GetExvoker(_syscalls));
_exports.Add("__syscalls", BizExvoker.GetExvoker(_syscalls, CallingConventionAdapters.Waterbox));
// load and connect all modules, starting with the executable
var todoModules = new Queue<string>();
@ -730,7 +730,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
_libcpatch = new LibcPatch(this);
_exports["libc.so"] = new PatchImportResolver(_exports["libc.so"], BizExvoker.GetExvoker(_libcpatch));
_exports["libc.so"] = new PatchImportResolver(_exports["libc.so"], BizExvoker.GetExvoker(_libcpatch, CallingConventionAdapters.Waterbox));
ConnectAllImports();
@ -764,7 +764,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
var libcEnter = _exports["libc.so"].SafeResolve("__libc_entry_routine");
var psxInit = _exports["libpsxscl.so"].SafeResolve("__psx_init");
var del = (LibcEntryRoutineD)Marshal.GetDelegateForFunctionPointer(libcEnter, typeof(LibcEntryRoutineD));
var del = (LibcEntryRoutineD)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libcEnter, typeof(LibcEntryRoutineD));
// the current mmglue code doesn't use the main pointer at all, and this just returns
del(IntPtr.Zero, psxInit, 0);
@ -811,7 +811,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
if (_exports.TryGetValue("libco.so", out libco))
{
Console.WriteLine("Calling co_clean()...");
Marshal.GetDelegateForFunctionPointer<Action>(libco.SafeResolve("co_clean"))();
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(libco.SafeResolve("co_clean"))();
}
_sealedheap.Seal();

View File

@ -1,4 +1,5 @@
using BizHawk.Common;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
using PeNet;
using System;
@ -77,12 +78,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
/*public bool RunDllEntry()
{
var entryThunk = (DllEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(DllEntry));
var entryThunk = (DllEntry)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(EntryPoint, typeof(DllEntry));
return entryThunk(Z.US(Start), 1, IntPtr.Zero); // DLL_PROCESS_ATTACH
}
public void RunExeEntry()
{
var entryThunk = (ExeEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(ExeEntry));
var entryThunk = (ExeEntry)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(EntryPoint, typeof(ExeEntry));
entryThunk();
}*/
public unsafe void RunGlobalCtors()
@ -94,7 +95,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
IntPtr f;
while ((f = *++p) != IntPtr.Zero) // skip 0th dummy pointer
{
var ctorThunk = (GlobalCtor)Marshal.GetDelegateForFunctionPointer(f, typeof(GlobalCtor));
var ctorThunk = (GlobalCtor)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(f, typeof(GlobalCtor));
//Console.WriteLine(f);
//System.Diagnostics.Debugger.Break();
ctorThunk();

View File

@ -1,4 +1,5 @@
using BizHawk.Common;
using BizHawk.Common.BizInvoke;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

View File

@ -54,7 +54,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
_exe = new PeRunner(options);
using (_exe.EnterExit())
{
var ret = BizInvoker.GetInvoker<T>(_exe, _exe);
var ret = BizInvoker.GetInvoker<T>(_exe, _exe, CallingConventionAdapters.Waterbox);
_core = ret;
return ret;
}

2
waterbox/thunk/build.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
gcc test.c -o test.exe -Wall

20
waterbox/thunk/gen.cs Normal file
View File

@ -0,0 +1,20 @@
private static readonly byte[][] Depart =
{
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x8b, 0x55, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x48, 0x89, 0xd1, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x4c, 0x89, 0x4d, 0xd0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd0, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
};
private static readonly byte[][] Arrive =
{
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x8b, 0x55, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x48, 0x89, 0xd1, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
new byte[] { 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x60, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x89, 0x75, 0xf0, 0x48, 0x89, 0x55, 0xe8, 0x48, 0x89, 0x4d, 0xe0, 0x4c, 0x89, 0x45, 0xd8, 0x4c, 0x89, 0x4d, 0xd0, 0x48, 0x8b, 0x7d, 0xe0, 0x48, 0x8b, 0x75, 0xe8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x45, 0xd0, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x45, 0xd8, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xb8, 0xce, 0xfa, 0xed, 0xfe, 0xef, 0xbe, 0xad, 0xde, 0x49, 0x89, 0xf9, 0x49, 0x89, 0xf0, 0xff, 0xd0, 0xc9, 0xc3, },
};

103
waterbox/thunk/test.c Normal file
View File

@ -0,0 +1,103 @@
#include <stdint.h>
typedef int64_t ll;
__attribute__((sysv_abi)) ll Depart0(void)
{
return ((__attribute__((ms_abi)) ll (*)(void))0xdeadbeeffeedface)();
}
__attribute__((sysv_abi)) ll Depart1(ll a)
{
return ((__attribute__((ms_abi)) ll (*)(ll))0xdeadbeeffeedface)(a);
}
__attribute__((sysv_abi)) ll Depart2(ll a, ll b)
{
return ((__attribute__((ms_abi)) ll (*)(ll, ll))0xdeadbeeffeedface)(a, b);
}
__attribute__((sysv_abi)) ll Depart3(ll a, ll b, ll c)
{
return ((__attribute__((ms_abi)) ll (*)(ll, ll, ll))0xdeadbeeffeedface)(a, b, c);
}
__attribute__((sysv_abi)) ll Depart4(ll a, ll b, ll c, ll d)
{
return ((__attribute__((ms_abi)) ll (*)(ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d);
}
__attribute__((sysv_abi)) ll Depart5(ll a, ll b, ll c, ll d, ll e)
{
return ((__attribute__((ms_abi)) ll (*)(ll, ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d, e);
}
__attribute__((sysv_abi)) ll Depart6(ll a, ll b, ll c, ll d, ll e, ll f)
{
return ((__attribute__((ms_abi)) ll (*)(ll, ll, ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d, e, f);
}
__attribute__((ms_abi)) ll Arrive0(void)
{
return ((__attribute__((sysv_abi)) ll (*)(void))0xdeadbeeffeedface)();
}
__attribute__((ms_abi)) ll Arrive1(ll a)
{
return ((__attribute__((sysv_abi)) ll (*)(ll))0xdeadbeeffeedface)(a);
}
__attribute__((ms_abi)) ll Arrive2(ll a, ll b)
{
return ((__attribute__((sysv_abi)) ll (*)(ll, ll))0xdeadbeeffeedface)(a, b);
}
__attribute__((ms_abi)) ll Arrive3(ll a, ll b, ll c)
{
return ((__attribute__((sysv_abi)) ll (*)(ll, ll, ll))0xdeadbeeffeedface)(a, b, c);
}
__attribute__((ms_abi)) ll Arrive4(ll a, ll b, ll c, ll d)
{
return ((__attribute__((sysv_abi)) ll (*)(ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d);
}
__attribute__((ms_abi)) ll Arrive5(ll a, ll b, ll c, ll d, ll e)
{
return ((__attribute__((sysv_abi)) ll (*)(ll, ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d, e);
}
__attribute__((ms_abi)) ll Arrive6(ll a, ll b, ll c, ll d, ll e, ll f)
{
return ((__attribute__((sysv_abi)) ll (*)(ll, ll, ll, ll, ll, ll))0xdeadbeeffeedface)(a, b, c, d, e, f);
}
void End(void)
{
}
#include <stdio.h>
const void* ptrs[] = { Depart0, Depart1, Depart2, Depart3, Depart4, Depart5, Depart6,
Arrive0, Arrive1, Arrive2, Arrive3, Arrive4, Arrive5, Arrive6, End };
void print(const char* name, int offs)
{
printf("private static readonly byte[][] %s =\n{\n", name);
for (int i = offs; i < offs + 7; i++)
{
printf("\tnew byte[] { ");
const uint8_t* start = ptrs[i];
const uint8_t* end = ptrs[i + 1];
while (start < end)
printf("0x%02x, ", *start++);
printf("},\n");
}
printf("};\n");
}
int main(void)
{
print("Depart", 0);
print("Arrive", 0);
return 0;
}

BIN
waterbox/thunk/test.exe Normal file

Binary file not shown.

682
waterbox/thunk/test.s Normal file
View File

@ -0,0 +1,682 @@
.file "test.c"
.text
.globl Depart0
.def Depart0; .scl 2; .type 32; .endef
Depart0:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
movabsq $-2401053088335136050, %rax
call *%rax
leave
ret
.globl Depart1
.def Depart1; .scl 2; .type 32; .endef
Depart1:
pushq %rbp
movq %rsp, %rbp
subq $48, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rdx
movabsq $-2401053088335136050, %rax
movq %rdx, %rcx
call *%rax
leave
ret
.globl Depart2
.def Depart2; .scl 2; .type 32; .endef
Depart2:
pushq %rbp
movq %rsp, %rbp
subq $48, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rdx
movq -8(%rbp), %rcx
movabsq $-2401053088335136050, %rax
call *%rax
leave
ret
.globl Depart3
.def Depart3; .scl 2; .type 32; .endef
Depart3:
pushq %rbp
movq %rsp, %rbp
subq $64, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
movq -24(%rbp), %rsi
movq -16(%rbp), %rdx
movq -8(%rbp), %rcx
movabsq $-2401053088335136050, %rax
movq %rsi, %r8
call *%rax
leave
ret
.globl Depart4
.def Depart4; .scl 2; .type 32; .endef
Depart4:
pushq %rbp
movq %rsp, %rbp
subq $64, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
movq %rcx, -32(%rbp)
movq -32(%rbp), %rdi
movq -24(%rbp), %rsi
movq -16(%rbp), %rdx
movq -8(%rbp), %rcx
movabsq $-2401053088335136050, %rax
movq %rdi, %r9
movq %rsi, %r8
call *%rax
leave
ret
.globl Depart5
.def Depart5; .scl 2; .type 32; .endef
Depart5:
pushq %rbp
movq %rsp, %rbp
subq $96, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
movq %rcx, -32(%rbp)
movq %r8, -40(%rbp)
movq -32(%rbp), %rdi
movq -24(%rbp), %rsi
movq -16(%rbp), %rdx
movq -8(%rbp), %rcx
movq -40(%rbp), %rax
movq %rax, 32(%rsp)
movabsq $-2401053088335136050, %rax
movq %rdi, %r9
movq %rsi, %r8
call *%rax
leave
ret
.globl Depart6
.def Depart6; .scl 2; .type 32; .endef
Depart6:
pushq %rbp
movq %rsp, %rbp
subq $96, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
movq %rcx, -32(%rbp)
movq %r8, -40(%rbp)
movq %r9, -48(%rbp)
movq -32(%rbp), %rdi
movq -24(%rbp), %rsi
movq -16(%rbp), %rdx
movq -8(%rbp), %rcx
movq -48(%rbp), %rax
movq %rax, 40(%rsp)
movq -40(%rbp), %rax
movq %rax, 32(%rsp)
movabsq $-2401053088335136050, %rax
movq %rdi, %r9
movq %rsi, %r8
call *%rax
leave
ret
.globl Arrive0
.def Arrive0; .scl 2; .type 32; .endef
.seh_proc Arrive0
Arrive0:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movabsq $-2401053088335136050, %rax
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive1
.def Arrive1; .scl 2; .type 32; .endef
.seh_proc Arrive1
Arrive1:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movabsq $-2401053088335136050, %rax
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive2
.def Arrive2; .scl 2; .type 32; .endef
.seh_proc Arrive2
Arrive2:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq 40(%rbp), %rdx
movabsq $-2401053088335136050, %rax
movq %rdx, %rsi
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive3
.def Arrive3; .scl 2; .type 32; .endef
.seh_proc Arrive3
Arrive3:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq %r8, 48(%rbp)
movq 48(%rbp), %rdx
movq 40(%rbp), %rcx
movabsq $-2401053088335136050, %rax
movq %rcx, %rsi
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive4
.def Arrive4; .scl 2; .type 32; .endef
.seh_proc Arrive4
Arrive4:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq %r8, 48(%rbp)
movq %r9, 56(%rbp)
movq 56(%rbp), %rcx
movq 48(%rbp), %rdx
movq 40(%rbp), %r8
movabsq $-2401053088335136050, %rax
movq %r8, %rsi
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive5
.def Arrive5; .scl 2; .type 32; .endef
.seh_proc Arrive5
Arrive5:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq %r8, 48(%rbp)
movq %r9, 56(%rbp)
movq 64(%rbp), %r8
movq 56(%rbp), %rcx
movq 48(%rbp), %rdx
movq 40(%rbp), %r9
movabsq $-2401053088335136050, %rax
movq %r9, %rsi
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl Arrive6
.def Arrive6; .scl 2; .type 32; .endef
.seh_proc Arrive6
Arrive6:
pushq %rbp
.seh_pushreg %rbp
pushq %rdi
.seh_pushreg %rdi
pushq %rsi
.seh_pushreg %rsi
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $160, %rsp
.seh_stackalloc 160
movaps %xmm6, (%rsp)
.seh_savexmm %xmm6, 0
movaps %xmm7, 16(%rsp)
.seh_savexmm %xmm7, 16
movaps %xmm8, -128(%rbp)
.seh_savexmm %xmm8, 32
movaps %xmm9, -112(%rbp)
.seh_savexmm %xmm9, 48
movaps %xmm10, -96(%rbp)
.seh_savexmm %xmm10, 64
movaps %xmm11, -80(%rbp)
.seh_savexmm %xmm11, 80
movaps %xmm12, -64(%rbp)
.seh_savexmm %xmm12, 96
movaps %xmm13, -48(%rbp)
.seh_savexmm %xmm13, 112
movaps %xmm14, -32(%rbp)
.seh_savexmm %xmm14, 128
movaps %xmm15, -16(%rbp)
.seh_savexmm %xmm15, 144
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq %r8, 48(%rbp)
movq %r9, 56(%rbp)
movq 72(%rbp), %r9
movq 64(%rbp), %r8
movq 56(%rbp), %rcx
movq 48(%rbp), %rdx
movq 40(%rbp), %r10
movabsq $-2401053088335136050, %rax
movq %r10, %rsi
movq 32(%rbp), %rdi
call *%rax
movaps (%rsp), %xmm6
movaps 16(%rsp), %xmm7
movaps -128(%rbp), %xmm8
movaps -112(%rbp), %xmm9
movaps -96(%rbp), %xmm10
movaps -80(%rbp), %xmm11
movaps -64(%rbp), %xmm12
movaps -48(%rbp), %xmm13
movaps -32(%rbp), %xmm14
movaps -16(%rbp), %xmm15
addq $160, %rsp
popq %rsi
popq %rdi
popq %rbp
ret
.seh_endproc
.globl End
.def End; .scl 2; .type 32; .endef
.seh_proc End
End:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
nop
popq %rbp
ret
.seh_endproc
.globl ptrs
.data
.align 32
ptrs:
.quad Depart0
.quad Depart1
.quad Depart2
.quad Depart3
.quad Depart4
.quad Depart5
.quad Depart6
.quad Arrive0
.quad Arrive1
.quad Arrive2
.quad Arrive3
.quad Arrive4
.quad Arrive5
.quad Arrive6
.quad End
.section .rdata,"dr"
.align 8
.LC0:
.ascii "private static readonly byte[][] %s =\12{\12\0"
.LC1:
.ascii "\11new byte[] { \0"
.LC2:
.ascii "0x%02x, \0"
.LC3:
.ascii "},\0"
.LC4:
.ascii "};\0"
.text
.globl print
.def print; .scl 2; .type 32; .endef
.seh_proc print
print:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $64, %rsp
.seh_stackalloc 64
.seh_endprologue
movq %rcx, 16(%rbp)
movl %edx, 24(%rbp)
movq 16(%rbp), %rdx
leaq .LC0(%rip), %rcx
call printf
movl 24(%rbp), %eax
movl %eax, -4(%rbp)
jmp .L31
.L34:
leaq .LC1(%rip), %rcx
call printf
movl -4(%rbp), %eax
cltq
leaq 0(,%rax,8), %rdx
leaq ptrs(%rip), %rax
movq (%rdx,%rax), %rax
movq %rax, -16(%rbp)
movl -4(%rbp), %eax
addl $1, %eax
cltq
leaq 0(,%rax,8), %rdx
leaq ptrs(%rip), %rax
movq (%rdx,%rax), %rax
movq %rax, -24(%rbp)
jmp .L32
.L33:
movq -16(%rbp), %rax
leaq 1(%rax), %rdx
movq %rdx, -16(%rbp)
movzbl (%rax), %eax
movzbl %al, %eax
movl %eax, %edx
leaq .LC2(%rip), %rcx
call printf
.L32:
movq -16(%rbp), %rax
cmpq -24(%rbp), %rax
jb .L33
leaq .LC3(%rip), %rcx
call puts
addl $1, -4(%rbp)
.L31:
movl 24(%rbp), %eax
addl $7, %eax
cmpl -4(%rbp), %eax
jg .L34
leaq .LC4(%rip), %rcx
call puts
nop
addq $64, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC5:
.ascii "Depart\0"
.LC6:
.ascii "Arrive\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
movl $0, %edx
leaq .LC5(%rip), %rcx
call print
movl $0, %edx
leaq .LC6(%rip), %rcx
call print
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (Rev2, Built by MSYS2 project) 5.3.0"
.def printf; .scl 2; .type 32; .endef
.def puts; .scl 2; .type 32; .endef