# TFX 2.05 executable and disassembly

The [native code browser](code/index.html) provides searchable x86 instructions, direct calls, possible callback targets, relocated references, strings and interpreter dispatch tables. It opens locally. Each routine can be downloaded as an annotated `.asm` listing.

The reference is `installs/cd_1994_09/TFX/TFX.DAT`, SHA-256 `2cc41a39fa95a2c9fd883c4220d7bdd9cca00c543c89b019eb270763f59d1d9a`. This is the protected-mode game executable, despite its `.DAT` extension; it is separate from the DID resource archive.

## Compiler and build clues

The retained binaries identify two toolchains. These offsets are file offsets within each named file, not all within TFX.DAT:

| Component | Embedded evidence | Offset |
| --- | --- | --- |
| `TFX.DAT` | `WATCOM C/C++32 Run-Time system` | `0xb454a`, immediately after the entry-point jump |
| `CONFIG.EXE` | The same Watcom runtime identification; setup also explicitly names Watcom C/C++ 32 | `0x2c626`; trademark text at `0x4296a` |
| `START.EXE` | `Borland C++ - Copyright 1991 Borland Intl.` | `0x8634` |
| `Q2.COM` | The same Borland runtime banner | `0x1574` |
| `GUS.COM` | The same Borland runtime banner | `0x4c14` |

The main image and CONFIG also contain **DOS/4GW Professional** loader banners (`TFX.DAT` at `0x3162e`, CONFIG at `0x218de`). START is a 16-bit MZ executable; its music/timer/driver work is separate from the game's 32-bit protected-mode LE image. GUS.COM is also MZ despite its suffix, while Q2.COM has a flat code header. A filename suffix alone does not establish the executable layout.

The ordinary game interfaces repeatedly pass arguments in EAX, EDX, EBX and ECX, matching [Watcom's documented register convention](https://open-watcom.github.io/open-watcom-1.9/cguide.html#32-bit%20Topics). For example, name entry at [0xa1ee0](code/index.html#a1ee0) receives four arguments in those registers, and the game entry at [0x70ad0](code/index.html#70ad0) receives its argument count and vector in EAX/EDX. Variadic formatting uses stack arguments. Standard C-runtime behaviour, conventional procedure frames and x87 floating-point calculations are also present. Together with the runtime identifications, this strongly supports a mixed **compiled C/C++ and specialised x86 build**. It is not evidence that every routine was handwritten assembly.

The runtime banners identify the compiler families, not the exact compiler versions or source language of every module. Their copyright years are not build dates. Watcom's combined C/C++ banner does not distinguish C from C++; the Borland banners likewise establish linked runtime provenance rather than prove that each helper's own source used classes. No original makefiles, linker response files or complete game source tree have been recovered.

The software renderer includes self-modifying paths and compiled drawing-code resources, so specialised assembly and code generation remain important parts of the pipeline. The flight model instead contains extensive x87 double-precision calculation. The separate [cockpit programs](cockpits.md) are executable VGA drawing assets, not a consequence of every other resource being machine code.

The audio component identifies itself as **OSL**: START contains track and device-driver banners for LMEDIT (`0x3e99`), ADLIB (`0x5800`), SCC1 (`0x68e0`) and LAPC1/MT32 (`0x7170`), each with an OSL copyright identification. See [the native audio captures](audio/README.md). These are identifiable runtime components; an expansion of OSL or a particular modern audio middleware lineage is not established by those banners alone.

The engine's surrounding asset tooling is custom: model/scenery programs have their own interpreters, missions retain readable authoring commands, and presentations are saved parser graphs. The 2,773-byte [ssinfo.h](../extracted/cd_1994_09/resources/ss/ssinfo.h) retains C-style enum declarations for scenery entry/custom-state indices, but includes incomplete lines and identifiers beginning with digits; it is an authoring artefact, not a usable original C header as shipped. Inferno-named rendering modes, resources and diagnostics suggest shared internal DID technology, without identifying a third-party 3D framework or establishing identical behaviour in the released Inferno engine. See [the cockpit provenance notes](cockpits.md).

## C library use and C++ evidence

There is positive identification of standard **C runtime** functions, not just a shared compiler banner. The string-copy loop at [0xc9602](code/index.html#c9602) follows the 386 small-data assembly pragma in Watcom's [strcpy source](https://github.com/open-watcom/open-watcom-v2/blob/master/bld/clib/string/c/strcpy.c), with register preservation added around it. The routines are present in the executable itself rather than visible only as imported names.

| Identified routine | File offset | Evidence |
| --- | --- | --- |
| `atoi` | [0xc70b1](code/index.html#c70b1) | Character-class table, whitespace/sign handling and decimal accumulation; five native cases |
| `strcmp` | [0xc7104](code/index.html#c7104) | NUL-terminated comparison with word-at-a-time zero detection; five native cases |
| `strcat` | [0xc7286](code/index.html#c7286) | Destination scan, source append and destination return; three native cases |
| `sprintf` | [0xc92a9](code/index.html#c92a9) | Variadic stack arguments, shared formatter and memory-output callback; native `%s/%03d` yields `scene/007`, return 9 |
| `strcpy` | [0xc9602](code/index.html#c9602) | Upstream instruction-pattern match; six native cases include empty/unaligned strings and a write canary |
| `strlen` | [0xc96a3](code/index.html#c96a3) | `REPNE SCASB`, excluding the terminator; six native cases |
| `abs` | [0xc96bc](code/index.html#c96bc) | Test/negate; three native non-overflow cases |
| Near `malloc` / `free` | [0xd3820](code/index.html#d3820), [0xd36ef](code/index.html#d36ef) | Runtime heap allocation/release helpers and heap-growth retries; static identification |
| x87 sine helper | [0xd22e7](code/index.html#d22e7) | Hardware `FSIN` path plus reduction fallback; seven native hardware-path cases |

The 28 string/integer cases, formatter case and seven sine cases execute isolated native routines. Flat segment selectors are initialised for instructions that reload ES, such as `strlen`; this setup is normally supplied by the DOS extender. Heap and filesystem operations are not exercised by these captures. The file-handle wrappers at `0xcc3e4`, `0xcc410` and `0xcc41c` forward to lower-level open/close/read routines; the thin wrappers impose the engine's 16-bit handle interface and should not be confused with the underlying library entries.

TFX also uses its own allocation layer: [0xc90ec](code/index.html#c90ec) reserves space from an arena, [0xc91a0](code/index.html#c91a0) records a temporary allocation with a size prefix, and [0xc91f0](code/index.html#c91f0) releases tracked temporary storage. Scenery handles and linked actor/projectile structures are further engine-specific machinery. The generator at `0xc98a3` is the game's own captured random sequence; it should not be renamed standard `rand` just because it supplies random values.

**No C++-specific language machinery is positively identified yet.** The survey distinguishes four questions:

- **RTTI:** no class/type-information descriptors or dynamic-cast/typeid support have been confirmed. Watcom's [RTTI support](https://github.com/open-watcom/open-watcom-v2/blob/master/bld/cpplib/runtime/cpp/rttisupp.cpp) demonstrates the vtable-associated class descriptors that would provide stronger evidence than ordinary pointer tables.
- **Exceptions:** none of the 16 diagnostic strings in the upstream [C++ runtime message header](https://github.com/open-watcom/open-watcom-v2/blob/master/bld/cpplib/runtime/h/rtmsgs.h) appear in TFX.DAT. No C++ throw/catch/unwind structures have been identified. DOS faults, floating-point domain/range errors and the C runtime's stack-overflow check do not establish C++ exceptions.
- **Vtables and object lifetime:** the LE fixups expose 135 runs of at least two adjacent code pointers, including seven in the data object. These are candidates for interpretation, not automatically vtables. In the 90,504 decoded instructions, the survey found no immediate object-field stores of pointers to those code-pointer slots, nor the simple two-pointer-load virtual-call patterns checked before direct-memory/register indirect calls. Known engine interpreter tables, renderer callbacks and runtime hooks account for the recognisable examples; no constructor/destructor/vtable relationship is confirmed.
- **C++ library components:** no `iostream` or Watcom C++ container/string library use is established. Plain C strings, explicit arrays/records, manual allocation and callback dispatch describe the currently mapped interfaces.

The LE debug offset and length are both zero, and the file ends exactly with the initialised LE image; no appended debug-symbol block is present. Runtime function names in the browser are research annotations, not recovered linker symbols. Upstream Open Watcom is a later descendant of the compiler runtime and is useful for comparison, not proof that this exact revision was used in 1994. The pointer/call-pattern survey covers the decoded instructions, not every executable byte or runtime state. Absence of these markers cannot rule out C++ classes without virtual methods, disabled RTTI/exceptions, or inlined templates. The defensible description is therefore a **Watcom C/C++ toolchain with clearly identified C library use**; predominantly C game source remains an inference, and the combined runtime banner alone does not prove C++.

## Development leftovers and embedded records

The [development survey](development-notes.md) traces the terrain-buffer joke diagnostic, default high-score roster and encoding, retained interactive graph debugger, parser defaults and animation-fix arguments. Isolated native checks distinguish those working paths from unreferenced strings and ordinary documented editor features.

## Embedded executable

DOS/4G precedes an embedded DOS MZ header at **file `0x352a4`**. Its extended-header pointer is `0x60`, locating the LE header at **`0x35304`**. This distinction matters: LE table offsets use the LE origin, while this file's data-page offset uses the embedded MZ origin. Treating both as LE-relative shifts the image by 96 bytes and produces plausible-looking but incorrect addresses.

The object/page tables describe 140 physical pages of 4,096 bytes. The final page contains 1,683 bytes. The three objects are:

| Object | File start | Preferred address | Virtual bytes | Initialised bytes |
| --- | --- | --- | ---: | ---: |
| 1: code, tables and renderer working data | `0x70aa4` | `0x10000` | 505,042 | 505,042 |
| 2: small executable object | `0xecaa4` | `0x90000` | 612 | 612 |
| 3: strings, globals and uninitialised data | `0xedaa4` | `0xa0000` | 166,208 | 59,027 |

Object 3 therefore has **107,181 bytes of uninitialised storage**, which must be zero-filled when reconstructing an image. It is incorrect to read that region from subsequent file bytes. The LE entry point is object 1 offset `0x43aa4`, or file **`0xb4548`**.

The decoder consumes 28,960 fixup records and retains **28,933 distinct relocation sources** after collapsing duplicate cross-page records. All observed source types are 32-bit offset fixups. Signed page-relative source offsets, 16/32-bit target offsets and object references are decoded explicitly. A few linker-biased target expressions lie outside the nominal object's range: their raw values are retained, rather than given a fabricated file address.

The record layout is checked against IBM's [linear executable format specification](https://komh.github.io/os2books/os2tk45/lxref.htm), especially its fixup-record section. That reference documents the general encoding; the addresses and counts above come from the reference executable itself.

## Earlier DID executable layout

The earlier TFX builds and the Inferno cinematic preview do not expose the whole program through their small LE images. That LE is a bootstrap which loads three **uncompressed** sections from the same file, using a 52-byte footer and a separate page-grouped relocation stream. No decompression is needed. The data allocation exceeds its stored extent; the bootstrap's BSS-only LE object also has no file page.

[The engine-build comparison](engine-builds.md#early-executable-loader) documents this layout and validates all 175,476 fixup sites across six early builds against their original relocation helpers. [inspect_did_executable.py](../tools/inspect_did_executable.py) supplies file-offset-preserving section/fixup records for those images, alongside ordinary LE handling for September 2.05. Analysis-selected allocation bases are explicitly distinguished from genuine LE preferred addresses. The comparison captures twenty-four native flight-preset calls across the eight engines and retains their exact data writes.

## Address conventions

Research notes and browser links use **file offsets**. Three other address forms occur in the code:

- A code-relative offset, such as `0x4a814`, can refer to object 1: `0x70aa4 + 0x4a814 = 0xbb2b8`, the shape drawing table.
- A data-object offset, such as `0x12bcc`, can refer to object 3's uninitialised storage. It has no corresponding initialised file bytes.
- A relocated linear address adds the target object's chosen load address. The preset emulator uses the LE preferred addresses and applies the relocation records.

The **relocation identifies the object**. Numeric magnitude alone cannot reliably distinguish code, globals, strings or pointers. The browser keeps the original operand spelling and annotates its object/offset/file target; it does not pretend that an unrelocated operand is already a linear runtime address.

## Control-flow coverage

The current pass follows **95,061 instructions**, totalling 336,889 distinct decoded bytes, from 2,161 entry roots. Roots include the LE entry, direct call destinations, known interpreter tables and plausible relocated callback pointers. These are analysis roots, not an original source-function count: assembly handlers can share tails and enter the middle of another routine.

Fourteen interpreter/switch tables are exposed: shape conversion, shape drawing, scenery events, part animation, presentation loading/execution/sub-flow loading, two player-flight mode switches, aircraft waypoint commands, three presentation-font dispatch tables and synth-bank preselection. Ordinary direct branches are followed; indirect sites remain visible. Absolute callback assignments can supply **possible** destinations, which are listed separately from direct calls. They are static evidence, not a runtime trace proving that a particular destination was selected.

Six undecodable traversal sites are retained in the [report](code/decode-report.json), including shared renderer paths. The executable contains self-modifying renderer code and embedded tables; treating the whole code object as one continuous instruction stream would create misleading disassembly. Handler names and responsibilities are recorded in [annotations.json](code/annotations.json), with their evidence.

Dynamic cockpit/HUD resources also contain x86 code. The catalogue identifies six such overlay resources; the executable browser currently analyses the main LE image. Their drawing contracts are now captured separately in the [cockpit notes](cockpits.md): five unique programs execute with emulated VGA masks, including a real-mode 16-bit prototype, retaining colour indices and coverage. Full live HUD composition remains separate work.

## Launch and configuration

The native command-line entry accepts a presentation-program name, with an optional leading environment assignment. `START tfx` selects the game graph; `START DID=D: tfx` selects resources from DOS drive D:. The [configuration notes](configuration.md) map the launcher/game keyword tables, HUD intensity controls, REALISM field order, retained memory flags and fixed VGA display setup.

The [launcher comparison](launcher-compatibility.md) traces the original floppy hardware-stamp check, install-time archive assembly, the `INT 60h`/`IRQBASE` sound-service interface and actual cross-version startup tests. March and September share `START.EXE`; earlier launchers require the documented compatibility settings.

## Reproduction

[inspect_executable.py](../tools/inspect_executable.py) needs Python and Capstone. Run it from the research root:

```sh
python3 tools/inspect_executable.py
```

The isolated [player-preset capture](entities/player-presets.json) additionally needs Unicorn. [capture_flight_presets.py](../tools/capture_flight_presets.py) loads the complete LE objects at their preferred addresses, zero-fills their virtual storage, applies relocations and executes each preset initialiser to a checked return. Its output covers native floating fields, with source offsets and exact bytes; field units and gameplay names require further tracing.

Continue with [game flow and simulation](game-logic.md), [model programs](model-format.md), [scenery definitions](terrain-and-scenery.md) and the [analysis index](index.html).
