source: trunk/kLdr/kLdrModLX.c@ 2889

Last change on this file since 2889 was 2889, checked in by bird, 19 years ago

started on fixups.

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