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.
73 lines
3.8 KiB
Python
73 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Statically compile the original MapVersion constructor and its declared I/O adapter."""
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import struct
|
|
import subprocess
|
|
from pathlib import Path
|
|
from a64_lift import Compiler
|
|
from lift_rng import arm64_image, file_range
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
ADDRESS, SIZE = 0x10150BF28, 192
|
|
EXPECTED = 'b9254262cde89c9e79a9fdf6d700860ff9fd623d53c576efaf431600096c8a9b'
|
|
READ = 0x10035E264
|
|
|
|
|
|
def run(*args):
|
|
print('+', ' '.join(map(str, args)), flush=True)
|
|
subprocess.run(list(map(str, args)), cwd=ROOT, check=True)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('binary', type=Path)
|
|
args = parser.parse_args()
|
|
image, slice_offset = arm64_image(args.binary.read_bytes())
|
|
offset = file_range(image, ADDRESS, SIZE)
|
|
body = image[offset:offset + SIZE]
|
|
if hashlib.sha256(body).hexdigest() != EXPECTED:
|
|
raise ValueError('Unrecognized MapVersion constructor bytes')
|
|
compiler = Compiler({READ: 'read_or_throw'})
|
|
wat = compiler.compile(body, ADDRESS)
|
|
out = ROOT / 'build/version'
|
|
out.mkdir(parents=True, exist_ok=True)
|
|
(out / 'factorio_version.wat').write_text(wat)
|
|
manifest = {'symbol': 'MapVersion::MapVersion(Deserialiser&)', 'address': hex(ADDRESS),
|
|
'source_file_offset': slice_offset + offset, 'bytes': SIZE, 'sha256': EXPECTED,
|
|
'instructions': compiler.instructions, 'host_calls': compiler.calls,
|
|
'scope': 'automatic straight-line integer lift; host read errors return status rather than C++ exceptions'}
|
|
(out / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n')
|
|
assembly = ['.text', '.p2align 2', '.globl _factorio_version_original', '_factorio_version_original:']
|
|
for (word,) in struct.iter_unpack('<I', body):
|
|
assembly.append(' bl _native_version_read' if word & 0xfc000000 == 0x94000000 else f' .long 0x{word:08x}')
|
|
(out / 'oracle.S').write_text('\n'.join(assembly) + '\n')
|
|
run(ROOT / 'build/wabt/wat2wasm', out / 'factorio_version.wat', '-o', out / 'factorio_version.wasm')
|
|
run(ROOT / 'build/wabt/wasm2c', out / 'factorio_version.wasm', '-o', out / 'factorio_version.c', '--module-name=factorio_version')
|
|
includes = ['-I' + str(out), '-I' + str(ROOT / 'runtime'), '-I' + str(ROOT / 'third_party/wabt/wasm2c')]
|
|
flags = ['-O2', '-DWASM_RT_USE_MMAP=0', '-DWASM_RT_MEMCHECK_BOUNDS_CHECK=1']
|
|
sources = [out / 'factorio_version.c', ROOT / 'runtime/version_bridge.c', ROOT / 'runtime/save_header.c']
|
|
runtime = [ROOT / 'third_party/wabt/wasm2c' / x for x in ['wasm-rt-impl.c', 'wasm-rt-mem-impl.c']]
|
|
run('xcrun', 'clang', *flags, *includes, *sources, *runtime, out / 'oracle.S',
|
|
ROOT / 'tests/version_equivalence.c', '-lz', '-o', out / 'verify_version')
|
|
run(out / 'verify_version')
|
|
run('xcrun', 'clang', *flags, *includes, *sources, *runtime, ROOT / 'tests/save_probe.c',
|
|
'-lz', '-o', out / 'save_probe')
|
|
sdk = subprocess.check_output(['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'], text=True).strip()
|
|
objects = []
|
|
for source in sources:
|
|
obj = out / (source.stem + '.ios.o')
|
|
run('xcrun', '--sdk', 'iphoneos', 'clang', '-target', 'arm64-apple-ios15.0', '-isysroot', sdk,
|
|
*flags, *includes, '-c', source, '-o', obj)
|
|
objects.append(obj)
|
|
run('xcrun', 'libtool', '-static', '-o', out / 'libfactorio_version_ios.a', *objects)
|
|
(out / 'verification.json').write_text(json.dumps({'status': 'pass', 'native_comparisons': 20000,
|
|
'instruction_count': len(compiler.instructions), 'host_calls': len(compiler.calls),
|
|
'scope': 'MapVersion constructor success path; stream errors use a host status adapter',
|
|
'whole_map_loading': False}, indent=2) + '\n')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|