Add enough changes so that snes9x now boots. This includes stubs for a bunch of syscalls, a few mmglue changes, and C++ global constructor support

This commit is contained in:
nattthebear 2017-05-27 12:29:05 -04:00
parent 7739b9dc80
commit 2665510502
7 changed files with 443 additions and 64 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace BizHawk.Common namespace BizHawk.Common
{ {
@ -29,4 +30,32 @@ namespace BizHawk.Common
return ret; return ret;
} }
} }
/// <summary>
/// compose multiple ImportResolvers, where subsequent ones takes precedence over earlier ones
/// </summary>
public class PatchImportResolver : IImportResolver
{
private readonly List<IImportResolver> _resolvers = new List<IImportResolver>();
public PatchImportResolver(params IImportResolver[] rr)
{
Add(rr);
}
public void Add(params IImportResolver[] rr)
{
_resolvers.AddRange(rr);
}
public IntPtr Resolve(string entryPoint)
{
for (int i = _resolvers.Count - 1; i >= 0; i--)
{
var ret = _resolvers[i].Resolve(entryPoint);
if (ret != IntPtr.Zero)
return ret;
}
return IntPtr.Zero;
}
}
} }

View File

@ -19,12 +19,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
ServiceProvider = new BasicServiceProvider(this); ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm; CoreComm = comm;
_exe = new PeRunner(comm.CoreFileProvider.DllPath(), "snes9x.exe", 20 * 1024 * 1024, 65536, 65536); _exe = new PeRunner(new PeRunnerOptions
{
Path = comm.CoreFileProvider.DllPath(),
Filename = "snes9x.exe",
NormalHeapSizeKB = 32 * 1024,
SealedHeapSizeKB = 32 * 1024,
InvisibleHeapSizeKB = 32 * 1024,
SpecialHeapSizeKB = 1024
});
try try
{ {
_core = BizInvoker.GetInvoker<LibSnes9x>(_exe, _exe); _core = BizInvoker.GetInvoker<LibSnes9x>(_exe, _exe);
//Console.WriteLine(_exe.Resolve("biz_init"));
//System.Diagnostics.Debugger.Break();
if (!_core.biz_init()) if (!_core.biz_init())
{ {
throw new InvalidOperationException("Init() failed"); throw new InvalidOperationException("Init() failed");

View File

@ -42,7 +42,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
try try
{ {
_elf = new PeRunner(comm.CoreFileProvider.DllPath(), "gpgx.exe", 8 * 1024 * 1024, 36 * 1024 * 1024, 4 * 1024 * 1024); _elf = new PeRunner(new PeRunnerOptions
{
Path = comm.CoreFileProvider.DllPath(),
Filename = "gpgx.exe",
NormalHeapSizeKB = 8 * 1024,
SealedHeapSizeKB = 36 * 1024,
InvisibleHeapSizeKB = 4 * 1024,
SpecialHeapSizeKB = 64
});
if (_elf.ShouldMonitor) if (_elf.ShouldMonitor)
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf); Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);

View File

@ -11,6 +11,41 @@ using System.Text;
namespace BizHawk.Emulation.Cores.Waterbox namespace BizHawk.Emulation.Cores.Waterbox
{ {
public class PeRunnerOptions
{
// string directory, string filename, ulong heapsize, ulong sealedheapsize, ulong invisibleheapsize
/// <summary>
/// path which the main executable and all associated libraries should be found
/// </summary>
public string Path { get; set; }
/// <summary>
/// filename of the main executable; expected to be in Path
/// </summary>
public string Filename { get; set; }
/// <summary>
/// how large the normal heap should be. it services sbrk calls
/// </summary>
public uint NormalHeapSizeKB { get; set; }
/// <summary>
/// how large the sealed heap should be. it services special allocations that become readonly after init
/// </summary>
public uint SealedHeapSizeKB { get; set; }
/// <summary>
/// how large the invisible heap should be. it services special allocations which are not savestated
/// </summary>
public uint InvisibleHeapSizeKB { get; set; }
/// <summary>
/// how large the special heap should be. it is savestated, and contains ??
/// </summary>
public uint SpecialHeapSizeKB { get; set; }
}
public class PeRunner : Swappable, IImportResolver, IBinaryStateable public class PeRunner : Swappable, IImportResolver, IBinaryStateable
{ {
/// <summary> /// <summary>
@ -41,12 +76,23 @@ namespace BizHawk.Emulation.Cores.Waterbox
public IntPtr EntryPoint { get; private set; } public IntPtr EntryPoint { get; private set; }
[UnmanagedFunctionPointer(CallingConvention.Winapi)] /// <summary>
/// for midipix-built PEs, pointer to the construtors to run during init
/// </summary>
public IntPtr CtorList { get; private set; }
/// <summary>
/// for midipix-build PEs, pointer to the destructors to run during fini
/// </summary>
public IntPtr DtorList { get; private set; }
/*[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved); private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Winapi)] [UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate void ExeEntry(); private delegate void ExeEntry();*/
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void GlobalCtor();
public bool RunDllEntry() /*public bool RunDllEntry()
{ {
var entryThunk = (DllEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(DllEntry)); var entryThunk = (DllEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(DllEntry));
return entryThunk(Z.US(Start), 1, IntPtr.Zero); // DLL_PROCESS_ATTACH return entryThunk(Z.US(Start), 1, IntPtr.Zero); // DLL_PROCESS_ATTACH
@ -55,6 +101,32 @@ namespace BizHawk.Emulation.Cores.Waterbox
{ {
var entryThunk = (ExeEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(ExeEntry)); var entryThunk = (ExeEntry)Marshal.GetDelegateForFunctionPointer(EntryPoint, typeof(ExeEntry));
entryThunk(); entryThunk();
}*/
public unsafe void RunGlobalCtors()
{
int did = 0;
if (CtorList != IntPtr.Zero)
{
IntPtr* p = (IntPtr*)CtorList;
IntPtr f;
while ((f = *++p) != IntPtr.Zero) // skip 0th dummy pointer
{
var ctorThunk = (GlobalCtor)Marshal.GetDelegateForFunctionPointer(f, typeof(GlobalCtor));
//Console.WriteLine(f);
//System.Diagnostics.Debugger.Break();
ctorThunk();
did++;
}
}
if (did > 0)
{
Console.WriteLine($"Did {did} global ctors for {ModuleName}");
}
else
{
Console.WriteLine($"Warn: no global ctors for {ModuleName}; possibly no C++?");
}
} }
public PeWrapper(string moduleName, byte[] fileData, ulong destAddress) public PeWrapper(string moduleName, byte[] fileData, ulong destAddress)
@ -127,6 +199,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
// apply relocations // apply relocations
var n32 = 0;
var n64 = 0;
foreach (var rel in _pe.ImageRelocationDirectory) foreach (var rel in _pe.ImageRelocationDirectory)
{ {
foreach (var to in rel.TypeOffsets) foreach (var to in rel.TypeOffsets)
@ -145,6 +219,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
uint val = BitConverter.ToUInt32(tmp, 0); uint val = BitConverter.ToUInt32(tmp, 0);
tmp = BitConverter.GetBytes((uint)(val + LoadOffset)); tmp = BitConverter.GetBytes((uint)(val + LoadOffset));
Marshal.Copy(tmp, 0, Z.US(address), 4); Marshal.Copy(tmp, 0, Z.US(address), 4);
n32++;
break; break;
} }
@ -155,11 +230,19 @@ namespace BizHawk.Emulation.Cores.Waterbox
long val = BitConverter.ToInt64(tmp, 0); long val = BitConverter.ToInt64(tmp, 0);
tmp = BitConverter.GetBytes(val + LoadOffset); tmp = BitConverter.GetBytes(val + LoadOffset);
Marshal.Copy(tmp, 0, Z.US(address), 8); Marshal.Copy(tmp, 0, Z.US(address), 8);
n64++;
break; break;
} }
} }
} }
} }
if (IntPtr.Size == 8 && n32 > 0)
{
// check mcmodel, etc
throw new InvalidOperationException("32 bit relocations found in 64 bit dll! This will fail.");
}
Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations");
ProtectMemory(); ProtectMemory();
// publish exports // publish exports
@ -184,6 +267,15 @@ namespace BizHawk.Emulation.Cores.Waterbox
module.Add(import.Name, Z.US(Start + import.Thunk)); module.Add(import.Name, Z.US(Start + import.Thunk));
} }
var midipix = _pe.ImageSectionHeaders.Where(s => s.Name.SequenceEqual(Encoding.ASCII.GetBytes(".midipix")))
.SingleOrDefault();
if (midipix != null)
{
var dataOffset = midipix.PointerToRawData;
CtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x30)) + LoadOffset);
DtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x38)) + LoadOffset);
}
Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}"); Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}");
foreach (var s in _pe.ImageSectionHeaders.OrderBy(s => s.VirtualAddress)) foreach (var s in _pe.ImageSectionHeaders.OrderBy(s => s.VirtualAddress))
{ {
@ -293,6 +385,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary> /// </summary>
private class Psx private class Psx
{ {
private static IntPtr BEXLAND;
static Psx()
{
BEXLAND = Marshal.AllocHGlobal(16);
}
private readonly PeRunner _parent; private readonly PeRunner _parent;
private readonly List<Delegate> _traps = new List<Delegate>(); private readonly List<Delegate> _traps = new List<Delegate>();
@ -326,9 +424,15 @@ namespace BizHawk.Emulation.Cores.Waterbox
if (ptr == IntPtr.Zero) if (ptr == IntPtr.Zero)
{ {
var s = string.Format("Trapped on unimplemented function {0}:{1}", moduleName, e); var s = string.Format("Trapped on unimplemented function {0}:{1}", moduleName, e);
Action del = () => { throw new InvalidOperationException(s); }; Action del = () =>
{
Console.WriteLine(s);
System.Diagnostics.Debugger.Break(); // do not remove this until all unwindings are fixed
throw new InvalidOperationException(s);
};
_traps.Add(del); _traps.Add(del);
ptr = Marshal.GetFunctionPointerForDelegate(del); ptr = Marshal.GetFunctionPointerForDelegate(del);
//ptr = BEXLAND;
} }
return ptr; return ptr;
}).ToArray(); }).ToArray();
@ -349,8 +453,13 @@ namespace BizHawk.Emulation.Cores.Waterbox
}, _ldsoVtable); }, _ldsoVtable);
PopulateVtable("__syscalls", new[] // psx PopulateVtable("__syscalls", new[] // psx
{ {
"start_main", "convert_thread", "unmapself", "log_output" "start_main", "convert_thread", "unmapself", "log_output", "pthread_self"
}, _psxVtable); }, _psxVtable);
/*unsafe
{
var ptr = (IntPtr*)_psxVtable;
Console.WriteLine("AWESOMES: " + ptr[0]);
}*/
} }
private IntPtr _syscallVtable; private IntPtr _syscallVtable;
@ -377,7 +486,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
context.SyscallVtable = _syscallVtable = AllocVtable(340); context.SyscallVtable = _syscallVtable = AllocVtable(340);
context.LdsoVtable = _ldsoVtable = AllocVtable(7); context.LdsoVtable = _ldsoVtable = AllocVtable(7);
context.PsxVtable = _psxVtable = AllocVtable(4); context.PsxVtable = _psxVtable = AllocVtable(5);
ReloadVtables(); ReloadVtables();
@ -439,6 +548,15 @@ namespace BizHawk.Emulation.Cores.Waterbox
_parent = parent; _parent = parent;
} }
private IntPtr _pthreadSelf;
public void Init()
{
// as the inits are done in a defined order with a defined memory map,
// we don't need to savestate _pthreadSelf
_pthreadSelf = Z.US(_parent._specheap.Allocate(65536, 1));
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "log_output")] [BizExport(CallingConvention.Cdecl, EntryPoint = "log_output")]
public void DebugPuts(IntPtr s) public void DebugPuts(IntPtr s)
{ {
@ -479,14 +597,215 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
// aka __psx_init_frame [BizExport(CallingConvention.Cdecl, EntryPoint = "n16")]
// in midipix, this just sets up SEH and does not do anything that start_main does in MUSL normally public int IoCtl(int fd, ulong req)
[BizExport(CallingConvention.Cdecl, EntryPoint = "start_main")]
public int StartMain(IntPtr u0, int u1, IntPtr u2, IntPtr main)
{ {
// since we don't really need main, we can blow up here return 0; // sure it worked, honest
throw new EndOfMainException();
} }
public struct Iovec
{
public IntPtr Base;
public ulong Length;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n0")]
public long Read(int fd, IntPtr buff, ulong count)
{
return 0;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n1")]
public long Write(int fd, IntPtr buff, ulong count)
{
return (long)count;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n19")]
public unsafe long Readv(int fd, Iovec* iov, int iovcnt)
{
return 0;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n20")]
public unsafe long Writev(int fd, Iovec* iov, int iovcnt)
{
long ret = 0;
for (int i = 0; i < iovcnt; i++)
{
ret += (long)iov[i].Length;
}
return ret;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n2")]
public int Open(string path, int flags, int mode)
{
return -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n3")]
public int Close(int fd)
{
return 0;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n4")]
public int Stat(string path, IntPtr statbuf)
{
return -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n5")]
public int Fstat(int fd, IntPtr statbuf)
{
return -1;
}
//[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
//private delegate int LibcStartMain(IntPtr main, int argc, IntPtr argv);
bool _firstTime = true;
// aka __psx_init_frame (it's used elsewhere for thread setup)
// in midipix, this just sets up a SEH frame and then calls musl's start_main
[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));
// this will init, and then call user main, and then call exit()
//del(main, argc, argv);
//int* foobar = stackalloc int[128];
// if we return from this, psx will then halt, so break out
//if (_firstTime)
//{
//_firstTime = false;
throw new EndOfMainException();
//}
//else
//{
// return 0;
//}
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_self")]
public IntPtr PthreadSelf()
{
return _pthreadSelf;
}
/*[BizExport(CallingConvention.Cdecl, EntryPoint = "convert_thread")]
public void ConvertThread()
{
}*/
[BizExport(CallingConvention.Cdecl, EntryPoint = "n218")]
public long SetTidAddress(IntPtr address)
{
return 8675309;
}
[StructLayout(LayoutKind.Sequential)]
public class TimeSpec
{
public long Seconds;
public long NanoSeconds;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n228")]
public int SysClockGetTime(int which, [In,Out] TimeSpec time)
{
time.Seconds = 1495889068;
time.NanoSeconds = 0;
return 0;
}
}
/// <summary>
/// libc.so functions that we want to redirect
/// </summary>
private class LibcPatch
{
private readonly PeRunner _parent;
public LibcPatch(PeRunner parent)
{
_parent = parent;
}
private bool _didOnce = false;
private readonly Dictionary<uint, IntPtr> _specificKeys = new Dictionary<uint, IntPtr>();
private uint _nextSpecificKey = 401;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PthreadCallback();
// pthread stuff:
// since we don't allow multiple threads (for now), this is all pretty simple
/*
// int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_key_create")]
public int PthreadKeyCreate(ref uint key, PthreadCallback destructor)
{
key = _nextSpecificKey++;
_specificKeys.Add(key, IntPtr.Zero);
return 0;
}
// int pthread_key_delete(pthread_key_t key);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_key_delete")]
public int PthreadKeyDelete(uint key)
{
_specificKeys.Remove(key);
return 0;
}
// int pthread_setspecific(pthread_key_t key, const void *value);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_setspecific")]
public int PthreadSetSpecific(uint key, IntPtr value)
{
_specificKeys[key] = value;
return 0;
}
// void *pthread_getspecific(pthread_key_t key);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_getspecific")]
public IntPtr PthreadGetSpecific(uint key)
{
IntPtr ret;
_specificKeys.TryGetValue(key, out ret);
return ret;
}
// int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_once")]
public int PthreadOnce(IntPtr control, PthreadCallback init)
{
if (!_didOnce)
{
System.Diagnostics.Debugger.Break();
_didOnce = true;
init();
}
return 0;
}
// int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t* attr);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_mutex_init")]
public int PthreadMutexInit(IntPtr mutex, IntPtr attr) { return 0; }
// int pthread_mutex_destroy(pthread_mutex_t* mutex);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_mutex_destroy")]
public int PthreadMutexDestroy(IntPtr mutex) { return 0; }
// int pthread_mutex_lock(pthread_mutex_t* mutex);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_mutex_lock")]
public int PthreadMutexLock(IntPtr mutex) { return 0; }
// int pthread_mutex_trylock(pthread_mutex_t* mutex);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_mutex_trylock")]
public int PthreadMutexTryLock(IntPtr mutex) { return 0; }
// int pthread_mutex_unlock(pthread_mutex_t* mutex);
[BizExport(CallingConvention.Cdecl, EntryPoint = "pthread_mutex_unlock")]
public int PthreadMutexUnlock(IntPtr mutex) { return 0; }*/
} }
// usual starting address for the executable // usual starting address for the executable
@ -522,6 +841,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary> /// </summary>
private Heap _invisibleheap; private Heap _invisibleheap;
/// <summary>
/// extra savestated heap
/// </summary>
private Heap _specheap;
/// <summary> /// <summary>
/// all loaded PE files /// all loaded PE files
/// </summary> /// </summary>
@ -545,13 +869,29 @@ namespace BizHawk.Emulation.Cores.Waterbox
private Psx _psx; private Psx _psx;
private Emu _emu; private Emu _emu;
private Syscalls _syscalls; private Syscalls _syscalls;
private LibcPatch _libcpatch;
/// <summary> /// <summary>
/// timestamp of creation acts as a sort of "object id" in the savestate /// timestamp of creation acts as a sort of "object id" in the savestate
/// </summary> /// </summary>
private readonly long _createstamp = WaterboxUtils.Timestamp(); private readonly long _createstamp = WaterboxUtils.Timestamp();
public PeRunner(string directory, string filename, ulong heapsize, ulong sealedheapsize, ulong invisibleheapsize) private Heap CreateHeapHelper(uint sizeKB, string name, bool saveStated)
{
var heap = new Heap(_nextStart, sizeKB * 1024, name);
heap.Memory.Activate();
ComputeNextStart(sizeKB * 1024);
AddMemoryBlock(heap.Memory);
if (saveStated)
_savestateComponents.Add(heap);
_disposeList.Add(heap);
return heap;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void LibcEntryRoutineD(IntPtr appMain, IntPtr psxInit, int options);
public PeRunner(PeRunnerOptions opt)
{ {
Initialize(_nextStart); Initialize(_nextStart);
Enter(); Enter();
@ -567,14 +907,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
// load and connect all modules, starting with the executable // load and connect all modules, starting with the executable
var todoModules = new Queue<string>(); var todoModules = new Queue<string>();
todoModules.Enqueue(filename); todoModules.Enqueue(opt.Filename);
while (todoModules.Count > 0) while (todoModules.Count > 0)
{ {
var moduleName = todoModules.Dequeue(); var moduleName = todoModules.Dequeue();
if (!_exports.ContainsKey(moduleName)) if (!_exports.ContainsKey(moduleName))
{ {
var module = new PeWrapper(moduleName, File.ReadAllBytes(Path.Combine(directory, moduleName)), _nextStart); var module = new PeWrapper(moduleName, File.ReadAllBytes(Path.Combine(opt.Path, moduleName)), _nextStart);
ComputeNextStart(module.Size); ComputeNextStart(module.Size);
AddMemoryBlock(module.Memory); AddMemoryBlock(module.Memory);
_savestateComponents.Add(module); _savestateComponents.Add(module);
@ -589,42 +929,49 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
_libcpatch = new LibcPatch(this);
_exports["libc.so"] = new PatchImportResolver(_exports["libc.so"], BizExvoker.GetExvoker(_libcpatch));
ConnectAllImports(); ConnectAllImports();
// load all heaps // load all heaps
_heap = new Heap(_nextStart, heapsize, "brk-heap"); _heap = CreateHeapHelper(opt.NormalHeapSizeKB, "brk-heap", true);
_heap.Memory.Activate(); _sealedheap = CreateHeapHelper(opt.SealedHeapSizeKB, "sealed-heap", true);
ComputeNextStart(heapsize); _invisibleheap = CreateHeapHelper(opt.InvisibleHeapSizeKB, "invisible-heap", false);
AddMemoryBlock(_heap.Memory); _specheap = CreateHeapHelper(opt.SpecialHeapSizeKB, "special-heap", true);
_savestateComponents.Add(_heap);
_disposeList.Add(_heap);
_sealedheap = new Heap(_nextStart, sealedheapsize, "sealed-heap"); _syscalls.Init();
_sealedheap.Memory.Activate();
ComputeNextStart(sealedheapsize);
AddMemoryBlock(_sealedheap.Memory);
_savestateComponents.Add(_sealedheap);
_disposeList.Add(_sealedheap);
_invisibleheap = new Heap(_nextStart, invisibleheapsize, "invisible-heap"); //System.Diagnostics.Debugger.Break();
_invisibleheap.Memory.Activate();
ComputeNextStart(invisibleheapsize);
AddMemoryBlock(_invisibleheap.Memory);
_savestateComponents.Add(_invisibleheap);
_disposeList.Add(_invisibleheap);
try // run unmanaged init code
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));
// the current mmglue code doesn't use the main pointer at all, and this just returns
del(IntPtr.Zero, psxInit, 0);
foreach (var m in _modules)
{
m.RunGlobalCtors();
}
/*try
{ {
_modules[0].RunExeEntry(); _modules[0].RunExeEntry();
throw new InvalidOperationException("main() returned!"); //throw new InvalidOperationException("main() returned!");
} }
catch (EndOfMainException) catch //(EndOfMainException)
{ } {
}
_modules[0].RunGlobalCtors();
foreach (var m in _modules.Skip(1)) foreach (var m in _modules.Skip(1))
{ {
if (!m.RunDllEntry()) if (!m.RunDllEntry())
throw new InvalidOperationException("DllMain() returned false"); throw new InvalidOperationException("DllMain() returned false");
} m.RunGlobalCtors();
}*/
} }
catch catch
{ {
@ -711,6 +1058,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
_heap = null; _heap = null;
_sealedheap = null; _sealedheap = null;
_invisibleheap = null; _invisibleheap = null;
_specheap = null;
} }
} }
} }

View File

@ -10,7 +10,7 @@ extern "C" {
// mark an entry point or callback pointer // mark an entry point or callback pointer
#define ECL_ENTRY #define ECL_ENTRY
// mark a visible symbol // mark a visible symbol
#define ECL_EXPORT #define ECL_EXPORT __attribute__((visibility("default")))
// allocate memory from the "sealed" pool. this memory can never be freed, // allocate memory from the "sealed" pool. this memory can never be freed,
// and can only be allocated or written to during the init phase. after that, the host // and can only be allocated or written to during the init phase. after that, the host

View File

@ -1,25 +1,12 @@
This is the experimental "waterbox" project for bizhawk. This is the experimental "waterbox" project for bizhawk.
Build has been tested only on a recent Debian, but many Linuxes will probably work. amd64 is the only supported platform.
libc: This is pdclib, with the jam makesystem butchered and replaced by a custom Makefile, and some things removed. libc.so, libgcc_s.so, libstdc++.so.6, and the waterbox executables are built with a modified verion of the midipix project.
libm from musl is added. sjlj from newlib is added. The makefiles for the cores only support the cross compilation setup (build from whatever linux box you built midipix
from).
gpgx: This is more or less our current gpgx core. Not much has been changed. The mmglue portion of the midipix project is modified; get the correct version from <insert git repo here>.
gpgx: This is a modified version of our gpgx core
snes9x: Based off of snes9x 1.54.
To build:
cd libc
make
cd ../gpgx
make
Copy gpgx.elf to Bizhawk's output64\dll folder.
Everything is still very much WIP.
Notes:
1. Remember ms-abi vs systemv!
2. gpgx codeblocks project isn't for building.
3. SJLJ might be busted.
4. VA_ARGS is probably busted.
5. STDIO isn't hooked up yet.

@ -1 +1 @@
Subproject commit 3a358804d34b9ed5b4bedd9266bcebf255d72cfe Subproject commit 849eeee8c8dc9c8dc0283720a091377eb92ee3a8