source: trunk/kLdr/kLdrModLX.c@ 2888

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

fixupsection loading.

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