Crusader_Decomp/docs/far-call-targets.md
MaddoScientisto 3daffbf113 Add extractor for Crusader's EUSECODE.FLX container
- Implemented a Python script to extract data from the EUSECODE.FLX file format.
- Defined data structures for candidate entries and extracted chunks using dataclasses.
- Added functions to read and parse the FLX table, extract candidate data, and generate human-readable output files.
- Included functionality for analyzing extracted data, including generating summaries, descriptors, and event family reports.
- Implemented utilities for calculating printable ratios, zero ratios, and identifying text-like data.
- Added support for writing various output formats, including JSON, TSV, and Markdown.
2026-03-22 14:27:38 +01:00

17 KiB
Raw Blame History

Far-Call Targets: Top-104 Most-Called Functions

Content extracted from crusader_decompilation_notes.md. Named via systematic analysis of 11,692 NE relocation fixup entries — the functions most frequently called through the CALLF 0x0000:ffff thunk mechanism.


Tier 1: Ranks 120 (73+ callers)

Rank Address Name Calls Description
1 000a:44fd seg091_func_00fd 331 Recovered boundary. Shares init flag 0x44a4 with runtime_init_or_abort; thunk-heavy non-returning wrapper.
2 0003:ac7e mem_alloc 272 Allocation wrapper → seg082:0000 (0009:a200)
3 0008:dbec entity_word_list_destroy 238 Frees entity word-list buffer.
4 0003:a751 mem_free 207 Free wrapper → seg082:007a (0009:a27a = mem_free_checked)
5 0008:bb4f mem_alloc_far 174 Thin wrapper → mem_alloc
6 0003:a897 far_memcpy 165 REP MOVSW + trailing MOVSB
7 0005:088f entity_get_type_word 130 Returns type word from table 0x7df9 indexed by slot
8 000b:358d sprite_tree_accumulate_pos 122 Recursively sums X/Y offsets (+0x21/+0x23) through linked child nodes (+0x19/+0x1b), copies 8-byte position block via far_memcpy
9 0008:ce3d entity_call_two_vtables 118 Calls vtable[+4] at entity+0x1e and +0x28
10 0004:26cd nop_void_stub 118 Empty function, returns void
11 0008:ce00 entity_call_two_vtables_base 117 Calls vtable[0] at entity+0x1e and +0x28
12 0008:bb8c entity_check_flag_0x4000 115 Short-circuits if flag 0x4000 set at +0x16
13 0008:cda7 entity_free_both_word_lists 115 Frees word lists at entity+0x1e and +0x28 if optional pointers at +0x24/+0x26 and +0x2e/+0x30 non-null. Both call entity_word_list_free_existing.
14 0004:26d2 nop_void_stub_b 111 Empty function, returns void
15 000a:45fe runtime_init_or_abort 108 Reentrancy-guarded init. Flag at 0x44a4; flushes via FUN_000a_4a56, then calls crt_exit_wrapper(1). Hidden code gap 0x4616-0x4643.
16 0004:3324 nop_return_zero 95 Returns 0
17 0009:c563 event_queue_push 82 Circular buffer enqueue. Ring index (+0xe) masked 0x3f, slot masked 0xfff8. Writes event type word + data byte pair.
18 0005:c448 list_remove_and_free 74 Unlinks node from linked list via FUN_0005_c495, optionally calls mem_free if bit 0 of flags set
19 000b:2e00 (no function in Ghidra) 74 Analysis gap at seg109:0000. Needs manual function creation.
20 0009:1f12 dos_file_lseek 73 DOS LSEEK (INT 21h AH=42h) wrapper with error reporting to 0x867a

Tier 2: Ranks 2140 (5673 callers)

Rank Address Name Calls Description
21 0009:3600 rotating_buffer_advance 73 Advances 5-slot circular counter at 0x3eb6, zeros pointer in table at 0x867c, dispatches via jump table
22 0009:943a entity_rect_compare_and_dispatch 68 Compares bounding rectangles of two entities, dispatches based on flag bits 4/2/1 at +0x16
23 0009:1e61 dos_file_close 65 DOS file close (INT 21h), error reporting, sets handle to -1
24 0005:e252 (unnamed — unclear) 65 Copies 11 words from Phar Lap extender area (FUN_0000_12c6+5), then calls thunk. Interrupt/trampoline setup?
25 0003:dbcc crt_format_string 64 MetaWare High C formatting wrapper. Calls FUN_0003_bb92 with runtime format dispatch table.
26 0007:5a00 (no function in Ghidra) 64 High-traffic raw target at seg043:0000. Earlier debris_spawn / seg001 mapping was rejected after checking relocation labels. Still needs manual function creation and direct analysis.
27 000a:4742 assert_buffer_valid 63 Validates handle: asserts param_2 == cookie at 0x45a6 and param_1 < limit at 0x87e0
28 0009:9216 entity_conditional_render_dispatch 63 Checks entity flag bits 4 and 1 at +0x16, dispatches to vtable[+0xc] or thunk
29 0008:cb2c entity_flag20_clear_and_update_target 61 Clears flag bit 0x20, writes target +0x12/+0x14, calls refresh
30 0008:cb5c entity_flag20_set_and_init_target 61 Sets flag bit 0x20, inits target if zero, calls refresh
31 0007:7306 entity_create_stack_object 58 Allocates 0xCC bytes on stack, inits via object_init_zero_fields (0005:c400), calls thunk
32 0007:8709 entity_mark_dirty_and_sync_tile_aux 58 Syncs tile aux, sets flag bit 0x04 at +0x42
33 0007:87c5 entity_set_flag20_from_field42 58 Reads entity +0x42/+0x44, calls entity_flag20_set_and_init_target with those values
34 0007:8508 entity_table_lookup_and_dispatch 58 Searches table at 0x2b46, dispatches via indirect jump
35 0007:8920 entity_call_vtable_slot0c 58 Calls vtable entry at +0x0c
36 000a:b988 sprite_node_get_or_traverse 57 If child pointer at +0x19/+0x1b non-null, traverses; otherwise returns leaf value
37 0003:a98b crt_signed_div32 56 Entry: adjusts near→far stack, sets CX=0 (signed quotient), jumps to crt_div32_impl
38 000a:7b44 nop_return_void_a 56 Empty function (default vtable slot?)
39 000a:7b49 nop_return_void_b 56 Empty function (default vtable slot?)
40 000a:7b53 nop_return_void_c 56 Empty function (default vtable slot?)

Supporting Functions Discovered

Address Name Description
000b:3a00 sprite_tree_sum_x_offset Recursive: sums field +0x21 through child chain +0x19/+0x1b
000b:3a35 sprite_tree_sum_y_offset Recursive: sums field +0x23 through child chain +0x19/+0x1b
0003:a845 crt_exit_wrapper Calls crt_exit_impl(param,0,0)
0003:a7ee crt_exit_impl Full C exit: atexit handlers, stdio flush, MetaWare runtime cleanup
0003:a9a8 crt_div32_impl 32-bit division core. CX flags: bit0=unsigned, bit1=modulo, bit2=negate
0005:c400 object_init_zero_fields Zeros fields +0x25, +0x29, +0x31, +0x32 of a struct. Returns pointer.
000a:4440 joystick_read_axes_and_buttons Reads PC game port 0x201. Times axis responses, reads button nibble to 0x44a2
000b:3380 sprite_node_is_dirty Checks flags at obj+0x29 & 3 == 1 or 3 → returns bool
000b:33a6 sprite_node_mark_dirty If not dirty, calls FUN_000b_3965 with mode=3 to invalidate

Tier 3: Ranks 4160 (4256 callers)

Rank Address Name Calls Description
41 000a:7b58 nop_return_zero_b 56 Returns 0 (default vtable slot)
42 000b:3ab2 sprite_node_dispatch_event 56 Large event dispatch: checks event type (2/4/8/0x100), updates global focus ptr at [0x4fd0:4fd2], dispatches via vtable methods [+0x14/+0x18/+0x20/+0x24] by event code. Switch table for 16 event types.
43 000a:48ff rng_next_modulo 55 Advances seg091 RNG state and returns the result modulo the requested bound; returns 0 when bound is 0.
44 000b:3362 sprite_tree_unwind_check 55 Validates SS == param_2 (stack segment guard), then decrements global counter at [0x4fd6]
45 000b:40ee sprite_node_update_and_dispatch 55 If sprite_node_is_dirty returns false: marks dirty, calcs accumulated bounds via sprite_tree_get_accumulated_bounds (3ed8), then dispatches via thunk
46 000a:7b5f vtable_stub_trampoline 55 Calls through fixup thunk (forwarder to another function)
47 000a:7b78 nop_return_void_e 55 Empty function (default vtable slot)
48 000a:7b7d nop_return_void_f 55 Empty function (default vtable slot)
49 000a:7b4e nop_return_void_d 54 Empty function (default vtable slot)
50 000b:330c sprite_tree_dispatch_wrapper 52 Pure thunk wrapper: calls through fixup
51 0009:2034 dos_file_seek 51 INT 21h AH=42h (LSEEK). Takes file object ptr, extracts handle at obj+4, seeks to offset param. Error reporting to [0x867a].
52 0005:0466 entity_resolve_slot_ptr 50 (pre-existing name)
53 0003:a880 (no function in Ghidra) 49 Analysis gap in CRT segment
54 0006:170c tile_class_get_byte 47 Looks up class data: indexes into table at [0x7e1e] by (*param_1 * 0x79), returns byte at offset +0xc
55 000b:4097 sprite_dispatch_with_event 45 Pushes event params + global [0x49c2:0x49c4], calls thunk
56 0005:02c1 entity_is_type_match 43 Compares *param_1 against global at [0x27c8], returns 1 if equal, 0 otherwise
57 0003:ad75 (no function in Ghidra) 43 Analysis gap in CRT segment
58 000a:e709 render_dispatch_by_flag 43 Dispatches between two thunk paths based on boolean flag at stack+0x10
59 0003:d0ff crt_sprintf_wrapper 42 Calls FUN_0003_bb92 (format engine) with rearranged params and string constant at 0x67ac
60 000b:326e sprite_node_destroy 42 Destructor: sets vtable ptr to 0x501a, clears global [0x4fd0:4fd2] if self, releases child nodes, calls mem_free via thunk

Analysis Gaps

Address NE Segment Callers Notes
000a:44fd seg091:00fd 331 Recovered as seg091_func_00fd; thunk-heavy init wrapper sharing flag 0x44a4.
000b:2e00 seg109:0000 74 Start of segment 109.
0007:5a00 seg043:0000 64 Start of segment 43. Earlier seg001 debris_spawn port was rejected; still needs manual function creation and direct analysis.
000a:48ff seg091:04ff 55 Recovered as rng_next_modulo; bounded wrapper around seg091 RNG state advance.
0003:a880 seg005:0880 49 In CRT segment near far_memcpy.
0003:ad75 seg005:0d75 43 In CRT segment near mem_alloc.
000a:454d seg091:014d 32 Recovered as seg091_func_014d; init/context helper using the 0x45a6 cookie/context global.

seg043 reconciliation:

  • The earlier standalone seg001 port hypothesis in this subrange was wrong.
  • Relocation data places raw 0007:5a00 at seg043:0000, and the named helper at 0007:5b6f sits at seg043:016f.
  • Because of that segment placement, standalone seg001 names such as debris_spawn (0x7490) and entity_die (0x75ff) should NOT be ported into this raw range.
  • 0007:5b6f no longer exists as a function after the PyGhidra repair pass. Its behavior now lines up with the repaired function 0007:5b7a = entity_set_at_target_update_facing.
  • The currently repaired functions at 0007:5a90 and 0007:5c1c should keep their positional names until a later pass resolves the thunk-heavy bodies more clearly.

Tier 4: Ranks 6180 (2942 callers)

Rank Address Name Calls Description
61 000b:30a5 sprite_tree_forward_wrapper 42 Pure thunk forwarder
62 0008:bc27 entity_set_event_type_checked 41 Sets event code at +0x06 with range/timer checks
63 0008:d214 entity_dispatch_entry_ctor_vtbl_3aa6 40 Constructor: alloc 0x40, vtbl 3AA6, flag 0x200
64 0005:1565 entity_action_by_type_dispatch 39 Checks entity type against whitelist (0x432,0x5a0,0x1fd,0x1fe,0x8f,0x59f,0x2b3,0x2ca), dispatches by flags at [0xc76] and [0x85f]
65 0008:4bba channel_slot_enable 39 Sets enable byte=1 in 5-slot table at 0x84ca (slot * 0xd stride)
66 0009:6f5a vga_palette_write 38 Writes RGB triplets to VGA DAC (port 0x3C8/0x3C9). Range param_2..param_3 from palette data at *param_1
67 0009:8ef6 line_draw_dispatch 38 Compares abs(dx) vs abs(dy) to determine major axis, dispatches to appropriate line draw routine
68 000a:7b30 nop_return_void_g 38 Empty function (default vtable slot)
69 000a:7b3f nop_return_void_h 38 Empty function (default vtable slot)
70 0009:6e7f palette_free_if_set 35 Frees existing palette data if ptr non-null, checks alignment
71 000a:7b35 nop_return_void_i 35 Empty function (default vtable slot)
72 0009:c433 event_queue_align_index 34 Returns param_1 & 0xFFF8 — aligns ring index to 8-byte event slot boundary
73 0009:2156 dos_file_get_size 33 Saves file position, does INT 21h AH=42h AL=02 (seek to end), restores position. Returns file size in DX:AX
74 000a:2c41 list_iterate_next 33 Linked list iterator: if *out==0 returns first from obj+2; else follows next at ptr+2/+4. Returns bool (has more)
75 000a:454d seg091_func_014d 32 Recovered boundary. Shares flag 0x44a4; checks optional long argument against the 0x45a6 cookie/context global.
76 000b:2446 sprite_clear_redraw_flag 31 Clears flag at obj+0x17e, then dispatches via thunk
77 0005:1238 entity_get_class_word 30 Looks up table at [0x7e01] indexed by *param_1 * 2, returns word. Sister of entity_get_type_word (which uses [0x7df9])
78 000b:1446 display_null_check_dispatch 30 Null-checks far ptr params, dispatches to different thunks based on result
79 000d:85da vga_palette_set_all_black 29 Sets byte at global_obj[0x6828]+0x40 = 1 if global non-null, then calls thunk. (Note: earlier name map_object_set_dirty_flag was incorrect; corrected in seg137 analysis.)
80 0005:1511 entity_destroy_trampoline 29 Pure thunk forwarder to entity destruction

Tier 5: Ranks 81104 (2429 callers)

Rank Address Name Calls Description
81 0009:1c00 dos_file_handle_init 29 Inits 6-byte file handle struct: dword=0, word+4=0xFFFF (invalid). Aborts on null ptr
82 0008:75f3 entity_get_ptr 29 Looks up entity far ptr from table at DS:0x39b0, indexed by id*4
83 0006:0208 entity_class_get_flag4 29 Returns bit 2 of classinfo byte at [0x7e1e]+*p1*0x79+0x13 → 0 or 1
84 000a:30d7 list_node_set_if_context 29 Sets node fields +2/+4 if params match context globals at 0x45a6/0x45a8
85 0009:c45f object_init_and_get_next 29 Calls object_init_zero_fields then returns *(result+2) — init+accessor combo
86 0004:d7a0 object_deref_get_word4 28 Dereferences far ptr chain: returns word at *(*(param_1)+4)
87 000a:5276 debug_check_flag_45aa 28 If byte at DS:0x45aa non-zero, calls thunk (diagnostic/assert check)
88 0003:d94f far_memset 28 Wrapper reordering params for CRT memset impl at 0003:d92b (odd-aligned, word-fill loop)
89 000a:7b3a nop_return_void_j 28 Empty function (default vtable slot)
90 0008:ca18 entity_pair_sync_b 27 Pairwise sync wrapper direction B
91 0008:bd20 entity_sprite_set_target_pos 27 Sets flag 0x1000, copies player pos to entity +0x0a/+0x0c
92 0009:3ceb buffer_release_and_dispatch 27 Frees far ptr at obj+0x3b if set, nulls it; conditionally dispatches on bit 0
93 0005:09b4 entity_get_flags_byte 27 Reads byte from [0x7dfd]+id, conditionally extends with classinfo byte at [0x7e1e]+id*0x79+0xf
94 0005:0fbb entity_lookup_sprite_word 27 Returns word from [0x7e05]+*p1*2 — sprite/visual index table
95 0008:d27e entity_dispatch_trampoline_b 26 Pure forwarder thunk (CALLF thunk only)
96 0005:0376 entity_resolve_base_type 26 Walks entity class hierarchy (bit 8 in [0x7e01]) via [0x7ded], returns base type from [0x7df1]
97 000b:2492 sprite_redraw_if_needed 26 If redraw flag at +0x17e is clear, calls update routine + thunk
98 0003:e4d3 dos_file_open_wrapper 26 Zeros output byte, delegates to file open impl at 0003:bb92
99 0005:033e entity_resolve_base_parent 25 Same hierarchy walk as entity_resolve_base_type but returns parent from [0x7ded]
100 000a:87fd render_clip_rect_to_viewport 25 Clips 4 rect params to viewport bounds at [0x4014], sets dirty flag at 0x8a16, increments draw counter at 0x4716
101 0005:3cf5 entity_class_has_flag2000 25 Returns (entity_get_class_word(slot) & 0x2000) != 0
102 0009:80db bbox_overlap_test 25 Boolean rectangle overlap test for two 4-word bbox structs; unlike bbox_intersect, it does not write back an intersection
103 000d:cc00 entity_compute_proximity_or_visibility_bucket 25 Returns 0x40 if entity is null or projected bbox overlaps viewport; otherwise buckets world-distance from current reference entity (0x7e22) into 0x32/0x20/0x10/0x08
104 000d:d413 entity_refresh_recent_proximity_or_visibility_buckets 24 Recomputes bucket values for the last four active entries in 0x69ac and notifies backing handles via 000a:6343 when a bucket changes