#include "ldrextrn.h" extern ldrste_t segtab; VOID ldrSetDescInfo( SEL Selector, // selector to set desc info on ULONG MemoryAddress, // base address of selector USHORT ste_flags, // ste flags USHORT SegSize) // size of segment { PROCESS_LDT_INFORMATION LdtInfo; NTSTATUS Status; LdtInfo.Start = Selector & 0xfff8; LdtInfo.Length = sizeof(LDT_ENTRY); LdtInfo.LdtEntries[0].LimitLow = SegSize - 1; LdtInfo.LdtEntries[0].BaseLow = (USHORT)(MemoryAddress); LdtInfo.LdtEntries[0].HighWord.Bytes.BaseMid = (UCHAR)(MemoryAddress >> 16); LdtInfo.LdtEntries[0].HighWord.Bytes.BaseHi = (UCHAR)(MemoryAddress >> 24); LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 = D_SEG+D_PRES+D_DPL3; LdtInfo.LdtEntries[0].HighWord.Bytes.Flags2 = 0; if ((ste_flags & STE_DATA) == 0) { LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_CODE; } if ((ste_flags & STE_ERONLY) == 0) { // The STE_ERONLY is applicable for both D_RX in CODE segments // and D_RW in DATA segments. D_RX and D_RW are the same bit LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_RX; } Status = NtSetInformationProcess( CurrentThread->Process->ProcessHandle, ProcessLdtInformation, &LdtInfo, sizeof(PROCESS_LDT_INFORMATION) ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint ("ldrSetDescInfo: Invalid request\n"); #endif } } /***LP ldrLoadModule - Load a new exe file for given module table entry. * * Each segment in the module which has not been * previously initialized will be initialized and * loaded as required. * * ENTRY plv - pointer to local variables * * EXIT Module marked as loaded * * * This procedure performs the following steps: * * - calls TKLibiRecordMTE * - calls DebugLoadSymMTE * - must attach to or load each module that is referenced by our module * - if 32-bit module finish loading objects * - mark mte as module has been loaded */ APIRET ldrLoadModule(plv) ldrlv_t *plv; /* local variables */ { register ldrmte_t *pmte; /* pointer to mte */ register ldrsmte_t *psmte; /* pointer to swappable mte */ ldrste_t *pste; ldrlibi_t *ptmp; ulong_t csegs; int rc; #if DBG IF_OL2_DEBUG ( TRACE ) { DbgPrint("OS2LDR: ldrLoadModule(pmte=%x) was called\n", plv->lv_pmte); } #endif pmte = plv->lv_pmte; /* point to mte */ psmte = pmte->mte_swapmte; /* pointer to swappable mte */ /* * Setup for Library init */ if (((pmte->mte_mflags & LIBRARYMOD) != 0) && ((pmte->mte_mflags & USED) == 0) && ((pmte->mte_mflags & (INSTLIBINIT | GINIDONE)) != GINIDONE)) { ptmp = &pldrLibiRecord[*pldrLibiCounter]; ptmp->handle = pmte->mte_handle; pste = ldrNumToSte(pmte, psmte->smte_startobj); ptmp->startaddr.ptr_off = (USHORT) psmte->smte_eip; ptmp->startaddr.ptr_sel = pste->ste_selector | 7; if (psmte->smte_stackobj != 0) { if ((pste = ldrNumToSte(pmte, psmte->smte_stackobj))==0) { rc = ERROR_INVALID_STACKSEG; return(rc); } ptmp->stackaddr.ptr_off = (USHORT) psmte->smte_esp; ptmp->stackaddr.ptr_sel = pste->ste_selector | 7; } else { ptmp->stackaddr.ptr_off = 0; ptmp->stackaddr.ptr_sel = 0; } if ((psmte->smte_autods == 0) || (pste = ldrNumToSte(pmte, psmte->smte_autods)) == NULL) ptmp->ds = 0; else ptmp->ds = pste->ste_selector | 7; ptmp->heapsize = (USHORT) psmte->smte_heapsize; (*pldrLibiCounter)++; pmte->mte_mflags |= GINIDONE; } // // For system dll's other than Doscalls don't load segments // if ((pmte->mte_mflags & DOSMOD) != 0) { ASSERT(LDRDoscallsSel != 0); return(NO_ERROR); } // // If this module has already been loaded, no need to load again // if ((pmte->mte_mflags & MTEPROCESSED) != 0) { return(NO_ERROR); } /* * Make sure starting point (or init routine) is ring 3 */ if (ldrIsNE(pmte) && psmte->smte_startobj != 0) { if ((pste=ldrNumToSte(pmte, psmte->smte_startobj)) == NULL) { rc = ERROR_INVALID_STARTING_CODESEG; return(rc); } if ((pste->ste_selector & RPL_MASK) != RPL_RING3) { if (pmte->mte_mflags & LIBRARYMOD) { rc = ERROR_INVALID_DLL_INIT_RING; } else { rc = ERROR_INVALID_STARTING_RING, pmte; } return(rc); } } pste = (ldrste_t *) psmte->smte_objtab; for (csegs = 0; csegs < psmte->smte_objcnt; csegs++, pste++ ) { if ((rc = ldrLoadSegment(pmte, pste)) != NO_ERROR) { #if DBG DbgPrint("OS2LDR: ldrGetModule - failed to ldrLoadSegment, rc = %d\n", rc); #endif return(rc); } } if ((psmte->smte_autods != 0) && (psmte->smte_autods <= psmte->smte_objcnt) ) { ldrEachObjEntry(0, pmte, ldrEditProlog, NULL); } pmte->mte_mflags |= MTEPROCESSED; return(NO_ERROR); } /***LP ldrAllocSegments - allocate segments/selectors for requested mte. * * Each segment in the module which requests to be * preloaded is allocated and all selectors for the * module are allocated for the child task. * * ENTRY plv - pointer to set of local variables * * EXIT None * * * This procedure performs the following steps: * * - For each segment in this module * - check if load should abort * - allocate memory */ APIRET ldrAllocSegments(plv) register ldrlv_t *plv; /* pointer to set of local variables */ { ldrmte_t *pmte; /* pointer to mte */ ldrsmte_t *psmte; /* pointer to swappable mte */ register ldrste_t *pste; /* pointer to a segment table entry */ //PVOID MemoryAddress; ULONG LastSuccessful; int rc; #if DBG IF_OL2_DEBUG ( TRACE ) { DbgPrint("OS2LDR: ldrAllocSegments(pste=%x) was called\n", plv->lv_pmte); } #endif pmte = plv->lv_pmte; psmte = pmte->mte_swapmte; pste = (ldrste_t *) psmte->smte_objtab; for (plv->lv_objnum = 1; plv->lv_objnum <= psmte->smte_objcnt; plv->lv_objnum++, pste++) { if ((rc=ldrAllocSegment(pmte, pste, plv->lv_objnum)) != NO_ERROR) { /* * We got an error allocating the segments for this * module. We must cleanup any segments that were * allocated before the error if the module we are loading * was a library module. The reason is that the mte for this * module will not have a run time attachment to this process. * The case we are covering here is if a module that references * another, is not loaded that module's module pointer table * will not get the pointer to the mte for this one. Therefore * when garbage collection is run this module will be freed * and the allocated segments will not get freed. */ LastSuccessful = plv->lv_objnum - 1; pste = (ldrste_t *) psmte->smte_objtab; for (plv->lv_objnum = 1; plv->lv_objnum <= LastSuccessful; plv->lv_objnum++, pste++) { NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle, SELTOFLAT(pste->ste_selector) ); if ((pmte->mte_mflags & MTEPROCESSED) == 0) { // // If the allocated segment is a ring 2 segment, check // entry records that need to be referenced by call gates. // Remove the emulation thunk for the call gate. // if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment ((pste->ste_flags & STE_DATA) == 0) && // code segment ((pste->ste_flags & STE_CONFORM) == 0) // non conforming ) { ldrEachObjEntry(plv->lv_objnum, pmte, ldrFreeCallGate, NULL); } NtUnmapViewOfSection(NtCurrentProcess(), SELTOFLAT(pste->ste_selector) ); NtClose((HANDLE)pste->ste_seghdl); ldrFreeSel(pste->ste_selector, 1); } } // /* // * Slip packed segments, free as one object later // */ // if (pste->ste_flags & STE_PACKED) // continue; // if ((pste->ste_seghdl != HOBNULL) && // (pste->ste_selector & SEL_LDTBIT) && // ((pste->ste_flags & STE_SHARED) == 0)) { // /* If cached instance data object */ // ldrAssert(pste->ste_offset != 0); // if (VMHandleVerify(pste->ste_seghdl, // 1,SSToDS(&pbcache)) == NO_ERROR) { // /* Free the pseudohandle */ // VMFreePseudoHandle(pste->ste_seghdl); // /* Free small caches from heap */ // VMFreeKHB(VM_HKH_PUB_SWAPRW, pbcache); // } // else { /* Else cache has own object */ // rc = VMGetLaddr(pste->ste_seghdl, SSToDS(&laddr)); // ldrAssert(rc == NO_ERROR); // while (VMFreeMem(laddr,HOBNULL,0)==ERROR_INTERRUPT) // ; /* Free the object */ // } // pste->ste_seghdl = HOBNULL; // /* Clear the handle */ // } // else if (pste->ste_selector != 0) // VMFreeMem(SelToLaTiled(pste->ste_selector), // (VMHOB) ((pPTDACur->ptda_child != HOBNULL) ? // pPTDACur->ptda_child : // pPTDACur->ptda_handle), // VMFM_NOLDR | VMFM_GC); // /* // * See if any packed segments exists, free as one object. // */ // if (psmte->smte_csegpack > 0) // VMFreeMem(psmte->smte_ssegpack, NA, NA); return(rc); } } /* * Clear packed segment flag for second load of EXE */ if (psmte->smte_csegpack > 0) psmte->smte_csegpack = 0; return(NO_ERROR); } /***LP ldrAllocSegment - verify allocation size and allocate memory * * If the segment's file size is larger than the minimum * allocation size an error is reported. * Both the allocation size and the segment handle are saved in * the segment table entry. Also indicate the segment * is being loaded so that it's memory will not be * discarded during the load. * * ldrAllocSegment (pmte, pste, iseg) * * ENTRY pmte - pointer to mte * pste - pointer to ste * iseg - segment number * RETURN int - error code (NO_ERROR if successful) * */ static ULONG RegionSize64K = _64K; APIRET ldrAllocSegment(pmte,pste,iseg) register ldrmte_t *pmte; /* MTE pointer */ register ldrste_t *pste; /* STE pointer */ ulong_t iseg; /* Segment number (1-based) */ { register ldrsmte_t *psmte; /* swappable mte pointer */ ulong_t fl; /* Memory allocation flags */ int frsrc; /* Resource segment flag */ int frsrcused; /* True if resource really used */ ULONG RegionSize; uchar_t sharename[23] = "\\sharemem\\"; uchar_t *psharename = sharename; uchar_t ext[3] = {0,0,0}; ulong_t Index; PVOID MemoryAddress; NTSTATUS Status; LARGE_INTEGER LargeRegionSize; HANDLE SectionHandle; ULONG ViewSize; ULONG Protect; BOOLEAN SectionCreated = FALSE; APIRET rc; #if DBG IF_OL2_DEBUG ( TRACE ) { DbgPrint("OS2LDR: ldrAllocSegment(pmte=%x) was called\n", pmte); } #endif psmte = pmte->mte_swapmte; frsrc = iseg > psmte->smte_objcnt - psmte->smte_rsrccnt; /* Set resource flag */ /* * Note that for debugging purposes, we will actually allocate * memory for resources that are not marked STE_PRELOAD if the * ldrLoadRsrc flag is set. Such resources are born with a * reference count of zero instead of one, however. The flag * frsrcused is used to distinguish the special case. */ // if (!(pste->ste_flags & STE_PRELOAD) && frsrc) // return(NO_ERROR); /* Skip non-preloaded resources */ frsrcused = FALSE; /* Assume not meant to be used yet */ fl = 0; /* Initialize VM and PG flags */ if ((pste->ste_flags & STE_PRELOAD)) { /* If swapping off or preload seg */ /* * For a resource, the preload attribute does not actually * mean the resource should be preloaded. It just means we * should allocate the segment for the resource at load time. * Unless we are loading the resource from a floppy, we should * always preload it. */ if (pste->ste_flags & STE_SHARED) { /* If shared object */ pste->ste_flags &= ~STE_PRELOAD; /* Only preload shared guys once */ frsrcused = TRUE; /* Resource actually referenced */ } } RegionSize = pste->ste_minsiz; if (RegionSize == 0) { RegionSize = _64K; } if ((pmte->mte_mflags & MTEPROCESSED) == 0) { if ((pmte->mte_mflags & DOSLIB) != 0) { Index = 0; // DOSCALLS.DLL is loaded into fixed locationions MemoryAddress = (PVOID)(DOSCALLS_BASE + (iseg - 1) * _64K); } else { Index = ldrAllocateSel(1, FALSE); // _64K are exactly 1 selector MemoryAddress = SELTOFLAT(Index); } // // Special handling for the R2XFER_BASE segment which has // already been allocated at ldrInit() // if (MemoryAddress == (PVOID)R2XFER_BASE) { pste->ste_seghdl = (ulong_t)R2XferSegHandle; SectionHandle = R2XferSegHandle; } else { LargeRegionSize.LowPart = _64K; LargeRegionSize.HighPart = 0; Status = NtCreateSection(&SectionHandle, SECTION_ALL_ACCESS, NULL, &LargeRegionSize, PAGE_EXECUTE_READWRITE, SEC_RESERVE, NULL ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("OS2LDR: ldrAllocSegment - Can't create section, Status=%x\n", Status); #endif if (Index != 0) { ldrFreeSel(Index, 1); } return(ERROR_NOT_ENOUGH_MEMORY); } ViewSize = 0; Status = NtMapViewOfSection(SectionHandle, NtCurrentProcess(), &MemoryAddress, 1, RegionSize, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to server process at addr=%x, Status=%x\n", MemoryAddress, Status); #endif NtClose(SectionHandle); if (Index != 0) { ldrFreeSel(Index, 1); } return(ERROR_NOT_ENOUGH_MEMORY); } SectionCreated = TRUE; pste->ste_seghdl = (ulong_t)SectionHandle; } } else { SectionHandle = (HANDLE)pste->ste_seghdl; MemoryAddress = SELTOFLAT(pste->ste_selector); } // // Any change in determinig the Protect value should be // done in ldrsubr.c LDRDosGetResource() too. // if ((pste->ste_flags & STE_DATA) == 0) { // This is a code segment if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) { Protect = PAGE_EXECUTE_WRITECOPY; } else { if ((pste->ste_flags & STE_ERONLY) != 0) { // This is an execute only segment Protect = PAGE_EXECUTE; } else { Protect = PAGE_EXECUTE_READ; } } } else { // This is a data segment if ((pste->ste_flags & STE_SHARED) != 0) { // This is a shared data segment if ((pste->ste_flags & STE_ERONLY) != 0) { // This is a read only segment Protect = PAGE_READONLY; } else { // This is a read/write segment Protect = PAGE_READWRITE; } } else { // This is a non shared data segment if ((pste->ste_flags & STE_ERONLY) != 0) { // This is a read only segment if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) { Protect = PAGE_EXECUTE_WRITECOPY; } else { Protect = PAGE_READONLY; } } else { // This is a sizeable read/write segment Protect = PAGE_EXECUTE_WRITECOPY; } } } if ((pmte->mte_mflags & MTEPROCESSED) == 0) { pste->ste_selector = FLATTOSEL((ULONG)MemoryAddress); pste->ste_selector = (SEL)((pste->ste_selector & SEL_RPLCLR) | ((pste->ste_flags & STE_SEGDPL) >> 10)); pste->ste_fixups = (ulong_t)MemoryAddress; } // // Non resource segments are mapped into the address space of the // client process. // Resources are not mapped yet into the address space of the process. // DosGetResource() does the mapping job for resources. // if (iseg <= psmte->smte_objcnt - psmte->smte_rsrccnt) { if (Protect == PAGE_EXECUTE_WRITECOPY) { ViewSize = RegionSize; } else { ViewSize = 0; } Status = NtMapViewOfSection(SectionHandle, CurrentThread->Process->ProcessHandle, &MemoryAddress, 1, RegionSize, NULL, &ViewSize, ViewUnmap, 0, Protect ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to client process %x at addr=%x, Status=%x\n", CurrentThread->Process->ProcessHandle, MemoryAddress, Status); #endif if (SectionCreated) { NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress); NtClose(SectionHandle); if (Index != 0) { ldrFreeSel(Index, 1); } } return(ERROR_NOT_ENOUGH_MEMORY); } if ((pmte->mte_mflags & MTEPROCESSED) == 0) { /* * If this is Doscalls module save the code selector * of the first code segment */ if (((pmte->mte_mflags & DOSLIB) != 0) && (iseg == 1) ) { LDRDoscallsSel = pste->ste_selector | 7; segtab = *pste; } // // If the allocated segment is a ring 2 segment, check for // entry records that need to be referenced by call gates. // Create an emulation thunk for the call gate. // if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment ((pste->ste_flags & STE_DATA) == 0) && // code segment ((pste->ste_flags & STE_CONFORM) == 0) // non conforming ) { rc = ldrEachObjEntry(iseg, pmte, ldrGetCallGate, NULL); if (rc != NO_ERROR) { ldrEachObjEntry(iseg, pmte, ldrFreeCallGate, NULL); NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle, MemoryAddress ); if (SectionCreated) { NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress); NtClose(SectionHandle); if (Index != 0) { ldrFreeSel(Index, 1); } } return(rc); } } } ldrSetDescInfo(pste->ste_selector, (ULONG) MemoryAddress, pste->ste_flags, pste->ste_minsiz); } return(NO_ERROR); } /***LP ldrLoadSegment - segment load * * Setup to call ldrLoadSegment * * ENTRY pmte - pointer to mte * pste - pointer to a segment table entry * * EXIT int - return code (NO_ERROR if successful) * */ APIRET ldrLoadSegment(pmte, pste) ldrmte_t *pmte; /* pointer to mte */ ldrste_t *pste; /* pointer to segment table entry */ { IO_STATUS_BLOCK IoStatusBlock; PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock; LARGE_INTEGER ByteOffset; ldrmte_t *ptgtmte; ldrsmte_t *psmte; ldrste_t *ptgtste; struct taddr_s taddr; ULONG laddr; ULONG seek; uchar_t relocbuf[RELOCBUFLEN]; ushort_t crelrecs; ushort_t i; ulong_t cbread; ushort_t crecs; ri_t *pri; uchar_t *pprocname; ushort_t ord; uchar_t *pchar; ulong_t minsiz; int rc = NO_ERROR; NTSTATUS Status; #if DBG IF_OL2_DEBUG ( TRACE ) { DbgPrint("OS2LDR: ldrLoadSegment(pmte=%x, pste=%x) was called\n", pmte, pste); } #endif ldrSetupSrcErrTxt(((char *) pmte->mte_modname)+1, (USHORT) *((char *) pmte->mte_modname)); psmte = pmte->mte_swapmte; // BUGBUG - remove after LDT defined // laddr = SelToLaTiled(pste->ste_selector); laddr = pste->ste_fixups; if (pste->ste_offset != 0) { if (pste->ste_flags & STE_ITERATED) { if ((rc = ldrLoadIteratedData(pmte, pste, pIoStatusBlock, laddr)) != NO_ERROR) { return(rc); } IoStatusBlock.Status -= laddr; cbread = IoStatusBlock.Information; ByteOffset.LowPart = (ULONG) (pste->ste_offset << psmte->smte_alignshift); ByteOffset.HighPart = 0; } else { seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift); ByteOffset.LowPart = seek; ByteOffset.HighPart = 0; cbread = (ulong_t) ((pste->ste_size == 0) ? _64K : pste->ste_size); if ((Status = NtReadFile(pmte->mte_sfn, 0, 0, 0, &IoStatusBlock, (void *) laddr, cbread, &ByteOffset, 0)) != 0) { return(ERROR_BAD_EXE_FORMAT); } } if (IoStatusBlock.Information != cbread) return(ERROR_BAD_EXE_FORMAT); if (pste->ste_size != 0) { minsiz = (ulong_t) pste->ste_minsiz; if (minsiz == 0) { /* size = 64k */ minsiz = 0x10000; } // // Need to handle this special case because the segment // is already set with the ring 2 xfer thunks // if (laddr != R2XFER_BASE) { memset((void *) (laddr + ((pste->ste_flags & STE_ITERATED) ? IoStatusBlock.Status : IoStatusBlock.Information)), '\0', (pste->ste_flags & STE_ITERATED) ? minsiz - IoStatusBlock.Status : minsiz - pste->ste_size); } } /* * HACK - This will check for Doscalls.dll and if it is * the code segment it will search the code for the OPCodes * "0xDD, 0x1f" which will be changed to a call to * _EntryFlat */ if (((pmte->mte_mflags & DOSLIB) != 0) && ((pste->ste_flags & STE_TYPE_MASK) == STE_CODE) && (!DoscallsLoaded) ) { pchar = (uchar_t *) laddr; while(TRUE) { while (*pchar++ != 0xdd && pchar < (uchar_t *) (laddr + cbread)); if (pchar == (uchar_t *) (laddr + cbread)) break; if (*pchar == 0x1f) { pchar--; *((ULONG *) pchar) = Ol2EntryFlat; break; } } DoscallsLoaded = TRUE; } } /* * Process fixups if present */ if (pste->ste_flags & STE_RELOCINFO) { /* * Read the number of relocation records */ cbread = 2; ByteOffset.LowPart += IoStatusBlock.Information; if ((Status = NtReadFile(pmte->mte_sfn, 0, 0, 0, &IoStatusBlock, &crelrecs, cbread, &ByteOffset, 0 )) != 0) { return(ERROR_BAD_EXE_FORMAT); } if (IoStatusBlock.Information != cbread) return(ERROR_BAD_EXE_FORMAT); crecs = RELOCSPERBUF; for (i = 0; i < crelrecs; i++, crecs++) { if ((crecs % RELOCSPERBUF) == 0) { if (crelrecs - i > RELOCSPERBUF) cbread = RELOCBUFLEN; else cbread = (crelrecs - i) * sizeof(struct ri_s); ByteOffset.LowPart += IoStatusBlock.Information; if ((Status = NtReadFile(pmte->mte_sfn, 0, 0, 0, &IoStatusBlock, &relocbuf, cbread, &ByteOffset, 0)) != 0) { return(ERROR_BAD_EXE_FORMAT); } if (IoStatusBlock.Information != cbread) return(ERROR_BAD_EXE_FORMAT); crecs = 0; } pri = (ri_t *) &relocbuf[crecs * sizeof(struct ri_s)]; switch (pri->ri_flags & TARGET_MASK) { case INTERNALREF: /* Internal fixup */ /* * Check for fixed or movable */ if (pri->ri_target_seg != B16MOVABLE) { if ((ptgtste=ldrNumToSte(pmte, pri->ri_target_seg ))== NULL) { return(ERROR_INVALID_SEGMENT_NUMBER); } taddr.tsel = ptgtste->ste_selector | 7; taddr.toff = (ulong_t) pri->ri_target_off; break; } /* * A movable entry exists */ else { if ((rc = ldrGetEntAddr(pri->ri_target_off, pmte, &taddr, pste, pmte)) != NO_ERROR) { return(ERROR_BAD_EXE_FORMAT); } break; } case IMPORTNAME: /* Import by name fixup */ case IMPORTORDINAL: /* Import by ordinal fixup */ if ((rc = ldrGetTgtMte(pri->ri_target_modnam, pmte, &ptgtmte)) != NO_ERROR) { return(rc); } ldrSetupTgtErrTxt(((char *) ptgtmte->mte_modname)+1, (USHORT) *((char *) ptgtmte->mte_modname)); if ((pri->ri_flags & TARGET_MASK) == IMPORTNAME) { pprocname = (uchar_t *) (psmte->smte_impproc + (ulong_t) pri->ri_target_impnam); if (pprocname[1] == '#') { //BUGBUG - convert routine from asm // ldrStop(0xffff, 0); // ord = (ushort_t) ldrAscToOrd(&pprocname[2], // (ushort_t) pprocname[0] - 1); } else { ldrProcNameBufL = (USHORT) (pprocname[0]); ldrProcNameBuf = (PUCHAR) (pprocname + 1); if ((rc = ldrGetOrdNum(ptgtmte, pprocname, &ord, STRINGNONNULL )) != NO_ERROR) { return(rc); } } } else { ord = pri->ri_target_ord; ldrProcNameBufL = 2; ldrProcNameBuf = (PUCHAR) &pri->ri_target_ord; } if ((rc = ldrGetEntAddr(ord, ptgtmte, &taddr, pste, pmte)) != NO_ERROR) { #if DBG DbgPrint("ldrLoadSegment: failed to locate ordinal %d in %s for %s\n", pri->ri_target_ord, 1+(char *) (ptgtmte->mte_modname), 1+(char *) (pmte->mte_modname) ); #endif return(rc); } ldrInvTgtErrTxt(); break; default: continue; } if ((rc = ldrDoFixups(pri, laddr, &taddr, pste->ste_minsiz)) != NO_ERROR) { return(rc); } } } return(rc); } /***LP ldrLoadIteratedData - load iterated data * * Reads the iterated data from the file, expands it and loads it into * the segment. * * ENTRY * pmte - pointer to mte * pste - pointer to segment table * pIoStatusBlock - pointer to IO status buffer * laddr - address of page we are loading * * EXIT int - return code (NO_ERROR if successful) * */ APIRET ldrLoadIteratedData(pmte, pste, pIoStatusBlock, laddr) ldrmte_t *pmte; ldrste_t *pste; PIO_STATUS_BLOCK pIoStatusBlock; ULONG laddr; { ldrsmte_t *psmte; ULONG IOcount = 0; ULONG seek; LARGE_INTEGER ByteOffset; ULONG cbread; int rc; ULONG filedata; ULONG segsize; struct iter { USHORT numberiter; USHORT patternsize; } iterdata; ULONG expandsize; ULONG temp; ULONG i; #if DBG IF_OL2_DEBUG ( TRACE ) { DbgPrint("OS2LDR: ldrLoadIteratedData(pmte=%x) was called\n", pmte); } #endif psmte = pmte->mte_swapmte; filedata = (ULONG) pste->ste_size; /* size of data */ if (filedata == 0) { /* check if file data = 64k */ filedata = 0x10000; } segsize = pste->ste_minsiz; /* size of segment */ if (segsize == 0) { /* check if size = 64k */ segsize = _64K; } seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift); while (TRUE) { if (filedata < 3) { return(ERROR_BAD_EXE_FORMAT); } filedata -= 4; if (filedata == 0) /* See if done */ break; ByteOffset.LowPart = seek; ByteOffset.HighPart = 0; cbread = 4; if ((rc = NtReadFile(pmte->mte_sfn, 0, 0, 0, pIoStatusBlock, &iterdata, cbread, &ByteOffset, 0)) != 0) { return(ERROR_BAD_EXE_FORMAT); } if (pIoStatusBlock->Information != cbread) { return(ERROR_BAD_EXE_FORMAT); } seek += 4; /* We read 4 bytes */ IOcount += pIoStatusBlock->Information; if (iterdata.numberiter == 0 || iterdata.patternsize == 0) continue; filedata -= iterdata.patternsize; if (filedata > 0xffff) { return(ERROR_BAD_EXE_FORMAT); } expandsize = (ULONG) (iterdata.patternsize * iterdata.numberiter); if (expandsize > 0xffff) { return(ERROR_ITERATED_DATA_EXCEEDS_64k); } segsize -= expandsize; if (segsize > 0xffff) { return(ERROR_INVALID_MINALLOCSIZE); } ByteOffset.LowPart = seek; ByteOffset.HighPart = 0; cbread = iterdata.patternsize; if ((rc = NtReadFile(pmte->mte_sfn, 0, 0, 0, pIoStatusBlock, (void *) laddr, cbread, &ByteOffset, 0)) != 0) { return(ERROR_BAD_EXE_FORMAT); } if (pIoStatusBlock->Information != cbread) { return(ERROR_BAD_EXE_FORMAT); } seek += iterdata.patternsize; IOcount += pIoStatusBlock->Information; temp = laddr; laddr += iterdata.patternsize; for (i=1; iInformation = IOcount; pIoStatusBlock->Status = laddr; return(NO_ERROR); } /***LP ldrDoFixups - Do the fixups following the source chain * * Apply fixups to source * * * ENTRY pri - pointer to fixup record * laddr - address of start of segment * taddr - pointer to target address * segsize - size of segment * * EXIT int - return code (NO_ERROR if successful) * */ APIRET ldrDoFixups(pri, laddr, ptaddr, segsize) ri_t *pri; /* pointer to fixup record */ ulong_t laddr; /* address of start of segment */ struct taddr_s *ptaddr; /* target address */ ushort_t segsize; /* size of segment */ { uchar_t *pcoffset; ushort_t *psoffset; ushort_t chain; int count; ulong_t segsize_l = RESIZE64K(segsize); #if DBG IF_OL2_DEBUG ( FIXUP ) { DbgPrint("OS2LDR: ldrDoFixups(): laddr=%x\n", laddr); } #endif chain = 1; /* we do at least one fixup */ count = (int) (segsize_l / sizeof(ushort_t)); if ((ulong_t)pri->ri_source > segsize_l) return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM); pcoffset = (uchar_t *) (laddr + (ulong_t) pri->ri_source); while (chain != 0xffff) { if (!(pri->ri_flags & ADDITIVE)) chain = *((ushort_t *) pcoffset); else chain = 0xffff; switch(pri->ri_stype & SOURCE_MASK) { case BYTE_ADR: if (pri->ri_flags & ADDITIVE) *pcoffset += (uchar_t) (ptaddr->toff & BYTEMASK); else *pcoffset = (uchar_t) (ptaddr->toff & BYTEMASK); break; case SEG_ADR: psoffset = (ushort_t *) pcoffset; if (pri->ri_flags & ADDITIVE) *psoffset += ptaddr->tsel; else *psoffset = ptaddr->tsel; break; case FAR_ADR: psoffset = (ushort_t *) pcoffset; if (pri->ri_flags & ADDITIVE) { *psoffset += (ushort_t) (ptaddr->toff & WORDMASK); psoffset++; *psoffset += ptaddr->tsel; } else { *psoffset = (ushort_t) (ptaddr->toff & WORDMASK); psoffset++; *psoffset = ptaddr->tsel; } break; case OFF_ADR: psoffset = (ushort_t *) pcoffset; if (pri->ri_flags & ADDITIVE) { *psoffset += (ushort_t) (ptaddr->toff & WORDMASK); } else { *psoffset = (ushort_t) (ptaddr->toff & WORDMASK); } } if (!(pri->ri_flags & ADDITIVE)) { if (chain != 0xffff && (ulong_t)chain > segsize_l) return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM); pcoffset = (uchar_t *) (laddr + (ulong_t) chain); } if (--count < 0) { // check for internal loops return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM); } } return(NO_ERROR); }