Files
tdkpin/original/reconstructed/tdkpin_heap.c
T
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
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
2026-08-23 16:41:17 +02:00

273 lines
8.5 KiB
C

/* Borland local/global Win16 heap core reconstructed from Code5. */
#include "tdkpin_heap.h"
static Win16FarPtr heap_address(uint16_t selector, uint16_t offset)
{
return win16_make_far_pointer(selector, offset);
}
static uint16_t heap_read(uint16_t selector, uint16_t offset)
{
return win16_read_u16(heap_address(selector, offset));
}
static void heap_write(uint16_t selector, uint16_t offset, uint16_t value)
{
win16_write_u16(heap_address(selector, 0), offset, value);
}
static uint16_t align_heap_size(uint16_t bytes)
{
return (uint16_t)((bytes + 3u) & 0xfffcu);
}
uint32_t borland_heap_free_space(void)
{
uint32_t total = GetFreeSpace16(0x1000);
uint16_t selector = g_borland_heap_segment_head;
if (selector != 0) {
do {
total += heap_read(selector, 8);
selector = heap_read(selector, 10);
} while (selector != g_borland_heap_segment_head);
}
return total;
}
uint32_t borland_heap_largest_block(void)
{
uint32_t largest = GlobalCompact16(0);
if ((largest >> 16) != 0) {
return largest;
}
uint16_t selector = g_borland_heap_segment_head;
if (selector != 0) {
do {
uint16_t local_free = heap_read(selector, 8);
if ((uint16_t)largest < local_free) {
largest = local_free;
}
selector = heap_read(selector, 10);
} while (selector != g_borland_heap_segment_head);
}
return largest;
}
BorlandLocalAllocation borland_local_allocate_in_segment(
uint16_t selector, uint16_t aligned_bytes)
{
uint16_t previous_link = 4;
while (true) {
uint16_t block = heap_read(selector, previous_link);
if (block == 0) {
return (BorlandLocalAllocation){0, true};
}
uint16_t block_size = heap_read(selector, (uint16_t)(block + 2));
if (block_size < aligned_bytes) {
previous_link = block;
continue;
}
uint16_t remaining = (uint16_t)(block_size - aligned_bytes);
uint16_t replacement = heap_read(selector, block);
if (remaining != 0) {
replacement = (uint16_t)(block + aligned_bytes);
heap_write(selector, replacement, heap_read(selector, block));
heap_write(selector, (uint16_t)(replacement + 2), remaining);
}
heap_write(selector, previous_link, replacement);
heap_write(
selector,
8,
(uint16_t)(heap_read(selector, 8) - aligned_bytes));
return (BorlandLocalAllocation){block, false};
}
}
void borland_local_merge_next(uint16_t selector, uint16_t block)
{
uint16_t next = heap_read(selector, block);
uint16_t adjacent =
(uint16_t)(block + heap_read(selector, (uint16_t)(block + 2)));
if (adjacent == next) {
heap_write(selector, block, heap_read(selector, next));
heap_write(
selector,
(uint16_t)(block + 2),
(uint16_t)(heap_read(selector, (uint16_t)(block + 2)) +
heap_read(selector, (uint16_t)(next + 2))));
}
}
uint16_t borland_create_local_heap_segment(void)
{
Win16FarPtr allocation =
borland_global_allocate(g_borland_heap_segment_bytes);
if (allocation == 0) {
return 0;
}
uint16_t selector = win16_far_selector(allocation);
uint16_t free_bytes =
(uint16_t)(g_borland_heap_segment_bytes - BORLAND_LOCAL_HEAP_HEADER_BYTES);
heap_write(selector, 0, BORLAND_LOCAL_HEAP_MAGIC);
heap_write(selector, 2, 0);
heap_write(selector, 4, BORLAND_LOCAL_HEAP_HEADER_BYTES);
heap_write(selector, 6, 0);
heap_write(selector, 8, free_bytes);
uint16_t next = selector;
if (g_borland_heap_segment_head != 0) {
next = heap_read(g_borland_heap_segment_head, 10);
heap_write(g_borland_heap_segment_head, 10, selector);
}
heap_write(selector, 10, next);
heap_write(selector, 12, 0);
heap_write(selector, 14, free_bytes);
return selector;
}
static BorlandAllocationAttempt borland_try_local_allocation(uint16_t bytes)
{
uint16_t aligned = align_heap_size(bytes);
uint16_t selector = g_borland_heap_segment_head;
if (selector != 0) {
do {
BorlandLocalAllocation local =
borland_local_allocate_in_segment(selector, aligned);
if (!local.failed) {
g_borland_heap_segment_head = selector;
return (BorlandAllocationAttempt){
heap_address(selector, local.offset), false};
}
selector = heap_read(selector, 10);
} while (selector != g_borland_heap_segment_head);
}
selector = borland_create_local_heap_segment();
if (selector == 0) {
return (BorlandAllocationAttempt){0, true};
}
BorlandLocalAllocation local =
borland_local_allocate_in_segment(selector, aligned);
if (local.failed) {
return (BorlandAllocationAttempt){0, true};
}
g_borland_heap_segment_head = selector;
return (BorlandAllocationAttempt){
heap_address(selector, local.offset), false};
}
BorlandAllocationAttempt borland_try_get_mem(uint16_t bytes)
{
if (bytes == 0) {
return (BorlandAllocationAttempt){0, false};
}
while (true) {
BorlandAllocationAttempt result;
if (bytes < g_borland_local_heap_limit) {
result = borland_try_local_allocation(bytes);
if (!result.failed) {
return result;
}
Win16FarPtr global = borland_global_allocate(bytes);
if (global != 0) {
return (BorlandAllocationAttempt){global, false};
}
} else {
Win16FarPtr global = borland_global_allocate(bytes);
if (global != 0) {
return (BorlandAllocationAttempt){global, false};
}
if (g_borland_local_heap_limit != 0 &&
bytes <=
(uint16_t)(g_borland_heap_segment_bytes -
BORLAND_LOCAL_HEAP_HEADER_BYTES)) {
result = borland_try_local_allocation(bytes);
if (!result.failed) {
return result;
}
}
}
uint16_t action = g_borland_heap_error_handler == 0
? 0
: win16_call_pascal_u16(g_borland_heap_error_handler, bytes);
if (action > 1) {
continue;
}
return (BorlandAllocationAttempt){0, action == 0};
}
}
static bool borland_global_free_selector(uint16_t selector)
{
if (selector == win16_far_selector(win16_dgroup_pointer(0))) {
return true;
}
HGLOBAL16 handle = GlobalHandle16(selector);
if (handle == 0) {
return true;
}
(void)GlobalUnlock16(handle);
(void)GlobalFree16(handle);
return false;
}
static bool borland_release_empty_local_segment(uint16_t selector)
{
uint16_t next = heap_read(selector, 10);
uint16_t new_head = 0;
if (next != selector) {
uint16_t previous = g_borland_heap_segment_head;
while (heap_read(previous, 10) != selector) {
previous = heap_read(previous, 10);
}
heap_write(previous, 10, next);
new_head = previous;
}
g_borland_heap_segment_head = new_head;
return borland_global_free_selector(selector);
}
bool borland_try_free_mem(Win16FarPtr block, uint16_t bytes)
{
if (bytes == 0) {
return false;
}
uint16_t selector = win16_far_selector(block);
uint16_t offset = win16_far_offset(block);
if (offset == 0) {
return borland_global_free_selector(selector);
}
uint16_t aligned = align_heap_size(bytes);
if (heap_read(selector, 0) != BORLAND_LOCAL_HEAP_MAGIC ||
(offset & 3) != 0) {
return true;
}
uint16_t previous_link = 4;
uint16_t current = heap_read(selector, previous_link);
while (current != 0 && offset > current) {
previous_link = current;
current = heap_read(selector, current);
}
if (offset == current) {
return true;
}
heap_write(selector, offset, current);
heap_write(selector, (uint16_t)(offset + 2), aligned);
uint16_t free_bytes = (uint16_t)(heap_read(selector, 8) + aligned);
heap_write(selector, 8, free_bytes);
if ((uint16_t)(free_bytes + BORLAND_LOCAL_HEAP_HEADER_BYTES) ==
g_borland_heap_segment_bytes) {
return borland_release_empty_local_segment(selector);
}
borland_local_merge_next(selector, offset);
heap_write(selector, previous_link, offset);
borland_local_merge_next(selector, previous_link);
return false;
}