Technical Documentation
Architecture reference for the Swordigo Runtime (SRT) — the layered system that runs a native ARM Android game binary on x86_64 Linux.
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 │
└───────────────────────────────────────────────────┘
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.
libswordigo.so and libsre.so ARM64 ELF headers, maps PT_LOAD segments into emulator memory.JNIEnv vtable with 200+ function pointers. Calls JNI_OnLoad in the guest.Java_com_touchfoo_swordigo_SwordigoLib_init.libsre.so function.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.
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.
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.
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.
├── 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
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