Files
factorio-ios/docs/research/initialization-progress.md
SashaGoncharov19 51d085e865 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.
2026-10-23 15:27:58 +04:00

55 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.