source: trunk/kLdr/kLdrModLX.c@ 3232

Last change on this file since 3232 was 2981, checked in by bird, 18 years ago

Implemented symbol enumeration.

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