Ignore:
Timestamp:
Jul 23, 2002, 3:51:49 PM (23 years ago)
Author:
sandervl
Message:

Enhanced PE loader class to support files with PE image starting at an offset ..= 0 (custom build) & Fixes for memory map view with offset

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/winimagepeldr.cpp

    r8883 r8913  
    1 /* $Id: winimagepeldr.cpp,v 1.98 2002-07-17 21:09:20 achimha Exp $ */
     1/* $Id: winimagepeldr.cpp,v 1.99 2002-07-23 13:51:49 sandervl Exp $ */
    22
    33/*
     
    2121 *       So an instance of this type can't be used for anything but resource lookup!
    2222 *
     23 * NOTE: File pointer operations relative to the start of the file must add
     24 *       ulPEOffset (in case PE image start != file start)
    2325 *
    2426 */
     
    118120    nrOrdExportsRegistered(0)
    119121{
    120  HFILE  dllfile;
     122    HFILE  dllfile;
    121123
    122124    fIsPEImage = TRUE;
     
    173175//******************************************************************************
    174176//******************************************************************************
    175 BOOL Win32PeLdrImage::init(ULONG reservedMem)
     177BOOL Win32PeLdrImage::init(ULONG reservedMem, ULONG ulPEOffset)
    176178{
    177179 LPVOID win32file = NULL;
     
    184186 IMAGE_DOS_HEADER doshdr;
    185187 ULONG  signature;
     188
     189    //offset in executable image where real PE file starts (default 0)
     190    this->ulPEOffset = ulPEOffset;
    186191
    187192    hFile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
     
    200205        goto failure;
    201206    }
    202     if(OSLibDosSetFilePtr(hFile, doshdr.e_lfanew, OSLIB_SETPTR_FILE_BEGIN) == -1) {
     207    if(OSLibDosSetFilePtr(hFile, ulPEOffset+doshdr.e_lfanew, OSLIB_SETPTR_FILE_BEGIN) == -1) {
    203208        goto failure;
    204209    }
     
    236241        goto failure;
    237242    }
    238     win32file = memmap->mapViewOfFile(0, 0, 2);
     243    //PE image starts at offset ulPEOffset (default 0)
     244    win32file = memmap->mapViewOfFile(0, ulPEOffset, 2);
    239245
    240246    if(DosQueryPathInfo(szFileName, FIL_QUERYFULLNAME, szFullPath, sizeof(szFullPath)) == 0) {
     
    580586
    581587#ifdef COMMIT_ALL
    582         // this is a workaround until we have full page fault handling. We
    583         // just commit all pages here, i.e. do the DosReads
    584588        for (i=0; i<nSections; i++) {
    585589            commitPage((ULONG)section[i].realvirtaddr, FALSE, COMPLETE_SECTION);
     
    597601        }
    598602#endif
    599         // here we are going to parse the export table and build a list
    600         // in memory of what this module exports
    601603        if(processExports((char *)win32file) == FALSE) {
    602604            dprintf((LOG, "Failed to process exported apis" ));
     
    612614#endif
    613615
    614     // a HINSTANCE in Windows is actually a pointer to the PE header!
     616    //SvL: Use pointer to image header as module handle now. Some apps needs this
    615617    hinstance = (HINSTANCE)realBaseAddress;
    616618
     
    627629    }
    628630
    629     // Allocate TLS index for this module
    630     // Must do this before dlls are loaded for this module. Some apps assume
    631     // they get TLS index 0 for their main executable
    632     // AH TODO: is this really safe here? We call processExports before and
    633     // the module might export forwarders so additional DLLs are loaded which
    634     // in turn might allocate TLS in the initterm routine!
     631    //Allocate TLS index for this module
     632    //Must do this before dlls are loaded for this module. Some apps assume
     633    //they get TLS index 0 for their main executable
    635634    {
    636635      USHORT sel = SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
     
    642641    if(!(dwFlags & (FLAG_PELDR_LOADASDATAFILE | FLAG_PELDR_SKIPIMPORTS)))
    643642    {
    644         // this will process all import statements and resolve them. I.e.
    645         // additional DLLs will be loaded automatically.
    646643        if(processImports((char *)win32file) == FALSE) {
    647644            dprintf((LOG, "Failed to process imports!" ));
     
    737734{
    738735 Section *section;
    739  ULONG fileoffset; // this will be the offset in the file we have to read at
    740                    // it will be calculated from the virtual address
    741  ULONG    offset, size, sectionsize, protflags, range, attr;
     736 ULONG    offset, size, sectionsize, protflags, fileoffset, range, attr;
    742737 ULONG    ulNewPos, ulRead, orgVirtAddress = virtAddress;
    743738 APIRET   rc;
     
    748743    }
    749744
    750     // round down to nearest page boundary
     745    //Round down to nearest page boundary
    751746    virtAddress = virtAddress & ~0xFFF;
    752747
    753     // check if this address corresponds to any PE section
    754748    section = findSectionByOS2Addr(virtAddress);
    755749    if(section == NULL) {
    756         // maybe the section does not start at a page boundary?
    757750        section = findSectionByOS2Addr(orgVirtAddress);
    758751        if(section) {
     
    760753        }
    761754    }
    762     // if we still haven't found the section, it's a special case
    763755    if(section == NULL) {
    764756        size        = 4096;
     
    766758        //Header page must be readonly (same as in NT)
    767759        protflags   = PAG_READ;
    768 
    769         // check if there is a previous section
    770760        section = findPreviousSectionByOS2Addr(virtAddress);
    771 
    772         // no, so it must be the PE header
    773         if(section == NULL) {
     761        if(section == NULL) {//access to header
    774762            offset     = 0;
    775763            fileoffset = virtAddress - realBaseAddress;
     
    785773        sectionsize = section->virtualsize - offset;
    786774
    787         // check if this is unitialized data (i.e. not present in the PE file
    788         // and set to 0 by the PE loader
    789775        if(offset > section->rawsize || section->type == SECTION_UNINITDATA) {
    790             // AH TODO shouldn't be abusing these variables here...
     776            //unintialized data (set to 0)
    791777            size = 0;
    792778            fileoffset = -1;
    793779        }
    794780        else {
    795             size = section->rawsize - offset;
     781            size = section->rawsize-offset;
    796782            fileoffset = section->rawoffset + offset;
    797783        }
     
    801787        }
    802788    }
    803     // we completely ignore debug sections!
    804     if(fPageCmd == COMPLETE_SECTION && (section && section->type == SECTION_DEBUG)) {
     789    if(fPageCmd == COMPLETE_SECTION && (section && section->type == SECTION_DEBUG)) {//ignore
    805790        return TRUE;
    806791    }
     
    832817    sectionsize = min(sectionsize, range);
    833818
    834     // make sure this is not address space that has no backing PE file data
    835     // (i.e. uninitialized data)
    836     // AH TODO: don't abuse these variables!
    837819    if(size && fileoffset != -1) {
    838820        rc = DosEnterCritSec();
     
    841823            goto fail;
    842824        }
    843         // we need write permissions for now to do the actual loading
    844825        rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
    845826        if(rc) {
     
    849830        }
    850831
    851         if(DosSetFilePtr(hFile, fileoffset, FILE_BEGIN, &ulNewPos) == -1) {
     832        if(DosSetFilePtr(hFile, ulPEOffset+fileoffset, FILE_BEGIN, &ulNewPos) == -1) {
    852833            DosExitCritSec();
    853834            dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetFilePtr failed for 0x%x!", fileoffset));
     
    874855        setFixups(virtAddress, sectionsize);
    875856
    876         // set the protection flags to what the section requests
    877857        rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
    878858        DosExitCritSec();
     
    883863    }
    884864    else {
    885         // unitialized data section, padded with 0 (done by OS/2)
    886 
    887865        rc = DosEnterCritSec();
    888866        if(rc) {
     
    891869        }
    892870
    893         // get temporary write permission
    894871        rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
    895872        if(rc) {
     
    900877        setFixups(virtAddress, sectionsize);
    901878
    902         // set the protection flags to what the section requests
    903879        rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
    904880        DosExitCritSec();
     
    955931        return allocFixedMem(reservedMem);
    956932    }
    957     // AH TODO: aren't we wasting 64kb address space here if things go bad?
    958933    rc = OSLibDosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | PAG_WRITE);
    959934    if(rc) {
     
    11291104}
    11301105//******************************************************************************
    1131 // setFixups:
    1132 //   this is the main fixup processing function. It uses the virtual image base
    1133 //   address (oh.ImageBase) and replaces all fixups by the relative virtual address
    1134 //   plus the image base address
    11351106//******************************************************************************
    11361107BOOL Win32PeLdrImage::setFixups(ULONG virtAddress, ULONG size)
    11371108{
    1138  int i;
     1109 int   i, j;
    11391110 char *page;
    11401111 ULONG count, newpage;
     
    11421113 PIMAGE_BASE_RELOCATION prel = pFixups;
    11431114
    1144   // is fixup processing required?
    11451115  if(realBaseAddress == oh.ImageBase || fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
    11461116        return(TRUE);
    11471117  }
    11481118
    1149   // convert the virtual address to a relative virtual address
    11501119  virtAddress -= realBaseAddress;
    1151 
    1152   // round size to next page boundary
    1153   size  = (size - 1) & ~0xFFF;
     1120  //round size to next page boundary
     1121  size  = (size-1) & ~0xFFF;
    11541122  size += PAGE_SIZE;
    11551123
    1156   // do we have relocation records (aka fixups)?
    11571124  if(prel) {
    1158         // move to the first relocation record
    1159         while(((ULONG)prel < (ULONG)pFixups + dwFixupSize) &&
     1125        j = 1;
     1126        while(((ULONG)prel < (ULONG)pFixups+dwFixupSize) &&
    11601127              prel->VirtualAddress && prel->VirtualAddress < virtAddress)
    11611128        {
    11621129            prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
    11631130        }
    1164         // go through all relocation records
    1165         while(((ULONG)prel < (ULONG)pFixups + dwFixupSize) &&
     1131        while(((ULONG)prel < (ULONG)pFixups+dwFixupSize) &&
    11661132               prel->VirtualAddress && prel->VirtualAddress < virtAddress + size)
    11671133        {
    11681134            page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
    1169             // determine how many fixups we have to process
    1170             count = (prel->SizeOfBlock - 8) / 2;
    1171             for(i = 0; i < count; i++) {
     1135            count  = (prel->SizeOfBlock - 8)/2;
     1136            j++;
     1137            for(i=0;i<count;i++) {
    11721138                int type   = prel->TypeOffset[i] >> 12;
    11731139                int offset = prel->TypeOffset[i] & 0xFFF;
     
    11841150                    break;
    11851151                }
    1186                 // if the fixup crosses the final page boundary,
    1187                 // then we have to load another page
     1152                //If the fixup crosses the final page boundary,
     1153                //then we have to load another page
    11881154                if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
    11891155                {
     
    11911157                    newpage &= ~0xFFF;
    11921158
    1193                     // find the corresponding section so that we know lateron
    1194                     // what permission bits we have to assign to the new page
    11951159                    section  = findSectionByOS2Addr(newpage);
    11961160                    if(section == NULL) {
    1197                         // should never happen
    1198                         dprintf((LOG, "setFixups -> section == NULL!!"));
     1161                        //should never happen
     1162                        dprintf((LOG, "::setFixups -> section == NULL!!"));
    11991163                        return FALSE;
    12001164                    }
    1201                     // explicitly read page from disk
     1165                    //SvL: Read page from disk
    12021166                    commitPage(newpage, FALSE, SINGLE_PAGE);
    12031167
    12041168                    //SvL: Enable write access (TODO: may need to prevent other threads from being active)
    1205                     DosSetMem((PVOID)newpage, PAGE_SIZE, PAG_READ | PAG_WRITE);
     1169                    DosSetMem((PVOID)newpage, PAGE_SIZE, PAG_READ|PAG_WRITE);
    12061170                }
    12071171
     
    12241188                        break;
    12251189                }
    1226                 // did we have to load another page?
    12271190                if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
    12281191                {
     
    12311194                }
    12321195            }
    1233             // move to the next relocation record
    12341196            prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
    12351197        }//while
     
    12451207BOOL Win32PeLdrImage::setFixups(PIMAGE_BASE_RELOCATION prel)
    12461208{
    1247  int   i;
    1248  #if DEBUG
    1249  int j;
    1250  #endif
     1209 int   i, j;
    12511210 char *page;
    12521211 ULONG count;
    12531212
    1254   // if there are no fixups, we have nothing to do...
    12551213  if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
    12561214        return(TRUE);
     
    12581216
    12591217  if(prel) {
    1260         #if DEBUG
    12611218        j = 1;
    1262         #endif
    1263         // loop through all relocation records
    12641219        while(prel->VirtualAddress) {
    12651220            page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
    1266             // determine how many fixups we have to process
    1267             count  = (prel->SizeOfBlock - 8) / 2;
    1268 
    1269             dprintf((LOG, "Page %d Address %x Count %d", j, prel->VirtualAddress, count));
    1270             #if DEBUG
     1221            count  = (prel->SizeOfBlock - 8)/2;
     1222            dprintf((LOG, "Page %d Address %x Count %d", j, prel->VirtualAddress, count ));
    12711223            j++;
    1272             #endif
    1273 
    1274             for(i = 0; i < count; i++) {
     1224            for(i=0;i<count;i++) {
    12751225                int type   = prel->TypeOffset[i] >> 12;
    12761226                int offset = prel->TypeOffset[i] & 0xFFF;
     
    12961246                }
    12971247            }
    1298             // advance to the next relocation record
    12991248            prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
    13001249        }//while
     
    13161265    fixup   = (ULONG *)(fixupaddr + realBaseAddress);
    13171266    orgaddr = *fixup;
    1318 ////  dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - oh.ImageBase)));
     1267//  dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - oh.ImageBase)));
    13191268    *fixup  = realBaseAddress + (*fixup - oh.ImageBase);
    13201269}
     
    16191568    }
    16201569
    1621     // if it's not a PE image, we let OS/2 load it (LX image)
    16221570    if(isPEImage(modname, NULL, NULL) != ERROR_SUCCESS_W)
    1623     {
     1571    {//LX image, so let OS/2 do all the work for us
    16241572        APIRET rc;
    16251573        char   szModuleFailure[CCHMAXPATH] = "";
     
    16271575        Win32LxDll *lxdll;
    16281576
    1629         // check if we have the .DLL extension or have to add it first
    16301577        char *dot = strchr(modname, '.');
    16311578        if(dot == NULL) {
    16321579            strcat(modname, DLL_EXTENSION);
    16331580        }
    1634         // here we load the module. This will also execute the initterm
    1635         // function in the DLL. We expect the LX DLL to callback RegisterLxDll
    1636         // to register with Odin. This also means we cannot load "standard"
    1637         // LX DLLs with this method - they have to be Odin aware
    16381581        rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), modname, (HMODULE *)&hInstanceNewDll);
    16391582        if(rc) {
     
    16431586            return NULL;
    16441587        }
    1645         // due to the callback requirement, we can expect to have a structure
    1646         // for it by now. Otherwise it didn't work out
    16471588        lxdll = Win32LxDll::findModuleByOS2Handle(hInstanceNewDll);
    16481589        if(lxdll == NULL) {//shouldn't happen!
    16491590            dprintf((LOG, "Just loaded the dll, but can't find it anywhere?!!?"));
    1650             // AH TODO: shouldn't we do a DosFreeModule here?
    16511591            errorState = ERROR_INTERNAL;
    16521592            return NULL;
    16531593        }
    16541594        lxdll->setDllHandleOS2(hInstanceNewDll);
    1655         // AddRef for a LX DLL is special - it does not increase the reference counter
    16561595        if(lxdll->AddRef() == -1) {//-1 -> load failed (attachProcess)
    16571596            dprintf((LOG, "Dll %s refused to be loaded; aborting", modname));
     
    16641603    else {
    16651604         Win32PeLdrDll *pedll;
    1666             // create an object for that DLL
     1605
    16671606            pedll = new Win32PeLdrDll(modname, this);
    16681607            if(pedll == NULL) {
     
    16751614            dprintf((LOG, "**********************     Loading Module        *********************" ));
    16761615            dprintf((LOG, "**********************************************************************" ));
    1677             // do the actual loading including all imports - so this is a point of recursion
    16781616            if(pedll->init(0) == FALSE) {
    16791617                dprintf((LOG, "Internal WinDll error ", pedll->getError() ));
     
    16841622            pedll->AddRef(getModuleName());
    16851623#else
    1686             // increase the reference count
    16871624            pedll->AddRef();
    16881625#endif
    1689             // send the attach process message to the DLL, i.e. call the handler
    16901626            if(pedll->attachProcess() == FALSE) {
    16911627                dprintf((LOG, "attachProcess failed!" ));
     
    21222058}
    21232059//******************************************************************************
    2124 // we link this function to all imports we couldn't resolve in our DLLs so the
    2125 // user gets a stupid error message dialog
    21262060//******************************************************************************
    21272061ULONG WIN32API MissingApi(char *message)
Note: See TracChangeset for help on using the changeset viewer.