VirtualBox

source: kStuff/trunk/kLdr/kLdrModLX.c@ 120

Last change on this file since 120 was 117, checked in by bird, 5 years ago

kLdrModNative: Added KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM to allow kWorker to re-init mspdb100.dll when _MSPDBSRV_ENDPOINT_ changes.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette