1 /* $Id: kLdrModLX.c 102 2017-10-02 10:45:31Z bird $ */
2 /** @file
3  * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
4  */
5 
6 /*
7  * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use,
13  * copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following
16  * conditions:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  */
30 
31 /*******************************************************************************
32 *   Header Files                                                               *
33 *******************************************************************************/
34 #include <k/kLdr.h>
35 #include "kLdrInternal.h"
36 #include <k/kLdrFmts/lx.h>
37 
38 
39 /*******************************************************************************
40 *   Defined Constants And Macros                                               *
41 *******************************************************************************/
42 /** @def KLDRMODLX_STRICT
43  * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
44 #define KLDRMODLX_STRICT 1
45 
46 /** @def KLDRMODLX_ASSERT
47  * Assert that an expression is true when KLDR_STRICT is defined.
48  */
49 #ifdef KLDRMODLX_STRICT
50 # define KLDRMODLX_ASSERT(expr)  kHlpAssert(expr)
51 #else
52 # define KLDRMODLX_ASSERT(expr)  do {} while (0)
53 #endif
54 
55 
56 /*******************************************************************************
57 *   Structures and Typedefs                                                    *
58 *******************************************************************************/
59 /**
60  * Instance data for the LX module interpreter.
61  */
62 typedef struct KLDRMODLX
63 {
64     /** Pointer to the module. (Follows the section table.) */
65     PKLDRMOD                pMod;
66     /** Pointer to the user mapping. */
67     const void             *pvMapping;
68     /** The size of the mapped LX image. */
69     KSIZE                   cbMapped;
70     /** Reserved flags. */
71     KU32                    f32Reserved;
72 
73     /** The offset of the LX header. */
74     KLDRFOFF                offHdr;
75     /** Copy of the LX header. */
76     struct e32_exe          Hdr;
77 
78     /** Pointer to the loader section.
79      * Allocated together with this strcture. */
80     const KU8              *pbLoaderSection;
81     /** Pointer to the last byte in the loader section. */
82     const KU8              *pbLoaderSectionLast;
83     /** Pointer to the object table in the loader section. */
84     const struct o32_obj   *paObjs;
85     /** Pointer to the object page map table in the loader section. */
86     const struct o32_map   *paPageMappings;
87     /** Pointer to the resource table in the loader section. */
88     const struct rsrc32    *paRsrcs;
89     /** Pointer to the resident name table in the loader section. */
90     const KU8              *pbResNameTab;
91     /** Pointer to the entry table in the loader section. */
92     const KU8              *pbEntryTab;
93 
94     /** Pointer to the non-resident name table. */
95     KU8                    *pbNonResNameTab;
96     /** Pointer to the last byte in the non-resident name table. */
97     const KU8              *pbNonResNameTabLast;
98 
99     /** Pointer to the fixup section. */
100     KU8                    *pbFixupSection;
101     /** Pointer to the last byte in the fixup section. */
102     const KU8              *pbFixupSectionLast;
103     /** Pointer to the fixup page table within pvFixupSection. */
104     const KU32             *paoffPageFixups;
105     /** Pointer to the fixup record table within pvFixupSection. */
106     const KU8              *pbFixupRecs;
107     /** Pointer to the import module name table within pvFixupSection. */
108     const KU8              *pbImportMods;
109     /** Pointer to the import module name table within pvFixupSection. */
110     const KU8              *pbImportProcs;
111 } KLDRMODLX, *PKLDRMODLX;
112 
113 
114 /*******************************************************************************
115 *   Internal Functions                                                         *
116 *******************************************************************************/
117 static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
118 static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
119                                  PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
120 static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX);
121 static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal);
122 static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol);
123 static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable,
124                                                        const char *pchSymbol, KSIZE cchSymbol);
125 static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
126 static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc);
127 static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc);
128 static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb);
129 static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
130 static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle);
131 static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
132                                      PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
133 static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
134 static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved);
135 static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
136                             int iSelector, KLDRADDR uValue, KU32 fKind);
137 
138 
139 /**
140  * Create a loader module instance interpreting the executable image found
141  * in the specified file provider instance.
142  *
143  * @returns 0 on success and *ppMod pointing to a module instance.
144  *          On failure, a non-zero OS specific error code is returned.
145  * @param   pOps            Pointer to the registered method table.
146  * @param   pRdr            The file provider instance to use.
147  * @param   fFlags          Flags, MBZ.
148  * @param   enmCpuArch      The desired CPU architecture. KCPUARCH_UNKNOWN means
149  *                          anything goes, but with a preference for the current
150  *                          host architecture.
151  * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
152  * @param   ppMod           Where to store the module instance pointer.
153  */
kldrModLXCreate(PCKLDRMODOPS pOps,PKRDR pRdr,KU32 fFlags,KCPUARCH enmCpuArch,KLDRFOFF offNewHdr,PPKLDRMOD ppMod)154 static int kldrModLXCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
155 {
156     PKLDRMODLX pModLX;
157     int rc;
158     K_NOREF(fFlags);
159 
160     /*
161      * Create the instance data and do a minimal header validation.
162      */
163     rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
164     if (!rc)
165     {
166         /*
167          * Match up against the requested CPU architecture.
168          */
169         if (    enmCpuArch == KCPUARCH_UNKNOWN
170             ||  pModLX->pMod->enmArch == enmCpuArch)
171         {
172             pModLX->pMod->pOps = pOps;
173             pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
174             *ppMod = pModLX->pMod;
175             return 0;
176         }
177         rc = KLDR_ERR_CPU_ARCH_MISMATCH;
178     }
179     kHlpFree(pModLX);
180     return rc;
181 }
182 
183 
184 /**
185  * Separate function for reading creating the LX module instance to
186  * simplify cleanup on failure.
187  */
kldrModLXDoCreate(PKRDR pRdr,KLDRFOFF offNewHdr,PKLDRMODLX * ppModLX)188 static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX)
189 {
190     struct e32_exe Hdr;
191     PKLDRMODLX pModLX;
192     PKLDRMOD pMod;
193     KSIZE cb;
194     KSIZE cchFilename;
195     KU32 off, offEnd;
196     KU32 i;
197     int rc;
198     int fCanOptimizeMapping;
199     KU32 NextRVA;
200     *ppModLX = NULL;
201 
202     /*
203      * Read the signature and file header.
204      */
205     rc = kRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
206     if (rc)
207         return rc;
208     if (    Hdr.e32_magic[0] != E32MAGIC1
209         ||  Hdr.e32_magic[1] != E32MAGIC2)
210         return KLDR_ERR_UNKNOWN_FORMAT;
211 
212     /* We're not interested in anything but x86 images. */
213     if (    Hdr.e32_level != E32LEVEL
214         ||  Hdr.e32_border != E32LEBO
215         ||  Hdr.e32_worder != E32LEWO
216         ||  Hdr.e32_cpu < E32CPU286
217         ||  Hdr.e32_cpu > E32CPU486
218         ||  Hdr.e32_pagesize != OBJPAGELEN
219         )
220         return KLDR_ERR_LX_BAD_HEADER;
221 
222     /* Some rough sanity checks. */
223     offEnd = kRdrSize(pRdr) >= (KLDRFOFF)~(KU32)16 ? ~(KU32)16 : (KU32)kRdrSize(pRdr);
224     if (    Hdr.e32_itermap > offEnd
225         ||  Hdr.e32_datapage > offEnd
226         ||  Hdr.e32_nrestab > offEnd
227         ||  Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
228         ||  Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
229         ||  Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
230         ||  Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
231         return KLDR_ERR_LX_BAD_HEADER;
232 
233     /* Verify the loader section. */
234     offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
235     if (Hdr.e32_objtab < sizeof(Hdr))
236         return KLDR_ERR_LX_BAD_LOADER_SECTION;
237     off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
238     if (off > offEnd)
239         return KLDR_ERR_LX_BAD_LOADER_SECTION;
240     if (    Hdr.e32_objmap
241         &&  (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
242         return KLDR_ERR_LX_BAD_LOADER_SECTION;
243     if (    Hdr.e32_rsrccnt
244         && (   Hdr.e32_rsrctab < off
245             || Hdr.e32_rsrctab > offEnd
246             || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
247         return KLDR_ERR_LX_BAD_LOADER_SECTION;
248     if (    Hdr.e32_restab
249         &&  (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
250         return KLDR_ERR_LX_BAD_LOADER_SECTION;
251     if (    Hdr.e32_enttab
252         &&  (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd))
253         return KLDR_ERR_LX_BAD_LOADER_SECTION;
254     if (    Hdr.e32_dircnt
255         && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2))
256         return KLDR_ERR_LX_BAD_LOADER_SECTION;
257 
258     /* Verify the fixup section. */
259     off = offEnd;
260     offEnd = off + Hdr.e32_fixupsize;
261     if (    Hdr.e32_fpagetab
262         &&  (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
263     {
264         /*
265          * wlink mixes the fixup section and the loader section.
266          */
267         off = Hdr.e32_fpagetab;
268         offEnd = off + Hdr.e32_fixupsize;
269         Hdr.e32_ldrsize = off - Hdr.e32_objtab;
270     }
271     if (    Hdr.e32_frectab
272         &&  (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
273         return KLDR_ERR_LX_BAD_FIXUP_SECTION;
274     if (    Hdr.e32_impmod
275         &&  (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
276         return KLDR_ERR_LX_BAD_FIXUP_SECTION;
277     if (    Hdr.e32_impproc
278         &&  (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
279         return KLDR_ERR_LX_BAD_FIXUP_SECTION;
280 
281     /*
282      * Calc the instance size, allocate and initialize it.
283      */
284     cchFilename = kHlpStrLen(kRdrName(pRdr));
285     cb = K_ALIGN_Z(sizeof(KLDRMODLX), 8)
286        + K_ALIGN_Z(K_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
287        + K_ALIGN_Z(cchFilename + 1, 8)
288        + Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */
289     pModLX = (PKLDRMODLX)kHlpAlloc(cb);
290     if (!pModLX)
291         return KERR_NO_MEMORY;
292     *ppModLX = pModLX;
293 
294     /* KLDRMOD */
295     pMod = (PKLDRMOD)((KU8 *)pModLX + K_ALIGN_Z(sizeof(KLDRMODLX), 8));
296     pMod->pvData = pModLX;
297     pMod->pRdr = pRdr;
298     pMod->pOps = NULL;      /* set upon success. */
299     pMod->cSegments = Hdr.e32_objcnt;
300     pMod->cchFilename = (KU32)cchFilename;
301     pMod->pszFilename = (char *)K_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
302     kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
303     pMod->pszName = NULL; /* finalized further down */
304     pMod->cchName = 0;
305     pMod->fFlags = 0;
306     switch (Hdr.e32_cpu)
307     {
308         case E32CPU286:
309             pMod->enmCpu = KCPU_I80286;
310             pMod->enmArch = KCPUARCH_X86_16;
311             break;
312         case E32CPU386:
313             pMod->enmCpu = KCPU_I386;
314             pMod->enmArch = KCPUARCH_X86_32;
315             break;
316         case E32CPU486:
317             pMod->enmCpu = KCPU_I486;
318             pMod->enmArch = KCPUARCH_X86_32;
319             break;
320     }
321     pMod->enmEndian = KLDRENDIAN_LITTLE;
322     pMod->enmFmt = KLDRFMT_LX;
323     switch (Hdr.e32_mflags & E32MODMASK)
324     {
325         case E32MODEXE:
326             pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
327                 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
328                 : KLDRTYPE_EXECUTABLE_FIXED;
329             break;
330 
331         case E32MODDLL:
332         case E32PROTDLL:
333         case E32MODPROTDLL:
334             pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
335                 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
336                 : KLDRTYPE_SHARED_LIBRARY_FIXED;
337             break;
338 
339         case E32MODPDEV:
340         case E32MODVDEV:
341             pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
342             break;
343     }
344     pMod->u32Magic = 0;     /* set upon success. */
345 
346     /* KLDRMODLX */
347     pModLX->pMod = pMod;
348     pModLX->pvMapping = 0;
349     pModLX->cbMapped = 0;
350     pModLX->f32Reserved = 0;
351 
352     pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
353     kHlpMemCopy(&pModLX->Hdr, &Hdr, sizeof(Hdr));
354 
355     pModLX->pbLoaderSection = K_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
356     pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1;
357     pModLX->paObjs = NULL;
358     pModLX->paPageMappings = NULL;
359     pModLX->paRsrcs = NULL;
360     pModLX->pbResNameTab = NULL;
361     pModLX->pbEntryTab = NULL;
362 
363     pModLX->pbNonResNameTab = NULL;
364     pModLX->pbNonResNameTabLast = NULL;
365 
366     pModLX->pbFixupSection = NULL;
367     pModLX->pbFixupSectionLast = NULL;
368     pModLX->paoffPageFixups = NULL;
369     pModLX->pbFixupRecs = NULL;
370     pModLX->pbImportMods = NULL;
371     pModLX->pbImportProcs = NULL;
372 
373     /*
374      * Read the loader data.
375      */
376     rc = kRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
377     if (rc)
378         return rc;
379     ((KU8 *)pModLX->pbLoaderSectionLast)[1] = 0;
380     ((KU8 *)pModLX->pbLoaderSectionLast)[2] = 0;
381     if (pModLX->Hdr.e32_objcnt)
382         pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
383     if (pModLX->Hdr.e32_objmap)
384         pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
385     if (pModLX->Hdr.e32_rsrccnt)
386         pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
387     if (pModLX->Hdr.e32_restab)
388         pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
389     if (pModLX->Hdr.e32_enttab)
390         pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
391 
392     /*
393      * Get the soname from the resident name table.
394      * Very convenient that it's the 0 ordinal, because then we get a
395      * free string terminator.
396      * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
397      */
398     if (pModLX->pbResNameTab)
399         pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
400                                                                           pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
401                                                                           0);
402     if (!pMod->pszName)
403         return KLDR_ERR_LX_NO_SONAME;
404     pMod->cchName = *(const KU8 *)pMod->pszName++;
405     if (pMod->cchName != kHlpStrLen(pMod->pszName))
406         return KLDR_ERR_LX_BAD_SONAME;
407 
408     /*
409      * Quick validation of the object table.
410      */
411     cb = 0;
412     for (i = 0; i < pMod->cSegments; i++)
413     {
414         if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
415             return KLDR_ERR_LX_BAD_OBJECT_TABLE;
416         if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
417             return KLDR_ERR_LX_BAD_OBJECT_TABLE;
418         if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
419             return KLDR_ERR_LX_BAD_OBJECT_TABLE;
420         if (    pModLX->paObjs[i].o32_mapsize
421             &&  (   (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
422                  || (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
423                      > pModLX->pbLoaderSectionLast))
424             return KLDR_ERR_LX_BAD_OBJECT_TABLE;
425         if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC))
426         {
427             if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
428                 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
429             if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
430                 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
431         }
432     }
433 
434     /*
435      * Check if we can optimize the mapping by using a different
436      * object alignment. The linker typically uses 64KB alignment,
437      * we can easily get away with page alignment in most cases.
438      */
439     fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL));
440     NextRVA = 0;
441 
442     /*
443      * Setup the KLDRMOD segment array.
444      */
445     for (i = 0; i < pMod->cSegments; i++)
446     {
447         /* unused */
448         pMod->aSegments[i].pvUser = NULL;
449         pMod->aSegments[i].MapAddress = 0;
450         pMod->aSegments[i].pchName = NULL;
451         pMod->aSegments[i].cchName = 0;
452         pMod->aSegments[i].offFile = -1;
453         pMod->aSegments[i].cbFile = -1;
454         pMod->aSegments[i].SelFlat = 0;
455         pMod->aSegments[i].Sel16bit = 0;
456 
457         /* flags */
458         pMod->aSegments[i].fFlags = 0;
459         if (pModLX->paObjs[i].o32_flags & OBJBIGDEF)
460             pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT;
461         if (pModLX->paObjs[i].o32_flags & OBJALIAS16)
462             pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16;
463         if (pModLX->paObjs[i].o32_flags & OBJCONFORM)
464             pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM;
465         if (pModLX->paObjs[i].o32_flags & OBJIOPL)
466             pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL;
467 
468         /* size and addresses */
469         pMod->aSegments[i].Alignment   = OBJPAGELEN;
470         pMod->aSegments[i].cb          = pModLX->paObjs[i].o32_size;
471         pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
472         pMod->aSegments[i].RVA         = NextRVA;
473         if (    fCanOptimizeMapping
474             ||  i + 1 >= pMod->cSegments
475             ||  (pModLX->paObjs[i].o32_flags & OBJRSRC)
476             ||  (pModLX->paObjs[i + 1].o32_flags & OBJRSRC))
477             pMod->aSegments[i].cbMapped = K_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN);
478         else
479             pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
480         NextRVA += (KU32)pMod->aSegments[i].cbMapped;
481 
482         /* protection */
483         switch (  pModLX->paObjs[i].o32_flags
484                 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
485         {
486             case 0:
487             case OBJSHARED:
488                 pMod->aSegments[i].enmProt = KPROT_NOACCESS;
489                 break;
490             case OBJREAD:
491             case OBJREAD | OBJSHARED:
492                 pMod->aSegments[i].enmProt = KPROT_READONLY;
493                 break;
494             case OBJWRITE:
495             case OBJWRITE | OBJREAD:
496                 pMod->aSegments[i].enmProt = KPROT_WRITECOPY;
497                 break;
498             case OBJWRITE | OBJSHARED:
499             case OBJWRITE | OBJSHARED | OBJREAD:
500                 pMod->aSegments[i].enmProt = KPROT_READWRITE;
501                 break;
502             case OBJEXEC:
503             case OBJEXEC | OBJSHARED:
504                 pMod->aSegments[i].enmProt = KPROT_EXECUTE;
505                 break;
506             case OBJEXEC | OBJREAD:
507             case OBJEXEC | OBJREAD | OBJSHARED:
508                 pMod->aSegments[i].enmProt = KPROT_EXECUTE_READ;
509                 break;
510             case OBJEXEC | OBJWRITE:
511             case OBJEXEC | OBJWRITE | OBJREAD:
512                 pMod->aSegments[i].enmProt = KPROT_EXECUTE_WRITECOPY;
513                 break;
514             case OBJEXEC | OBJWRITE | OBJSHARED:
515             case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
516                 pMod->aSegments[i].enmProt = KPROT_EXECUTE_READWRITE;
517                 break;
518         }
519         if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
520             pMod->aSegments[i].enmProt = KPROT_READONLY;
521         /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
522         pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
523         pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
524     }
525 
526     /* set the mapping size */
527     pModLX->cbMapped = NextRVA;
528 
529     /*
530      * We're done.
531      */
532     *ppModLX = pModLX;
533     return 0;
534 }
535 
536 
537 /** @copydoc KLDRMODOPS::pfnDestroy */
kldrModLXDestroy(PKLDRMOD pMod)538 static int kldrModLXDestroy(PKLDRMOD pMod)
539 {
540     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
541     int rc = 0;
542     KLDRMODLX_ASSERT(!pModLX->pvMapping);
543 
544     if (pMod->pRdr)
545     {
546         rc = kRdrClose(pMod->pRdr);
547         pMod->pRdr = NULL;
548     }
549     if (pModLX->pbNonResNameTab)
550     {
551         kHlpFree(pModLX->pbNonResNameTab);
552         pModLX->pbNonResNameTab = NULL;
553     }
554     if (pModLX->pbFixupSection)
555     {
556         kHlpFree(pModLX->pbFixupSection);
557         pModLX->pbFixupSection = NULL;
558     }
559     pMod->u32Magic = 0;
560     pMod->pOps = NULL;
561     kHlpFree(pModLX);
562     return rc;
563 }
564 
565 
566 /**
567  * Resolved base address aliases.
568  *
569  * @param   pModLX          The interpreter module instance
570  * @param   pBaseAddress    The base address, IN & OUT.
571  */
kldrModLXResolveBaseAddress(PKLDRMODLX pModLX,PKLDRADDR pBaseAddress)572 static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
573 {
574     if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
575         *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
576     else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
577         *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
578 }
579 
580 
581 /** @copydoc kLdrModQuerySymbol */
kldrModLXQuerySymbol(PKLDRMOD pMod,const void * pvBits,KLDRADDR BaseAddress,KU32 iSymbol,const char * pchSymbol,KSIZE cchSymbol,const char * pszVersion,PFNKLDRMODGETIMPORT pfnGetForwarder,void * pvUser,PKLDRADDR puValue,KU32 * pfKind)582 static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
583                                 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
584                                 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
585 {
586     PKLDRMODLX                  pModLX = (PKLDRMODLX)pMod->pvData;
587     KU32                        iOrdinal;
588     int                         rc;
589     const struct b32_bundle     *pBundle;
590     K_NOREF(pvBits);
591     K_NOREF(pszVersion);
592 
593     /*
594      * Give up at once if there is no entry table.
595      */
596     if (!pModLX->Hdr.e32_enttab)
597         return KLDR_ERR_SYMBOL_NOT_FOUND;
598 
599     /*
600      * Translate the symbol name into an ordinal.
601      */
602     if (pchSymbol)
603     {
604         rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol);
605         if (rc)
606             return rc;
607     }
608 
609     /*
610      * Iterate the entry table.
611      * (The entry table is made up of bundles of similar exports.)
612      */
613     iOrdinal = 1;
614     pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
615     while (pBundle->b32_cnt && iOrdinal <= iSymbol)
616     {
617         static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 };
618 
619         /*
620          * Check for a hit first.
621          */
622         iOrdinal += pBundle->b32_cnt;
623         if (iSymbol < iOrdinal)
624         {
625             KU32 offObject;
626             const struct e32_entry *pEntry = (const struct e32_entry *)((KUPTR)(pBundle + 1)
627                                                                         +   (iSymbol - (iOrdinal - pBundle->b32_cnt))
628                                                                           * s_cbEntry[pBundle->b32_type]);
629 
630             /*
631              * Calculate the return address.
632              */
633             kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
634             switch (pBundle->b32_type)
635             {
636                 /* empty bundles are place holders unused ordinal ranges. */
637                 case EMPTY:
638                     return KLDR_ERR_SYMBOL_NOT_FOUND;
639 
640                 /* e32_flags + a 16-bit offset. */
641                 case ENTRY16:
642                     offObject = pEntry->e32_variant.e32_offset.offset16;
643                     if (pfKind)
644                         *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
645                     break;
646 
647                 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
648                 case GATE16:
649                     offObject = pEntry->e32_variant.e32_callgate.offset;
650                     if (pfKind)
651                         *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
652                     break;
653 
654                 /* e32_flags + a 32-bit offset. */
655                 case ENTRY32:
656                     offObject = pEntry->e32_variant.e32_offset.offset32;
657                     if (pfKind)
658                         *pfKind = KLDRSYMKIND_32BIT;
659                     break;
660 
661                 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
662                 case ENTRYFWD:
663                     return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
664 
665                 default:
666                     /* anyone actually using TYPEINFO will end up here. */
667                     KLDRMODLX_ASSERT(!"Bad bundle type");
668                     return KLDR_ERR_LX_BAD_BUNDLE;
669             }
670 
671             /*
672              * Validate the object number and calc the return address.
673              */
674             if (    pBundle->b32_obj <= 0
675                 ||  pBundle->b32_obj > pMod->cSegments)
676                 return KLDR_ERR_LX_BAD_BUNDLE;
677             if (puValue)
678                 *puValue = BaseAddress
679                          + offObject
680                          + pMod->aSegments[pBundle->b32_obj - 1].RVA;
681             return 0;
682         }
683 
684         /*
685          * Skip the bundle.
686          */
687         if (pBundle->b32_type > ENTRYFWD)
688         {
689             KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
690             return KLDR_ERR_LX_BAD_BUNDLE;
691         }
692         if (pBundle->b32_type == 0)
693             pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2);
694         else
695             pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
696     }
697 
698     return KLDR_ERR_SYMBOL_NOT_FOUND;
699 }
700 
701 
702 /**
703  * Do name lookup.
704  *
705  * @returns See kLdrModQuerySymbol.
706  * @param   pModLX      The module to lookup the symbol in.
707  * @param   pchSymbol   The symbol to lookup.
708  * @param   cchSymbol   The symbol name length.
709  * @param   piSymbol    Where to store the symbol ordinal.
710  */
kldrModLXDoNameLookup(PKLDRMODLX pModLX,const char * pchSymbol,KSIZE cchSymbol,KU32 * piSymbol)711 static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol)
712 {
713 
714     /*
715      * First do a hash table lookup.
716      */
717     /** @todo hash name table for speed. */
718 
719     /*
720      * Search the name tables.
721      */
722     const KU8 *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
723                                                          pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
724                                                          pchSymbol, cchSymbol);
725     if (!pbName)
726     {
727         if (!pModLX->pbNonResNameTab)
728         {
729             /* lazy load it */
730             /** @todo non-resident name table. */
731         }
732         if (pModLX->pbNonResNameTab)
733             pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
734                                                       pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1,
735                                                       pchSymbol, cchSymbol);
736     }
737     if (!pbName)
738         return KLDR_ERR_SYMBOL_NOT_FOUND;
739 
740     *piSymbol = *(const KU16 *)(pbName + 1 + *pbName);
741     return 0;
742 }
743 
744 
745 #if 0
746 /**
747  * Hash a symbol using the algorithm from sdbm.
748  *
749  * The following was is the documenation of the orignal sdbm functions:
750  *
751  * This algorithm was created for sdbm (a public-domain reimplementation of
752  * ndbm) database library. it was found to do well in scrambling bits,
753  * causing better distribution of the keys and fewer splits. it also happens
754  * to be a good general hashing function with good distribution. the actual
755  * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
756  * is the faster version used in gawk. [there is even a faster, duff-device
757  * version] the magic constant 65599 was picked out of thin air while
758  * experimenting with different constants, and turns out to be a prime.
759  * this is one of the algorithms used in berkeley db (see sleepycat) and
760  * elsewhere.
761  */
762 static KU32 kldrModLXDoHash(const char *pchSymbol, KU8 cchSymbol)
763 {
764     KU32 hash = 0;
765     int ch;
766 
767     while (     cchSymbol-- > 0
768            &&   (ch = *(unsigned const char *)pchSymbol++))
769         hash = ch + (hash << 6) + (hash << 16) - hash;
770 
771     return hash;
772 }
773 #endif
774 
775 
776 /**
777  * Lookup a name table entry by name.
778  *
779  * @returns Pointer to the name table entry if found.
780  * @returns NULL if not found.
781  * @param   pbNameTable     Pointer to the name table that should be searched.
782  * @param   cbNameTable     The size of the name table.
783  * @param   pchSymbol       The name of the symbol we're looking for.
784  * @param   cchSymbol       The length of the symbol name.
785  */
kldrModLXDoNameTableLookupByName(const KU8 * pbNameTable,KSSIZE cbNameTable,const char * pchSymbol,KSIZE cchSymbol)786 static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable,
787                                                    const char *pchSymbol, KSIZE cchSymbol)
788 {
789     /*
790      * Determin the namelength up front so we can skip anything which doesn't matches the length.
791      */
792     KU8 cbSymbol8Bit = (KU8)cchSymbol;
793     if (cbSymbol8Bit != cchSymbol)
794         return NULL; /* too long. */
795 
796     /*
797      * Walk the name table.
798      */
799     while (*pbNameTable != 0 && cbNameTable > 0)
800     {
801         const KU8 cbName = *pbNameTable;
802 
803         cbNameTable -= cbName + 1 + 2;
804         if (cbNameTable < 0)
805             break;
806 
807         if (    cbName == cbSymbol8Bit
808             &&  !kHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
809             return pbNameTable;
810 
811         /* next entry */
812         pbNameTable += cbName + 1 + 2;
813     }
814 
815     return NULL;
816 }
817 
818 
819 /**
820  * Deal with a forwarder entry.
821  *
822  * @returns See kLdrModQuerySymbol.
823  * @param   pModLX          The PE module interpreter instance.
824  * @param   pEntry          The forwarder entry.
825  * @param   pfnGetForwarder The callback for resolving forwarder symbols. (optional)
826  * @param   pvUser          The user argument for the callback.
827  * @param   puValue         Where to put the value. (optional)
828  * @param   pfKind          Where to put the symbol kind. (optional)
829  */
kldrModLXDoForwarderQuery(PKLDRMODLX pModLX,const struct e32_entry * pEntry,PFNKLDRMODGETIMPORT pfnGetForwarder,void * pvUser,PKLDRADDR puValue,KU32 * pfKind)830 static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
831                                      PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
832 {
833     int rc;
834     KU32 iSymbol;
835     const char *pchSymbol;
836     KU8 cchSymbol;
837 
838     if (!pfnGetForwarder)
839         return KLDR_ERR_FORWARDER_SYMBOL;
840 
841     /*
842      * Validate the entry import module ordinal.
843      */
844     if (    !pEntry->e32_variant.e32_fwd.modord
845         ||  pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
846         return KLDR_ERR_LX_BAD_FORWARDER;
847 
848     /*
849      * Figure out the parameters.
850      */
851     if (pEntry->e32_flags & FWD_ORDINAL)
852     {
853         iSymbol = pEntry->e32_variant.e32_fwd.value;
854         pchSymbol = NULL;                   /* no symbol name. */
855         cchSymbol = 0;
856     }
857     else
858     {
859         const KU8 *pbName;
860 
861         /* load the fixup section if necessary. */
862         if (!pModLX->pbImportProcs)
863         {
864             rc = kldrModLXDoLoadFixupSection(pModLX);
865             if (rc)
866                 return rc;
867         }
868 
869         /* Make name pointer. */
870         pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
871         if (    pbName >= pModLX->pbFixupSectionLast
872             ||  pbName < pModLX->pbFixupSection
873             || !*pbName)
874             return KLDR_ERR_LX_BAD_FORWARDER;
875 
876 
877         /* check for '#' name. */
878         if (pbName[1] == '#')
879         {
880             KU8         cbLeft = *pbName;
881             const KU8  *pb = pbName + 1;
882             unsigned    uBase;
883 
884             /* base detection */
885             uBase = 10;
886             if (    cbLeft > 1
887                 &&  pb[1] == '0'
888                 &&  (pb[2] == 'x' || pb[2] == 'X'))
889             {
890                 uBase = 16;
891                 pb += 2;
892                 cbLeft -= 2;
893             }
894 
895             /* ascii to integer */
896             iSymbol = 0;
897             while (cbLeft-- > 0)
898             {
899                 /* convert char to digit. */
900                 unsigned uDigit = *pb++;
901                 if (uDigit >= '0' && uDigit <= '9')
902                     uDigit -= '0';
903                 else if (uDigit >= 'a' && uDigit <= 'z')
904                     uDigit -= 'a' + 10;
905                 else if (uDigit >= 'A' && uDigit <= 'Z')
906                     uDigit -= 'A' + 10;
907                 else if (!uDigit)
908                     break;
909                 else
910                     return KLDR_ERR_LX_BAD_FORWARDER;
911                 if (uDigit >= uBase)
912                     return KLDR_ERR_LX_BAD_FORWARDER;
913 
914                 /* insert the digit */
915                 iSymbol *= uBase;
916                 iSymbol += uDigit;
917             }
918             if (!iSymbol)
919                 return KLDR_ERR_LX_BAD_FORWARDER;
920 
921             pchSymbol = NULL;               /* no symbol name. */
922             cchSymbol = 0;
923         }
924         else
925         {
926             pchSymbol = (char *)pbName + 1;
927             cchSymbol = *pbName;
928             iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
929         }
930     }
931 
932     /*
933      * Resolve the forwarder.
934      */
935     rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser);
936     if (!rc && pfKind)
937         *pfKind |= KLDRSYMKIND_FORWARDER;
938     return rc;
939 }
940 
941 
942 /**
943  * Loads the fixup section from the executable image.
944  *
945  * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
946  *
947  * @returns 0 on success, non-zero kLdr or native status code on failure.
948  * @param   pModLX          The PE module interpreter instance.
949  */
kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)950 static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
951 {
952     int rc;
953     KU32 off;
954     void *pv;
955 
956     pv = kHlpAlloc(pModLX->Hdr.e32_fixupsize);
957     if (!pv)
958         return KERR_NO_MEMORY;
959 
960     off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize;
961     rc = kRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize,
962                      off + pModLX->offHdr);
963     if (!rc)
964     {
965         pModLX->pbFixupSection = pv;
966         pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize;
967         KLDRMODLX_ASSERT(!pModLX->paoffPageFixups);
968         if (pModLX->Hdr.e32_fpagetab)
969             pModLX->paoffPageFixups = (const KU32 *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off);
970         KLDRMODLX_ASSERT(!pModLX->pbFixupRecs);
971         if (pModLX->Hdr.e32_frectab)
972             pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off;
973         KLDRMODLX_ASSERT(!pModLX->pbImportMods);
974         if (pModLX->Hdr.e32_impmod)
975             pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off;
976         KLDRMODLX_ASSERT(!pModLX->pbImportProcs);
977         if (pModLX->Hdr.e32_impproc)
978             pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off;
979     }
980     else
981         kHlpFree(pv);
982     return rc;
983 }
984 
985 
986 /** @copydoc kLdrModEnumSymbols */
kldrModLXEnumSymbols(PKLDRMOD pMod,const void * pvBits,KLDRADDR BaseAddress,KU32 fFlags,PFNKLDRMODENUMSYMS pfnCallback,void * pvUser)987 static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
988                                 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
989 {
990     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
991     const struct b32_bundle *pBundle;
992     KU32 iOrdinal;
993     int rc = 0;
994     K_NOREF(pvBits);
995     K_NOREF(fFlags);
996 
997     kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
998 
999     /*
1000      * Enumerate the entry table.
1001      * (The entry table is made up of bundles of similar exports.)
1002      */
1003     iOrdinal = 1;
1004     pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
1005     while (pBundle->b32_cnt && iOrdinal)
1006     {
1007         static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 };
1008 
1009         /*
1010          * Enum the entries in the bundle.
1011          */
1012         if (pBundle->b32_type != EMPTY)
1013         {
1014             const struct e32_entry *pEntry;
1015             KSIZE cbEntry;
1016             KLDRADDR BundleRVA;
1017             unsigned cLeft;
1018 
1019 
1020             /* Validate the bundle. */
1021             switch (pBundle->b32_type)
1022             {
1023                 case ENTRY16:
1024                 case GATE16:
1025                 case ENTRY32:
1026                     if (    pBundle->b32_obj <= 0
1027                         ||  pBundle->b32_obj > pMod->cSegments)
1028                         return KLDR_ERR_LX_BAD_BUNDLE;
1029                     BundleRVA = pMod->aSegments[pBundle->b32_obj - 1].RVA;
1030                     break;
1031 
1032                 case ENTRYFWD:
1033                     BundleRVA = 0;
1034                     break;
1035 
1036                 default:
1037                     /* anyone actually using TYPEINFO will end up here. */
1038                     KLDRMODLX_ASSERT(!"Bad bundle type");
1039                     return KLDR_ERR_LX_BAD_BUNDLE;
1040             }
1041 
1042             /* iterate the bundle entries. */
1043             cbEntry = s_cbEntry[pBundle->b32_type];
1044             pEntry = (const struct e32_entry *)(pBundle + 1);
1045             cLeft = pBundle->b32_cnt;
1046             while (cLeft-- > 0)
1047             {
1048                 KLDRADDR uValue;
1049                 KU32 fKind;
1050                 int fFoundName;
1051                 const KU8 *pbName;
1052 
1053                 /*
1054                  * Calc the symbol value and kind.
1055                  */
1056                 switch (pBundle->b32_type)
1057                 {
1058                     /* e32_flags + a 16-bit offset. */
1059                     case ENTRY16:
1060                         uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16;
1061                         fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
1062                         break;
1063 
1064                     /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
1065                     case GATE16:
1066                         uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset;
1067                         fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
1068                         break;
1069 
1070                     /* e32_flags + a 32-bit offset. */
1071                     case ENTRY32:
1072                         uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32;
1073                         fKind = KLDRSYMKIND_32BIT;
1074                         break;
1075 
1076                     /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
1077                     case ENTRYFWD:
1078                         uValue = 0; /** @todo implement enumeration of forwarders properly. */
1079                         fKind = KLDRSYMKIND_FORWARDER;
1080                         break;
1081 
1082                     default: /* shut up gcc. */
1083                         uValue = 0;
1084                         fKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE;
1085                         break;
1086                 }
1087 
1088                 /*
1089                  * Any symbol names?
1090                  */
1091                 fFoundName = 0;
1092 
1093                 /* resident name table. */
1094                 pbName = pModLX->pbResNameTab;
1095                 if (pbName)
1096                 {
1097                     do
1098                     {
1099                         pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal);
1100                         if (!pbName)
1101                             break;
1102                         fFoundName = 1;
1103                         rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser);
1104                         if (rc)
1105                             return rc;
1106 
1107                         /* skip to the next entry */
1108                         pbName += 1 + *pbName + 2;
1109                     } while (pbName < pModLX->pbLoaderSectionLast);
1110                 }
1111 
1112                 /* resident name table. */
1113                 pbName = pModLX->pbNonResNameTab;
1114                 /** @todo lazy load the non-resident name table. */
1115                 if (pbName)
1116                 {
1117                     do
1118                     {
1119                         pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal);
1120                         if (!pbName)
1121                             break;
1122                         fFoundName = 1;
1123                         rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser);
1124                         if (rc)
1125                             return rc;
1126 
1127                         /* skip to the next entry */
1128                         pbName += 1 + *pbName + 2;
1129                     } while (pbName < pModLX->pbLoaderSectionLast);
1130                 }
1131 
1132                 /*
1133                  * If no names, call once with the ordinal only.
1134                  */
1135                 if (!fFoundName)
1136                 {
1137                     rc = pfnCallback(pMod, iOrdinal, NULL, 0, NULL, uValue, fKind, pvUser);
1138                     if (rc)
1139                         return rc;
1140                 }
1141 
1142                 /* next */
1143                 iOrdinal++;
1144                 pEntry = (const struct e32_entry *)((KUPTR)pEntry + cbEntry);
1145             }
1146         }
1147 
1148         /*
1149          * The next bundle.
1150          */
1151         if (pBundle->b32_type > ENTRYFWD)
1152         {
1153             KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
1154             return KLDR_ERR_LX_BAD_BUNDLE;
1155         }
1156         if (pBundle->b32_type == 0)
1157             pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2);
1158         else
1159             pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
1160     }
1161 
1162     return 0;
1163 }
1164 
1165 
1166 /**
1167  * Lookup a name table entry by ordinal.
1168  *
1169  * @returns Pointer to the name table entry if found.
1170  * @returns NULL if not found.
1171  * @param   pbNameTable Pointer to the name table that should be searched.
1172  * @param   cbNameTable The size of the name table.
1173  * @param   iOrdinal    The ordinal to search for.
1174  */
kldrModLXDoNameTableLookupByOrdinal(const KU8 * pbNameTable,KSSIZE cbNameTable,KU32 iOrdinal)1175 static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal)
1176 {
1177     while (*pbNameTable != 0 && cbNameTable > 0)
1178     {
1179         const KU8   cbName = *pbNameTable;
1180         KU32        iName;
1181 
1182         cbNameTable -= cbName + 1 + 2;
1183         if (cbNameTable < 0)
1184             break;
1185 
1186         iName = *(pbNameTable + cbName + 1)
1187               | ((unsigned)*(pbNameTable + cbName + 2) << 8);
1188         if (iName == iOrdinal)
1189             return pbNameTable;
1190 
1191         /* next entry */
1192         pbNameTable += cbName + 1 + 2;
1193     }
1194 
1195     return NULL;
1196 }
1197 
1198 
1199 /** @copydoc kLdrModGetImport */
kldrModLXGetImport(PKLDRMOD pMod,const void * pvBits,KU32 iImport,char * pszName,KSIZE cchName)1200 static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
1201 {
1202     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
1203     const KU8  *pb;
1204     int         rc;
1205     K_NOREF(pvBits);
1206 
1207     /*
1208      * Validate
1209      */
1210     if (iImport >= pModLX->Hdr.e32_impmodcnt)
1211         return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1212 
1213     /*
1214      * Lazy loading the fixup section.
1215      */
1216     if (!pModLX->pbImportMods)
1217     {
1218         rc = kldrModLXDoLoadFixupSection(pModLX);
1219         if (rc)
1220             return rc;
1221     }
1222 
1223     /*
1224      * Iterate the module import table until we reach the requested import ordinal.
1225      */
1226     pb = pModLX->pbImportMods;
1227     while (iImport-- > 0)
1228         pb += *pb + 1;
1229 
1230     /*
1231      * Copy out the result.
1232      */
1233     if (*pb < cchName)
1234     {
1235         kHlpMemCopy(pszName, pb + 1, *pb);
1236         pszName[*pb] = '\0';
1237         rc = 0;
1238     }
1239     else
1240     {
1241         kHlpMemCopy(pszName, pb + 1, cchName);
1242         if (cchName)
1243             pszName[cchName - 1] = '\0';
1244         rc = KERR_BUFFER_OVERFLOW;
1245     }
1246 
1247     return rc;
1248 }
1249 
1250 
1251 /** @copydoc kLdrModNumberOfImports */
kldrModLXNumberOfImports(PKLDRMOD pMod,const void * pvBits)1252 static KI32 kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
1253 {
1254     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1255     K_NOREF(pvBits);
1256     return pModLX->Hdr.e32_impmodcnt;
1257 }
1258 
1259 
1260 /** @copydoc kLdrModGetStackInfo */
kldrModLXGetStackInfo(PKLDRMOD pMod,const void * pvBits,KLDRADDR BaseAddress,PKLDRSTACKINFO pStackInfo)1261 static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1262 {
1263     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1264     const KU32 i = pModLX->Hdr.e32_stackobj;
1265     K_NOREF(pvBits);
1266 
1267     if (    i
1268         &&  i <= pMod->cSegments
1269         &&  pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
1270         &&  pModLX->Hdr.e32_stacksize
1271         &&  pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
1272     {
1273 
1274         kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1275         pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
1276         pStackInfo->Address = BaseAddress
1277                             + pMod->aSegments[i - 1].RVA
1278                             + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
1279     }
1280     else
1281     {
1282         pStackInfo->Address = NIL_KLDRADDR;
1283         pStackInfo->LinkAddress = NIL_KLDRADDR;
1284     }
1285     pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
1286     pStackInfo->cbStackThread = 0;
1287 
1288     return 0;
1289 }
1290 
1291 
1292 /** @copydoc kLdrModQueryMainEntrypoint */
kldrModLXQueryMainEntrypoint(PKLDRMOD pMod,const void * pvBits,KLDRADDR BaseAddress,PKLDRADDR pMainEPAddress)1293 static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1294 {
1295     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1296     K_NOREF(pvBits);
1297 
1298     /*
1299      * Convert the address from the header.
1300      */
1301     kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1302     *pMainEPAddress = pModLX->Hdr.e32_startobj
1303                    && pModLX->Hdr.e32_startobj <= pMod->cSegments
1304                    && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1305         ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1306         : NIL_KLDRADDR;
1307     return 0;
1308 }
1309 
1310 
1311 /** @copydoc kLdrModEnumDbgInfo */
kldrModLXEnumDbgInfo(PKLDRMOD pMod,const void * pvBits,PFNKLDRENUMDBG pfnCallback,void * pvUser)1312 static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1313 {
1314     /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
1315     K_NOREF(pfnCallback);
1316     K_NOREF(pvUser);
1317 
1318     /*
1319      * Quit immediately if no debug info.
1320      */
1321     if (kldrModLXHasDbgInfo(pMod, pvBits))
1322         return 0;
1323 #if 0
1324     /*
1325      * Read the debug info and look for familiar magics and structures.
1326      */
1327     /** @todo */
1328 #endif
1329 
1330     return 0;
1331 }
1332 
1333 
1334 /** @copydoc kLdrModHasDbgInfo */
kldrModLXHasDbgInfo(PKLDRMOD pMod,const void * pvBits)1335 static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1336 {
1337     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1338     K_NOREF(pvBits);
1339 
1340     /*
1341      * Don't curretnly bother with linkers which doesn't advertise it in the header.
1342      */
1343     if (    !pModLX->Hdr.e32_debuginfo
1344         ||  !pModLX->Hdr.e32_debuglen)
1345         return KLDR_ERR_NO_DEBUG_INFO;
1346     return 0;
1347 }
1348 
1349 
1350 /** @copydoc kLdrModMap */
kldrModLXMap(PKLDRMOD pMod)1351 static int kldrModLXMap(PKLDRMOD pMod)
1352 {
1353     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
1354     unsigned    fFixed;
1355     void       *pvBase;
1356     int         rc;
1357 
1358     /*
1359      * Already mapped?
1360      */
1361     if (pModLX->pvMapping)
1362         return KLDR_ERR_ALREADY_MAPPED;
1363 
1364     /*
1365      * Allocate memory for it.
1366      */
1367     /* fixed image? */
1368     fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1369           || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1370     if (!fFixed)
1371         pvBase = NULL;
1372     else
1373     {
1374         pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
1375         if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
1376             return KLDR_ERR_ADDRESS_OVERFLOW;
1377     }
1378     rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed);
1379     if (rc)
1380         return rc;
1381 
1382     /*
1383      * Load the bits, apply page protection, and update the segment table.
1384      */
1385     rc = kldrModLXDoLoadBits(pModLX, pvBase);
1386     if (!rc)
1387         rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1388     if (!rc)
1389     {
1390         KU32 i;
1391         for (i = 0; i < pMod->cSegments; i++)
1392         {
1393             if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1394                 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
1395         }
1396         pModLX->pvMapping = pvBase;
1397     }
1398     else
1399         kHlpPageFree(pvBase, pModLX->cbMapped);
1400     return rc;
1401 }
1402 
1403 
1404 /**
1405  * Loads the LX pages into the specified memory mapping.
1406  *
1407  * @returns 0 on success.
1408  * @returns non-zero kLdr or OS status code on failure.
1409  *
1410  * @param   pModLX  The LX module interpreter instance.
1411  * @param   pvBits  Where to load the bits.
1412  */
kldrModLXDoLoadBits(PKLDRMODLX pModLX,void * pvBits)1413 static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1414 {
1415     const PKRDR pRdr = pModLX->pMod->pRdr;
1416     KU8 *pbTmpPage = NULL;
1417     int rc = 0;
1418     KU32 i;
1419 
1420     /*
1421      * Iterate the segments.
1422      */
1423     for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1424     {
1425         const struct o32_obj * const pObj = &pModLX->paObjs[i];
1426         const KU32      cPages = (KU32)(pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN);
1427         KU32            iPage;
1428         KU8            *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[i].RVA;
1429 
1430         /*
1431          * Iterate the page map pages.
1432          */
1433         for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1434         {
1435             const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1436             switch (pMap->o32_pageflags)
1437             {
1438                 case VALID:
1439                     if (pMap->o32_pagesize == OBJPAGELEN)
1440                         rc = kRdrRead(pRdr, pbPage, OBJPAGELEN,
1441                                          pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1442                     else if (pMap->o32_pagesize < OBJPAGELEN)
1443                     {
1444                         rc = kRdrRead(pRdr, pbPage, pMap->o32_pagesize,
1445                                          pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1446                         kHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1447                     }
1448                     else
1449                         rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1450                     break;
1451 
1452                 case ITERDATA:
1453                 case ITERDATA2:
1454                     /* make sure we've got a temp page .*/
1455                     if (!pbTmpPage)
1456                     {
1457                         pbTmpPage = kHlpAlloc(OBJPAGELEN + 256);
1458                         if (!pbTmpPage)
1459                             break;
1460                     }
1461                     /* validate the size. */
1462                     if (pMap->o32_pagesize > OBJPAGELEN + 252)
1463                     {
1464                         rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1465                         break;
1466                     }
1467 
1468                     /* read it and ensure 4 extra zero bytes. */
1469                     rc = kRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize,
1470                                      pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1471                     if (rc)
1472                         break;
1473                     kHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
1474 
1475                     /* unpack it into the image page. */
1476                     if (pMap->o32_pageflags == ITERDATA2)
1477                         rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1478                     else
1479                         rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1480                     break;
1481 
1482                 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1483                 case ZEROED:
1484                     kHlpMemSet(pbPage, 0, OBJPAGELEN);
1485                     break;
1486 
1487                 case RANGE:
1488                     KLDRMODLX_ASSERT(!"RANGE");
1489                     /* Falls through. */
1490                 default:
1491                     rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1492                     break;
1493             }
1494         }
1495         if (rc)
1496             break;
1497 
1498         /*
1499          * Zero the remaining pages.
1500          */
1501         if (iPage < cPages)
1502             kHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1503     }
1504 
1505     if (pbTmpPage)
1506         kHlpFree(pbTmpPage);
1507     return rc;
1508 }
1509 
1510 
1511 /**
1512  * Unpacks iterdata (aka EXEPACK).
1513  *
1514  * @returns 0 on success, non-zero kLdr status code on failure.
1515  * @param   pbDst       Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1516  * @param   pbSrc       The compressed source data.
1517  * @param   cbSrc       The file size of the compressed data. The source buffer
1518  *                      contains 4 additional zero bytes.
1519  */
kldrModLXDoIterDataUnpacking(KU8 * pbDst,const KU8 * pbSrc,int cbSrc)1520 static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc)
1521 {
1522     const struct LX_Iter   *pIter = (const struct LX_Iter *)pbSrc;
1523     int                     cbDst = OBJPAGELEN;
1524 
1525     /* Validate size of data. */
1526     if (cbSrc >= (int)OBJPAGELEN - 2)
1527         return KLDR_ERR_LX_BAD_ITERDATA;
1528 
1529     /*
1530      * Expand the page.
1531      */
1532     while (cbSrc > 0 && pIter->LX_nIter)
1533     {
1534         if (pIter->LX_nBytes == 1)
1535         {
1536             /*
1537              * Special case - one databyte.
1538              */
1539             cbDst -= pIter->LX_nIter;
1540             if (cbDst < 0)
1541                 return KLDR_ERR_LX_BAD_ITERDATA;
1542 
1543             cbSrc -= 4 + 1;
1544             if (cbSrc < -4)
1545                 return KLDR_ERR_LX_BAD_ITERDATA;
1546 
1547             kHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1548             pbDst += pIter->LX_nIter;
1549             pIter++;
1550         }
1551         else
1552         {
1553             /*
1554              * General.
1555              */
1556             int i;
1557 
1558             cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1559             if (cbDst < 0)
1560                 return KLDR_ERR_LX_BAD_ITERDATA;
1561 
1562             cbSrc -= 4 + pIter->LX_nBytes;
1563             if (cbSrc < -4)
1564                 return KLDR_ERR_LX_BAD_ITERDATA;
1565 
1566             for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
1567                 kHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
1568             pIter   = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1569         }
1570     }
1571 
1572     /*
1573      * Zero remainder of the page.
1574      */
1575     if (cbDst > 0)
1576         kHlpMemSet(pbDst, 0, cbDst);
1577 
1578     return 0;
1579 }
1580 
1581 
1582 /**
1583  * Unpacks iterdata (aka EXEPACK).
1584  *
1585  * @returns 0 on success, non-zero kLdr status code on failure.
1586  * @param   pbDst       Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1587  * @param   pbSrc       The compressed source data.
1588  * @param   cbSrc       The file size of the compressed data. The source buffer
1589  *                      contains 4 additional zero bytes.
1590  */
kldrModLXDoIterData2Unpacking(KU8 * pbDst,const KU8 * pbSrc,int cbSrc)1591 static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc)
1592 {
1593     int cbDst = OBJPAGELEN;
1594 
1595     while (cbSrc > 0)
1596     {
1597         /*
1598          * Bit 0 and 1 is the encoding type.
1599          */
1600         switch (*pbSrc & 0x03)
1601         {
1602             /*
1603              *
1604              *  0  1  2  3  4  5  6  7
1605              *  type  |              |
1606              *        ----------------
1607              *             cb         <cb bytes of data>
1608              *
1609              * Bits 2-7 is, if not zero, the length of an uncompressed run
1610              * starting at the following byte.
1611              *
1612              *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1613              *  type  |              |  |                    | |                     |
1614              *        ----------------  ---------------------- -----------------------
1615              *             zero                 cb                 char to multiply
1616              *
1617              * If the bits are zero, the following two bytes describes a 1 byte interation
1618              * run. First byte is count, second is the byte to copy. A count of zero is
1619              * means end of data, and we simply stops. In that case the rest of the data
1620              * should be zero.
1621              */
1622             case 0:
1623             {
1624                 if (*pbSrc)
1625                 {
1626                     const int cb = *pbSrc >> 2;
1627                     cbDst -= cb;
1628                     if (cbDst < 0)
1629                         return KLDR_ERR_LX_BAD_ITERDATA2;
1630                     cbSrc -= cb + 1;
1631                     if (cbSrc < 0)
1632                         return KLDR_ERR_LX_BAD_ITERDATA2;
1633                     kHlpMemCopy(pbDst, ++pbSrc, cb);
1634                     pbDst += cb;
1635                     pbSrc += cb;
1636                 }
1637                 else if (cbSrc < 2)
1638                     return KLDR_ERR_LX_BAD_ITERDATA2;
1639                 else
1640                 {
1641                     const int cb = pbSrc[1];
1642                     if (!cb)
1643                         goto l_endloop;
1644                     cbDst -= cb;
1645                     if (cbDst < 0)
1646                         return KLDR_ERR_LX_BAD_ITERDATA2;
1647                     cbSrc -= 3;
1648                     if (cbSrc < 0)
1649                         return KLDR_ERR_LX_BAD_ITERDATA2;
1650                     kHlpMemSet(pbDst, pbSrc[2], cb);
1651                     pbDst += cb;
1652                     pbSrc += 3;
1653                 }
1654                 break;
1655             }
1656 
1657 
1658             /*
1659              *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
1660              *  type  |  |  |     |  |                       |
1661              *        ----  -------  -------------------------
1662              *        cb1   cb2 - 3          offset            <cb1 bytes of data>
1663              *
1664              * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1665              * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1666              * data relative to the current position. The data copied as you would expect it to be.
1667              */
1668             case 1:
1669             {
1670                 cbSrc -= 2;
1671                 if (cbSrc < 0)
1672                     return KLDR_ERR_LX_BAD_ITERDATA2;
1673                 else
1674                 {
1675                     const unsigned  off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1676                     const int       cb1 = (*pbSrc >> 2) & 3;
1677                     const int       cb2 = ((*pbSrc >> 4) & 7) + 3;
1678 
1679                     pbSrc += 2;
1680                     cbSrc -= cb1;
1681                     if (cbSrc < 0)
1682                         return KLDR_ERR_LX_BAD_ITERDATA2;
1683                     cbDst -= cb1;
1684                     if (cbDst < 0)
1685                         return KLDR_ERR_LX_BAD_ITERDATA2;
1686                     kHlpMemCopy(pbDst, pbSrc, cb1);
1687                     pbDst += cb1;
1688                     pbSrc += cb1;
1689 
1690                     if (off > OBJPAGELEN - (unsigned)cbDst)
1691                         return KLDR_ERR_LX_BAD_ITERDATA2;
1692                     cbDst -= cb2;
1693                     if (cbDst < 0)
1694                         return KLDR_ERR_LX_BAD_ITERDATA2;
1695                     kHlpMemMove(pbDst, pbDst - off, cb2);
1696                     pbDst += cb2;
1697                 }
1698                 break;
1699             }
1700 
1701 
1702             /*
1703              *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
1704              *  type  |  |  |                                |
1705              *        ----  ----------------------------------
1706              *       cb-3               offset
1707              *
1708              * Two bytes layed out as described above.
1709              * The cb(+3) and offset describes an amount of data to be copied from the expanded
1710              * data relative to the current position.
1711              *
1712              * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1713              */
1714             case 2:
1715             {
1716                 cbSrc -= 2;
1717                 if (cbSrc < 0)
1718                     return KLDR_ERR_LX_BAD_ITERDATA2;
1719                 else
1720                 {
1721                     const unsigned  off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4);
1722                     const int       cb = ((*pbSrc >> 2) & 3) + 3;
1723 
1724                     pbSrc += 2;
1725                     if (off > OBJPAGELEN - (unsigned)cbDst)
1726                         return KLDR_ERR_LX_BAD_ITERDATA2;
1727                     cbDst -= cb;
1728                     if (cbDst < 0)
1729                         return KLDR_ERR_LX_BAD_ITERDATA2;
1730                     kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1731                     pbDst += cb;
1732                 }
1733                 break;
1734             }
1735 
1736 
1737             /*
1738              *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1739              *  type  |        |  |              |  |                                |
1740              *        ----------  ----------------  ----------------------------------
1741              *           cb1            cb2                      offset                <cb1 bytes of data>
1742              *
1743              * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1744              * The cb2 and offset describes an amount of data to be copied from the expanded
1745              * data relative to the current position.
1746              *
1747              * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1748              */
1749             case 3:
1750             {
1751                 cbSrc -= 3;
1752                 if (cbSrc < 0)
1753                     return KLDR_ERR_LX_BAD_ITERDATA2;
1754                 else
1755                 {
1756                     const int       cb1 = (*pbSrc >> 2) & 0xf;
1757                     const int       cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1758                     const unsigned  off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1759 
1760                     pbSrc += 3;
1761                     cbSrc -= cb1;
1762                     if (cbSrc < 0)
1763                         return KLDR_ERR_LX_BAD_ITERDATA2;
1764                     cbDst -= cb1;
1765                     if (cbDst < 0)
1766                         return KLDR_ERR_LX_BAD_ITERDATA2;
1767                     kHlpMemCopy(pbDst, pbSrc, cb1);
1768                     pbDst += cb1;
1769                     pbSrc += cb1;
1770 
1771                     if (off > OBJPAGELEN - (unsigned)cbDst)
1772                         return KLDR_ERR_LX_BAD_ITERDATA2;
1773                     cbDst -= cb2;
1774                     if (cbDst < 0)
1775                         return KLDR_ERR_LX_BAD_ITERDATA2;
1776                     kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1777                     pbDst += cb2;
1778                 }
1779                 break;
1780             }
1781         } /* type switch. */
1782     } /* unpack loop */
1783 
1784 l_endloop:
1785 
1786 
1787     /*
1788      * Zero remainder of the page.
1789      */
1790     if (cbDst > 0)
1791         kHlpMemSet(pbDst, 0, cbDst);
1792 
1793     return 0;
1794 }
1795 
1796 
1797 /**
1798  * Special memcpy employed by the iterdata2 algorithm.
1799  *
1800  * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
1801  * has if src is very close to the destination.
1802  *
1803  * @param   pbDst   Destination pointer.
1804  * @param   pbSrc   Source pointer. Will always be <= pbDst.
1805  * @param   cb      Amount of data to be copied.
1806  * @remark  This assumes that unaligned word and dword access is fine.
1807  */
kLdrModLXMemCopyW(KU8 * pbDst,const KU8 * pbSrc,int cb)1808 static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb)
1809 {
1810     switch (pbDst - pbSrc)
1811     {
1812         case 0:
1813         case 1:
1814         case 2:
1815         case 3:
1816             /* 16-bit copy (unaligned) */
1817             if (cb & 1)
1818                 *pbDst++ = *pbSrc++;
1819             for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
1820                 *(KU16 *)pbDst = *(const KU16 *)pbSrc;
1821             break;
1822 
1823         default:
1824             /* 32-bit copy (unaligned) */
1825             if (cb & 1)
1826                 *pbDst++ = *pbSrc++;
1827             if (cb & 2)
1828             {
1829                 *(KU16 *)pbDst = *(const KU16 *)pbSrc;
1830                 pbDst += 2;
1831                 pbSrc += 2;
1832             }
1833             for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
1834                 *(KU32 *)pbDst = *(const KU32 *)pbSrc;
1835             break;
1836     }
1837 }
1838 
1839 
1840 /**
1841  * Unprotects or protects the specified image mapping.
1842  *
1843  * @returns 0 on success.
1844  * @returns non-zero kLdr or OS status code on failure.
1845  *
1846  * @param   pModLX  The LX module interpreter instance.
1847  * @param   pvBits  The mapping to protect.
1848  * @param   UnprotectOrProtect  If 1 unprotect (i.e. make all writable), otherwise
1849  *          protect according to the object table.
1850  */
kldrModLXDoProtect(PKLDRMODLX pModLX,void * pvBits,unsigned fUnprotectOrProtect)1851 static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
1852 {
1853     KU32 i;
1854     PKLDRMOD pMod = pModLX->pMod;
1855 
1856     /*
1857      * Change object protection.
1858      */
1859     for (i = 0; i < pMod->cSegments; i++)
1860     {
1861         int rc;
1862         void *pv;
1863         KPROT enmProt;
1864 
1865         /* calc new protection. */
1866         enmProt = pMod->aSegments[i].enmProt;
1867         if (fUnprotectOrProtect)
1868         {
1869             switch (enmProt)
1870             {
1871                 case KPROT_NOACCESS:
1872                 case KPROT_READONLY:
1873                 case KPROT_READWRITE:
1874                 case KPROT_WRITECOPY:
1875                     enmProt = KPROT_READWRITE;
1876                     break;
1877                 case KPROT_EXECUTE:
1878                 case KPROT_EXECUTE_READ:
1879                 case KPROT_EXECUTE_READWRITE:
1880                 case KPROT_EXECUTE_WRITECOPY:
1881                     enmProt = KPROT_EXECUTE_READWRITE;
1882                     break;
1883                 default:
1884                     KLDRMODLX_ASSERT(!"bad enmProt");
1885                     return -1;
1886             }
1887         }
1888         else
1889         {
1890             /* copy on write -> normal write. */
1891             if (enmProt == KPROT_EXECUTE_WRITECOPY)
1892                 enmProt = KPROT_EXECUTE_READWRITE;
1893             else if (enmProt == KPROT_WRITECOPY)
1894                 enmProt = KPROT_READWRITE;
1895         }
1896 
1897 
1898         /* calc the address and set page protection. */
1899         pv = (KU8 *)pvBits + pMod->aSegments[i].RVA;
1900 
1901         rc = kHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
1902         if (rc)
1903             break;
1904 
1905         /** @todo the gap page should be marked NOACCESS! */
1906     }
1907 
1908     return 0;
1909 }
1910 
1911 
1912 /** @copydoc kLdrModUnmap */
kldrModLXUnmap(PKLDRMOD pMod)1913 static int kldrModLXUnmap(PKLDRMOD pMod)
1914 {
1915     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
1916     KU32        i;
1917     int         rc;
1918 
1919     /*
1920      * Mapped?
1921      */
1922     if (!pModLX->pvMapping)
1923         return KLDR_ERR_NOT_MAPPED;
1924 
1925     /*
1926      * Free the mapping and update the segments.
1927      */
1928     rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
1929     KLDRMODLX_ASSERT(!rc);
1930     pModLX->pvMapping = NULL;
1931 
1932     for (i = 0; i < pMod->cSegments; i++)
1933         pMod->aSegments[i].MapAddress = 0;
1934 
1935     return rc;
1936 }
1937 
1938 
1939 /** @copydoc kLdrModAllocTLS */
kldrModLXAllocTLS(PKLDRMOD pMod,void * pvMapping)1940 static int kldrModLXAllocTLS(PKLDRMOD pMod, void *pvMapping)
1941 {
1942     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
1943 
1944     /* no tls, just do the error checking. */
1945     if (   pvMapping == KLDRMOD_INT_MAP
1946         && pModLX->pvMapping)
1947         return KLDR_ERR_NOT_MAPPED;
1948     return 0;
1949 }
1950 
1951 
1952 /** @copydoc kLdrModFreeTLS */
kldrModLXFreeTLS(PKLDRMOD pMod,void * pvMapping)1953 static void kldrModLXFreeTLS(PKLDRMOD pMod, void *pvMapping)
1954 {
1955     /* no tls. */
1956     K_NOREF(pMod);
1957     K_NOREF(pvMapping);
1958 
1959 }
1960 
1961 
1962 /** @copydoc kLdrModReload */
kldrModLXReload(PKLDRMOD pMod)1963 static int kldrModLXReload(PKLDRMOD pMod)
1964 {
1965     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1966     int rc, rc2;
1967 
1968     /*
1969      * Mapped?
1970      */
1971     if (!pModLX->pvMapping)
1972         return KLDR_ERR_NOT_MAPPED;
1973 
1974     /*
1975      * Before doing anything we'll have to make all pages writable.
1976      */
1977     rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1978     if (rc)
1979         return rc;
1980 
1981     /*
1982      * Load the bits again.
1983      */
1984     rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping);
1985 
1986     /*
1987      * Restore protection.
1988      */
1989     rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1990     if (!rc && rc2)
1991         rc = rc2;
1992     return rc;
1993 }
1994 
1995 
1996 /** @copydoc kLdrModFixupMapping */
kldrModLXFixupMapping(PKLDRMOD pMod,PFNKLDRMODGETIMPORT pfnGetImport,void * pvUser)1997 static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1998 {
1999     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
2000     int rc, rc2;
2001 
2002     /*
2003      * Mapped?
2004      */
2005     if (!pModLX->pvMapping)
2006         return KLDR_ERR_NOT_MAPPED;
2007 
2008     /*
2009      * Before doing anything we'll have to make all pages writable.
2010      */
2011     rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
2012     if (rc)
2013         return rc;
2014 
2015     /*
2016      * Apply fixups and resolve imports.
2017      */
2018     rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (KUPTR)pModLX->pvMapping,
2019                                pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
2020 
2021     /*
2022      * Restore protection.
2023      */
2024     rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
2025     if (!rc && rc2)
2026         rc = rc2;
2027     return rc;
2028 }
2029 
2030 
2031 /** @copydoc kLdrModCallInit */
kldrModLXCallInit(PKLDRMOD pMod,void * pvMapping,KUPTR uHandle)2032 static int kldrModLXCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
2033 {
2034     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
2035     int rc;
2036 
2037     /*
2038      * Mapped?
2039      */
2040     if (pvMapping == KLDRMOD_INT_MAP)
2041     {
2042         pvMapping = (void *)pModLX->pvMapping;
2043         if (!pvMapping)
2044             return KLDR_ERR_NOT_MAPPED;
2045     }
2046 
2047     /*
2048      * Do TLS callbacks first and then call the init/term function if it's a DLL.
2049      */
2050     if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
2051         rc = kldrModLXDoCallDLL(pModLX, pvMapping, 0 /* attach */, uHandle);
2052     else
2053         rc = 0;
2054     return rc;
2055 }
2056 
2057 
2058 /**
2059  * Call the DLL entrypoint.
2060  *
2061  * @returns 0 on success.
2062  * @returns KLDR_ERR_MODULE_INIT_FAILED  or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
2063  * @param   pModLX          The LX module interpreter instance.
2064  * @param   pvMapping       The module mapping to use (resolved).
2065  * @param   uOp             The operation (DLL_*).
2066  * @param   uHandle         The module handle to present.
2067  */
kldrModLXDoCallDLL(PKLDRMODLX pModLX,void * pvMapping,unsigned uOp,KUPTR uHandle)2068 static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle)
2069 {
2070     int rc;
2071 
2072     /*
2073      * If no entrypoint there isn't anything to be done.
2074      */
2075     if (    !pModLX->Hdr.e32_startobj
2076         ||  pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
2077         return 0;
2078 
2079     /*
2080      * Invoke the entrypoint and convert the boolean result to a kLdr status code.
2081      */
2082     rc = kldrModLXDoCall((KUPTR)pvMapping
2083                          + (KUPTR)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
2084                          + pModLX->Hdr.e32_eip,
2085                          uHandle, uOp, NULL);
2086     if (rc)
2087         rc = 0;
2088     else if (uOp == 0 /* attach */)
2089         rc = KLDR_ERR_MODULE_INIT_FAILED;
2090     else /* detach: ignore failures */
2091         rc = 0;
2092     return rc;
2093 }
2094 
2095 
2096 /**
2097  * Do a 3 parameter callback.
2098  *
2099  * @returns 32-bit callback return.
2100  * @param   uEntrypoint     The address of the function to be called.
2101  * @param   uHandle         The first argument, the module handle.
2102  * @param   uOp             The second argumnet, the reason we're calling.
2103  * @param   pvReserved      The third argument, reserved argument. (figure this one out)
2104  */
kldrModLXDoCall(KUPTR uEntrypoint,KUPTR uHandle,KU32 uOp,void * pvReserved)2105 static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved)
2106 {
2107 #if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
2108     KI32 rc;
2109 /** @todo try/except */
2110 
2111     /*
2112      * Paranoia.
2113      */
2114 # ifdef __GNUC__
2115     __asm__ __volatile__(
2116         "pushl  %2\n\t"
2117         "pushl  %1\n\t"
2118         "pushl  %0\n\t"
2119         "lea   12(%%esp), %2\n\t"
2120         "call  *%3\n\t"
2121         "movl   %2, %%esp\n\t"
2122         : "=a" (rc)
2123         : "d" (uOp),
2124           "S" (0),
2125           "c" (uEntrypoint),
2126           "0" (uHandle));
2127 # elif defined(_MSC_VER)
2128     __asm {
2129         mov     eax, [uHandle]
2130         mov     edx, [uOp]
2131         mov     ecx, 0
2132         mov     ebx, [uEntrypoint]
2133         push    edi
2134         mov     edi, esp
2135         push    ecx
2136         push    edx
2137         push    eax
2138         call    ebx
2139         mov     esp, edi
2140         pop     edi
2141         mov     [rc], eax
2142     }
2143 # else
2144 #  error "port me!"
2145 # endif
2146     K_NOREF(pvReserved);
2147     return rc;
2148 
2149 #else
2150     K_NOREF(uEntrypoint);
2151     K_NOREF(uHandle);
2152     K_NOREF(uOp);
2153     K_NOREF(pvReserved);
2154     return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
2155 #endif
2156 }
2157 
2158 
2159 /** @copydoc kLdrModCallTerm */
kldrModLXCallTerm(PKLDRMOD pMod,void * pvMapping,KUPTR uHandle)2160 static int kldrModLXCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
2161 {
2162     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
2163 
2164     /*
2165      * Mapped?
2166      */
2167     if (pvMapping == KLDRMOD_INT_MAP)
2168     {
2169         pvMapping = (void *)pModLX->pvMapping;
2170         if (!pvMapping)
2171             return KLDR_ERR_NOT_MAPPED;
2172     }
2173 
2174     /*
2175      * Do the call.
2176      */
2177     if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
2178         kldrModLXDoCallDLL(pModLX, pvMapping, 1 /* detach */, uHandle);
2179 
2180     return 0;
2181 }
2182 
2183 
2184 /** @copydoc kLdrModCallThread */
kldrModLXCallThread(PKLDRMOD pMod,void * pvMapping,KUPTR uHandle,unsigned fAttachingOrDetaching)2185 static int kldrModLXCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching)
2186 {
2187     /* no thread attach/detach callout. */
2188     K_NOREF(pMod);
2189     K_NOREF(pvMapping);
2190     K_NOREF(uHandle);
2191     K_NOREF(fAttachingOrDetaching);
2192     return 0;
2193 }
2194 
2195 
2196 /** @copydoc kLdrModSize */
kldrModLXSize(PKLDRMOD pMod)2197 static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
2198 {
2199     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
2200     return pModLX->cbMapped;
2201 }
2202 
2203 
2204 /** @copydoc kLdrModGetBits */
kldrModLXGetBits(PKLDRMOD pMod,void * pvBits,KLDRADDR BaseAddress,PFNKLDRMODGETIMPORT pfnGetImport,void * pvUser)2205 static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2206 {
2207     PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
2208     int         rc;
2209 
2210     /*
2211      * Load the image bits.
2212      */
2213     rc = kldrModLXDoLoadBits(pModLX, pvBits);
2214     if (rc)
2215         return rc;
2216 
2217     /*
2218      * Perform relocations.
2219      */
2220     return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
2221 
2222 }
2223 
2224 
2225 /** @copydoc kLdrModRelocateBits */
kldrModLXRelocateBits(PKLDRMOD pMod,void * pvBits,KLDRADDR NewBaseAddress,KLDRADDR OldBaseAddress,PFNKLDRMODGETIMPORT pfnGetImport,void * pvUser)2226 static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
2227                                  PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2228 {
2229     PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
2230     KU32 iSeg;
2231     int rc;
2232 
2233     /*
2234      * Do we need to to *anything*?
2235      */
2236     if (    NewBaseAddress == OldBaseAddress
2237         &&  NewBaseAddress == pModLX->paObjs[0].o32_base
2238         &&  !pModLX->Hdr.e32_impmodcnt)
2239         return 0;
2240 
2241     /*
2242      * Load the fixup section.
2243      */
2244     if (!pModLX->pbFixupSection)
2245     {
2246         rc = kldrModLXDoLoadFixupSection(pModLX);
2247         if (rc)
2248             return rc;
2249     }
2250 
2251     /*
2252      * Iterate the segments.
2253      */
2254     for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
2255     {
2256         const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
2257         KLDRADDR        PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA;
2258         KU32            iPage;
2259         KU8            *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[iSeg].RVA;
2260 
2261         /*
2262          * Iterate the page map pages.
2263          */
2264         for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
2265         {
2266             const KU8 * const   pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
2267             const KU8          *pb            = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
2268             KLDRADDR            uValue        = NIL_KLDRADDR;
2269             KU32                fKind         = 0;
2270             int                 iSelector;
2271 
2272             /* sanity */
2273             if (pbFixupRecEnd < pb)
2274                 return KLDR_ERR_BAD_FIXUP;
2275             if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
2276                 return KLDR_ERR_BAD_FIXUP;
2277             if (pb < pModLX->pbFixupSection)
2278                 return KLDR_ERR_BAD_FIXUP;
2279 
2280             /*
2281              * Iterate the fixup record.
2282              */
2283             while (pb < pbFixupRecEnd)
2284             {
2285                 union _rel
2286                 {
2287                     const KU8 *             pb;
2288                     const struct r32_rlc   *prlc;
2289                 } u;
2290 
2291                 u.pb = pb;
2292                 pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
2293 
2294                 /*
2295                  * Figure out the target.
2296                  */
2297                 switch (u.prlc->nr_flags & NRRTYP)
2298                 {
2299                     /*
2300                      * Internal fixup.
2301                      */
2302                     case NRRINT:
2303                     {
2304                         KU16 iTrgObject;
2305                         KU32 offTrgObject;
2306 
2307                         /* the object */
2308                         if (u.prlc->nr_flags & NR16OBJMOD)
2309                         {
2310                             iTrgObject = *(const KU16 *)pb;
2311                             pb += 2;
2312                         }
2313                         else
2314                             iTrgObject = *pb++;
2315                         iTrgObject--;
2316                         if (iTrgObject >= pModLX->Hdr.e32_objcnt)
2317                             return KLDR_ERR_BAD_FIXUP;
2318 
2319                         /* the target */
2320                         if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
2321                         {
2322                             if (u.prlc->nr_flags & NR32BITOFF)
2323                             {
2324                                 offTrgObject = *(const KU32 *)pb;
2325                                 pb += 4;
2326                             }
2327                             else
2328                             {
2329                                 offTrgObject = *(const KU16 *)pb;
2330                                 pb += 2;
2331                             }
2332 
2333                             /* calculate the symbol info. */
2334                             uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
2335                         }
2336                         else
2337                             uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
2338                         if (    (u.prlc->nr_stype & NRALIAS)
2339                             ||  (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT))
2340                             iSelector = pMod->aSegments[iTrgObject].Sel16bit;
2341                         else
2342                             iSelector = pMod->aSegments[iTrgObject].SelFlat;
2343                         fKind = 0;
2344                         break;
2345                     }
2346 
2347                     /*
2348                      * Import by symbol ordinal.
2349                      */
2350                     case NRRORD:
2351                     {
2352                         KU16 iModule;
2353                         KU32 iSymbol;
2354 
2355                         /* the module ordinal */
2356                         if (u.prlc->nr_flags & NR16OBJMOD)
2357                         {
2358                             iModule = *(const KU16 *)pb;
2359                             pb += 2;
2360                         }
2361                         else
2362                             iModule = *pb++;
2363                         iModule--;
2364                         if (iModule >= pModLX->Hdr.e32_impmodcnt)
2365                             return KLDR_ERR_BAD_FIXUP;
2366 #if 1
2367                         if (u.prlc->nr_flags & NRICHAIN)
2368                             return KLDR_ERR_BAD_FIXUP;
2369 #endif
2370 
2371                         /* . */
2372                         if (u.prlc->nr_flags & NR32BITOFF)
2373                         {
2374                             iSymbol = *(const KU32 *)pb;
2375                             pb += 4;
2376                         }
2377                         else if (!(u.prlc->nr_flags & NR8BITORD))
2378                         {
2379                             iSymbol = *(const KU16 *)pb;
2380                             pb += 2;
2381                         }
2382                         else
2383                             iSymbol = *pb++;
2384 
2385                         /* resolve it. */
2386                         rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser);
2387                         if (rc)
2388                             return rc;
2389                         iSelector = -1;
2390                         break;
2391                     }
2392 
2393                     /*
2394                      * Import by symbol name.
2395                      */
2396                     case NRRNAM:
2397                     {
2398                         KU32 iModule;
2399                         KU16 offSymbol;
2400                         const KU8 *pbSymbol;
2401 
2402                         /* the module ordinal */
2403                         if (u.prlc->nr_flags & NR16OBJMOD)
2404                         {
2405                             iModule = *(const KU16 *)pb;
2406                             pb += 2;
2407                         }
2408                         else
2409                             iModule = *pb++;
2410                         iModule--;
2411                         if (iModule >= pModLX->Hdr.e32_impmodcnt)
2412                             return KLDR_ERR_BAD_FIXUP;
2413 #if 1
2414                         if (u.prlc->nr_flags & NRICHAIN)
2415                             return KLDR_ERR_BAD_FIXUP;
2416 #endif
2417 
2418                         /* . */
2419                         if (u.prlc->nr_flags & NR32BITOFF)
2420                         {
2421                             offSymbol = *(const KU32 *)pb;
2422                             pb += 4;
2423                         }
2424                         else if (!(u.prlc->nr_flags & NR8BITORD))
2425                         {
2426                             offSymbol = *(const KU16 *)pb;
2427                             pb += 2;
2428                         }
2429                         else
2430                             offSymbol = *pb++;
2431                         pbSymbol = pModLX->pbImportProcs + offSymbol;
2432                         if (    pbSymbol < pModLX->pbImportProcs
2433                             ||  pbSymbol > pModLX->pbFixupSectionLast)
2434                             return KLDR_ERR_BAD_FIXUP;
2435 
2436                         /* resolve it. */
2437                         rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL,
2438                                           &uValue, &fKind, pvUser);
2439                         if (rc)
2440                             return rc;
2441                         iSelector = -1;
2442                         break;
2443                     }
2444 
2445                     case NRRENT:
2446                         KLDRMODLX_ASSERT(!"NRRENT");
2447                         /* Falls through. */
2448                     default:
2449                         iSelector = -1;
2450                         break;
2451                 }
2452 
2453                 /* addend */
2454                 if (u.prlc->nr_flags & NRADD)
2455                 {
2456                     if (u.prlc->nr_flags & NR32BITADD)
2457                     {
2458                         uValue += *(const KU32 *)pb;
2459                         pb += 4;
2460                     }
2461                     else
2462                     {
2463                         uValue += *(const KU16 *)pb;
2464                         pb += 2;
2465                     }
2466                 }
2467 
2468 
2469                 /*
2470                  * Deal with the 'source' (i.e. the place that should be modified - very logical).
2471                  */
2472                 if (!(u.prlc->nr_stype & NRCHAIN))
2473                 {
2474                     int off = u.prlc->r32_soff;
2475 
2476                     /* common / simple */
2477                     if (    (u.prlc->nr_stype & NRSRCMASK) == NROFF32
2478                         &&  off >= 0
2479                         &&  off <= (int)OBJPAGELEN - 4)
2480                         *(KU32 *)&pbPage[off] = (KU32)uValue;
2481                     else if (    (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
2482                             &&  off >= 0
2483                             &&  off <= (int)OBJPAGELEN - 4)
2484                         *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4));
2485                     else
2486                     {
2487                         /* generic */
2488                         rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2489                         if (rc)
2490                             return rc;
2491                     }
2492                 }
2493                 else if (!(u.prlc->nr_flags & NRICHAIN))
2494                 {
2495                     const KI16 *poffSrc = (const KI16 *)pb;
2496                     KU8 c = u.pb[2];
2497 
2498                     /* common / simple */
2499                     if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
2500                     {
2501                         while (c-- > 0)
2502                         {
2503                             int off = *poffSrc++;
2504                             if (off >= 0 && off <= (int)OBJPAGELEN - 4)
2505                                 *(KU32 *)&pbPage[off] = (KU32)uValue;
2506                             else
2507                             {
2508                                 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2509                                 if (rc)
2510                                     return rc;
2511                             }
2512                         }
2513                     }
2514                     else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
2515                     {
2516                         while (c-- > 0)
2517                         {
2518                             int off = *poffSrc++;
2519                             if (off >= 0 && off <= (int)OBJPAGELEN - 4)
2520                                 *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4));
2521                             else
2522                             {
2523                                 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2524                                 if (rc)
2525                                     return rc;
2526                             }
2527                         }
2528                     }
2529                     else
2530                     {
2531                         while (c-- > 0)
2532                         {
2533                             rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
2534                             if (rc)
2535                                 return rc;
2536                         }
2537                     }
2538                     pb = (const KU8 *)poffSrc;
2539                 }
2540                 else
2541                 {
2542                     /* This is a pain because it will require virgin pages on a relocation. */
2543                     KLDRMODLX_ASSERT(!"NRICHAIN");
2544                     return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED;
2545                 }
2546             }
2547         }
2548     }
2549 
2550     return 0;
2551 }
2552 
2553 
2554 /**
2555  * Applies the relocation to one 'source' in a page.
2556  *
2557  * This takes care of the more esotic case while the common cases
2558  * are dealt with seperately.
2559  *
2560  * @returns 0 on success, non-zero kLdr status code on failure.
2561  * @param   pbPage      The page in which to apply the fixup.
2562  * @param   off         Page relative offset of where to apply the offset.
2563  * @param   uValue      The target value.
2564  * @param   fKind       The target kind.
2565  */
kldrModLXDoReloc(KU8 * pbPage,int off,KLDRADDR PageAddress,const struct r32_rlc * prlc,int iSelector,KLDRADDR uValue,KU32 fKind)2566 static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
2567                             int iSelector, KLDRADDR uValue, KU32 fKind)
2568 {
2569 #pragma pack(1) /* just to be sure */
2570     union
2571     {
2572         KU8         ab[6];
2573         KU32        off32;
2574         KU16        off16;
2575         KU8         off8;
2576         struct
2577         {
2578             KU16    off;
2579             KU16    Sel;
2580         }           Far16;
2581         struct
2582         {
2583             KU32    off;
2584             KU16    Sel;
2585         }           Far32;
2586     }               uData;
2587 #pragma pack()
2588     const KU8      *pbSrc;
2589     KU8            *pbDst;
2590     KU8             cb;
2591 
2592     K_NOREF(fKind);
2593 
2594     /*
2595      * Compose the fixup data.
2596      */
2597     switch (prlc->nr_stype & NRSRCMASK)
2598     {
2599         case NRSBYT:
2600             uData.off8 = (KU8)uValue;
2601             cb = 1;
2602             break;
2603         case NRSSEG:
2604             if (iSelector == -1)
2605             {
2606                 /* fixme */
2607             }
2608             uData.off16 = iSelector;
2609             cb = 2;
2610             break;
2611         case NRSPTR:
2612             if (iSelector == -1)
2613             {
2614                 /* fixme */
2615             }
2616             uData.Far16.off = (KU16)uValue;
2617             uData.Far16.Sel = iSelector;
2618             cb = 4;
2619             break;
2620         case NRSOFF:
2621             uData.off16 = (KU16)uValue;
2622             cb = 2;
2623             break;
2624         case NRPTR48:
2625             if (iSelector == -1)
2626             {
2627                 /* fixme */
2628             }
2629             uData.Far32.off = (KU32)uValue;
2630             uData.Far32.Sel = iSelector;
2631             cb = 6;
2632             break;
2633         case NROFF32:
2634             uData.off32 = (KU32)uValue;
2635             cb = 4;
2636             break;
2637         case NRSOFF32:
2638             uData.off32 = (KU32)(uValue - (PageAddress + off + 4));
2639             cb = 4;
2640             break;
2641         default:
2642             return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */
2643     }
2644 
2645     /*
2646      * Apply it. This is sloooow...
2647      */
2648     pbSrc = &uData.ab[0];
2649     pbDst = pbPage + off;
2650     while (cb-- > 0)
2651     {
2652         if (off > (int)OBJPAGELEN)
2653             break;
2654         if (off >= 0)
2655             *pbDst = *pbSrc;
2656         pbSrc++;
2657         pbDst++;
2658     }
2659 
2660     return 0;
2661 }
2662 
2663 
2664 /**
2665  * The LX module interpreter method table.
2666  */
2667 KLDRMODOPS g_kLdrModLXOps =
2668 {
2669     "LX",
2670     NULL,
2671     kldrModLXCreate,
2672     kldrModLXDestroy,
2673     kldrModLXQuerySymbol,
2674     kldrModLXEnumSymbols,
2675     kldrModLXGetImport,
2676     kldrModLXNumberOfImports,
2677     NULL /* can execute one is optional */,
2678     kldrModLXGetStackInfo,
2679     kldrModLXQueryMainEntrypoint,
2680     NULL /* pfnQueryImageUuid */,
2681     NULL /* fixme */,
2682     NULL /* fixme */,
2683     kldrModLXEnumDbgInfo,
2684     kldrModLXHasDbgInfo,
2685     kldrModLXMap,
2686     kldrModLXUnmap,
2687     kldrModLXAllocTLS,
2688     kldrModLXFreeTLS,
2689     kldrModLXReload,
2690     kldrModLXFixupMapping,
2691     kldrModLXCallInit,
2692     kldrModLXCallTerm,
2693     kldrModLXCallThread,
2694     kldrModLXSize,
2695     kldrModLXGetBits,
2696     kldrModLXRelocateBits,
2697     NULL /* fixme: pfnMostlyDone */,
2698     42 /* the end */
2699 };
2700 
2701