diff --git a/Research/Borland C++ decompilation.md b/Research/Borland C++ decompilation.md index 7b174143..8df43d15 100644 --- a/Research/Borland C++ decompilation.md +++ b/Research/Borland C++ decompilation.md @@ -205,6 +205,40 @@ case it's part of an arithmetic expression that was promoted to `int`. However, this only generates identical code to the original optimization if passing the `other` parameter can be inlined, which isn't always the case. +## Function pointers + +Type syntax (cf. [platform.h](../platform.h)): + +| | … near function | … far function | +|------------------|---------------------------|--------------------------| +| Near pointer to… | `int (near *near nn_t)()` | `int (far *near fn_t)()` | +| Far pointer to… | `int (near *far  nf_t)()` | `int (far *far  ff_t)()` | + +Calling conventions can be added before the `*`. + +* Assigning a `near` function defined in a different group to a `nn_t` will + cause a fixup overflow error at link time. The reason for that is pointed + out in the compiler's assembly output (`-S)`: + + | C | ASM | + |--------------------------|----------------------------------------------------------------------------------------| + | `void near bar();` | `extrn _bar:near` | + | `static nn_t foo = bar;` | `mov word ptr DGROUP:_popup, offset CURRENTLY_​COMPILED_​BUT_​NOT_​ACTUAL_​GROUP_​OF:_bar` | + + The only known way of enforcing this assignment involves declaring `bar()` as + a far function and then casting its implicit segment away: + + ```c++ + void far bar(); + static nn_t foo = reinterpret_cast(bar); + ``` + + This wrong declaration of `bar()` must, of course, not be `#include`d into + the translation unit that actually defines `bar()` as a `near` function, as + it was intended. It can't also be local to an inlined function that's part of + a public header, since those declarations seem to escape to the global scope + there. + ## `switch` statements * Sequence of the individual cases is identical in both C and ASM diff --git a/th04/main/hud/popup.hpp b/th04/main/hud/popup.hpp index dabc4bac..dadb3781 100644 --- a/th04/main/hud/popup.hpp +++ b/th04/main/hud/popup.hpp @@ -16,7 +16,16 @@ extern nearfunc_t_near overlay_text; extern nearfunc_t_near popup; extern unsigned long popup_bonus; -void pascal near popup_update_and_render(void); +#define popup_show(popup_new) \ + /* Yup, the only known way of assigning a `near` function to a `near` */ \ + /* function pointer from a group outside the one where the `near` */ \ + /* function was declared in involves lying to the compiler about the */ \ + /* true distance of the function. That's also why we can't correctly */ \ + /* declare this function at global scope. */ \ + void pascal far popup_update_and_render(void); \ + \ + popup_id_new = popup_new; \ + popup = reinterpret_cast(popup_update_and_render); /// Stage and BGM titles /// --------------------