<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Reverse-Engineering on TurboVision</title>
    <link>https://turbovision.in6-addr.net/tags/reverse-engineering/</link>
    <description>Recent content in Reverse-Engineering on TurboVision</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Tue, 21 Apr 2026 14:06:12 +0000</lastBuildDate>
    <atom:link href="https://turbovision.in6-addr.net/tags/reverse-engineering/index.xml" rel="self" type="application/rss&#43;xml" />
    
    
    
    <item>
      <title>Turbo Pascal Toolchain, Part 2: Objects, Units, and Binary Investigation</title>
      <link>https://turbovision.in6-addr.net/retro/dos/tp/toolchain/turbo-pascal-toolchain-part-2-objects-units-and-binary-investigation/</link>
      <pubDate>Sun, 22 Feb 2026 00:00:00 +0000</pubDate>
      <lastBuildDate>Sat, 14 Mar 2026 12:00:00 +0100</lastBuildDate>
      <guid>https://turbovision.in6-addr.net/retro/dos/tp/toolchain/turbo-pascal-toolchain-part-2-objects-units-and-binary-investigation/</guid>
      <description>&lt;p&gt;Part 1 covered workflow. Part 2 goes where practical debugging starts: the
actual artifacts on disk. In Turbo Pascal, build failures and runtime bugs are
often solved faster by reading files and link maps than by re-reading source.
The tools are simple—TDUMP, MAP files, &lt;code&gt;strings&lt;/code&gt;, hex diffs—but used
systematically they turn &amp;ldquo;it used to work&amp;rdquo; into &amp;ldquo;here is exactly what
changed.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structure map.&lt;/strong&gt; This article proceeds in eleven sections: (1) artifact
catalog and operational meaning, (2) TP5 unit-resolution behavior, (3) TPU
constraints and version coupling, (4) TPU differential forensics and
reconstruction when source is missing, (5) OBJ/LIB forensics and OMF orientation,
(6) MAP file workflow and TDUMP-style inspection loops, (7) EXE-level checks
before deep disassembly, (8) external OBJ integration and calling-convention
cautions, (9) repeatable troubleshooting matrix with high-signal checks, (10)
manipulating artifacts safely and team discipline for reproducibility, and
(11) unit libraries and cross references.&lt;/p&gt;
&lt;h2 id=&#34;artifact-catalog-with-operational-meaning&#34;&gt;Artifact catalog with operational meaning&lt;/h2&gt;
&lt;p&gt;Typical TP/BP project artifacts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.PAS&lt;/code&gt;: Pascal source (program or unit)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.TPU&lt;/code&gt;: compiled unit (compiler-consumable binary module)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.OBJ&lt;/code&gt;: object module (often OMF format)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.LIB&lt;/code&gt;: archive of &lt;code&gt;.OBJ&lt;/code&gt; modules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.EXE&lt;/code&gt;/&lt;code&gt;.COM&lt;/code&gt;: linked executable&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.MAP&lt;/code&gt;: linker map with symbol/segment addresses&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.OVR&lt;/code&gt;: overlay file (if overlay build path is enabled)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.BGI&lt;/code&gt;/&lt;code&gt;.CHR&lt;/code&gt;: Graph unit driver/font assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list is not trivia. It is your debugging map. OVR files are loaded at runtime
when overlay code executes; if the OVR path is wrong or the file is missing, the
program may hang or crash on overlay entry rather than at startup. BGI and CHR
are resolved by path at runtime—Graph unit &lt;code&gt;InitGraph&lt;/code&gt; searches the driver path.
Capture these paths in your environment documentation; &amp;ldquo;works here, fails there&amp;rdquo;
often traces to BGI/OVR path differences.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tool availability.&lt;/strong&gt; TDUMP ships with Borland toolchains; if missing,
&lt;code&gt;omfdump&lt;/code&gt; (from the OMFutils project) or &lt;code&gt;objdump&lt;/code&gt; with appropriate flags
can suffice for OBJ/LIB inspection, though output format differs. On modern
systems, &lt;code&gt;strings&lt;/code&gt; and &lt;code&gt;hexdump&lt;/code&gt; are standard. The workflows described here
assume TDUMP is available; adapt commands if using substitutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inspection tool mapping.&lt;/strong&gt; Each artifact type has a primary inspection path:
TPU → &lt;code&gt;strings&lt;/code&gt;, &lt;code&gt;hexdump&lt;/code&gt;, or compiler re-compile test; OBJ/LIB/EXE →
&lt;code&gt;TDUMP&lt;/code&gt;; MAP → diff against baseline. When troubleshooting, pick the artifact
closest to the failure and work outward. Link failures start at OBJ/LIB; unit
mismatch starts at TPU; runtime crashes may need EXE + MAP to correlate
addresses with symbols.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Artifact dependency graph.&lt;/strong&gt; A program&amp;rsquo;s build products form a directed
graph: sources (&lt;code&gt;.PAS&lt;/code&gt;, &lt;code&gt;.ASM&lt;/code&gt;) produce TPU/OBJ; those plus linker input
produce EXE; optional MAP records the link result. When a failure occurs,
identify which edge of this graph is broken. &amp;ldquo;Compile works, link fails&amp;rdquo; means
the TPU→EXE or OBJ→EXE edge; &amp;ldquo;link works, crash on startup&amp;rdquo; means the EXE
itself or its runtime dependencies (BGI, OVR, paths). Staying aware of the
graph prevents conflating compile-time and link-time issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regression triage.&lt;/strong&gt; When a previously working build starts failing, the
fastest diagnostic is a binary diff: compare the new MAP and EXE (or checksums)
to the last known-good. If the MAP is identical, the problem is environmental
(paths, runtime, machine). If the MAP changed, the regression is in the
build; then compare OBJ/TPU timestamps to see which module changed. This
two-step filter—build vs environment, then which module—cuts investigation
time dramatically.&lt;/p&gt;
&lt;h2 id=&#34;tp5-unit-resolution-behavior-manual-grounded&#34;&gt;TP5 unit-resolution behavior (manual-grounded)&lt;/h2&gt;
&lt;p&gt;Turbo Pascal 5.0 describes a concrete unit lookup order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;check resident units loaded from &lt;code&gt;TURBO.TPL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if not resident, search &lt;code&gt;&amp;lt;UnitName&amp;gt;.TPU&lt;/code&gt; in current directory&lt;/li&gt;
&lt;li&gt;then search configured unit directories (&lt;code&gt;/U&lt;/code&gt; or IDE Unit Directories)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For make/build flows that compile unit sources, &lt;code&gt;&amp;lt;UnitName&amp;gt;.PAS&lt;/code&gt; follows the
same directory search pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path-order trap.&lt;/strong&gt; If &lt;code&gt;CORE.TPU&lt;/code&gt; exists in both the current directory and a
configured unit path, the first match wins. Two developers with different
path or unit-dir settings can compile &amp;ldquo;the same&amp;rdquo; project and get different
TPUs. Fix: use a single canonical unit directory and document it in
&lt;code&gt;BUILD.BAT&lt;/code&gt; or &lt;code&gt;README&lt;/code&gt;. Resident units from &lt;code&gt;TURBO.TPL&lt;/code&gt; bypass file search;
updating a &lt;code&gt;.TPU&lt;/code&gt; on disk has no effect if the resident copy is used. For
custom units, use non-resident layout so you control the artifact.&lt;/p&gt;
&lt;h2 id=&#34;tpu-reality-powerful-version-coupled-poorly-documented&#34;&gt;TPU reality: powerful, version-coupled, poorly documented&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.TPU&lt;/code&gt; is a compiled unit format designed for compiler/linker consumption, not
for human readability. Two facts matter in practice:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TPUs are tightly tied to compiler version/family. TP5 TPUs are not
guaranteed compatible with TP6 or BP7; even minor compiler bumps can change
internal layout.&lt;/li&gt;
&lt;li&gt;Mixing stale or cross-version TPUs causes misleading failures: &amp;ldquo;unit version
mismatch,&amp;rdquo; phantom unresolved externals, or runtime corruption that does not
correlate with recent edits.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Version-pinning rule: lock the compiler and RTL version for a project and do
not mix TPUs built by different compilers. If migrating, rebuild all units from
source under the new toolchain rather than reusing old TPUs.&lt;/p&gt;
&lt;p&gt;Important honesty point: I cannot verify a complete, official, stable
byte-level specification for late TPU variants in this repo. Practical
reverse-engineering material exists, but fields and layout differ by version.
So treat any fixed &amp;ldquo;TPU format diagram&amp;rdquo; from random sources as version-scoped,
not universal.&lt;/p&gt;
&lt;h2 id=&#34;tpu-differential-forensics-high-signal-technique&#34;&gt;TPU differential forensics (high signal technique)&lt;/h2&gt;
&lt;p&gt;When format docs are weak, compare binaries under controlled source changes.&lt;/p&gt;
&lt;p&gt;Recommended experiment:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;compile baseline unit and save &lt;code&gt;U0.TPU&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;change implementation only, compile &lt;code&gt;U1.TPU&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;change interface signature, compile &lt;code&gt;U2.TPU&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;compare byte-level deltas (&lt;code&gt;fc /b&lt;/code&gt; or hex diff tool)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Expected outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;implementation-only changes affect localized regions (code blocks, constants)&lt;/li&gt;
&lt;li&gt;interface changes tend to alter broader metadata/signature regions and may
shift offsets used by dependent units&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concrete example: if you add one procedure to an interface, dependent units
that &lt;code&gt;uses&lt;/code&gt; it must be recompiled. The TPU header/symbol tables change; a
stale dependent TPU can produce &amp;ldquo;unit version mismatch&amp;rdquo; or subtle ABI drift.
Always keep the forensics baseline (&lt;code&gt;U0.TPU&lt;/code&gt;) immutable; copy, don&amp;rsquo;t overwrite.&lt;/p&gt;
&lt;p&gt;When comparing deltas, focus on regions near the start (header/metadata) versus
the tail (code and data blocks). Interface changes often perturb both; pure
implementation changes usually leave the header stable and alter only later
regions. If a delta spans many disjoint areas, treat the unit as incompatible
with prior dependents and schedule a full recompile. This gives practical
understanding of compatibility sensitivity without relying on undocumented
magic constants.&lt;/p&gt;
&lt;h2 id=&#34;what-to-do-when-you-only-have-a-tpu-no-source&#34;&gt;What to do when you only have a TPU (no source)&lt;/h2&gt;
&lt;p&gt;This is a common retro-maintenance scenario.&lt;/p&gt;
&lt;h3 id=&#34;step-1-classify-before-touching-code&#34;&gt;Step 1: classify before touching code&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;identify likely compiler generation (project docs, timestamps, known toolchain)&lt;/li&gt;
&lt;li&gt;keep original TPU immutable (copy to &lt;code&gt;forensics/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;confirm build environment matches expected compiler generation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wrong compiler often produces &amp;ldquo;unit format error&amp;rdquo; or similar before any useful
diagnostic. If you have multiple TP versions installed, ensure &lt;code&gt;PATH&lt;/code&gt; and
invocation point at the correct one.&lt;/p&gt;
&lt;h3 id=&#34;step-2-inspect-for-recoverable-metadata&#34;&gt;Step 2: inspect for recoverable metadata&lt;/h3&gt;
&lt;p&gt;Use lightweight inspection first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;strings SOMEUNIT.TPU &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; less
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hexdump -C SOMEUNIT.TPU &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; less&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Expected outcome:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;discover symbol-like names or error strings&lt;/li&gt;
&lt;li&gt;estimate whether unit contains useful identifiers or is mostly opaque&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If identifiers are absent, you still can treat the unit as a black-box provider.&lt;/p&gt;
&lt;h3 id=&#34;step-3-reconstruct-interface-incrementally&#34;&gt;Step 3: reconstruct interface incrementally&lt;/h3&gt;
&lt;p&gt;If you know or infer exported symbols, create a probe unit/program and compile
against the TPU using conservative declarations. Iterate by compiler feedback:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;declare one procedure/function candidate&lt;/li&gt;
&lt;li&gt;compile&lt;/li&gt;
&lt;li&gt;fix signature assumptions from diagnostics&lt;/li&gt;
&lt;li&gt;repeat&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is slow and effective. Think of it as ABI archaeology, not decompilation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No-source caveat.&lt;/strong&gt; Reconstructing an interface from a TPU alone is
best-effort. Some identifiers may be mangled or stripped; constant values and
exact type layouts are harder to recover. When in doubt, treat the unit as
opaque and call only what you can confirm compiles and behaves correctly.
Do not assume undocumented TPU layout is stable across compiler versions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recovery priority.&lt;/strong&gt; If you have partial source (e.g. one unit&amp;rsquo;s &lt;code&gt;.PAS&lt;/code&gt; but
not its dependencies), compile that first and see what the compiler reports as
missing. The error messages often reveal needed unit or symbol names. Work
from known-good declarations inward; avoid guessing large interface blocks from
scratch when you can narrow the surface with compiler feedback.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version-scoping of claims.&lt;/strong&gt; The TPU layout and OMF record details
described here are based on commonly observed behavior in TP5/BP7-era
toolchains. Tool variants (TASM vs MASM, TLINK vs other linkers) can produce
slightly different OBJ/LIB layouts. Where this article makes format-specific
claims, treat them as applicable to the Borland toolchain family; other
environments may differ.&lt;/p&gt;
&lt;h2 id=&#34;obj-and-lib-forensics-where-link-truth-lives&#34;&gt;OBJ and LIB forensics: where link truth lives&lt;/h2&gt;
&lt;p&gt;When external modules are involved, &lt;code&gt;.OBJ&lt;/code&gt; and &lt;code&gt;.LIB&lt;/code&gt; are usually where truth
is found. In many Borland-era environments, object modules follow OMF records;
you can inspect structure with &lt;code&gt;TDUMP&lt;/code&gt; or compatible tools (e.g. &lt;code&gt;omfdump&lt;/code&gt;,
&lt;code&gt;objdump&lt;/code&gt; with OMF support where available).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Basic inspection workflow:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tdump FASTBLIT.OBJ &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; FASTBLIT.DMP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tdump RUNTIME.LIB &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; RUNTIME.DMP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tdump MAIN.EXE &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; MAIN.DMP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For &lt;code&gt;.LIB&lt;/code&gt; files, TDUMP lists contained object modules and their publics. For
&lt;code&gt;.OBJ&lt;/code&gt; files, you see the single module&amp;rsquo;s records. For &lt;code&gt;.EXE&lt;/code&gt; files, you see
the linked image and segment layout.&lt;/p&gt;
&lt;p&gt;In dumps, you are looking for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;exported/public symbol names (exact spelling and decoration, if any)&lt;/li&gt;
&lt;li&gt;unresolved externals expected from other modules&lt;/li&gt;
&lt;li&gt;segment/class patterns that do not match expectations (e.g. &lt;code&gt;CODE&lt;/code&gt; vs
&lt;code&gt;CSEG&lt;/code&gt;, &lt;code&gt;FAR&lt;/code&gt; vs &lt;code&gt;NEAR&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If names look right but link still fails, calling convention or far/near model
mismatch is often the real issue.&lt;/p&gt;
&lt;p&gt;Manual anchor: TP5 external declarations are linked through &lt;code&gt;{$L filename}&lt;/code&gt;.
This is documented as the assembly-language interop path for &lt;code&gt;external&lt;/code&gt;
subprogram declarations. The linker searches object directories when path is
not explicit; document that search order for your setup.&lt;/p&gt;
&lt;h3 id=&#34;omf-record-level-orientation-why-tdump-output-matters&#34;&gt;OMF record-level orientation (why TDUMP output matters)&lt;/h3&gt;
&lt;p&gt;You will often see record classes such as module header (&lt;code&gt;THEADR&lt;/code&gt;), external
definitions (&lt;code&gt;EXTDEF&lt;/code&gt;), public definitions (&lt;code&gt;PUBDEF&lt;/code&gt;), communal definitions
(&lt;code&gt;COMDEF&lt;/code&gt;), segment definitions (&lt;code&gt;SEGDEF&lt;/code&gt;), data records (&lt;code&gt;LEDATA&lt;/code&gt;/&lt;code&gt;LIDATA&lt;/code&gt;),
fixups (&lt;code&gt;FIXUPP&lt;/code&gt;), and module end (&lt;code&gt;MODEND&lt;/code&gt;). You do not need to memorize
every byte code to gain value. What matters is recognizing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what this module exports (look for &lt;code&gt;PUBDEF&lt;/code&gt; and similar)&lt;/li&gt;
&lt;li&gt;what this module imports (look for &lt;code&gt;EXTDEF&lt;/code&gt; and unresolved refs)&lt;/li&gt;
&lt;li&gt;where relocation/fixup pressure appears (segments, frame numbers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example: if &lt;code&gt;tdump FASTBLIT.OBJ&lt;/code&gt; shows a public &lt;code&gt;FastCopy&lt;/code&gt; in segment &lt;code&gt;CODE&lt;/code&gt;,
and your Pascal declares &lt;code&gt;procedure FastBlit(...) external;&lt;/code&gt;, the name mismatch
(&lt;code&gt;FastCopy&lt;/code&gt; vs &lt;code&gt;FastBlit&lt;/code&gt;) will cause &amp;ldquo;unresolved external.&amp;rdquo; The dump gives
you the ground truth. OMF does not standardize symbol decoration; Borland
tools typically emit undecorated public names for Pascal-callable routines,
whereas C compilers may prefix with underscore or use name mangling. If an OBJ
came from a C build, &lt;code&gt;strings&lt;/code&gt; on the OBJ or TDUMP&amp;rsquo;s public list shows the
actual external name—use that exact form in your &lt;code&gt;external&lt;/code&gt; declaration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample TDUMP output interpretation.&lt;/strong&gt; A typical OBJ dump might show:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Module: FASTBLIT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Segment: CODE  Align: Word  Combine: Public
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Publics: FastCopy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Externals: (none)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This tells you: the routine is named &lt;code&gt;FastCopy&lt;/code&gt;, lives in &lt;code&gt;CODE&lt;/code&gt;, and does not
import any external symbols. If your Pascal expects &lt;code&gt;FastBlit&lt;/code&gt; or a different
segment, the mismatch is clear. For LIB dumps, you see one such block per
contained OBJ; scan for the symbol you need and note which module provides it.
If an OBJ lists externals, those must be satisfied by other linked modules or
libraries; unresolved externals at link time usually mean a missing OBJ or LIB
in the link command, or a symbol name typo in the providing module. For LIB
files, link order can matter: the linker pulls in members to satisfy unresolved
externals in sequence. If two OBJs in a LIB have circular references, their
relative order in the archive may determine whether resolution succeeds. When
adding new OBJs to a LIB, run &lt;code&gt;tdump LIBNAME.LIB&lt;/code&gt; afterward to confirm the
member list and publics; TDUMP typically does not reorder members, but some
library tools do. That is enough to explain most &amp;ldquo;why does this link differently
now?&amp;rdquo; questions.&lt;/p&gt;
&lt;h2 id=&#34;map-files-the-fastest-way-to-end-speculation&#34;&gt;Map files: the fastest way to end speculation&lt;/h2&gt;
&lt;p&gt;Generate a map file for non-trivial builds. In IDE: Options → Linker → Map file
(create detailed map). On CLI: &lt;code&gt;TLINK&lt;/code&gt; typically has a &lt;code&gt;/M&lt;/code&gt; or similar switch
for map output. Once you have a map, you can answer quickly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;did the symbol land in the expected segment?&lt;/li&gt;
&lt;li&gt;did the expected object module get linked at all?&lt;/li&gt;
&lt;li&gt;which module caused unexpected size growth?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;MAP forensics loop:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build with map enabled. Save &lt;code&gt;GOOD.MAP&lt;/code&gt; as baseline.&lt;/li&gt;
&lt;li&gt;After a change or failure, build again and compare segment/symbol layout.&lt;/li&gt;
&lt;li&gt;If a symbol is missing or moved unexpectedly, trace back to OBJ/TPU
ownership.&lt;/li&gt;
&lt;li&gt;If total size jumps, scan the map for newly included modules or segments.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example interpretation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0001:03A0  MainLoop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0001:07C0  DrawHud
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0002:0010  FastCopy   (from FASTBLIT.OBJ)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This gives direct evidence that your assembly object is linked and reachable.
The &lt;code&gt;0002:0010&lt;/code&gt; format is segment:offset; the &lt;code&gt;(from FASTBLIT.OBJ)&lt;/code&gt; annotation
confirms the symbol&amp;rsquo;s origin. If &lt;code&gt;FastCopy&lt;/code&gt; does not appear, the OBJ was not
linked—check &lt;code&gt;{$L}&lt;/code&gt; and link order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;End-to-end artifact workflow example.&lt;/strong&gt; Suppose a project fails to link with
&amp;ldquo;Unresolved external FastBlit.&amp;rdquo;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;tdump ASM\FASTBLIT.OBJ&lt;/code&gt; → inspect publics. If the symbol is &lt;code&gt;FastCopy&lt;/code&gt;
not &lt;code&gt;FastBlit&lt;/code&gt;, fix the Pascal &lt;code&gt;external&lt;/code&gt; declaration to match.&lt;/li&gt;
&lt;li&gt;Verify &lt;code&gt;{$L ASM\FASTBLIT.OBJ}&lt;/code&gt; is present and path correct.&lt;/li&gt;
&lt;li&gt;Rebuild with map enabled. Check that &lt;code&gt;FastCopy&lt;/code&gt; (or corrected name) appears
in the MAP with &lt;code&gt;(from FASTBLIT.OBJ)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If MAP shows the symbol but runtime crashes on call, switch to
calling-convention checklist (near/far, Pascal vs cdecl, parameter order).&lt;/li&gt;
&lt;li&gt;If all above pass, run &lt;code&gt;tdump MYAPP.EXE&lt;/code&gt; and confirm segment layout matches
expectations; then consider disassembly only as a last step.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This sequence uses TPU/OBJ/LIB/MAP/EXE in order of diagnostic payoff. Skipping
to EXE or disassembly before resolving OBJ/MAP questions wastes time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When MAP generation fails.&lt;/strong&gt; Some minimal IDE profiles omit map output by
default. If you cannot enable it, capture at least: EXE file size, list of
&lt;code&gt;{$L}&lt;/code&gt; and &lt;code&gt;uses&lt;/code&gt; entries, and a TDUMP of the EXE for segment layout. That
still beats debugging without any artifact visibility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Checksum vs size.&lt;/strong&gt; File size is a fast sanity check; if the EXE grows by
50KB with no new features, something changed. A simple checksum (e.g. DOS
&lt;code&gt;certutil&lt;/code&gt; or Unix &lt;code&gt;cksum&lt;/code&gt;) catches content drift when size alone is
unchanged. For release verification, checksum the EXE and key TPUs/OBJs and
record them in the build log. Teams that automate this in their build script
catch integration drift before it reaches users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MAP format nuances.&lt;/strong&gt; TLINK map files use segment:offset notation; the segment
number corresponds to the link order of segments. A &amp;ldquo;detailed&amp;rdquo; map includes
module origins—which OBJ or unit contributed each segment—so you can trace
size bloat to a specific module. Segment class names (&lt;code&gt;CODE&lt;/code&gt;, &lt;code&gt;DATA&lt;/code&gt;, &lt;code&gt;CSEG&lt;/code&gt;,
&lt;code&gt;DSEG&lt;/code&gt;) reflect compiler/linker output; minor differences across TP versions are
common. When diffing MAPs, compare symbol-to-segment assignments and segment
sizes rather than raw class names. A symbol that moved from one segment to
another between builds can indicate model changes (e.g. near vs far) or link
order tweaks.&lt;/p&gt;
&lt;h2 id=&#34;manipulating-artifacts-safely&#34;&gt;Manipulating artifacts safely&lt;/h2&gt;
&lt;p&gt;Three levels of &amp;ldquo;manipulation&amp;rdquo; exist; do not mix them casually.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clean rebuild manipulation&lt;/strong&gt;: remove stale TPUs/OBJs and rebuild. Safe and
repeatable. Script it: &lt;code&gt;del *.TPU *.OBJ&lt;/code&gt; (or equivalent) before build.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Link graph manipulation&lt;/strong&gt;: reorder/add/remove OBJ/LIB participation.
Changes code layout; verify with MAP. Can expose far/near or segment
ordering issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Binary patch manipulation&lt;/strong&gt;: edit executable bytes post-link. Risky.
Use only for experiments; document offsets, hashes, and rationale. Never
treat patched binaries as release artifacts without explicit process.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rule: if a problem appears after link-graph or binary manipulation, revert to
last known-good clean build before drawing conclusions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clean script pattern.&lt;/strong&gt; A minimal DOS-era clean step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;del&lt;/span&gt; *.TPU *.OBJ &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;nul
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;exist&lt;/span&gt; BIN\*.EXE &lt;span class=&#34;k&#34;&gt;del&lt;/span&gt; BIN\*.EXE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;exist&lt;/span&gt; BIN\*.MAP &lt;span class=&#34;k&#34;&gt;del&lt;/span&gt; BIN\*.MAP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Run this before any &amp;ldquo;full rebuild&amp;rdquo; or when chasing artifact-related bugs. Keep
source (&lt;code&gt;.PAS&lt;/code&gt;, &lt;code&gt;.ASM&lt;/code&gt;) and build scripts; treat everything else as regenerable.&lt;/p&gt;
&lt;h2 id=&#34;unit-libraries-and-tpumover-note&#34;&gt;Unit libraries and TPUMOVER note&lt;/h2&gt;
&lt;p&gt;Some TP/BP installations include tooling such as &lt;code&gt;TPUMOVER&lt;/code&gt; for packaging unit
modules into library containers. Availability and exact workflows are
installation-dependent. If present, treat library generation as a release
artifact with version pinning, not as a casual local convenience. Migrating
TPUs between library and loose-file form can alter search order; document
which layout the project uses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Libraries vs loose TPUs.&lt;/strong&gt; Loose TPUs in a directory are easier to
individually inspect, checksum, and replace during development. Library
(TUM-style) packaging reduces file count and can speed unit search on slow
media. Choose one approach per project and stick with it; mixing both for the
same units invites &amp;ldquo;which version did we actually link?&amp;rdquo; confusion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TPUMOVER and library maintenance.&lt;/strong&gt; When you add or remove units from a
library, always rebuild the library from a clean state rather than
incrementally patching. Stale or partially updated libraries produce the same
mystery failures as stale TPUs. After any library change, run a full clean
rebuild of the main program and verify the MAP reflects the expected unit set.
Treat the library as an intermediate build product, not a hand-edited asset.&lt;/p&gt;
&lt;h2 id=&#34;external-obj-integration-robust-declaration-pattern&#34;&gt;External OBJ integration: robust declaration pattern&lt;/h2&gt;
&lt;p&gt;Pascal side:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-pascal&#34; data-lang=&#34;pascal&#34;&gt;{$L FASTBLIT.OBJ}
procedure FastBlit(var Dst; const Src; Count: Word); external;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Expected outcome before first run:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;link succeeds with no unresolved external&lt;/li&gt;
&lt;li&gt;call does not corrupt stack&lt;/li&gt;
&lt;li&gt;output buffer changes exactly as test vector predicts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If link succeeds but behavior is wrong, suspect ABI mismatch first. Before
blaming the algorithm, verify parameter alignment: Turbo Pascal typically aligns
parameters to word boundaries; an assembly routine expecting byte-precise
layout may read garbage. Return-value handling also varies: functions returning
&lt;code&gt;Word&lt;/code&gt; or &lt;code&gt;Integer&lt;/code&gt; use AX; &lt;code&gt;LongInt&lt;/code&gt; uses DX:AX; records and strings use
hidden pointer parameters. Document what your external returns and how the
caller expects it; mismatches cause wrong values, not link errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Calling-convention cautions.&lt;/strong&gt; Turbo Pascal&amp;rsquo;s default calling convention
(typically near, Pascal-style: left-to-right push, caller cleans stack) must
match the external routine. Common failure modes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;C vs Pascal convention&lt;/strong&gt;: C pushes right-to-left and often uses different
name decoration. If the OBJ came from C (&lt;code&gt;TCC&lt;/code&gt;, &lt;code&gt;BCC&lt;/code&gt;), declare with
&lt;code&gt;cdecl&lt;/code&gt; or equivalent where the compiler supports it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Near vs far&lt;/strong&gt;: &lt;code&gt;{$F+}&lt;/code&gt; forces far calls; assembly routines must use
&lt;code&gt;RET FAR&lt;/code&gt; and matching prolog. Mismatch causes return to wrong address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameter order and types&lt;/strong&gt;: &lt;code&gt;var&lt;/code&gt; passes pointer; &lt;code&gt;const&lt;/code&gt; can pass
pointer or value depending on size. Word-sized &lt;code&gt;Count&lt;/code&gt; must match assembly
expectations (byte, word, or dword).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Segment assumptions&lt;/strong&gt;: If the OBJ assumes a particular &lt;code&gt;DS&lt;/code&gt; or &lt;code&gt;ES&lt;/code&gt; setup,
document it. Pascal does not guarantee segment registers at call boundary.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Document every external in a small header comment: source file, compiler/TASM
options used, calling convention, and any non-default assumptions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integration test pattern.&lt;/strong&gt; Before relying on an external in production
code, add a minimal harness that calls it with known inputs and verifies
output. For example, fill two buffers, call the routine, and assert the
result. If that passes, the OBJ is correctly integrated; failures point to
convention or parameter mismatches before you bury the call in complex logic.
Run it immediately after linking.&lt;/p&gt;
&lt;p&gt;TP5 reference also states &lt;code&gt;{$L filename}&lt;/code&gt; is a local directive and searches
object directories when a path is not explicit, which is a common source of
machine-to-machine drift. Prefer explicit paths in build scripts: &lt;code&gt;{$L ASM\FASTBLIT.OBJ}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TLIB workflow for multi-module assembly.&lt;/strong&gt; When you have several &lt;code&gt;.ASM&lt;/code&gt; files
producing &lt;code&gt;.OBJ&lt;/code&gt; modules, you can either list each with &lt;code&gt;{$L mod1.OBJ}&lt;/code&gt; &lt;code&gt;{$L mod2.OBJ}&lt;/code&gt; &amp;hellip; or build a &lt;code&gt;.LIB&lt;/code&gt; and link that. TLIB creates/updates
libraries:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tlib FASTMATH +FASTBLIT +FASTMUL +FASTDIV&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then &lt;code&gt;{$L FASTMATH.LIB}&lt;/code&gt; pulls in all modules. TDUMP on the LIB shows which
modules and publics it contains. Use a LIB when you have many OBJ files and
want a single linkable unit; keep OBJ references when you need explicit control
over link order (e.g. for overlays or segment placement).&lt;/p&gt;
&lt;h2 id=&#34;exe-level-checks-before-disassembly&#34;&gt;EXE-level checks before disassembly&lt;/h2&gt;
&lt;p&gt;Before deep reversing, inspect executable-level metadata. TDUMP on &lt;code&gt;.EXE&lt;/code&gt; shows
DOS header, relocation table, segment layout, and entry point. The DOS header
contains the relocation count (number of fixups applied at load), initial CS:IP
(entry point), and initial SS:SP (stack). Relocation entries point to segment
references that the loader patches when loading at a non-default base; a change
in relocation count often indicates new far pointers or segment-relative refs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;High-signal EXE checks:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;relocation count changes (indicates new segments or far model shifts)&lt;/li&gt;
&lt;li&gt;stack/code entry metadata drift&lt;/li&gt;
&lt;li&gt;total image size deltas&lt;/li&gt;
&lt;li&gt;segment order and class names (e.g. &lt;code&gt;CODE&lt;/code&gt;, &lt;code&gt;DATA&lt;/code&gt;, &lt;code&gt;STACK&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tdump MYAPP.EXE &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; findstr /i &lt;span class=&#34;s2&#34;&gt;&amp;#34;reloc entry segment&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Or capture full dump and diff against known-good:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tdump MYAPP.EXE &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; MYAPP_EXE.DMP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fc /b MYAPP_EXE.DMP BASELINE_EXE.DMP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Large unexpected changes usually indicate build-profile or link-graph drift,
not random compiler mood. This quick check avoids hours of aimless debugging.
If the EXE header and relocation table match a known-good build, but behavior
differs, the problem is likely runtime (paths, overlays, memory) rather than
link-time.&lt;/p&gt;
&lt;h2 id=&#34;high-value-troubleshooting-table&#34;&gt;High-value troubleshooting table&lt;/h2&gt;
&lt;p&gt;Use this as a repeatable decision matrix. Check in order; do not skip to
disassembly before ruling out high-signal causes. The goal is to eliminate
most failures with minimal tool use—TDUMP, MAP diff, and clean rebuild cover
the majority of cases.&lt;/p&gt;
&lt;h3 id=&#34;unresolved-external&#34;&gt;&amp;ldquo;Unresolved external&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes (check first):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;symbol spelling/case mismatch (TDUMP the OBJ for exact public name)&lt;/li&gt;
&lt;li&gt;missing object or library in link graph (verify &lt;code&gt;{$L}&lt;/code&gt; and TLINK command)&lt;/li&gt;
&lt;li&gt;module compiled for incompatible object format/profile (OMF vs COFF, etc.)&lt;/li&gt;
&lt;li&gt;wrong unit or OBJ pulled from alternate path (path order, current dir)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; &lt;code&gt;tdump SYMBOL.OBJ | findstr /i &amp;quot;public pubdef&amp;quot;&lt;/code&gt; — does the
exported name match your Pascal &lt;code&gt;external&lt;/code&gt; declaration exactly?&lt;/p&gt;
&lt;h3 id=&#34;runs-then-random-crash-after-external-call&#34;&gt;&amp;ldquo;Runs, then random crash after external call&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes (check first):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;parameter passing mismatch (order, size, var vs value)&lt;/li&gt;
&lt;li&gt;caller/callee stack cleanup mismatch (Pascal vs cdecl)&lt;/li&gt;
&lt;li&gt;near/far routine mismatch (return address on wrong stack location)&lt;/li&gt;
&lt;li&gt;segment register assumptions violated (DS, ES not as assembly expects)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; Add a minimal passthrough test: call the routine with
known-good inputs and confirm output. If that works, the failure is in
integration, not the routine itself.&lt;/p&gt;
&lt;h3 id=&#34;unit-version-mismatch&#34;&gt;&amp;ldquo;Unit version mismatch&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TPU built by different compiler version&lt;/li&gt;
&lt;li&gt;interface changed but dependent unit not recompiled&lt;/li&gt;
&lt;li&gt;stale TPU in a path that shadows the correct one&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; Delete all TPUs, rebuild from scratch. If it works, you had
stale artifacts.&lt;/p&gt;
&lt;h3 id=&#34;binary-suddenly-huge&#34;&gt;&amp;ldquo;Binary suddenly huge&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;profile drift (debug info/checks enabled)&lt;/li&gt;
&lt;li&gt;broad library dependency pull&lt;/li&gt;
&lt;li&gt;accidental static inclusion of assets/modules (BGI linked in, large data)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; Compare MAP files. New segments or modules explain the growth.&lt;/p&gt;
&lt;h3 id=&#34;works-on-my-machine-fails-elsewhere&#34;&gt;&amp;ldquo;Works on my machine, fails elsewhere&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;path differences (unit dir, object dir, BGI dir, overlay dir)&lt;/li&gt;
&lt;li&gt;different DOS/TSR footprint (less conventional memory)&lt;/li&gt;
&lt;li&gt;different compiler or RTL version installed&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; Document paths and versions on working machine; replicate
exactly on failing one, or ship with explicit relative paths.&lt;/p&gt;
&lt;h3 id=&#34;overlay-load-fails-or-hangs&#34;&gt;&amp;ldquo;Overlay load fails or hangs&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most likely causes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;OVR file not in working directory or configured overlay path&lt;/li&gt;
&lt;li&gt;overlay unit compiled with different memory model than main program&lt;/li&gt;
&lt;li&gt;overlay segment size exceeds OVR file (truncated or mismatched build)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; Confirm OVR file size matches expectations; run &lt;code&gt;tdump&lt;/code&gt; on the
EXE to see overlay segment declarations. Compare with a known-good overlay build.&lt;/p&gt;
&lt;h3 id=&#34;summary-signal-order-for-artifact-inspection&#34;&gt;Summary: signal order for artifact inspection&lt;/h3&gt;
&lt;p&gt;When you do not know where to start, use this priority:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MAP&lt;/strong&gt; — fastest way to see what actually linked. Generate it; diff it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OBJ/LIB + TDUMP&lt;/strong&gt; — resolves &amp;ldquo;unresolved external&amp;rdquo; and symbol-name issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TPU&lt;/strong&gt; — resolves &amp;ldquo;unit version mismatch&amp;rdquo; and interface drift; use
differential forensics when format is unknown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EXE + TDUMP&lt;/strong&gt; — confirms final layout; use when MAP and OBJ checks pass
but runtime behavior is wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disassembly&lt;/strong&gt; — last resort when binary layout is correct but logic is
suspect.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most TP toolchain bugs are solved at steps 1–3. Avoid jumping to 4–5 without
evidence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Checkpoint discipline.&lt;/strong&gt; When you have a working build, immediately: (a) save
&lt;code&gt;BASELINE.MAP&lt;/code&gt;, (b) note EXE size and optionally CRC, (c) archive BUILD.TXT.
If a later change breaks things, you can diff MAP vs baseline, compare sizes,
and often pinpoint the regression without touching source. Teams that skip
checkpoints repeat the same forensic work repeatedly. A single baseline from a
known-good build can save hours of regression hunting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before seeking help.&lt;/strong&gt; If you are stuck and plan to ask a colleague or
post online, gather: exact error message, compiler/linker version, output of
&lt;code&gt;tdump&lt;/code&gt; on the failing OBJ (for link errors) or EXE (for runtime), and a
one-line description of the last change. That context turns &amp;ldquo;it doesn&amp;rsquo;t work&amp;rdquo;
into a solvable puzzle. Omitting the MAP or TDUMP output is the most common
reason diagnostic threads go nowhere.&lt;/p&gt;
&lt;h2 id=&#34;a-disciplined-binary-investigation-loop&#34;&gt;A disciplined binary investigation loop&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;state expected outcome before run&lt;/li&gt;
&lt;li&gt;build clean (no stale TPU/OBJ)&lt;/li&gt;
&lt;li&gt;capture &lt;code&gt;.EXE&lt;/code&gt; size/hash + &lt;code&gt;.MAP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;inspect changed symbols/segments first&lt;/li&gt;
&lt;li&gt;only then debug/disassemble&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This order keeps you from chasing folklore. Teams that skip step 3 often waste
hours on &amp;ldquo;it used to work&amp;rdquo; bugs that are pure link/artifact drift.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When the loop stalls.&lt;/strong&gt; If you have done clean rebuild, MAP diff, TDUMP on
OBJ and EXE, and the problem persists, the cause may be environmental: TSR
conflicts, EMS/XMS driver behavior, or DOS version differences. At that point
narrow the environment: boot minimal config, disable TSRs, try a different DOS
version or machine. Document the minimal repro configuration; that becomes the
bug report. Before concluding &amp;ldquo;environment only,&amp;rdquo; re-run the loop with a
single-source-change variation: revert the most recent edit, rebuild, and
compare. If the revert fixes it, the regression is in that change, not the
environment—even when the artifact diff is subtle.&lt;/p&gt;
&lt;h2 id=&#34;team-and-process-discipline-for-artifact-reproducibility&#34;&gt;Team and process discipline for artifact reproducibility&lt;/h2&gt;
&lt;p&gt;Reproducibility fails when one developer has hidden state that others do not.
Enforce these practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version-lock the toolchain&lt;/strong&gt;: document exact TP/BP version, TASM version,
and any third-party units. Rebuild from source on a clean checkout must
produce identical artifacts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit paths in scripts&lt;/strong&gt;: avoid &amp;ldquo;current directory&amp;rdquo; assumptions. Build
scripts should set &lt;code&gt;PATH&lt;/code&gt;, unit dirs, and object dirs explicitly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archive build products with releases&lt;/strong&gt;: keep &lt;code&gt;EXE&lt;/code&gt; + &lt;code&gt;MAP&lt;/code&gt; + optional
&lt;code&gt;OVR&lt;/code&gt; and a short &lt;code&gt;BUILD.TXT&lt;/code&gt; (compiler version, options, date) in the
release package. That gives future maintainers a diff target.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One clean rebuild before any &amp;ldquo;weird bug&amp;rdquo; investigation&lt;/strong&gt;: if a bug appears
after days of incremental builds, delete TPUs/OBJs and rebuild. Many
&amp;ldquo;impossible&amp;rdquo; bugs vanish.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ABI checkpoint for externals&lt;/strong&gt;: when integrating a new OBJ, record its
public symbols (from TDUMP), calling convention, and any segment or
alignment assumptions in a small integration doc. Future maintainers can
verify correctness without re-deriving the ABI from scratch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treat TPU/OBJ as derived, never committed&lt;/strong&gt;: only source (&lt;code&gt;.PAS&lt;/code&gt;, &lt;code&gt;.ASM&lt;/code&gt;)
goes in version control. Rebuild artifact sets from source on each machine.
Committed TPUs from one developer&amp;rsquo;s machine can silently break another&amp;rsquo;s
build when compiler versions differ. Document this policy in the project
README.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These rules are low-cost and eliminate a large class of non-reproducible
failures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build log discipline.&lt;/strong&gt; For each release or debugging baseline, record in
&lt;code&gt;BUILD.TXT&lt;/code&gt; or equivalent: compiler executable and version, key options
(&lt;code&gt;{$D+}&lt;/code&gt;, &lt;code&gt;{$R+}&lt;/code&gt;, memory model), unit and object paths, and checksum or size
of the main EXE. When a bug report arrives months later, that log tells you
whether you can reproduce the exact binary or must narrow the search.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Handoff protocol.&lt;/strong&gt; When passing a project to another maintainer, include:
source tree, BUILD.BAT or equivalent, BASELINE.MAP from last known-good build,
and a one-page &amp;ldquo;toolchain and paths&amp;rdquo; document. Without that, the next person
spends days rediscovering unit search order, object paths, and which TP
version was used. The hour you spend documenting pays off on the first
&amp;ldquo;works on my machine&amp;rdquo; incident.&lt;/p&gt;
&lt;h2 id=&#34;cross-references&#34;&gt;Cross references&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/toolchain/turbo-pascal-toolchain-part-1-anatomy-and-workflow/&#34;&gt;Turbo Pascal Toolchain, Part 1: Anatomy and Workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/turbo-pascal-units-as-architecture/&#34;&gt;Turbo Pascal Units as Architecture, Not Just Reuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/turbo-pascal-overlay-tutorial-build-package-and-debug-an-ovr-application/&#34;&gt;Turbo Pascal Overlay Tutorial: Build, Package, and Debug an OVR Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/turbo-pascal-bgi-tutorial-dynamic-drivers-linked-drivers-and-diagnostic-harnesses/&#34;&gt;Turbo Pascal BGI Tutorial: Dynamic Drivers, Linked Drivers, and Diagnostic Harnesses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/turbo-pascal-in-2025/&#34;&gt;Writing Turbo Pascal in 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;next-part&#34;&gt;Next part&lt;/h2&gt;
&lt;p&gt;Part 3 moves from artifacts to runtime memory strategy: overlays, near/far
costs, and link strategy under hard 640K pressure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/retro/dos/tp/toolchain/turbo-pascal-toolchain-part-3-overlays-memory-models-and-link-strategy/&#34;&gt;Turbo Pascal Toolchain, Part 3: Overlays, Memory Models, and Link Strategy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Summary for busy maintainers.&lt;/strong&gt; When a TP project misbehaves: (1) clean
rebuild first; (2) generate and diff the MAP; (3) TDUMP any external OBJs to
confirm symbol names; (4) verify calling conventions on externals; (5) check
path and version consistency. Most failures resolve before you touch a
disassembler. Treat TPU/OBJ as version-locked, path-explicit, and
never-committed. Document once; benefit forever. The artifact-focused mindset
that Part 1 introduced becomes concrete here: files on disk are your primary
evidence, source code is secondary when debugging build and link failures.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ghidra: First Steps in Reverse Engineering</title>
      <link>https://turbovision.in6-addr.net/hacking/tools/ghidra-first-steps/</link>
      <pubDate>Thu, 22 Jan 2026 00:00:00 +0000</pubDate>
      <lastBuildDate>Sun, 22 Feb 2026 15:49:08 +0100</lastBuildDate>
      <guid>https://turbovision.in6-addr.net/hacking/tools/ghidra-first-steps/</guid>
      <description>&lt;p&gt;Ghidra is the NSA&amp;rsquo;s gift to the reversing community. Free, cross-platform,
and surprisingly capable.&lt;/p&gt;
&lt;p&gt;We load a stripped ELF binary, let the auto-analysis run, and explore the
decompiler output. The key insight: Ghidra&amp;rsquo;s decompiler doesn&amp;rsquo;t produce
compilable C — it produces &lt;em&gt;readable&lt;/em&gt; pseudocode. Renaming variables and
retyping structs manually is where the real reverse engineering happens.&lt;/p&gt;
&lt;p&gt;The biggest beginner mistake is trusting auto-analysis too much. Ghidra gives
you a strong first draft, not ground truth. The real work starts when you
challenge defaults: unknown function signatures, wrong variable types, and
misidentified control flow around indirect calls.&lt;/p&gt;
&lt;h2 id=&#34;first-session-workflow&#34;&gt;First-session workflow&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Run analysis with default options.&lt;/li&gt;
&lt;li&gt;Find &lt;code&gt;main&lt;/code&gt; (or likely entry flow) and map high-level behavior.&lt;/li&gt;
&lt;li&gt;Rename obvious functions by side effects (&lt;code&gt;read_config&lt;/code&gt;, &lt;code&gt;decrypt_blob&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Define structs for repeated pointer patterns.&lt;/li&gt;
&lt;li&gt;Revisit call sites and fix function signatures incrementally.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Doing this in loops is faster than trying to perfect one function in isolation.
Each corrected type makes several other decompiler views clearer.&lt;/p&gt;
&lt;h2 id=&#34;practical-tip&#34;&gt;Practical tip&lt;/h2&gt;
&lt;p&gt;Keep a small text log while reversing: assumptions, confirmed facts, and
open questions. It prevents circular analysis and makes handoff easier when
you return days later. Reverse engineering is part technical, part narrative.
If the story of the binary is coherent, your findings are usually solid.&lt;/p&gt;
&lt;p&gt;Related reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/hacking/exploits/buffer-overflow-101/&#34;&gt;Buffer Overflow 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turbovision.in6-addr.net/hacking/exploits/format-string-attacks/&#34;&gt;Format String Attacks Demystified&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
