Technical Documentation

Architecture reference for the Swordigo Runtime (SRT) — the layered system that runs a native ARM Android game binary on x86_64 Linux.

200+
Bridged JNI Functions
30+
SRE Hooks
2
ARM ISAs (v7 + v8)
5
Runtime Layers

SRT (Swordigo Runtime) is the umbrella name for the full desktop runtime architecture. It is a stack of five distinct layers, each solving one part of the problem of running an ARM Android game natively on a Linux desktop:

  • Platform Layer — SDL3, OpenGL, OpenAL, and Linux platform APIs on the host x86_64 machine.
  • JNI Bridge — 200+ shimmed functions that emulate the Android Java environment the game expects.
  • ELF Loader — Custom loader that maps ARM32 and ARM64 ELF shared objects into memory.
  • Unicorn Engine — CPU emulator that executes ARMv7 and AArch64 instructions on x86_64.
  • libsre.so — Guest-side ARM64 shared library with 30+ hooks that intercept and replace engine functions.
  • libswordigo.so — The original game binary, the gameplay kernel, running under emulation.

Stack Diagram

Execution flows downward. The host platform layer sits at the top; the original game binary is at the bottom, running entirely under emulation.

┌───────────────────────────────────────────────────┐
│  Platform Layer (Host x86_64)                     │
│  SDL3  ·  OpenGL  ·  OpenAL  ·  Linux             │
├───────────────────────────────────────────────────┤
│  JNI Bridge  (200+ bridged functions)             │
│  JNIEnv · AssetManager · Log · Configuration      │
├───────────────────────────────────────────────────┤
│  Unicorn Engine  (ARMv7 + AArch64 emulation)      │
│  Memory mapping · Syscall translation · Hooks     │
├───────────────────────────────────────────────────┤
│  libsre.so  (30+ hooks, Guest ARM64)              │
│  HUD · Music · Background · GUI · Crash recovery  │
├───────────────────────────────────────────────────┤
│  libswordigo.so  (Gameplay Kernel)                │
│  Physics · Scenes · Lua scripting · AI · Renderer  │
└───────────────────────────────────────────────────┘
Why Two ARM Architectures?

Swordigo shipped with both armeabi-v7a and arm64-v8a binaries. SRT primarily targets v1.4.12 ARM64 (AArch64) for best performance under Unicorn, but retains ARMv7 support for older APK versions.

Execution Flow

From launch to gameplay — every step of the boot sequence.

01
swordigo_boot — Host x86_64 binary initializes SDL3 window, OpenGL context, and OpenAL audio device.
02
ELF Loader — Parses libswordigo.so and libsre.so ARM64 ELF headers, maps PT_LOAD segments into emulator memory.
03
Relocation & Linking — Resolves dynamic relocations, patches the GOT/PLT, and applies SRE hook trampolines.
04
JNI Init — Constructs a fake JNIEnv vtable with 200+ function pointers. Calls JNI_OnLoad in the guest.
05
Unicorn Execution — Begins emulating ARM64 instructions starting at Java_com_touchfoo_swordigo_SwordigoLib_init.
06
Hook Interception — When the game calls a hooked address, Unicorn redirects execution to the corresponding libsre.so function.
07
Main Loop — The game enters its main loop. SRE's ProgramState hook runs every frame, managing HUD, music, and input.

ELF Loader

The custom ELF loader (src/loader/elf_loader.cpp) handles ARM32 and ARM64 shared objects. It parses ELF headers, allocates memory with proper permissions via Unicorn's memory API, processes relocations (R_AARCH64_RELATIVE, R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT), and resolves symbols.

Key Feature: Dual-Library Loading

The loader maps both libswordigo.so and libsre.so into the same Unicorn address space. SRE is loaded at a non-conflicting base address, allowing it to directly reference game memory and intercept function calls via the hook table.

// Dual-library loading sequence
ElfLoader game_loader("libswordigo.so", GAME_BASE_ADDR);
ElfLoader sre_loader("libsre.so", SRE_BASE_ADDR);

if (!game_loader.load(uc) || !sre_loader.load(uc)) {
    Logger::error("Failed to map ARM64 binaries");
    return -1;
}

// Resolve cross-library references
sre_loader.linkAgainst(game_loader);

// Apply hook table
HookTable::install(uc, sre_loader, game_loader);

JNI Bridge

The game engine expects a full Android Java environment. SRT provides a comprehensive JNI bridge that constructs a fake JNIEnv struct with 200+ function pointers, each marshalling data between the ARM emulator and native x86_64 C++ code.

Symbol Mapping

Maps Android-specific JNI symbols (FindClass, GetMethodID, CallObjectMethod) to native shims that return sensible values.

String Marshalling

Converts UTF-8 ↔ modified-UTF-8 ↔ UTF-16 strings between the ARM guest and host, handling JNI jstring lifecycle.

AssetManager Shim

Intercepts AAssetManager_open and friends, redirecting file reads to the local assets/resources/ directory on disk.

Service Emulators

Fakes android.util.Log, Configuration, Display, and SharedPreferences so the game's Java-side logic runs without a VM.

Rendering Pipeline

The original game uses OpenGL ES 1.x fixed-function calls. SRT translates these to desktop OpenGL 3.3+ on the host, while SRE hooks inject custom rendering for backgrounds, HUD, and GUI elements.

GLES → Desktop GL

Fixed-function calls like glTexEnvi, glColor4f, and matrix stack operations are translated to shader-based equivalents.

FBO Resolution Scaling

Game renders to a fixed-resolution FBO, then scales to window size with high-quality filtering for crisp visuals at any resolution.

Audio Engine

SRT replaces the entire Android MediaPlayer and SoundPool stack with an OpenAL-based audio system on the host. Sound effects are decoded from the game's asset files, and music playback is handled entirely by SRE's music system hooks.

OpenAL Backend

All audio output goes through OpenAL Soft, supporting PulseAudio and PipeWire. Sound effects use AL buffers with 3D spatial positioning.

MP3 Streaming

Music files (res/raw/*.mp3) are decoded on the host using minimp3 and streamed into OpenAL buffers with crossfade transitions.

SRE Hook System

libsre.so (Swordigo Runtime Engine) is an ARM64 shared library compiled with aarch64-linux-gnu-gcc and loaded into the Unicorn address space alongside libswordigo.so. It provides 30+ function hooks that intercept and replace problematic or missing engine functionality.

How Hooks Work

Each hook is defined by a hook table entry containing three fields: the offset in libswordigo.so to intercept, the name of the original function, and a relay pointer to the replacement function in libsre.so. At load time, the ELF loader patches the game binary's code at each offset with a branch instruction (B relay_addr) that redirects execution to the SRE function. The SRE function runs under the same Unicorn context with full access to guest memory and registers.

Hook Categories

Category Hooks What It Replaces
CppString 4 Atomic STXR spin loops that deadlock under emulation — replaced with simple non-atomic string operations.
MusicPlayer 6 Entire Android MediaPlayer music system — replaced with host-side OpenAL MP3 streaming.
Background 3 Custom sky gradient and parallax background rendering per-biome.
GameSceneView 1 Full HUD reimplementation — health bar, mana bar, item slots, and touch controls removed for keyboard/gamepad.
Death / Respawn 1 Ad SDK invocation on death — skipped entirely for instant respawn without ad prompts.
GUI DrawRect 8 Native button, label, slider, and panel rendering using game UI atlas textures instead of Android Views.
Lua Safety 3 Crash recovery wrappers around Lua script execution — catches panics and logs errors instead of segfaulting.
Audio Volume 1 Engine volume control calls routed to OpenAL alListenerf(AL_GAIN) on the host.
ProgramState 1 Frame-level game loop hook — runs every frame to manage input polling, HUD updates, and music transitions.
// Example hook table entry (src/sre/hook_table.h)
typedef struct {
    uint64_t    offset;     // Offset in libswordigo.so to patch
    const char* name;       // Original function name
    void*       relay;      // Pointer to SRE replacement function
} HookEntry;

static const HookEntry HOOK_TABLE[] = {
    { 0x1A3F40, "MusicPlayer::play",      (void*)sre_music_play      },
    { 0x1A4120, "MusicPlayer::stop",      (void*)sre_music_stop      },
    { 0x1A4280, "MusicPlayer::setVolume", (void*)sre_music_set_volume},
    { 0x09B6C0, "GameSceneView::draw",   (void*)sre_hud_draw        },
    { 0x0D8A10, "ProgramState::update",  (void*)sre_frame_update    },
    // ... 25+ more entries
};

GUI Stack

SRE completely replaces the game's GUI rendering. The original game used Android View widgets for menus and HUD. On desktop, SRE implements a custom immediate-mode GUI stack that draws directly via OpenGL using the game's own ui_atlas.png sprite sheet.

8 DrawRect Hooks

Buttons, labels, sliders, panels, and progress bars are all rendered by intercepting the engine's rectangle-drawing functions and replacing them with atlas-textured quads.

Input Remapping

Touch coordinates are translated from keyboard/gamepad events. SDL3 input events are injected into the guest as synthetic touch events at button coordinates.

Music System

The 6 MusicPlayer hooks fully replace Android's MediaPlayer API. Music tracks are MP3 files in res/raw/, decoded on the host with minimp3 and streamed through OpenAL with gapless crossfade transitions between areas.

Crossfade Engine

When the game triggers a track change (e.g. entering a cave from the overworld), the music system fades out the current track over 500ms while simultaneously fading in the new track. Two OpenAL sources are maintained at all times to enable seamless blending.

Runtime Data Layout

SRT uses a Minecraft-style data layout: all game assets, engine binaries, music, and saves live in the user's home directory. Users have full access to modify, mod, or backup their data.

~/.local/share/swordigo-desktop/
├── assets/resources/ # Game textures, models, scenes, Lua scripts
├── engine/ # ARM binaries: libswordigo.so + libsre.so per version
├── res/raw/ # Music .mp3 files
├── save/ # User save files (never packaged)
└── manifest.json # Launcher instance registry
Packaging Principle

RPM/DEB packages bundle all runtime files. No external downloads, no nested archives. On install, a post-install script copies from /usr/share/swordigo-desktop/ to the user's ~/.local/share/swordigo-desktop/ for full user-level access and moddability.

Build System

The project uses a Makefile-based build system. No CMake. The host components (swordigo_boot, asset_viewer) are compiled with the system GCC, while libsre.so is cross-compiled for AArch64.

Host Build

gcc / g++ targeting x86_64. Links against SDL3, OpenGL, OpenAL, Unicorn, and minimp3. Output: swordigo_boot.

Guest Cross-Compile

aarch64-linux-gnu-gcc targeting ARM64. Produces libsre.so — a position-independent shared object loaded into the Unicorn address space.

# Cross-compile libsre.so for ARM64
aarch64-linux-gnu-gcc -shared -fPIC -O2 -nostdlib \
    -o libsre.so \
    src/sre/hooks.c src/sre/music.c src/sre/gui.c src/sre/hud.c

# Build host runtime
make -j$(nproc) swordigo_boot

# Package for distribution
builder/package.sh --rpm --deb