mirror of https://github.com/nmlgc/ReC98.git
[Research] Assigning near functions from other groups to near function pointers
Yup, P0148 didn't actually solve the issue it was meant to solve, and I still had to research this workaround. Part of P0149, funded by Blue Bolt, Ember2528, and -Tom-.
This commit is contained in:
parent
3e658b590d
commit
6233a3c3e3
|
@ -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<nn_t>(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
|
||||
|
|
|
@ -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<nearfunc_t_near>(popup_update_and_render);
|
||||
|
||||
/// Stage and BGM titles
|
||||
/// --------------------
|
||||
|
|
Loading…
Reference in New Issue