Replace the partial mechanics transcriptions with a separate, readable C11 reconstruction of the complete Win16 image while preserving the original raw Ghidra export as immutable evidence. Cover all ordinary and overlapping entry points, Borland runtime behavior, Win16 imports, segmented data, callbacks, resources, indirect control flow, physics, rendering, persistence, and startup/shutdown lifecycles. Add deterministic extraction and audit tooling plus address-linked ledgers for functions, imports, DGROUP ranges and objects, relocations, resources, and callbacks. The final gate records zero raw, partial, restored, unknown, blocked, or unclassified required units. Keep the semantic-fidelity boundary explicit: the portable C is not claimed to reproduce a byte-identical Borland NE build. Add strict focused harnesses for every reconstructed C unit, exact resource round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source or Cargo metadata is changed in this phase. Test Plan: - `bash original/tools/test_reconstructed_c.sh` -- passed - `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit - `python3 original/tools/audit_reconstruction.py --require-complete` -- passed - `git diff --cached --check` -- passed - `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
162 lines
5.0 KiB
C
162 lines
5.0 KiB
C
#include "../tdkpin_object_lifecycle.h"
|
|
|
|
#include <assert.h>
|
|
|
|
static unsigned g_sequence;
|
|
static Win16FarPtr g_object;
|
|
static Win16FarPtr g_parent;
|
|
static Win16FarPtr g_thunk;
|
|
static Win16FarPtr g_teardown;
|
|
static bool g_enter_result;
|
|
static unsigned g_construct_sequence;
|
|
|
|
void win16_call_object_method(
|
|
Win16FarPtr procedure, Win16FarPtr object)
|
|
{
|
|
assert(++g_sequence == 1);
|
|
assert(procedure == g_teardown && object == g_object);
|
|
}
|
|
|
|
void object_windows_for_each_child(
|
|
Win16FarPtr container, Win16FarPtr action)
|
|
{
|
|
assert(++g_sequence == 2);
|
|
assert(container == g_object);
|
|
assert(action == win16_make_far_pointer(0x6000, 0x03e9));
|
|
}
|
|
|
|
void object_windows_remove_child(
|
|
Win16FarPtr container, Win16FarPtr child)
|
|
{
|
|
assert(++g_sequence == 3);
|
|
assert(container == g_parent && child == g_object);
|
|
}
|
|
|
|
void object_windows_release_bound_thunk(Win16FarPtr thunk)
|
|
{
|
|
assert(++g_sequence == (g_parent == 0 ? 3u : 4u));
|
|
assert(thunk == g_thunk);
|
|
}
|
|
|
|
void borland_default_object_destructor(
|
|
Win16FarPtr object, uint16_t vmt)
|
|
{
|
|
assert(++g_sequence == (g_parent == 0 ? 4u : 5u));
|
|
assert(object == g_object && vmt == 0);
|
|
}
|
|
|
|
void borland_finish_object_destructor(
|
|
BorlandObjectCallFrame *frame, uint16_t vmt_field_offset)
|
|
{
|
|
assert(++g_sequence == (g_parent == 0 ? 5u : 6u));
|
|
assert(frame->object == g_object && frame->vmt_argument == 0x0200);
|
|
assert(vmt_field_offset == 0);
|
|
}
|
|
|
|
bool borland_enter_object_constructor(
|
|
BorlandObjectCallFrame *frame, uint16_t vmt_field_offset)
|
|
{
|
|
assert(++g_construct_sequence == 1);
|
|
assert(frame->object == g_object && frame->vmt_argument == 0x0200);
|
|
assert(vmt_field_offset == 0);
|
|
return g_enter_result;
|
|
}
|
|
|
|
Win16FarPtr borland_default_object_constructor(
|
|
Win16FarPtr object, uint16_t vmt)
|
|
{
|
|
assert(++g_construct_sequence == 2);
|
|
assert(object == g_object && vmt == 0);
|
|
return object;
|
|
}
|
|
|
|
void object_windows_append_child(
|
|
Win16FarPtr container, Win16FarPtr child)
|
|
{
|
|
assert(++g_construct_sequence == 3);
|
|
assert(container == g_parent && child == g_object);
|
|
}
|
|
|
|
Win16FarPtr object_windows_allocate_bound_thunk(Win16FarPtr object)
|
|
{
|
|
unsigned expected = g_parent == 0 ? 3u : 4u;
|
|
assert(++g_construct_sequence == expected);
|
|
assert(object == g_object);
|
|
return g_thunk;
|
|
}
|
|
|
|
void object_windows_set_flag_4(Win16FarPtr object)
|
|
{
|
|
unsigned expected = g_parent == 0 ? 4u : 5u;
|
|
assert(++g_construct_sequence == expected);
|
|
assert(object == g_object);
|
|
Win16FarPtr address = win16_far_add_offset(object, 0x16);
|
|
win16_write_u8(address, (uint8_t)(win16_read_u8(address) | 4));
|
|
}
|
|
|
|
static void write_far(Win16FarPtr object, uint16_t offset, Win16FarPtr value)
|
|
{
|
|
win16_write_u16(object, offset, win16_far_offset(value));
|
|
win16_write_u16(
|
|
object, (uint16_t)(offset + 2), win16_far_selector(value));
|
|
}
|
|
|
|
static void run_case(bool with_parent)
|
|
{
|
|
g_sequence = 0;
|
|
g_parent = with_parent ? win16_make_far_pointer(0x7100, 2) : 0;
|
|
write_far(g_object, 6, g_parent);
|
|
object_windows_object_destruct(g_object, 0x0200);
|
|
assert(g_sequence == (with_parent ? 6u : 5u));
|
|
}
|
|
|
|
static void run_construct_case(bool with_parent)
|
|
{
|
|
g_construct_sequence = 0;
|
|
g_enter_result = true;
|
|
g_parent = with_parent ? win16_make_far_pointer(0x7100, 2) : 0;
|
|
assert(object_windows_object_construct(g_object, 0x0200, g_parent) ==
|
|
g_object);
|
|
assert(g_construct_sequence == (with_parent ? 5u : 4u));
|
|
assert(win16_read_u16(win16_far_add_offset(g_object, 2)) == 0);
|
|
assert(win16_read_u16(win16_far_add_offset(g_object, 4)) == 0);
|
|
assert(win16_read_far_pointer(g_object, 6) == g_parent);
|
|
assert(win16_read_far_pointer(g_object, 0x0a) == 0);
|
|
assert(win16_read_far_pointer(g_object, 0x0e) == 0);
|
|
assert(win16_read_far_pointer(g_object, 0x12) == g_thunk);
|
|
assert(win16_read_u8(win16_far_add_offset(g_object, 0x16)) == 4);
|
|
if (!with_parent) {
|
|
assert(win16_read_far_pointer(g_object, 0x19) == 0);
|
|
}
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
static uint8_t dgroup[0x1000];
|
|
static uint8_t code[0x1000];
|
|
static uint8_t object_bytes[64];
|
|
static uint8_t parent_bytes[64];
|
|
win16_reset_segment_bindings();
|
|
win16_bind_segment(0x5000, dgroup, sizeof(dgroup), true);
|
|
win16_set_dgroup_selector(0x5000);
|
|
win16_bind_ne_segment(4, 0x6000, code, sizeof(code), false);
|
|
win16_bind_segment(0x7000, object_bytes, sizeof(object_bytes), true);
|
|
win16_bind_segment(0x7100, parent_bytes, sizeof(parent_bytes), true);
|
|
|
|
g_object = win16_make_far_pointer(0x7000, 2);
|
|
g_thunk = win16_make_far_pointer(0x6200, 0x1234);
|
|
g_teardown = win16_make_far_pointer(0x6100, 0x4321);
|
|
win16_write_u16(g_object, 0, 0x0100);
|
|
write_far(win16_dgroup_pointer(0x0124), 0, g_teardown);
|
|
write_far(g_object, 0x12, g_thunk);
|
|
run_case(true);
|
|
run_case(false);
|
|
run_construct_case(true);
|
|
run_construct_case(false);
|
|
g_construct_sequence = 0;
|
|
g_enter_result = false;
|
|
assert(object_windows_object_construct(g_object, 0x0200, 0) == g_object);
|
|
assert(g_construct_sequence == 1);
|
|
return 0;
|
|
}
|