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

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

kHlp work...

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