I'm trying to reverse engineer an ages-old game compiled with Borland C++ in 1995. So far, I have found out that start @0x401000 passes to __startup in cw3220.dll (which apparently is Borland's C++ runtime dll) the following:

  1. pointer to the begin of a list of global static constructors ({ char flag0; char flag1; void* fun})

  2. pointer to end of said list

  3. pointer to begin of a list of destructors (as above)
  4. pointer to end of dtor list
  5. int flag - GUI app or not (should __startup call main(argc,argv,env) or WinMain(hInstance,hPrevInstance,lpCmdLine,nShowCmd))
  6. unknown int flag1
  7. pointer to entry function
  8. pointer to a function which IDA has automagically named matherr
  9. pointer to a function matherrl
  10. unknown int flag2
  11. unknown int flag3

Is there any documentation available which tells the meaning of flag1/2/3 in the info struct, flag0/1 in the ctor list entries and how Borland C++ handles exceptions - functions using classes always call __InitExceptBlock, but I never see checks for exceptions after function calls, how is try/catch handled?

1 Answer 1


cw3220.dll indicates that you're looking at BC++ 5.0. AFAICS the only official documentation regarding the startup code is BC5/source/RTL/source/startup/Win32/c0nt.asm, plus _startup.h and startup.c (also somewhere under source/RTL). The struct is defined in _startup.h:

typedef struct module_data
    INIT *init_start;           /* start of a module's _INIT_ segment */
    INIT *init_end;             /* end of a module's _INIT_ segment */
    INIT *exit_start;           /* start of a module's _EXIT_ segment */
    INIT *exit_end;             /* end of a module's _EXIT_ segment */
    int  flags;                 /* flags (see below) */
    int  hmod;                  /* module handle */
    int  (*main)();             /* main/WinMain/_dllmain function */
    int  (*matherr)(void *);    /* (EXE only) _matherr function */
    int  (*matherrl)(void *);   /* (EXE only) _matherrl function */
    long stackbase;             /* (EXE only) base of stack */
    int  *fmode;                /* (EXE only) address of _fmode variable */

/* MODULE_DATA flags.
#define MF_WINDOWS  1           /* this is a Windows application */

If you install from PAKs then it can happen that the RTL sources don't get installed even if you select everything, but the RTL source is present in the BC5 directory on the installation CD (at least in my copy). That documents at least the calling side.

A lot of BC++ 4 internals were documented in the Borland Open Architecture Handbook that had to be ordered separately at nominal cost (one floppy). I can't locate the stuff ATM but I've seen copies floating around on the 'net, under the name of bc4boa.zip...

  • Do you happen to know where one can download the RTL source code? I have tried nearly everything, but I cannot find any form of download, neither legal nor illegal, of the CD...
    – Skynet
    Dec 28, 2014 at 12:38
  • Or can you please pastebin me the file that contains the code of malloc/calloc? I'd need to know what information is placed at *(ptr-1) - I believe it to be some kind of counter, but not sure yet...
    – Skynet
    Dec 28, 2014 at 12:58
  • Borland's free command line compiler (v5.5) is still downloadable; you could use it to compile tiny test programs for functions that you're interested in and then trace into them using your favourite debugger or use static analysis using the free IDA or the trial. IDA is fairly good at recognising BC++ library functions; if all else fails you can tell it to apply various BC++ signatures explicitly. The C library code included with the free compiler should be fairly similar to that shipped with BC++ 5.02 (see heap.c).
    – DarthGizka
    Dec 28, 2014 at 13:13
  • Ah, thanks. I believe that something has changed at least in c0nt.asm from 5.00 to 5.02 - compare the relevant segment at pastebin.com/CxgGHWv2 to what should be in there... the contents after the module_data struct don't match the asm file at all
    – Skynet
    Dec 28, 2014 at 13:29
  • 1
    Bitwise correspondence is rare, and the .asm doesn't even match the c0w32.obj in the same installation (see an IDA disassembly of the c0w32.obj _DATA segment). That's why I mentioned using small test programs and a similar-enough reference compiler; that allows you to match functions and data incrementally by their function and the way they're used by other code (e.g. startup).
    – DarthGizka
    Dec 28, 2014 at 13:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.