Win32 PE executable with DJGPP GNU C/C++ compiller.

Small description of utilites.

The software described in this document is destributed under a GNU General Public License.

GNU software is Copyright by the Free Software Foundation.

DJGPP is Copyright by DJ Delorie.

Windows is a trademark of Microsoft Corporation.
Windows NT is a trademark of Microsoft Corporation.
Windows 2000 is a trademark of Microsoft Corporation.

Other product names mentioned in this description may be trademarks or registered trademarks of their respective companies and are hereby acknowledged.

How to install?

To install your need:
  1. Unpack arhive. E.g. type:
    pkunzip -p c:\djgpp  
    (The good idea is to read this document up to end beforhand)

  2. Make linkable libraries (.a files) for Win32 API DLL. As   rule it's nessesary to make libraries for user32.dll, kernel32.dll, gdi32.dll. As well frequently advapi32.dll, comdlg32.dll, shell32.dll are nessesary too. To use Socket your need library for wsock32.dll, to use PlaySound function your need winmm.dll, etc. To make library you can create temporary directory, the first, is good idea, but it's dispensable. Change curent directory to it and run dll2a.exe for each DLL need you. E.g. type:
    c:\>mkdir c:\lib_temp
    c:\>cd c:\lib_temp
    c:\lib_temp>dll2a.exe user32.dll
    c:\lib_temp>ren user32.a c:\djgpp\lib\libuser.a
    You can use next makefile and generate all automaticaly with DJGPP GNU MAKE.
    #begin of 'makefile'
    # For Windows NT or 2000 DLLDIR must by
    # WINDIR -- predefined Windows enviroment variable
    # DJDIR --  DJGPP enviroment variable, must be defined
    # in DJGPP.ENV
    lib: libuser.a libuser.a libkern.a libgdi.a \
     libshell.a libwadv.a lwinmm.a lwinmm.a lcdlg.a
    libuser.a: user32.dll
    	dll2s.exe -o $@  $<
    libkern.a: %(DLLDIR)kernel32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libgdi.a: %(DLLDIR)gdi32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libshell.a: %(DLLDIR)shell32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libwadv.a: %(DLLDIR)advapi32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libwinmm.a: %(DLLDIR)winmm.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libcdlg.a: %(DLLDIR)comdlg32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    libwsock.a: %(DLLDIR)wsock32.dll
    	dll2s.exe -o $(LIBDIR)$@  $<
    #end of 'makefile'
    It borrows some time, because for each function in each library assembler file will be created, exec "as.exe" and exec "ar.exe". Up to ten minuit per library for big library and slow machin.

  3. At last you must customize your "specs" file to run make_pe.exe to convert a.out to Win32 PE. By default arhive contents valid "specs" file, and by default it replase that file in DJGPP\LIB directory, but any GCC newer then 2.8 find this file in DJGPP\LIB\GCC-LIB\DJGPP\2.952 for GNU C++ 2.952 or DJGPP\LIB\GCC-LIB\DJGPP\EGCS-291.66 for EGCS C++ 2.91.66, etc. I don't know, what version you use, I thing it's not a problem for you replase or update using file by your own. The "specs" in my arhive add two key to GCC:
    • -Zpe --to generate Win32 PE executable
    • -Zcon --used only with -Zpe to generate Win32 console application.
    You can define your own keys. To generate PE you must use "djgppe.djl" linker script. "*startfile" for PE must be "crt0pe.o". These files are also present in my arhive and be default placed to DJGPP\LIB.

  4. The big trouble it is header files, and description of API functions. It is part of Microsoft Windows SDK, and I can't destribute tham. Now you can found these files in diferent location. It is included in any other Windows compiller, but in many case they doesn't directly compilled with GNU. To compile Microsoft's header with GNU compiller, easy changes must be done. In the begining of the file
    #define __stdcall __attribute__((stdcall))
    must be inserted. In some case you must edit Microsoft's function declaration, move "PASCAL" to the end of declaration. E.g. if in SDK header present:
    struct hostent* PASCAL gethostbyname(const char* name);
      you must make:
    struct hostent* gethostbyname(const char* name) PASCAL;
    If you have nothing, use header's generated by DLL2S. In this case you must edit these files, insert argument in declaration of each function or use "gw_api.h". This file contents next definetion:
    inline void PUSH(int a)
    { asm volatile("pushl %0;": :"g" (a) ); };
    inline void PUSH(void* a)
    { asm volatile("pushl %0;": :"g" (a) ); };
    #define API1(f,a)  ( PUSH(a),f())
    #define API2(f,a1,a2)  ( PUSH(a2),PUSH(a1),f())
    And you can call to API e.g. this way:
           #include "gw_api.h"
    extern "C" {
           #include <user32.h>
           #include <kernel32.h>
       API4( MessageBox, 0, &"Hello world !",&"Test",  0);
    Warning! In this case you must use optimisation (keys -O1, -O2, -O#), otherwise GNU compiller generate inline function as no inline, and PUSH failure. In this case you can use #define instead inline. This might be use only with GNU 2.8x or older.

DLL to .a convertor

This program read incomming DLL-file, get names of functions from it, and for each function:
  • generate easy assembler file;
  • exec "as.exe" to compile this file;
  • exec "ar.exe" to add this file to output library;
  • add incomplete declaration of function to output header file.
    At the last header file is stored.
    Command line have next format:
    dll2s.exe {[-keys]}[-o out_file_name][-n filename] file.dll
    Next option's keys supported:
    • -s -- store assembler source, otherwise temporary assembler files are deleted.
    • -a -- generate one AT&T assembler file only.
    • -i -- generate one Intel assembler file only.
    • -u -- add "unnamed" functions. Some DLL-functions could have no name. It might be linked by number. Program also could add these functions to the library, but what's the reason ?
    • -l -- always use number for link. Default name of function is used, so it's possible. It is calculable. To use number you must overwrite startup file "crt0pe.o".
    • -d -- no generate header file.
    • -j -- store objects, otherwise temporary objects files are deleted.
    • -n -- name for assembler file.
    • -r -- generate header file only
    • -f -- no generate #define for A-function. All Windows API functions that recive string as argument have ASCI and UNICODE versions. Usually one DLL contents both functions. The last symbol in the name of ASCI version is 'A'. The last symbol in the name of UNICODE version is 'W'. By default, for each ASCI function DLL2S add to header file #define that define name without last 'A' as name with 'A'.

    Make PE from COFF a.out

    This program only adds DOS stub and first part of PE header. Command line have next format:
    make_pe [-c][-s Stack_Reserve_Size][-p Heap_Reserve_Size][-o out_file] input_file

    Next option's keys supported:
    • -c -- to generate Win32 console application.
    • -s -- to define Stack Reserve Size. By default it is 64 Kb.
    • -p -- to define Heap Reserve Size. By default it is 1 Mb.
    • -o -- to define name of output file.
    This program always setup Commit Heap Size and Commit Stack Size to 4 Kb. Program will not use more memory until program doesn't requist it. This program could convert only specifed COFF files, that begin from the last part of PE header. This part is precent in the "crt0pe.o" -- startup file. It must be linked the first. It defines in "djgppe.djl" -- linker script.

    max (Shift-2)
    M. Feoktistov

    Table of Contents

    /var/www/mkpe/win_pe.shtml# File