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