#!/usr/bin/env python3 """Translate the pinned TargetDeserialiser initialization graph, without unwinding.""" import argparse import hashlib import json import struct import subprocess from pathlib import Path from a64_program import ProgramCompiler from lift_rng import arm64_image, file_range ROOT = Path(__file__).resolve().parents[1] RANGES = [ (0x101AB7C74, 108, '2ada8a5d403d8d30f9bc053f3cad0e74d08103d6c96bcdbf4db44d481ba6d4d0'), (0x10244A4BC, 1260, '0e450e3ad613dded236f6627d78a07894d48b46e845baa40877d6929043b171a'), (0x102FC2D98, 32, 'c991e960829a78707ab67384d3dbf5d296aaa8fc9f33878ae7c1e7571f779dce')] HOSTS = {0x1027D36E4:'allocate', 0x1027D36B4:'unsupported_delete', 0x10244A9D4:'unsupported_length', 0x100035550:'unsupported_array_length'} def run(*args): 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()) slice_hash=hashlib.sha256(image).hexdigest() if slice_hash!='2cb4de127b50d54c6c5666acfef2263fae16d11a3361ad39353ecf8a66a4d9c7': raise ValueError('Unrecognized Factorio ARM64 image') bodies={} for address,size,expected in RANGES: offset=file_range(image,address,size) data=image[offset:offset+size] if hashlib.sha256(data).hexdigest()!=expected: raise ValueError(f'Unrecognized target bytes at {address:#x}') bodies[address]=data compiler=ProgramCompiler(HOSTS,returning_hosts={0x1027D36E4}, memory_pages=16, static_pages={0x102FC2000:65536}) functions={address:bodies[address] for address,_,_ in RANGES[:2]} wat=compiler.compile(functions,RANGES[0][0]).replace('(import "env"','(import "target_host"') out=ROOT/'build/target-deserialiser' out.mkdir(parents=True,exist_ok=True) (out/'factorio_target.wat').write_text(wat) run(ROOT/'build/wabt/wat2wasm',out/'factorio_target.wat','-o',out/'factorio_target.wasm') run(ROOT/'build/wabt/wasm2c',out/'factorio_target.wasm','-o',out/'factorio_target.c','--module-name=factorio_target') # Only the desktop oracle executes copied ARM64 instructions. Relocate # direct calls, immediate branches and the one ADRP+ADD vtable reference. assembly=['.text','.p2align 2','.globl _factorio_target_original'] labels={address:f'Ltarget_{address:x}' for address in functions} for address,data in functions.items(): if address==RANGES[0][0]: assembly.append('_factorio_target_original:') for i,(word,) in enumerate(struct.iter_unpack('