Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS: - tools/retarget.py: header-only Mach-O retargeting to an iOS dylib - platform/native: UIKit host and macOS API shims (AppKit for SDL's Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device properties, Wuffs PNG decoding, Steam and peripheral stubs) - touch, overlay, iOS keyboard and hardware keyboard input - tools/build_native.py: build, sign, install, data copy, launch - docs: build guide, controls, architecture Also includes the earlier static-translation research (ARM64 -> WASM -> native) under docs/research, runtime/, tests/ and tools/. No game files are included; the build reads them from a local install.
This commit is contained in:
commit
51d085e865
89 files changed
+7999
No files matched your search
@@ -0,0 +1,113 @@
|
||||
#include "target_bridge.h"
|
||||
#include "target_host.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void *factorio_target_original(void *);
|
||||
extern const uint8_t native_target_vtable[];
|
||||
static _Alignas(16) uint8_t native_heap[65536];
|
||||
static size_t native_cursor;
|
||||
static unsigned native_allocations;
|
||||
void *native_target_allocate(size_t size) {
|
||||
native_cursor=(native_cursor+15)&~(size_t)15;
|
||||
assert(size<=sizeof(native_heap)-native_cursor);
|
||||
void *result=native_heap+native_cursor;
|
||||
native_cursor+=size; ++native_allocations;
|
||||
return result;
|
||||
}
|
||||
void native_target_unsupported_delete(void *p) {(void)p;abort();}
|
||||
void native_target_unsupported_length(void *p) {(void)p;abort();}
|
||||
void native_target_unsupported_array_length(void *p) {(void)p;abort();}
|
||||
static uint64_t get(const uint8_t *data,size_t at) {uint64_t x;memcpy(&x,data+at,8);return x;}
|
||||
static void put(uint8_t *data,size_t at,uint64_t x) {memcpy(data+at,&x,8);}
|
||||
static uint64_t relocate(uint64_t pointer,uint64_t begin) {
|
||||
assert(pointer>=(uintptr_t)native_heap && pointer<=(uintptr_t)native_heap+sizeof(native_heap));
|
||||
return pointer-(uintptr_t)native_heap+begin;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
wasm_rt_init();
|
||||
w2c_factorio__target module;
|
||||
struct w2c_target__host env={.module=&module};
|
||||
wasm2c_factorio__target_instantiate(&module,&env);
|
||||
wasm_rt_memory_t *ram=w2c_factorio__target_memory(&module);
|
||||
assert(ram->size==1048576);
|
||||
uint8_t *memory=ram->data;
|
||||
for (unsigned iteration=0;iteration<512;++iteration) {
|
||||
uint64_t begin=131072+iteration*16,object=4096+(iteration%16)*256;
|
||||
memset(memory,0xa5,(size_t)ram->size);
|
||||
memset(native_heap,0xa5,sizeof(native_heap));
|
||||
uint8_t original[144];memset(original,0xa5,sizeof(original));
|
||||
native_cursor=0;native_allocations=0;
|
||||
assert(factorio_target_original(original)==original);
|
||||
assert(native_allocations==4 && native_cursor==2104);
|
||||
assert(factorio_guest_heap_init(&env.heap,memory,ram->size,begin,begin+65536)==0);
|
||||
uint64_t registers[32]={0};
|
||||
for(unsigned i=19;i<30;++i) registers[i]=0x1234567800000000ull+iteration+i;
|
||||
registers[0]=object;registers[31]=ram->size-256;
|
||||
memcpy(memory,registers,sizeof(registers));
|
||||
assert(w2c_factorio__target_run(&module,0,10000)==0);
|
||||
assert(env.heap.allocations==4 && env.heap.cursor-begin==native_cursor);
|
||||
assert(get(memory,0)==object);
|
||||
for(unsigned i=19;i<32;++i) assert(get(memory,i*8)==registers[i]);
|
||||
const unsigned fields[]={8,16,24,56,64,72};
|
||||
for(unsigned i=0;i<sizeof(fields)/sizeof(fields[0]);++i)
|
||||
put(original,fields[i],relocate(get(original,fields[i]),begin));
|
||||
assert(memcmp(memory+object,original,sizeof(original))==0);
|
||||
/* Normalize every native pointer in the allocated object graph. */
|
||||
for(unsigned i=0;i<3;++i) put(native_heap,i*8,relocate(get(native_heap,i*8),begin));
|
||||
put(native_heap,2080,relocate(get(native_heap,2080),begin));
|
||||
for(unsigned i=0;i<64;++i) {
|
||||
assert(get(native_heap,32+i*32)==(uintptr_t)native_target_vtable+16);
|
||||
put(native_heap,32+i*32,65536+0xda8);
|
||||
}
|
||||
assert(memcmp(memory+begin,native_heap,native_cursor)==0);
|
||||
for(size_t i=256;i<ram->size;++i) {
|
||||
if(i>=object && i<object+144) continue;
|
||||
if(i>=begin && i<begin+native_cursor) continue;
|
||||
if(i>=ram->size-368 && i<ram->size-256) continue;
|
||||
assert(memory[i]==0xa5);
|
||||
}
|
||||
}
|
||||
/* Each original allocation can fail without returning a forged pointer. */
|
||||
const uint64_t lengths[]={0,23,24,2079,2080,2087,2088,2103,2104};
|
||||
for(unsigned i=0;i<sizeof(lengths)/sizeof(lengths[0]);++i) {
|
||||
memset(memory,0xa5,(size_t)ram->size);
|
||||
assert(factorio_guest_heap_init(&env.heap,memory,ram->size,131072,131072+lengths[i])==0);
|
||||
uint64_t registers[32]={0};registers[0]=4096;registers[31]=ram->size-256;
|
||||
memcpy(memory,registers,sizeof(registers));
|
||||
assert(w2c_factorio__target_run(&module,0,10000)==(lengths[i]<2104 ? 5u:0u));
|
||||
for(uint64_t j=131072+lengths[i];j<196608;++j) assert(memory[j]==0xa5);
|
||||
}
|
||||
assert(w2c_factorio__target_run(&module,1048576-255,10000)==2);
|
||||
assert(w2c_factorio__target_run(&module,UINT32_MAX,10000)==2);
|
||||
uint64_t registers[32]={0};registers[0]=4096;registers[31]=ram->size-256;
|
||||
memcpy(memory,registers,sizeof(registers));
|
||||
assert(w2c_factorio__target_run(&module,0,0)==3);
|
||||
/* Heap input arithmetic is checked before any addition or narrowing. */
|
||||
FactorioGuestHeap heap;
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,196608)==0);
|
||||
FactorioGuestHeap before=heap;uint64_t address=123;
|
||||
assert(factorio_guest_heap_allocate(&heap,UINT64_MAX,&address)==1);
|
||||
assert(address==123 && memcmp(&before,&heap,sizeof(heap))==0);
|
||||
assert(factorio_guest_heap_allocate(&heap,0,&address)==0 && address==131072);
|
||||
assert(factorio_guest_heap_allocate(&heap,0,&address)==0 && address==131088);
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,0,196608)==2);
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,131073,196608)==2);
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,UINT64_MAX)==2);
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,131071)==2);
|
||||
assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,196608)==0);
|
||||
heap.cursor=heap.end+1;address=123;
|
||||
assert(factorio_guest_heap_allocate(&heap,8,&address)==2 && address==123);
|
||||
heap.cursor=131072;heap.allocations=UINT32_MAX;
|
||||
assert(factorio_guest_heap_allocate(&heap,8,&address)==2 && address==123);
|
||||
FactorioTargetProbe report={0};
|
||||
assert(factorio_target_probe(&report)==0);
|
||||
assert(report.allocations==4 && report.initialized_targets==64 && report.heap_bytes==2104);
|
||||
assert(factorio_target_probe(NULL)==2);
|
||||
wasm2c_factorio__target_free(&module);wasm_rt_free();
|
||||
puts("PASS: 512 original ARM64 object graphs, 64 targets each, relocated pointers, heap exhaustion, output/register/memory guards");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user