From edb70162e0d300e647869a29f187b6615e721a97 Mon Sep 17 00:00:00 2001 From: nmlgc Date: Sat, 4 Jul 2020 13:52:53 +0200 Subject: [PATCH] [Decompilation] [th01] Pellets: Manager class constructor Note how Turbo C++ auto-generates that call to `operator new`, which you don't see in the decompilation anymore. So yeah, as soon as you add a constructor, Turbo C++ enforces heap allocation for any instance of that class, even function-local ones that would otherwise be stack-allocated. That's where the bad reputation of C++ comes from, I guess? Part of P0102, funded by Yanga. --- Makefile.mak | 2 +- Research/Borland C++ decompilation.md | 44 ++++++++++++++ th01/main/bullet/pellet.cpp | 27 ++++++--- th01/main/bullet/pellet.hpp | 2 + th01/main/player/shots.cpp | 8 --- th01/main_38.cpp | 19 ++++-- th01/main_38_.cpp | 15 ----- th01_reiiden.asm | 86 +++------------------------ 8 files changed, 89 insertions(+), 114 deletions(-) delete mode 100644 th01/main_38_.cpp diff --git a/Makefile.mak b/Makefile.mak index d7f12723..f13f4efe 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -59,7 +59,7 @@ bin\th01\op.exe: bin\piloadc.obj bin\th01\op.obj th01\op_01.cpp th01\op_02.c th0 $** | -bin\th01\reiiden.exe: bin\piloadc.obj bin\th01\reiiden.obj th01\main_01.cpp th01\main_01_.cpp th01\main_02.c th01\main_03.c th01\main_04.c th01\main_05.c th01\main_06.cpp th01\main_07.cpp th01\main_08.cpp th01\main_09.cpp th01\main_12.c th01\main_13.cpp th01\main_13_.cpp th01\main_14.cpp th01\main_16.c th01\main_19.cpp th01\main_25.cpp th01\main_27.cpp th01\main_38.cpp th01\main_38_.cpp +bin\th01\reiiden.exe: bin\piloadc.obj bin\th01\reiiden.obj th01\main_01.cpp th01\main_01_.cpp th01\main_02.c th01\main_03.c th01\main_04.c th01\main_05.c th01\main_06.cpp th01\main_07.cpp th01\main_08.cpp th01\main_09.cpp th01\main_12.c th01\main_13.cpp th01\main_13_.cpp th01\main_14.cpp th01\main_16.c th01\main_19.cpp th01\main_25.cpp th01\main_27.cpp th01\main_38.cpp $(CC) $(CFLAGS) -ml -3 -DGAME=1 -DBINARY='M' -nbin\th01\ -eREIIDEN.EXE @&&| $** | diff --git a/Research/Borland C++ decompilation.md b/Research/Borland C++ decompilation.md index 9392087b..466c1b29 100644 --- a/Research/Borland C++ decompilation.md +++ b/Research/Borland C++ decompilation.md @@ -269,6 +269,50 @@ Examples: **Certainty**: Maybe Borland (not Turbo) C++ has an optimization option against it? +### Boilerplate for constructors defined outside the class declaration + +```c++ +struct MyClass { + // Members… + + MyClass(); +}; + +MyClass::MyClass() { + // Initialization… +} +``` + +Resulting ASM: + +```asm +; MyClass::MyClass(MyClass* this) +; Exact instructions differ depending on the memory model. Model-independent +; ASM instructions are in UPPERCASE. +@MyClass@$bctr$qv proc + PUSH BP + MOV BP, SP + ; (saving SI and DI, if used in constructor code) + ; (if this, 0) + JNZ @@ctor_code + PUSH sizeof(MyClass) + CALL @$bnew$qui ; operator new(uint) + POP CX + ; (this = value_returned_from_new) + ; (if this) + JZ @@ret + +@@ctor_code: + ; Initialization… + +@@ret: + ; (retval = this) + ; (restoring DI and SI, if used in constructor code) + POP BP + RET +@MyClass@$bctr$qv endp +``` + ## Limits of decompilability ### `MOV BX, SP`-style functions, or others with no standard stack frame diff --git a/th01/main/bullet/pellet.cpp b/th01/main/bullet/pellet.cpp index 6e319acb..511e51dd 100644 --- a/th01/main/bullet/pellet.cpp +++ b/th01/main/bullet/pellet.cpp @@ -1,12 +1,3 @@ -#include "th01/math/subpixel.hpp" -#include "th01/math/vector.hpp" -#include "th01/main/vars.hpp" -#include "th01/main/bullet/pellet.hpp" -#include "th01/main/playfld.hpp" -#include "th01/main/player/orb.hpp" -#include "th01/main/player/player.hpp" -#include "th01/main/player/shots.hpp" - /// Constants /// --------- // Can't declare these as `static const` variables, because that would break @@ -25,6 +16,24 @@ static const unsigned int PELLET_DESTROY_SCORE = 10; pellet_t near *pellet_cur; /// ------- +CPellets::CPellets(void) +{ + int i; + + #define p pellet_cur + p = iteration_start(); + for(i = 0; i < PELLET_COUNT; i++, p++) { + p->moving = false; + p->not_rendered = false; + } + #undef p + + alive_count = 0; + for(i = 0; i < sizeof(unknown_zero) / sizeof(unknown_zero[0]); i++) { + unknown_zero[i] = 0; + } +} + void vector2_to_player_from( int x, int y, int &ret_x, int &ret_y, int length, unsigned char plus_angle ) diff --git a/th01/main/bullet/pellet.hpp b/th01/main/bullet/pellet.hpp index 8f780014..8834bb48 100644 --- a/th01/main/bullet/pellet.hpp +++ b/th01/main/bullet/pellet.hpp @@ -168,6 +168,8 @@ protected: bool16 visible_after_hittests_for_cur(int pellet_left, int pellet_top); public: + CPellets(void); + // Spawns a number of bullets according to the given [pattern], with their // corresponding velocities, at (left, top). [speed_base] is tuned // according to the currently played difficulty and the resident diff --git a/th01/main/player/shots.cpp b/th01/main/player/shots.cpp index aaac8a47..1f1f03a3 100644 --- a/th01/main/player/shots.cpp +++ b/th01/main/player/shots.cpp @@ -1,11 +1,3 @@ -#include "th01/snd/mdrv2.h" -#include "th01/formats/ptn.hpp" -#include "th01/hardware/egc.h" -#include "th01/main/playfld.hpp" -#include "th01/main/player/player.hpp" -#include "th01/main/player/orb.hpp" -#include "th01/main/player/shots.hpp" - static const int SHOT_SPRITE_MARGIN = 2; static const int SHOT_DECAY_FRAMES = 7; diff --git a/th01/main_38.cpp b/th01/main_38.cpp index 463d86a0..5632189c 100644 --- a/th01/main_38.cpp +++ b/th01/main_38.cpp @@ -1,15 +1,26 @@ /* ReC98 * ----- - * 1st part of code segment #38 of TH01's REIIDEN.EXE + * Code segment #38 of TH01's REIIDEN.EXE */ #pragma option -Z extern "C" { -#include "platform.h" -#include "pc98.h" -#include "planar.h" +#include "th01/th01.h" +#include "th01/ranks.h" +#include "th01/snd/mdrv2.h" +#include "th01/formats/ptn.hpp" +#include "th01/hardware/egc.h" #include "th01/math/subpixel.hpp" +#include "th01/math/vector.hpp" +#include "th01/main/vars.hpp" +#include "th01/main/playfld.hpp" +#include "th01/main/player/player.hpp" +#include "th01/main/player/orb.hpp" +#include "th01/main/bullet/pellet.hpp" +#include "th01/main/player/shots.hpp" #include "th01/main/player/shots.cpp" +#include "th01/main/bullet/pellet.cpp" + } diff --git a/th01/main_38_.cpp b/th01/main_38_.cpp deleted file mode 100644 index ff8f83b6..00000000 --- a/th01/main_38_.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* ReC98 - * ----- - * 2nd part of code segment #38 of TH01's REIIDEN.EXE - */ - -#pragma codeseg main_38__TEXT main_38 -#pragma option -Z - -extern "C" { -#include "th01/th01.h" -#include "th01/ranks.h" - -#include "th01/main/bullet/pellet.cpp" - -} diff --git a/th01_reiiden.asm b/th01_reiiden.asm index e40c49f3..100bf844 100644 --- a/th01_reiiden.asm +++ b/th01_reiiden.asm @@ -73,7 +73,7 @@ main_13 group main_13_TEXT, main_13__TEXT main_19 group main_19_TEXT, main_19__TEXT main_25 group main_25_TEXT, main_25__TEXT main_27 group main_27_TEXT, main_27__TEXT -main_38 group main_38_TEXT, main_38__TEXT, main_38___TEXT +main_38 group main_38_TEXT, main_38__TEXT ; =========================================================================== @@ -4483,7 +4483,7 @@ word_E309 dw 4, 9, 0Eh, 13h sub_E319 proc far push bp mov bp, sp - call sub_30047 c, offset _Pellets, ds + call @CPellets@$bctr$qv c, offset _Pellets, ds mov _Shots.SHOT_unknown[0 * word], 50h mov _Shots.SHOT_unknown[1 * word], 60h mov _Shots.SHOT_unknown[2 * word], 70h @@ -53930,90 +53930,22 @@ main_37_TEXT ends ; Segment type: Pure code main_38_TEXT segment byte public 'CODE' use16 -main_38_TEXT ends - -main_38__TEXT segment byte public 'CODE' use16 - assume cs:main_38 - ;org 4 - assume es:nothing, ss:nothing, ds:_DATA, fs:nothing, gs:nothing - extern @CShots@add$qii:proc extern @CShots@unput_and_reset_all$qv:proc extern @CShots@unput_update_render$qv:proc extern @CShots@hittest_pellet$qii:proc extern @CShots@hittest_boss$qiiii:proc - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_30047 proc far - -@@CPellets = dword ptr 6 - - push bp - mov bp, sp - push si - cmp [bp+@@CPellets], 0 - jnz short loc_30065 - push size CPellets - call @$bnew$qui ; operator new(uint) - pop cx - mov word ptr [bp+@@CPellets+2], dx - mov word ptr [bp+@@CPellets], ax - or ax, dx - jz short loc_300AA - -loc_30065: - mov ax, word ptr [bp+@@CPellets] - mov _pellet_cur, ax - xor si, si - jmp short loc_30081 -; --------------------------------------------------------------------------- - -loc_3006F: - mov bx, _pellet_cur - mov byte ptr [bx], 0 - mov word ptr [bx+18h], 0 - inc si - add _pellet_cur, size pellet_t - -loc_30081: - cmp si, PELLET_COUNT - jl short loc_3006F - les bx, [bp+@@CPellets] - mov es:[bx+CPellets.PELLET_alive_count], 0 - xor si, si - jmp short loc_300A5 -; --------------------------------------------------------------------------- - -loc_30094: - mov ax, si - add ax, ax - les bx, [bp+@@CPellets] - add bx, ax - mov es:[bx+PELLET_unknown_zero], 0 - inc si - -loc_300A5: - cmp si, 10 - jl short loc_30094 - -loc_300AA: - mov dx, word ptr [bp+@@CPellets+2] - mov ax, word ptr [bp+@@CPellets] - pop si - pop bp - retf -sub_30047 endp -main_38__TEXT ends - -main_38___TEXT segment byte public 'CODE' use16 + extern @CPellets@$bctr$qv:proc extern @CPellets@add_pattern$qii16pellet_pattern_ti:proc extern @CPellets@add_single$qiiii15pellet_motion_tiii:proc extern @CPellets@motion_type_apply_for_cur$qv:proc extern @CPellets@visible_after_hittests_for_cur$qii:proc extern _pellet_render:proc +main_38_TEXT ends + +main_38__TEXT segment byte public 'CODE' use16 + assume cs:main_38 + assume es:nothing, ss:nothing, ds:_DATA, fs:nothing, gs:nothing ; =============== S U B R O U T I N E ======================================= @@ -54609,7 +54541,7 @@ sub_30F70 endp ; --------------------------------------------------------------------------- dw 0 -main_38___TEXT ends +main_38__TEXT ends .data