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:
SashaGoncharov19 committed 2026-10-23 15:27:58 +04:00
commit 51d085e865
89 files changed
+7999

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
# Loader allocation and initialization (2026-10-20)
Signed **build 4** runs the original TargetDeserialiser/memory-pool initialization graph on the iPhone 15 Pro, through ARM64 → WASM → wasm2c → native iOS. Its report records four allocations, a capacity of 64, 64 initialized targets and **2,104 bytes** consumed by the aligned guest arena. The version constructor, both MapHeader branches and the actual-save header probe also pass in the same launch. The save's header remains at decoded byte 333 with three raw values of 720001. This initializes one isolated loader dependency; it does not load a world or provide gameplay.
## Original code and adapters
| Input | Address | Bytes | SHA-256 |
| --- | --- | --- | --- |
| TargetDeserialiser C2 normal body | `0x101ab7c74` | 108 | `2ada8a5d403d8d30f9bc053f3cad0e74d08103d6c96bcdbf4db44d481ba6d4d0` |
| TypeAwareMemoryPool C2 normal CFG | `0x10244a4bc` | 1260 | `0e450e3ad613dded236f6627d78a07894d48b46e845baa40877d6929043b171a` |
| Source vtable identity range | `0x102fc2d98` | 32 | `c991e960829a78707ab67384d3dbf5d296aaa8fc9f33878ae7c1e7571f779dce` |
The complete source ARM64 SHA-256 is pinned to `2cb4de127b50d54c6c5666acfef2263fae16d11a3361ad39353ecf8a66a4d9c7`. These inputs are checked before generation. The translated program contains 342 original instructions and shares guest registers, stack and an instruction budget between both functions.
The allocator is a **host-side service**, not translated operator new. It returns 16-byte-aligned offsets into a bounded per-run arena, leaves bytes uninitialized and reports exhaustion explicitly. A new opt-in import ABI snapshots the guest register context and reloads only x0 after a successful call. Other guest registers retain their local values; host calls invalidate the compiler's NZCV facts. Failed calls abort the run, with partial guest state discarded when the module is freed.
Guest memory is a fixed 1 MiB, with a 64 KiB arena at offset 131072, an isolated stack and a controlled output object. Addresses are checked at 64-bit width before narrowing. The ADRP source page `0x102fc2000` maps to guest page 65536. The constructor stores the resulting vtable **identity** at guest offset `0x10da8`; no vtable bytes, native pointers or callable virtual methods are installed there. Virtual dispatch remains unsupported.
New instruction support is limited to non-flag-setting logical immediates, ASR immediates, declared ADRP pages, BRK traps and contiguous MOVI-zero/Q-store sequences. The vector idiom cannot transport values across calls or branches. General SIMD remains unsupported.
The constructors' exception landing pads at `0x101ab7ce0..0x101ab7d0c` and `0x10244a9a8..0x10244a9d4` are excluded. Delete and length-error imports return an explicit unsupported-service status; allocation failure returns status 5. No C++ exception unwinding, destructor or general free service is supplied. No startup, Steam, world or rendering code is introduced into the iOS binary.
## Validation
- **512 original ARM64 object-graph comparisons**, varying guest object and heap offsets. Each compares the complete 144-byte output object and the complete allocated graph, normalizing native heap pointers and the vtable identity. Guards include alignment gaps, padding, unallocated RAM and preserved x19–x30/SP.
- Eight insufficient-heap cases exercise aborts before each allocation can succeed; exact 2,104-byte capacity succeeds. Overflow-size, zero-size allocation, invalid arena/context and instruction-budget checks also pass.
- **66,048 native instruction comparisons** cover 129 ASR/logical-mask forms, signed input edges and randomized values. Extended-memory writes, near-end accesses, addresses above 4 GiB and twelve rejection cases pass.
- Existing **80,000 guest-program comparisons** and **20,000 original MapHeader comparisons** still pass after the shared compiler changes.
- Physical build 4 reports share launch ID `D0C96658-439A-466B-99A8-768D93E86E57`, build identity `Oct 20 2026 19:31:52` and report time `2026-10-20T15:33:10Z`.
- The signed executable's imports/dependencies contain no Steam integration, and desktop oracle symbols are absent.
The desktop oracle executes copied original ARM64 words, relocating only direct BL calls and the ADRP/ADD vtable identity reference. The iOS target links only generated C and runtime adapters. Finite comparisons cover constructor initialization and allocation aborts; they do not establish arbitrary mutation paths or whole-engine equivalence.
## Reproduce
```sh
python3 tools/build_target_deserialiser.py build/factorio.arm64
python3 tests/check_a64_initialization.py
python3 tests/check_a64_program.py
python3 tools/build_map_header.py build/factorio.arm64
python3 tools/package_ios.py
```
Generated sources, function/call manifests and desktop validation are under `build/target-deserialiser/`. Downloaded device reports are `iphone-*-result.json`; `python3 tools/check_target_device.py` checks them against the signed build and existing desktop save result, then writes `device-verification.json`. Original instructions and generated game code remain in ignored local artifacts.
## REA evidence and resolved provenance check
REA observed the original constructor assembly in records `ev_1a00dc8f1f23ce6c1e54f8d189d163fbdd012621890e0288643b8f83a8b11611` (TargetDeserialiser) and `ev_b08fa6c3b275200505c3e78c71046526444b5c0ec603ef09d18d5db53dbf0eab` (memory pool). Complete MCP responses are retained in `evidence/1792510440817-2-procedure_assembly.json` and `evidence/1792510440863-3-procedure_assembly.json`. The local evidence index combines these unchanged records with the previous export in `evidence/target-initialization-final.json`.
The three source ranges were initially hash-pinned directly from the unchanged Mach-O and independently decoded with LLVM; the extra REA byte export was pending at the end of build 4. **Resolved in the build 5 batch:** complete matching REA `read_bytes` observations are now exported in `evidence/deserialiser-final.json`. `tools/check_initialization_rea.py` validates all three ranges and writes a passing `build/target-deserialiser/rea-provenance.json`. See [deserialiser-progress.md](deserialiser-progress.md) for the records. Later compiler support extends the original contiguous zero-store idiom to definitely-zero facts checked across control flow.
## Next dependency
The next step from build 4 was integration into the original MapDeserialiser constructor, including its additional allocations, bzero and version-error handling. **Build 5 now completes that isolated initialization probe**; see [deserialiser-progress.md](deserialiser-progress.md). Next is MapGenSettings at the beginning of Map::loadData. Full image relocation, object reference reconstruction, nonempty startup settings, entities, simulation, graphics, sound and touch controls remain unimplemented.