Changeset 21942 for trunk/src


Ignore:
Timestamp:
Jan 18, 2012, 11:33:39 AM (14 years ago)
Author:
dmik
Message:

Use custom startup code for PE loader.

This allows to grab the lowest memory address before any DLL
(including the C library) kicks in and reserves memory for its own
purposes. This fixes #54.

Location:
trunk/src/peldr
Files:
3 added
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/peldr/Makefile.kmk

    r21924 r21942  
    88PROGRAMS           += pe
    99pe_TEMPLATE         = OdinApp
    10 pe_SOURCES          = pe.cpp pe.def
     10pe_SOURCES          = pe.c pe.def helpers.c $(pe_0_OUTDIR)/crt0.obj
     11pe_LDFLAGS          = -nostdlib -llibos2
    1112
    1213PROGRAMS           += pec
    1314pec_TEMPLATE        = OdinApp
    1415pec_DEFS            = COMMAND_LINE_VERSION
    15 pec_SOURCES         = pe.cpp pec.def
     16pec_SOURCES         = pe.c pec.def helpers.c $(pe_0_OUTDIR)/crt0.obj
     17pec_LDFLAGS         = -nostdlib -llibos2
     18
     19$$(pe_0_OUTDIR)/crt0.obj: crt0.s
     20        $(QUIET)gcc -c -x assembler-with-cpp crt0.s -o $@.o
     21        $(QUIET)emxomf -m__text $@.o -o $@
    1622
    1723include $(FILE_KBUILD_SUB_FOOTER)
  • trunk/src/peldr/pe.c

    r21940 r21942  
    33 *
    44 * Copyright 1998-2001 Sander van Leeuwen (sandervl@xs4all.nl)
     5 * Copyright 2012 Dmitriy Kuminov
    56 *
    67 * Command line options:
     
    1011 *
    1112 * Project Odin Software License can be found in LICENSE.TXT
    12  *
    1313 */
     14
    1415#define INCL_DOSFILEMGR          /* File Manager values      */
    1516#define INCL_DOSERRORS           /* DOS Error values         */
     
    2122#include <os2.h>
    2223#include <bseord.h>
    23 #include <stdio.h>
    24 #include <string.h>
    25 #include <stdlib.h>
    26 #include <string.h>
    27 #include <assert.h>
    2824#include <win32type.h>
    2925#include <misc.h>
     
    3329#include "pe.h"
    3430
     31#include "helpers.h"
     32
    3533char INFO_BANNER[]      = "Usage: PE winexe commandline";
    3634char szErrorTitle[]     = "Odin";
    3735char szLoadErrorMsg[]   = "Can't load executable %s";
    38 char szFileNotFound[]   = "File not found.";
     36char szFileNotFound[]   = "File not found: %s";
    3937char szFileErrorMsg[]   = "File IO error";
    4038char szPEErrorMsg[]     = "Not a valid win32 exe. (perhaps 16 bits windows)";
     
    4442char szInteralErrorMsg1[]= "Internal Error";
    4543char szNoKernel32Msg[]  = "Can't load/find kernel32.dll (rc=%d, module %s)";
    46 char szDosInfoBlocks[]  = "DosInfoBlocks failed!";
    4744char szErrorExports[]   = "Unable to process exports of %s";
    4845char szErrorMemory[]    = "Memory allocation failure while loading %s";
    4946char szErrorImports[]   = "Failure to load \"%s\" due to bad or missing %s";
    5047
    51 char szErrDosStartSession[] = "Failed to start win16 session (rc=%d)";
     48char szErrDosStartSession[] = "Failed to start win16 (%s) for %s (rc=%d)";
    5249
    5350char fullpath[CCHMAXPATH];
     
    8077BOOL AllocateExeMem(char *filename, BOOL *fNEExe);
    8178
    82 //******************************************************************************
    83 //******************************************************************************
    84 int main(int argc, char *argv[])
     79#ifdef DEBUG
     80void print(const char *fmt, ...)
    8581{
     82    static char buf[1024];
     83    char *s, *e;
     84    ULONG dummy;
     85    int len;
     86    va_list args;
     87    va_start(args, fmt);
     88    len = vsnprintf(buf, sizeof(buf), fmt, args);
     89    va_end(args);
     90    s = buf;
     91    while (*s)
     92    {
     93        e = (char *)str_find_char(s, '\n');
     94        DosWrite((HFILE)1, s, e - s, &dummy);
     95        if (*e == '\n')
     96        {
     97            DosWrite((HFILE)1, "\n\r", 2, &dummy);
     98            e++;
     99        }
     100        s = e;
     101    }
     102}
     103#define DBG(a) do { print a; } while (0)
     104#else
     105#define DBG(a) do {} while (0)
     106#endif
     107
     108//******************************************************************************
     109//******************************************************************************
     110int simple_main()
     111{
     112    DBG(("PE: BEGIN (DEBUG mode)\n"));
     113
    86114    HAB    hab = 0;                             /* PM anchor block handle       */
    87115    HMQ    hmq = 0;                             /* Message queue handle         */
    88116    char   exeName[CCHMAXPATH];
    89     char   fullpath[CCHMAXPATH];
     117    char   fullpath[CCHMAXPATH * 2];
    90118    char   errorMod[CCHMAXPATH];
     119    char   szErrorMsg[512];
    91120    char  *pszErrorMsg = NULL;
    92121    APIRET  rc;
     
    94123    PTIB   ptib;
    95124    PPIB   ppib;
    96     char  *cmdline, *win32cmdline, *peoptions, *newcmdline;
    97     BOOL   fQuote = FALSE, fVioConsole, fIsNEExe, fEndOfCmdLine = FALSE;
    98     int    nrTries = 1;
    99 
     125    char  *cmdline, *win32cmdline, *peoptions;
     126    BOOL   fVioConsole, fIsNEExe;
     127
     128    char *pszTemp, *pszTemp2;
     129
     130    DosGetInfoBlocks(&ptib, &ppib);
     131
     132#ifdef COMMAND_LINE_VERSION
    100133    if(DosGetInfoBlocks(&ptib, &ppib) == 0)
    101134    {
    102         char *pszTemp;
    103 
    104         fullpath[0] = 0;
    105         DosQueryModuleName(ppib->pib_hmte, sizeof(fullpath), fullpath);
    106 
    107         strupr(fullpath);
    108 #ifdef COMMAND_LINE_VERSION
    109         pszTemp = strstr(fullpath, "PEC.EXE");
    110 #else
    111         pszTemp = strstr(fullpath, "PE.EXE");
     135        //switch process type to PM so the command line app can create PM
     136        //windows
     137        ppib->pib_ultype = 3;
     138    }
    112139#endif
    113         if(pszTemp == NULL) {
    114             pszErrorMsg = szInteralErrorMsg1;
    115             goto failerror;
    116         }
    117         pszTemp--; //to go trailing backslash
     140
     141    fullpath[0] = 0;
     142    DosQueryModuleName(ppib->pib_hmte, sizeof(fullpath), fullpath);
     143
     144    pszTemp = fullpath + strlen(fullpath) - 1;
     145    while (pszTemp >= fullpath && (*pszTemp != '\\' && *pszTemp != '/'))
     146        --pszTemp;
     147    if (pszTemp >= fullpath)
     148    {
    118149        *pszTemp = 0;
    119150        strcat(fullpath, ";%BeginLIBPATH%");
    120151        DosSetExtLIBPATH(fullpath, BEGIN_LIBPATH);
    121     }
    122 
    123     if(argc >= 2) {
    124         if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
    125 tryagain:
    126             cmdline = ppib->pib_pchcmd;
    127             cmdline += strlen(cmdline)+1;       //skip pe.exe
    128             peoptions = strstr(cmdline, "/OPT:[");
    129             if(peoptions) {
    130                 newcmdline = strchr(peoptions, ']');
    131                 if(newcmdline) {
    132                     cmdline = newcmdline+1;
    133                 }
    134 #ifdef DEBUG
    135                 else    _interrupt(3);  //should not happen!
    136 #endif
     152        DBG(("PE: Added '%s' to BEGINLIBPATH\n", fullpath));
     153    }
     154
     155    cmdline = ppib->pib_pchcmd;
     156    if (cmdline)
     157    {
     158        cmdline += strlen(cmdline) + 1; // skip executable name
     159        if (!*cmdline)
     160            cmdline = NULL;
     161    }
     162
     163    if (cmdline)
     164    {
     165        DBG(("PE: Full command line:  '%s'\n", cmdline));
     166
     167        pszTemp = (char *)str_skip_char(cmdline, ' ');
     168
     169        // get PE options
     170        if (str_starts_with(pszTemp, "/OPT:["))
     171        {
     172            const char *end = str_find_char(pszTemp , ']');
     173            if (*end)
     174                pszTemp = (char *)str_skip_char(end + 1, ' ');
     175            else
     176                peoptions = NULL;
     177        }
     178
     179        // get Win32 executable name
     180        int delim = ' ';
     181        if (*pszTemp == '"')
     182        {
     183            pszTemp++;
     184            delim = '"';
     185        }
     186        pszTemp2 = exeName;
     187        while (*pszTemp && *pszTemp != delim &&
     188               (pszTemp2 - exeName) < CCHMAXPATH - 1)
     189        {
     190            *pszTemp2++ = *pszTemp++;
     191        }
     192        *pszTemp2 = '\0';
     193        if (delim == '"')
     194            pszTemp++;
     195        pszTemp = (char *)str_skip_char(pszTemp, ' ');
     196
     197        // get Win32 command line
     198        win32cmdline = pszTemp;
     199
     200        // add the .EXE extension if missing
     201        int i = strlen(exeName);
     202        if (i < 4 || !((exeName[i-1] == 'E' || exeName[i-1] == 'e') &&
     203                       (exeName[i-2] == 'X' || exeName[i-2] == 'x') &&
     204                       (exeName[i-3] == 'E' || exeName[i-3] == 'e') &&
     205                       exeName[i-4] == '.'))
     206        {
     207            if (i + 4 < CCHMAXPATH)
     208                strcat(exeName, ".exe");
     209        }
     210
     211        // try to locate the executable
     212        pszTemp = exeName + strlen(exeName) - 1;
     213        while (pszTemp >= exeName && (*pszTemp != '\\' && *pszTemp != '/'))
     214            --pszTemp;
     215        if (pszTemp < exeName)
     216        {
     217            // no path information, perform a search
     218
     219            char newExeName[CCHMAXPATH];
     220
     221            if(DosSearchPath( SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT | SEARCH_IGNORENETERRS
     222                              , "WINDOWSPATH"           /* environment value */
     223                              , exeName                 /* Name of file to look for */
     224                              , newExeName              /* Result of the search     */
     225                              , sizeof(newExeName)      /* Length of search buffer  */
     226                              ) == NO_ERROR)
     227            {
     228                strcpy(exeName, newExeName);
    137229            }
    138             while(*cmdline == ' ')      cmdline++; //skip leading space
    139             if(*cmdline == '"') {
    140                 cmdline++;
    141                 fQuote = TRUE;
    142             }
    143             win32cmdline = cmdline;
    144 
    145             strncpy(exeName, cmdline, sizeof(exeName)-1);
    146             exeName[sizeof(exeName)-1] = 0;
    147             char *p = exeName;
    148             if(fQuote) {
    149                 while(*p != '"' && *p != 0) p++;
    150             }
    151             else {
    152                 for(int i=0;i<nrTries;i++) {
    153                     while(*p != ' ' && *p != 0) p++;
    154                     if(*p == 0) break;
    155                     if(i != nrTries-1) {
    156                         while(*p == ' ' && *p != 0) p++;
    157                     }
    158                 }
    159                 if(nrTries > 1 && *p == 0) {
    160                     fEndOfCmdLine = TRUE;
    161                 }
    162             }
    163             *p = 0;
    164             strupr(exeName);
    165             cmdline = strstr(exeName, ".EXE");
    166             if(cmdline) {
    167                 cmdline[4] = 0;
    168                 win32cmdline += ((ULONG)cmdline - (ULONG)exeName) + 4;
    169             }
    170             else {
    171                 win32cmdline += strlen(exeName);
    172                 if(strstr(exeName, ".") == NULL) {
    173                     strcat(exeName, ".EXE");
    174                 }
    175             }
    176             if(fQuote) win32cmdline++;
    177             while(*win32cmdline == ' ') win32cmdline++; //skip spaces
    178 
    179             cmdline = exeName + strlen(exeName) - 1;
    180             while(*cmdline == ' ') cmdline--;
    181             cmdline[1] = 0;
    182 
    183             char drive[_MAX_DRIVE];
    184             char dir[_MAX_DIR];
    185             char fname[_MAX_FNAME];
    186             char ext[_MAX_EXT];
    187             char exeShortName[_MAX_FNAME+_MAX_EXT];
    188             _splitpath(exeName, drive, dir, fname, ext);
    189 
    190             strcpy(fullpath, drive);
    191             strcat(fullpath, dir);
    192 
    193             strcpy(exeShortName, fname);
    194             strcat(exeShortName, ext);
    195 
    196             if ( strlen(fullpath) == 0 )
    197             {
    198                 char newExeName[CCHMAXPATH];
    199 
    200                 if(DosSearchPath( SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT | SEARCH_IGNORENETERRS
    201                                   , "WINDOWSPATH"           /* environment value */
    202                                   , exeShortName            /* Name of file to look for */
    203                                   , newExeName              /* Result of the search     */
    204                                   , sizeof(newExeName)      /* Length of search buffer  */
    205                                   ) == NO_ERROR)
    206                 {
    207                     strcpy(exeName, newExeName);
    208                 }
    209             }
    210 
    211             FILESTATUS3 fstat3;
    212             if(DosQueryPathInfo(exeName, FIL_STANDARD, (PVOID)&fstat3, sizeof(fstat3)))
    213             {
    214                 nrTries++;
    215                 if(fEndOfCmdLine) {
    216                     pszErrorMsg = szFileNotFound;
    217                     goto failerror;
    218                 }
    219 
    220                 if(*win32cmdline != NULL && !fQuote) {
    221                     goto tryagain;
    222                 }
    223             }
    224         }
    225         else {//should never happen!
    226             pszErrorMsg = szDosInfoBlocks;
     230        }
     231
     232        DBG(("PE: Win32 EXE:          '%s'\n", exeName));
     233        DBG(("PE: Win32 command line: '%s'\n", win32cmdline));
     234
     235        FILESTATUS3 fstat3;
     236        if (DosQueryPathInfo(exeName, FIL_STANDARD, (PVOID)&fstat3, sizeof(fstat3)) != NO_ERROR)
     237        {
     238            snprintf(szErrorMsg, sizeof(szErrorMsg), szFileNotFound, exeName);
     239            pszErrorMsg = szErrorMsg;
    227240            goto failerror;
    228241        }
     242
    229243        AllocateExeMem(exeName, &fIsNEExe);
    230         if(fIsNEExe) {
     244
     245        if (fIsNEExe)
     246        {
    231247            STARTDATA sdata = {0};
    232248            ULONG idSession;
     
    242258            sdata.SessionType = SSF_TYPE_WINDOWEDVDM;
    243259            rc = DosStartSession(&sdata, &idSession, &pid);
    244             if(rc) {
    245                 sprintf(fullpath, szErrDosStartSession, rc);
    246                 pszErrorMsg = fullpath;
     260            if (rc)
     261            {
     262                snprintf(szErrorMsg, sizeof(szErrorMsg), szErrDosStartSession, sdata.PgmName, exeName, rc);
     263                pszErrorMsg = szErrorMsg;
    247264                goto failerror;
    248265            }
     
    250267        }
    251268    }
    252 
    253 #ifdef COMMAND_LINE_VERSION
    254     if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
    255         //switch process type to PM so the command line app can create PM
    256         //windows
    257         ppib->pib_ultype = 3;
    258     }
    259 #endif
    260269
    261270    rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN", &hmodPMWin);
     
    271280    hmq = MyWinCreateMsgQueue(hab, 0);
    272281
    273     if(argc < 2) {
    274         MyWinMessageBox(HWND_DESKTOP, NULL, INFO_BANNER, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
     282    if (!cmdline) {
     283        MyWinMessageBox(HWND_DESKTOP, NULLHANDLE, INFO_BANNER, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
    275284        goto fail;
    276285    }
     
    279288    rc = DosLoadModule(errorMod, sizeof(errorMod), "KERNEL32", &hmodKernel32);
    280289    if(rc) {
    281         sprintf(fullpath, szNoKernel32Msg, rc, errorMod);
    282         MyWinMessageBox(HWND_DESKTOP, NULL, fullpath, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
     290        snprintf(fullpath, CCHMAXPATH, szNoKernel32Msg, rc, errorMod);
     291        MyWinMessageBox(HWND_DESKTOP, NULLHANDLE, fullpath, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
    283292        goto fail;
    284293    }
     
    294303    if(rc != LDRERROR_SUCCESS)
    295304    {
    296         char szErrorMsg[512];
    297 
    298305        switch(rc) {
    299306        case LDRERROR_INVALID_MODULE:
    300             sprintf(szErrorMsg, szLoadErrorMsg, exeName);
     307            snprintf(szErrorMsg, sizeof(szErrorMsg), szLoadErrorMsg, exeName);
    301308            break;
    302309        case LDRERROR_INVALID_CPU:
    303             sprintf(pszErrorMsg, szCPUErrorMsg, exeName);
     310            snprintf(szErrorMsg, sizeof(szErrorMsg), szCPUErrorMsg, exeName);
    304311            break;
    305312        case LDRERROR_FILE_SYSTEM:
    306             sprintf(szErrorMsg, szExeErrorMsg, exeName);
     313            snprintf(szErrorMsg, sizeof(szErrorMsg), szExeErrorMsg, exeName);
    307314            break;
    308315        case LDRERROR_MEMORY:
    309             sprintf(szErrorMsg, szErrorMemory, exeName);
     316            snprintf(szErrorMsg, sizeof(szErrorMsg), szErrorMemory, exeName);
    310317            break;
    311318        case LDRERROR_EXPORTS:
    312             sprintf(szErrorMsg, szErrorExports, exeName);
     319            snprintf(szErrorMsg, sizeof(szErrorMsg), szErrorExports, exeName);
    313320            break;
    314321        case LDRERROR_IMPORTS:
    315             sprintf(szErrorMsg, szErrorImports, exeName, errorMod);
     322            snprintf(szErrorMsg, sizeof(szErrorMsg), szErrorImports, exeName, errorMod);
    316323            break;
    317324        case LDRERROR_INVALID_SECTION:
    318325        default:
    319             sprintf(szErrorMsg, szInteralErrorMsg, exeName);
     326            snprintf(szErrorMsg, sizeof(szErrorMsg), szInteralErrorMsg, exeName);
    320327            break;
    321328        }
     
    330337    DosFreeModule(hmodPMWin);
    331338    DosFreeModule(hmodKernel32);
     339
     340    DBG(("PE: END (returning 0)\n"));
    332341    return 0;
    333342
     
    338347    if(hmodPMWin)       DosFreeModule(hmodPMWin);
    339348    if(hmodKernel32)    DosFreeModule(hmodKernel32);
     349
     350    DBG(("PE: END (returning 1)\n"));
    340351    return(1);
    341352
     
    353364        hmq = MyWinCreateMsgQueue(hab, 0);
    354365
    355         MyWinMessageBox(HWND_DESKTOP, NULL, pszErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
     366        MyWinMessageBox(HWND_DESKTOP, NULLHANDLE, pszErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
    356367    }
    357368    if(hmq) MyWinDestroyMsgQueue( hmq );             /* Tidy up...                   */
    358369    if(hab) MyWinTerminate( hab );                   /* Terminate the application    */
    359370    if(hmodPMWin)       DosFreeModule(hmodPMWin);
     371
     372    DBG(("PE: END (returning 1)\n"));
    360373    return 1;
    361374}
     
    368381{
    369382    HFILE  dllfile = 0;
    370     char   szFileName[CCHMAXPATH], *tmp;
    371     char   szResult[CCHMAXPATH];
     383    char   *tmp;
    372384    ULONG  action, ulRead, signature;
    373385    APIRET rc;
     
    376388    IMAGE_FILE_HEADER     fh;
    377389    ULONG  address = 0;
    378     ULONG  *memallocs;
    379390    ULONG  alloccnt = 0;
    380391    ULONG  diff, i, baseAddress;
     
    382393    BOOL   ret = FALSE;
    383394
     395    //Reserve enough space to store 4096 pointers to 1MB memory chunks
     396    static ULONG memallocs[4096];
     397
    384398    *fNEExe = FALSE;
    385     strcpy(szFileName, filename);
    386 
    387     rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
    388     if(rc != 0) {
    389         if(!strstr(szFileName, ".EXE")) {
    390             strcat(szFileName,".EXE");
    391         }
    392     }
    393     else        DosClose(dllfile);
    394 
    395     rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
     399
     400    rc = DosOpen(filename, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
    396401    if(rc) {
    397         if(DosSearchPath(SEARCH_IGNORENETERRS|SEARCH_ENVIRONMENT, "PATH",
    398                          szFileName, szResult, sizeof(szResult)) != 0) {
    399             goto end; //oops
    400         }
    401         rc = DosOpen(szResult, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
    402         if(rc) {
    403             goto end; //oops
    404         }
     402        goto end; //oops
    405403    }
    406404
     
    432430    fConsoleApp = (oh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
    433431
     432    DBG(("PE: AllocateExeMem: oh.Subsystem: %d\n", oh.Subsystem));
     433    DBG(("PE: AllocateExeMem: oh.ImageBase: 0x%08X\n", oh.ImageBase));
     434
    434435    // check for high memory support
    435436    rc = DosQuerySysInfo(QSV_VIRTUALADDRESSLIMIT, QSV_VIRTUALADDRESSLIMIT, &ulSysinfo, sizeof(ulSysinfo));
     
    439440    }
    440441
    441     //Reserve enough space to store 4096 pointers to 1MB memory chunks
    442     memallocs = (ULONG *)alloca(4096*sizeof(ULONG *));
    443     if(memallocs == NULL) {
    444         goto end; //oops
    445     }
     442    DBG(("PE: AllocateExeMem: VIRTUALADDRESSLIMIT: %d (rc %d)\n", ulSysinfo, rc));
    446443
    447444    if(oh.ImageBase < 512*1024*1024) {
     
    483480        DosFreeMem((PVOID)memallocs[i]);
    484481    }
     482    DBG(("PE: AllocateExeMem: reservedMemory: 0x%08X\n", reservedMemory));
    485483    ret = TRUE;
    486484end:
    487485    if(dllfile) DosClose(dllfile);
     486    DBG(("PE: AllocateExeMem: returning %d\n", ret));
    488487    return ret;
    489488}
Note: See TracChangeset for help on using the changeset viewer.